/*
   Copyright (C) 1998 T. Scott Dattalo

This file is part of gpsim.

gpsim is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

gpsim is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with gpasm; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

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

#include "../config.h"
#include "pic-processor.h"
#include "14bit-instructions.h"
#include "registers.h"
#include "symbol.h"
#include "xref.h"


instruction::instruction(Processor *pProcessor,
			 unsigned int uOpCode, 
			 unsigned int uAddrOfInstr)
  : gpsimValue(pProcessor),
    m_bIsModified(false),
    cycle_count(0),
    opcode(uOpCode), 
    m_uAddrOfInstr(uAddrOfInstr),
    file_id(-1),
    hll_file_id(-1),
    src_line(-1),
    lst_line(-1),
    hll_src_line(-1)
{
}

void instruction::decode(Processor *new_cpu, unsigned int new_opcode)
{
  cpu = new_cpu;
  opcode = new_opcode;
}

void invalid_instruction::execute(void)  
{ 
  //cout << "*** INVALID INSTRUCTION ***\n";
#ifdef __DEBUG_VERBOSE__
  debug();
#endif

  /* Don't know what to do, so just plow through like nothing happened */
  if(cpu_pic)
    cpu_pic->pc->increment();

};

invalid_instruction::invalid_instruction(Processor *new_cpu,unsigned int new_opcode)
  : instruction(new_cpu,new_opcode,0)
{
  new_name("INVALID");
}

invalid_instruction::invalid_instruction(Processor *new_cpu,
                                         unsigned int address, 
                                         unsigned int new_opcode)
  : instruction(new_cpu,new_opcode,address)
{
  new_name("INVALID");
}

// Instantiate an invalid instruction
invalid_instruction bad_instruction;


//------------------------------------------------------------------------
void instruction::add_line_number_symbol(int address)
{

  symbol_table.add_line_number(address);

}
//------------------------------------------------------------------------
// update_line_number(int file, int sline, int lline, int hllfile, int hllsline)
// 
// map the instruction to the source file that generated it.
// If a line number is less than 0, then this means that the
// existing mapping should remain unchanged. This allows this 
// method to be called multiple times; once for each type of
// mapping.

void instruction::update_line_number(int file, int sline, int lline, int hllfile, int hllsline)
{
  file_id      = file<0     ? file_id      : file;
  src_line     = sline<0    ? src_line     : sline;
  lst_line     = lline<0    ? lst_line     : lline;
  hll_src_line = hllsline<0 ? hll_src_line : hllsline;
  hll_file_id  = hllfile<0  ? hll_file_id  : hllfile;
}
char *instruction::ReadSrcLine(char *buf, int nBytes)
{
  if (buf && nBytes && cpu)
    return ((Processor *)cpu)->files.ReadLine(file_id,src_line,buf,nBytes);

  return buf;
}
char *instruction::ReadHLLLine(char *buf, int nBytes)
{
  if (buf && nBytes && cpu)
    return ((Processor *)cpu)->files.ReadLine(hll_file_id,hll_src_line,buf,nBytes);

  return buf;
}

char *instruction::ReadLstLine(char *buf, int nBytes)
{
  if (buf && nBytes && cpu)
    return ((Processor *)cpu)->files.ReadLine(((Processor *)cpu)->files.list_id(),lst_line,buf,nBytes);

  return buf;
}

//------------------------------------------------------------------------
AliasedInstruction::AliasedInstruction(instruction *_replaced)
  : instruction(0,0,0), m_replaced(_replaced)
{
}

AliasedInstruction::AliasedInstruction()
  : instruction(0,0,0), m_replaced(0)
{
}

AliasedInstruction::AliasedInstruction(Processor *pProcessor, 
		     unsigned int uOpCode, 
		     unsigned int uAddrOfInstr)
  : instruction(pProcessor, uOpCode, uAddrOfInstr), 
    m_replaced(0)
{
}

void AliasedInstruction::setReplaced(instruction *_replaced)
{
  if (!m_replaced)
    m_replaced = _replaced;
}

instruction * AliasedInstruction::getReplaced()
{
  return m_replaced ? m_replaced : &bad_instruction;
}

void AliasedInstruction::execute()
{
  getReplaced()->execute();
}
void AliasedInstruction::debug()
{
  getReplaced()->debug();
}
int AliasedInstruction::instruction_size()
{
  return getReplaced()->instruction_size();
}
unsigned int AliasedInstruction::get_opcode()
{
  return getReplaced()->get_opcode();
}
unsigned int AliasedInstruction::get_value()
{
  return getReplaced()->get_value();
}
void AliasedInstruction::put_value(unsigned int new_value)
{
  getReplaced()->put_value(new_value);
}
int AliasedInstruction::get_src_line()
{
  return getReplaced()->get_src_line();
}
int AliasedInstruction::get_hll_src_line()
{
  return getReplaced()->get_hll_src_line();
}
int AliasedInstruction::get_lst_line()
{
  return getReplaced()->get_lst_line();
}
int AliasedInstruction::get_file_id()
{
  return getReplaced()->get_file_id();
}
int AliasedInstruction::get_hll_file_id()
{
  return getReplaced()->get_hll_file_id();
}
enum instruction::INSTRUCTION_TYPES AliasedInstruction::isa()
{
  return getReplaced()->isa();
}
void AliasedInstruction::initialize(bool init_state)
{
  getReplaced()->initialize(init_state);
}
char *AliasedInstruction::name(char *cPtr,int len)
{
  return getReplaced()->name(cPtr,len);
}
void AliasedInstruction::update(void)
{
  getReplaced()->update();
}
void AliasedInstruction::add_xref(void *an_xref)
{
  getReplaced()->add_xref(an_xref);
}
void AliasedInstruction::remove_xref(void *an_xref)
{
  getReplaced()->remove_xref(an_xref);
}
bool AliasedInstruction::isBase()
{
  return getReplaced()->isBase();
}


//------------------------------------------------------------------------
Literal_op::Literal_op(Processor *pProcessor, 
		       unsigned int uOpCode, 
		       unsigned int uAddrOfInstr)
  : instruction(pProcessor, uOpCode, uAddrOfInstr),
    L(uOpCode&0xff)
{
}
char *Literal_op::name(char *return_str,int len)
{

  snprintf(return_str,len,"%s\t0x%02x",
	   gpsimValue::name().c_str(),L);

  return(return_str);
}

void Literal_op::decode(Processor *new_cpu, unsigned int new_opcode)
{
  opcode = new_opcode;
  cpu = new_cpu;
  L = opcode & 0xff;
}

Bit_op::Bit_op(Processor *pProcessor, 
		       unsigned int uOpCode, 
		       unsigned int uAddrOfInstr)
  : instruction(pProcessor, uOpCode, uAddrOfInstr),
    mask(0),register_address(0),
    access(false),
    reg(0)
{
}

void Bit_op::decode(Processor *new_cpu, unsigned int new_opcode)
{
  opcode = new_opcode;

  cpu = new_cpu;
  switch(cpu_pic->base_isa())
    {
    case _16BIT_PROCESSOR_:
      switch(cpu_pic->isa()) {
        case  _P18Cxx2_:
	case  _P18C2x2_:
	case  _P18C242_:
	case  _P18C252_:
	case  _P18C442_:
	case  _P18C452_:
	case  _P18F242_:
	case  _P18F252_:
	case  _P18F442_:
	case  _P18F248_:
	case  _P18F448_:
	case  _P18F452_:
	case  _P18F1220_:
	case  _P18F1320_:
          mask = 1 << ((opcode >> 9) & 7);
          register_address = opcode & REG_MASK_16BIT;
		  access = (opcode & ACCESS_MASK_16BIT) ? true : false;
          if((!access) && (opcode & 0x80))
	    register_address |= 0xf00;

          break;
	case _P17C7xx_:
	case _P17C75x_:
	case _P17C756_:
	case _P17C756A_:
	case _P17C762_:
	case _P17C766_:
          mask = 1 << ((opcode >> 8) & 7);
          register_address = opcode & REG_MASK_16BIT;
          access = 0;
	  break;

	default:
          cout << "ERROR: (Bit_op) the processor is not defined\n";
	  break;
      }
      break;

    case _14BIT_PROCESSOR_:
      mask = 1 << ((opcode >> 7) & 7);
      register_address = opcode & REG_MASK_14BIT;
      access = 1;
      break;

    case _12BIT_PROCESSOR_:
      mask = 1 << ((opcode >> 5) & 7);
      register_address = opcode & REG_MASK_12BIT;
      access = 1;
      break;
    default:
      cout << "ERROR: (Bit_op) the processor has a bad base type\n";
    }


}

char * Bit_op::name(char *return_str,int len)
{
  //  %%% FIX ME %%% Actually just a slight dilemma - the source register will always be in
  //                 the lower bank of memory...

  reg = get_cpu()->registers[register_address];

  unsigned int bit;

  switch(cpu_pic->base_isa())
    {
    case _16BIT_PROCESSOR_:
      bit = ((opcode >> 9) & 7);
      snprintf(return_str,len,"%s\t%s,%d,%c",
	       gpsimValue::name().c_str(),
	       reg->name().c_str(), 
	       bit,
	       access ? '1' : '0');

      return(return_str);
      break;

    case _14BIT_PROCESSOR_:
      bit = ((opcode >> 7) & 7);
      break;

    case _12BIT_PROCESSOR_:
      bit = ((opcode >> 5) & 7);
      break;
    default:
      bit = 0;
    }


  snprintf(return_str,len,"%s\t%s,%d",
	   gpsimValue::name().c_str(),
	   reg->name().c_str(),
	   bit);

  return(return_str);
}


//----------------------------------------------------------------
Register_op::Register_op(Processor *pProcessor, 
		       unsigned int uOpCode, 
		       unsigned int uAddrOfInstr)
  : instruction(pProcessor, uOpCode, uAddrOfInstr),
    register_address(0),
    destination(false), access(false)
{
}

//----------------------------------------------------------------
//
// Register_op::name
//

char * Register_op::name(char *return_str,int len)
{
  //  %%% FIX ME %%% Actually just a slight dilemma - the source register will always be in
  //                 the lower bank of memory (for the 12 and 14 bit cores).

  source = get_cpu()->registers[register_address];

  if(cpu_pic->base_isa() != _16BIT_PROCESSOR_)
    snprintf(return_str,len,"%s\t%s,%c",
	     gpsimValue::name().c_str(),
	     source->name().c_str(),
	     destination ? 'f' : 'w');
  else
    snprintf(return_str,len,"%s\t%s,%c,%c",
	     gpsimValue::name().c_str(),
	     source->name().c_str(), 
	     destination ? 'f' : 'w',
	     access ? '1' : '0');

  return(return_str);
}

//----------------------------------------------------------------
//
// Register_op::decode
//
// Base class to decode all 'register' type instructions. The main thing
// it does is obtains the register's address from the opcode. Note that this
// is processor dependent: in the 12-bit core processors, the register address
// is the lower 5 bits while in the 14-bit core it's the lower 7.

void  Register_op::decode(Processor *new_cpu, unsigned int new_opcode)
{ 
  opcode = new_opcode;
  cpu = new_cpu;

  switch(cpu_pic->base_isa())
    {
    case _16BIT_PROCESSOR_:
		destination = (opcode & DESTINATION_MASK_16BIT) ? true : false;
		access = (opcode & ACCESS_MASK_16BIT) ? true : false;
      register_address = opcode & REG_MASK_16BIT;
      if((!access) && (opcode & 0x80))
	register_address |= 0xf00;

      break;

    case _14BIT_PROCESSOR_:
      register_address = opcode & REG_MASK_14BIT;
	  destination = (opcode & DESTINATION_MASK_14BIT) ? true : false;
      access = 1;
      break;

    case _12BIT_PROCESSOR_:
      register_address = opcode & REG_MASK_12BIT;
	  destination = (opcode & DESTINATION_MASK_12BIT) ? true : false;
      access = 1;
      break;

    default:
      cout << "ERROR: (Register_op) the processor has a bad base type\n";
    }

}



Register * Register_op::source = 0;

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

ADDWF::ADDWF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{

  decode(new_cpu, new_opcode);
  new_name("addwf");

}

void ADDWF::execute(void)
{
  unsigned int new_value,src_value,w_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  new_value = (src_value = source->get()) + (w_value = cpu_pic->W->value.get());

  // Store the result

  if(destination)
    source->put(new_value & 0xff);      // Result goes to source
  else
    cpu_pic->W->put(new_value & 0xff);

  cpu_pic->status->put_Z_C_DC(new_value, src_value, w_value);

  cpu_pic->pc->increment();

}

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

ANDLW::ANDLW (Processor *new_cpu, unsigned int new_opcode)
  : Literal_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("andlw");
}

void ANDLW::execute(void)
{
  unsigned int new_value;

  new_value = cpu_pic->W->value.get() & L;

  cpu_pic->W->put(new_value);
  cpu_pic->status->put_Z(0==new_value);

  cpu_pic->pc->increment();

}

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

ANDWF::ANDWF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{

  decode(new_cpu, new_opcode);
  new_name("andwf");

}

void ANDWF::execute(void)
{
  unsigned int new_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  new_value = source->get() & cpu_pic->W->value.get();

  if(destination)
    source->put(new_value);      // Result goes to source
  else
    cpu_pic->W->put(new_value);

  cpu_pic->status->put_Z(0==new_value);

  cpu_pic->pc->increment();

}


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

BCF::BCF (Processor *new_cpu, unsigned int new_opcode)
  : Bit_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  mask ^= 0xff;        // decode initializes the mask to 1<<bit
  new_name("bcf");
}

void BCF::execute(void)
{

  if(!access)
    reg = cpu_pic->registers[register_address];
  else
    reg = cpu_pic->register_bank[register_address];

  reg->put(reg->get() & mask);

  cpu_pic->pc->increment();

}

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

BSF::BSF (Processor *new_cpu, unsigned int new_opcode)
  : Bit_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("bsf");
}

void BSF::execute(void)
{

  if(!access)
    reg = cpu_pic->registers[register_address];
  else
    reg = cpu_pic->register_bank[register_address];

  reg->put(reg->get() | mask);


  cpu_pic->pc->increment();

}

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

BTFSC::BTFSC (Processor *new_cpu, unsigned int new_opcode)
  : Bit_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("btfsc");
}

void BTFSC::execute(void)
{

  if(!access)
    reg = cpu_pic->registers[register_address];
  else
    reg = cpu_pic->register_bank[register_address];

  unsigned int result = mask & reg->get();

  if(!result)
    cpu_pic->pc->skip();                  // Skip next instruction

  cpu_pic->pc->increment();

}

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

BTFSS::BTFSS (Processor *new_cpu, unsigned int new_opcode)
  : Bit_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("btfss");
}

void BTFSS::execute(void)
{

  if(!access)
    reg = cpu_pic->registers[register_address];
  else
    reg = cpu_pic->register_bank[register_address];

  unsigned int result = mask & reg->get();

  if(result)
    cpu_pic->pc->skip();                  // Skip next instruction

  cpu_pic->pc->increment();

}

//--------------------------------------------------
CALL::CALL (Processor *new_cpu, unsigned int new_opcode)
  : instruction(new_cpu, new_opcode, 0)
{

  switch(cpu_pic->base_isa())
    {
    case _14BIT_PROCESSOR_:
      destination = opcode&0x7ff;
      break;

    case _12BIT_PROCESSOR_:
      destination = opcode&0xff;
      break;
    default:
      cout << "ERROR: (Bit_op) the processor has a bad base type\n";
    }

  new_name("call");
}

void CALL::execute(void)
{

  cpu_pic->stack->push(cpu_pic->pc->get_next());

  cpu_pic->pc->jump(cpu_pic->get_pclath_branching_jump() | destination);

}

char * CALL::name(char *return_str,int len)
{

  snprintf(return_str,len,"%s\t0x%04x",
	   gpsimValue::name().c_str(),
	   destination);

  return(return_str);
}


//--------------------------------------------------
CLRF::CLRF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);

  new_name("clrf");
}

void CLRF::execute(void)
{

  if(!access)
    cpu_pic->registers[register_address]->put(0);
  else
    cpu_pic->register_bank[register_address]->put(0);

  cpu_pic->status->put_Z(1);

  cpu_pic->pc->increment();
}

char * CLRF::name(char *return_str,int len)
{

  snprintf(return_str,len,"%s\t%s",
	   gpsimValue::name().c_str(),
	   get_cpu()->registers[register_address]->name().c_str());

  return(return_str);
}


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

CLRW::CLRW (Processor *new_cpu, unsigned int new_opcode)
  : instruction(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("clrw");
}

void CLRW::execute(void)
{

  cpu_pic->W->put(0);

  cpu_pic->status->put_Z(1);
  cpu_pic->pc->increment();

}

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

CLRWDT::CLRWDT (Processor *new_cpu, unsigned int new_opcode)
  : instruction(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("clrwdt");
}

void CLRWDT::execute(void)
{


  cpu_pic->wdt.clear();

  cpu_pic->status->put_TO(1);
  cpu_pic->status->put_PD(1);
  cpu_pic->pc->increment();

}

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

COMF::COMF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("comf");
}

void COMF::execute(void)
{
  unsigned int new_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  new_value = source->get() ^ 0xff;

  if(destination)
    source->put(new_value);      // Result goes to source
  else
    cpu_pic->W->put(new_value);

  cpu_pic->status->put_Z(0==new_value);

  cpu_pic->pc->increment();

}

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

DECF::DECF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("decf");
}

void DECF::execute(void)
{
  unsigned int new_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  new_value = (source->get() - 1)&0xff;

  if(destination)
    source->put(new_value);      // Result goes to source
  else
    cpu_pic->W->put(new_value);

  cpu_pic->status->put_Z(0==new_value);

  cpu_pic->pc->increment();

}

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

DECFSZ::DECFSZ (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("decfsz");
}

void DECFSZ::execute(void)
{
  unsigned int new_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  new_value = (source->get() - 1)&0xff;

  if(destination)
    source->put(new_value);      // Result goes to source
  else
    cpu_pic->W->put(new_value);

  if(0==new_value)
    cpu_pic->pc->skip();                  // Skip next instruction

  cpu_pic->pc->increment();

}

//--------------------------------------------------
GOTO::GOTO (Processor *new_cpu, unsigned int new_opcode)
  : instruction(new_cpu, new_opcode, 0)
{

  switch(cpu_pic->base_isa())
    {
    case _14BIT_PROCESSOR_:
      destination = opcode&0x7ff;
      break;

    case _12BIT_PROCESSOR_:
      destination = opcode&0x1ff;
      break;
    default:
      cout << "ERROR: (Bit_op) the processor has a bad base type\n";
    }

  new_name("goto");
}

void GOTO::execute(void)
{

  cpu_pic->pc->jump(cpu_pic->get_pclath_branching_jump() | destination);

}

char * GOTO::name(char *return_str,int len)
{

  snprintf(return_str,len,"%s\t0x%04x",
	  gpsimValue::name().c_str(),destination);

  return(return_str);
}


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

INCF::INCF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("incf");
}

void INCF::execute(void)
{
  unsigned int new_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  new_value = (source->get() + 1)&0xff;

  // Store the result

  if(destination)
    source->put(new_value);
  else
    cpu_pic->W->put(new_value);


  cpu_pic->status->put_Z(0==new_value);

  cpu_pic->pc->increment();

}

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

INCFSZ::INCFSZ (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("incfsz");
}

void INCFSZ::execute(void)
{
  unsigned int new_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  new_value = (source->get() + 1)&0xff;

  if(destination)
    source->put(new_value);      // Result goes to source
  else
    cpu_pic->W->put(new_value);

  if(0==new_value)
    cpu_pic->pc->skip();                  // Skip next instruction

  cpu_pic->pc->increment();

}

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

IORLW::IORLW (Processor *new_cpu, unsigned int new_opcode)
  : Literal_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("iorlw");
}

void IORLW::execute(void)
{
  unsigned int new_value;

  new_value = cpu_pic->W->value.get() | L;

  cpu_pic->W->put(new_value);
  cpu_pic->status->put_Z(0==new_value);

  cpu_pic->pc->increment();

}

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

IORWF::IORWF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("iorwf");
}

void IORWF::execute(void)
{
  unsigned int new_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  new_value = source->get() | cpu_pic->W->value.get();

  if(destination)
    source->put(new_value);      // Result goes to source
  else
    cpu_pic->W->put(new_value);

  cpu_pic->status->put_Z(0==new_value);

  cpu_pic->pc->increment();

}

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

MOVLW::MOVLW (Processor *new_cpu, unsigned int new_opcode)
  : Literal_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("movlw");
}

void MOVLW::execute(void)
{

  cpu_pic->W->put(L);

  cpu_pic->pc->increment();

}

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

MOVF::MOVF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("movf");
}

void MOVF::execute(void)
{
  unsigned int source_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  source_value = source->get();

  // Store the result

  if(destination)
    source->put(source_value);
  else
    cpu_pic->W->put(source_value);


  cpu_pic->status->put_Z(0==source_value);

  cpu_pic->pc->increment();

}


void MOVF::debug(void)
{

   cout << "MOVF:  ";

}

//--------------------------------------------------
MOVWF::MOVWF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("movwf");
}

void MOVWF::execute(void)
{

  if(!access)
    cpu_pic->registers[register_address]->put(cpu_pic->W->get());
  else
    cpu_pic->register_bank[register_address]->put(cpu_pic->W->get());

  cpu_pic->pc->increment();
}

char * MOVWF::name(char *return_str, int len)
{

  snprintf(return_str,len,"%s\t%s",
	   gpsimValue::name().c_str(),
	   get_cpu()->registers[register_address]->name().c_str());

  return(return_str);
}


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

NOP::NOP (Processor *new_cpu, unsigned int new_opcode)
  : instruction(new_cpu,new_opcode,0)
{

  decode(new_cpu,new_opcode);
  new_name("nop");

  // For the 18cxxx family, this 'nop' may in fact be the
  // 2nd word in a 2-word opcode. So just to be safe, let's
  // initialize the cross references to the source file.
  // (Subsequent initialization code will overwrite this,
  // but there is a chance that this info will be accessed
  // before that occurs).
  /*
  file_id = 0;
  src_line = 0;
  lst_line = 0;
  */
}

void NOP::execute(void)
{
  cpu_pic->pc->increment();
}

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

OPTION::OPTION (Processor *new_cpu, unsigned int new_opcode)
  : instruction(new_cpu,new_opcode,0)
{
  decode(new_cpu, new_opcode);
  new_name("option");
}

void OPTION::execute(void)
{

  cpu_pic->option_reg.put(cpu_pic->W->get());

  cpu_pic->pc->increment();

}

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

RETLW::RETLW (Processor *new_cpu, unsigned int new_opcode)
  : Literal_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("retlw");
}

void RETLW::execute(void)
{

  cpu_pic->W->put(L);

  cpu_pic->pc->new_address(cpu_pic->stack->pop());

}

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

RLF::RLF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("rlf");
}

void RLF::execute(void)
{
  unsigned int new_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  new_value = (source->get() << 1) | cpu_pic->status->get_C();

  if(destination)
    source->put(new_value&0xff);      // Result goes to source
  else
    cpu_pic->W->put(new_value&0xff);

  cpu_pic->status->put_C(new_value>0xff);

  cpu_pic->pc->increment();

}

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

RRF::RRF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("rrf");
}

void RRF::execute(void)
{
  unsigned int new_value,old_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  old_value = source->get();
  new_value = (old_value >> 1) | (cpu_pic->status->get_C() ? 0x80 : 0);

  if(destination)
    source->put(new_value&0xff);      // Result goes to source
  else
    cpu_pic->W->put(new_value&0xff);

  cpu_pic->status->put_C(old_value&0x01);

  cpu_pic->pc->increment();

}

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

SLEEP::SLEEP (Processor *new_cpu, unsigned int new_opcode)
  : instruction(new_cpu,new_opcode,0)
{
  decode(new_cpu, new_opcode);
  new_name("sleep");
}

void SLEEP::execute(void)
{

  cpu_pic->enter_sleep();
  bp.set_sleep();
}

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

SUBWF::SUBWF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("subwf");
}

void SUBWF::execute(void)
{
  unsigned int new_value,src_value,w_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  new_value = (src_value = source->get()) - (w_value = cpu_pic->W->value.get());

  // Store the result

  if(destination)
    source->put(new_value & 0xff);      // Result goes to source
  else
    cpu_pic->W->put(new_value & 0xff);

  cpu_pic->status->put_Z_C_DC_for_sub(new_value, src_value, w_value);

  cpu_pic->pc->increment();

}


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

SWAPF::SWAPF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("swapf");
}

void SWAPF::execute(void)
{
  unsigned int src_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  src_value = source->get();

  if(destination)
    source->put( ((src_value >> 4) & 0x0f) | ( (src_value << 4) & 0xf0) );
  else
    cpu_pic->W->put( ((src_value >> 4) & 0x0f) | ( (src_value << 4) & 0xf0) );

  cpu_pic->pc->increment();

}


//--------------------------------------------------
TRIS::TRIS (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);

  // The TRIS instruction only uses the lower three bits to determine
  // the destination register

  register_address &= 7;

  // Furthermore, those three bits can only be 5,6, or 7

  if( (register_address > 7) || (register_address < 5))
    {
      cout << "Warning: TRIS address '" << register_address << "' is  out of range\n";

	// set the address to a 'bad value' that's
	// easy to detect at run time:
	register_address = 0;
      
    }
  else {
     if(cpu_pic->base_isa() == _14BIT_PROCESSOR_)
       register_address |= 0x80;  // The destination register is the TRIS
  }
  new_name("tris");
}

void TRIS::execute(void)
{
  if(register_address)
    {
      // Execute the instruction only if the register is valid.
      if(cpu_pic->base_isa() == _14BIT_PROCESSOR_)
	cpu_pic->registers[register_address]->put(cpu_pic->W->get());
      else
	cpu_pic->tris_instruction(register_address);
    }

  cpu_pic->pc->increment();
}

char * TRIS::name(char *return_str,int len)
{

  snprintf(return_str,len,"%s\t%s",
	   gpsimValue::name().c_str(),
	   cpu_pic->registers[register_address]->name().c_str());

  return(return_str);
}


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

XORLW::XORLW (Processor *new_cpu, unsigned int new_opcode)
  : Literal_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("xorlw");
}

void XORLW::execute(void)
{
  unsigned int new_value;

  new_value = cpu_pic->W->value.get() ^ L;

  cpu_pic->W->put(new_value);
  cpu_pic->status->put_Z(0==new_value);

  cpu_pic->pc->increment();

}

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

XORWF::XORWF (Processor *new_cpu, unsigned int new_opcode)
  : Register_op(new_cpu, new_opcode, 0)
{
  decode(new_cpu, new_opcode);
  new_name("xorwf");
}

void XORWF::execute(void)
{
  unsigned int new_value;

  if(!access)
    source = cpu_pic->registers[register_address];
  else
    source = cpu_pic->register_bank[register_address];

  new_value = source->get() ^ cpu_pic->W->value.get();

  if(destination)
    source->put(new_value);      // Result goes to source
  else
    cpu_pic->W->put(new_value);

  cpu_pic->status->put_Z(0==new_value);

  cpu_pic->pc->increment();

}


syntax highlighted by Code2HTML, v. 0.9.1