/***************************************************************************
 *   Copyright (C) 2004-2005 by Daniel Clarke <daniel.jc@gmail.com>        *
 *                      2005 by David Saxton <david@bluehaze.org>          *
 *                                                                         *
 *   This program 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 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef INSTRUCTION_H
#define INSTRUCTION_H

#include <qmap.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qvaluelist.h>

class Code;
class CodeIterator;
class CodeConstIterator;
class Instruction;
class PIC14;

typedef QValueList<Instruction*> InstructionList;


/**
Abstraction for a Register - should be used instead of a register name. Contains
info like whether or not the adressing of the register depends on the bank
selection.

@author David Saxton
*/
class Register
{
	public:
		enum Type
		{
			TMR0,
			OPTION_REG,
			PCL,
			STATUS,
			FSR,
			PORTA,
			TRISA,
			PORTB,
			TRISB,
			EEDATA,
			EECON1,
			EEADR,
			EECON2,
			PCLATH,
			INTCON,
			
			// The following three are "special"
			WORKING, // Not a register that is addressable by an address
			GPR, // Refers to the collection of General Purpose Registers
			none, // used in default constructor
		};
		
		// These banks are used for ORing together in the banks() function
		enum Banks
		{
			Bank0 = 1 << 0,
			Bank1 = 1 << 1,
		};
		
		/**
		 * Creates a register of the given type, giving it the appropriate name.
		 * Note that this constructor should not be used for GPR.
		 */
		Register( Type type = none );
		/**
		 * Construct a Register with the given name. If the name is not
		 * recognized, then it is assumed to be a GPR register.
		 */
		Register( const QString & name );
		/**
		 * Construct a Register with the given name. If the name is not
		 * recognized, then it is assumed to be a GPR register.
		 */
		Register( const char * name );
		/**
		 * @return less-than-equality between registers; name is only compared
		 * if both registers have type GPR.
		 */
		bool operator < ( const Register & reg ) const;
		/**
		 * @return equality between registers; name is only compared if both
		 * registers have type GPR.
		 */
		bool operator == ( const Register & reg ) const;
		/**
		 * @return 0x1 and 0x2 for being addressable from banks 0 and 1
		 * respectively, OR'ed together.
		 */
		uchar banks() const;
		/**
		 * Convenience function.
		 * @see banks
		 */
		bool bankDependent() const;
		/**
		 * Returns the name of the register, or the alias for the GPR.
		 */
		QString name() const { return m_name; }
		/**
		 * @return the type of register.
		 */
		Type type() const { return m_type; }
		/**
		 * From the Optimizer's perspective, it is OK to remove, change or add
		 * any instruction so long as there are no visible external changes that
		 * go against the original intention of the microbe source (a general
		 * guiding principle). Therefore, this function returns true for PORT
		 * and TRIS registers, false for everything else.
		 */
		bool affectsExternal() const;
		
	protected:
		QString m_name;
		Type m_type;
};



class RegisterBit
{
	public:
		enum STATUS_bits
		{
			C			= 0, // Carry
			DC			= 1, // Digit carry
			Z			= 2, // Zero
			NOT_PD		= 3, // Power-down
			NOT_TO		= 4, // Time-out
			RP0			= 5, // Bank Select
			RP1			= 6,
			IRP			= 7,
		};
		
		enum INTCON_bits
		{
			RBIF		= 0,
			INTF		= 1,
			T0IF		= 2,
			RBIE		= 3,
			INTE		= 4,
			T0IE		= 5,
			EEIE		= 6,
			GIE			= 7,
		};
		
		enum OPTION_bits
		{
			PS0			= 0,
			PS1			= 1,
			PS2			= 2,
			PSA			= 3,
			T0SE		= 4,
			T0CS		= 5,
			INTEDG		= 6,
			NOT_RBPU	= 7,
		};
		
		enum EECON1_bits
		{
			RD			= 0,
			WR			= 1,
			WREN		= 2,
			WRERR		= 3,
			EEIF		= 4,
		};
		/**
		 * Constructs a bit of the given register type at the given position.
		 */
		RegisterBit( uchar bitPos = 0, Register::Type reg = Register::none );
		/**
		 * Construct a register bit with the given name.
		 */
		RegisterBit( const QString & name );
		/**
		 * Construct a register bit with the given name.
		 */
		RegisterBit( const char * name );
		/**
		 * @warning do not trust this value! actually, this function should be
		 * removed, or the constructors fixed so that this value can be trusted.
		 * @return the register type that the bit belongs to.
		 */
		Register::Type registerType() const { return m_registerType; }
		/**
		 * @return the position of the bit, e.g. "5" for RP0.
		 */
		uchar bitPos() const { return m_bitPos; }
		/**
		 * @return the bit, e.g. "0x20" for Z.
		 */
		uchar bit() const { return (1 << m_bitPos); }
		/**
		 * @return the name of the bit, e.g. "Z" for Z.
		 */
		QString name() const { return m_name; }
		
		
	protected:
		/**
		 * Determines the register type and bit pos from the bit name (m_name).
		 */
		void initFromName();
		
		Register::Type m_registerType;
		uchar m_bitPos:3;
		QString m_name;
};




/**
Contains information on the state of a register before an instruction is
executed.

Note that all the "uchar" values in this class should be considered as the 8
bits of a register. So for example, if known=0x2, then only the second bit of
the register is known, and its value is given in the second bit of value.

@author David Saxton
*/
class RegisterState
{
	public:
		RegisterState();
		
		/**
		 * Merges the known and values together, (possibly) reducing what is
		 * known.
		 */
		void merge( const RegisterState & state );
		/**
		 * Sets known to unknown and value to zero.
		 */
		void reset();
		/**
		 * Returns the bits that are definitely zero.
		 */
		uchar definiteZeros() const { return (~value) & known; }
		/**
		 * Returns the bits that are definitely one.
		 */
		uchar definiteOnes() const { return value & known; }
		/**
		 * Returns the bits that are unknown.
		 */
		uchar unknown() const { return ~known; }
		/**
		 * @return the largest possible value that this register might be
		 * storing, based on which bits are known and the value of those bits.
		 */
		uchar maxValue() const { return (value & known) | (~known); }
		/**
		 * @return the smallest possible value that this register might be
		 * storing, based on which bits are known and the value of those bits.
		 */
		uchar minValue() const { return (value & known); }
		/**
		 * @return whether the known and value uchars are equal
		 */
		bool operator == ( const RegisterState & state ) const;
		/**
		 * @return whether either of the known and value uchars are not equal.
		 */
		bool operator != ( const RegisterState & state ) const { return !( *this == state ); }
		/**
		 * Prints known and value.
		 */
		void print();
		
		/// Whether or not the value is known (for each bit).
		uchar known;
		
		/// The value of the register.
		uchar value;
};


/**
Setting and dependency information for register bits. See the respective member
descriptions for more information.

@author David Saxton
*/
class RegisterBehaviour
{
	public:
		RegisterBehaviour();
		/**
		 * Sets "depends", "indep" and "changes" to 0x0.
		 */
		void reset();
		
		/**
		 * The bits whose value before the instruction is executed will affect
		 * the processor state after execution. So for example,
		 *   in MOVLW this will be 0x0;
		 *   in ANDLW this will be the bits that are non-zero in the literal;
		 *   in BTFSC this will be the bit being tested (if this is the register
		 *      being tested).
		 */
		uchar depends;
		
		/**
		 * The bits whose value after the instruction is executed is independent
		 * of the value before execution. So for example,
		 *   in MOVLW, this will be 0xff;
		 *   in ANDLW this will be the bits that are zero in the literal;
		 *   in BTFSC this will be 0x0.
		 */
		uchar indep;
};



/**
Contains information on the state of a processor; e.g. register values

@author David Saxton
 */
class ProcessorState
{
	public:
		ProcessorState();
		/**
		 * Calls merge for each RegisterState.
		 */
		void merge( const ProcessorState & state );
		/**
		 * Calls reset() for each RegisterState.
		 */
		void reset();
		/**
		 * @return state for the given register.
		 */
		RegisterState & reg( const Register & reg );
		/**
		 * @return state for the given register.
		 */
		RegisterState reg( const Register & reg ) const;
		/**
		 * @return whether all the RegisterStates are identical
		 */
		bool operator == ( const ProcessorState & state ) const;
		/**
		 * @return whether any of the RegisterStates are not equal.
		 */
		bool operator != ( const ProcessorState & state ) const { return !( *this == state ); }
		/**
		 * Displays each register's name and calls RegisterState::print in turn.
		 */
		void print();
		
		/// The working register
		RegisterState working;
		
		/// The status register
		RegisterState status;
		
	protected:
		typedef QMap< Register, RegisterState > RegisterMap;
		/**
		 * All registers other than working and status. Entries are created on
		 * calls to reg with a new Register.
		 */
		RegisterMap m_registers;
};


/**
Contains behavioural information for each register.

@author David Saxton
*/
class ProcessorBehaviour
{
	public:
		ProcessorBehaviour();
		/**
		 * Calls reset() for each RegisterBehaviour.
		 */
		void reset();
		/**
		 * @return behaviour for the given register.
		 */
		RegisterBehaviour & reg( const Register & reg );
		
		/// The working register
		RegisterBehaviour working;
		
		/// The status register
		RegisterBehaviour status;
		
	protected:
		typedef QMap< Register, RegisterBehaviour > RegisterMap;
		/**
		 * All registers other than working and status. Entries are created on
		 * calls to reg with a new Register.
		 */
		RegisterMap m_registers;
};


/**
Contains information on whether a register is overwritten before its value is
used. Each uchar respresents the 8 bits of the register; if the bit is 1, then
the corresponding bit of the register is used by the Instruction or one
of its outputs before it is overwritten.

@author David Saxton
*/
class RegisterDepends
{
	public:
		RegisterDepends();
		/**
		 * Sets all the depends values to 0x0.
		 */
		void reset();
		/**
		 * @return behaviour for the given register.
		 */
		uchar & reg( const Register & reg );
		
		/// The working register
		uchar working;
		
		/// The status register
		uchar status;
		
	protected:
		typedef QMap< Register, uchar > RegisterMap;
		/**
		 * All registers other than working and status. Entries are created on
		 * calls to reg with a new Register.
		 */
		RegisterMap m_registers;
};



/**
Holds a program structure; an (ordered) list of blocks of code, each of which
contains a list of instructions. The structure is such as to provide easy
manipulation of the program, as well as aiding the optimizer.

@author David Saxton
*/
class Code
{
	public:
		Code();
		
		typedef CodeIterator iterator;
		typedef CodeConstIterator const_iterator;
		
		enum InstructionPosition
		{
			InterruptHandler	= 0,
			LookupTable			= 1,
			Middle				= 2, ///< Used for main code
			Subroutine			= 3, ///< Used for subroutines
			
			PositionCount		= 4, ///< This must remain the last item and be the number of valid positions
		};
		
		CodeIterator begin();
		CodeIterator end();
		CodeConstIterator begin() const;
		CodeConstIterator end() const;
		
		/**
		 * Queues a label to be given to the next instruction to be added in the
		 * given position
		 */
		void queueLabel( const QString & label, InstructionPosition position = Middle );
		/**
		 * Returns the list of queued labels for the given position. This is
		 * used in merging code, as we also need to merge any queued labels.
		 */
		QStringList queuedLabels( InstructionPosition position ) const { return m_queuedLabels[position]; }
		/**
		 * Adds the Instruction at the given position.
		 */
		void append( Instruction * instruction, InstructionPosition position = Middle );
		/**
		 * @returns the Instruction with the given label (or null if no such
		 * Instruction).
		 */
		Instruction * instruction( const QString & label ) const;
		/**
		 * Look for an Assembly instruction (other types are ignored).
		 * @return an iterator to the current instruction, or end if it wasn't
		 * found.
		 */
		iterator find( Instruction * instruction );
		/**
		 * Removes the Instruction (regardless of position).
		 * @warning You should always use only this function to remove an
		 * instruction as this function handles stuff such as pushing labels
		 * from this instruction onto the next before deletion.
		 */
		void removeInstruction( Instruction * instruction );
		/**
		 * Merges all the blocks output together with other magic such as adding
		 * variables, gpasm directives, etc.
		 */
		QString generateCode( PIC14 * pic ) const;
		/**
		 * Appends the InstructionLists to the end of the ones in this instance.
		 * @param middleInsertionPosition is the position where the middle code
		 * blocks of the given code will be merged at.
		 */
		void merge( Code * code, InstructionPosition middleInsertionPosition = Middle );
		/**
		 * @returns the InstructionList for the given insertion position.
		 */
		InstructionList * instructionList( InstructionPosition position ) { return & m_instructionLists[position]; }
		/**
		 * @returns the InstructionList for the given insertion position.
		 */
		const InstructionList * instructionList( InstructionPosition position ) const { return & m_instructionLists[position]; }
		/**
		 * Calls generateOutputLinks for each Instruction
		 */
		void generateLinksAndStates();
		/**
		 * Calls setUsed(false) for all instructions.
		 */
		void setAllUnused();
		/**
		 * Does any work that is needed to the code before it can be passed to
		 * the optimizer (such as flushing out queued labels). This is called
		 * after all the instructions have been added to the code.
		 */
		void postCompileConstruct();
		
	protected:
		/**
		 * Used when generating the code. Finds the list of general purpose
		 * registers that are referenced and returns their aliases.
		 */
		QStringList findVariables() const;
		
		InstructionList m_instructionLists[ PositionCount ]; ///< @see InstructionPosition
		QStringList m_queuedLabels[ PositionCount ]; ///< @see InstructionPosition
		
	private: // Disable copy constructor and operator=
		Code( const Code & );
		Code &operator=( const Code & );
};


/**
Iterates over all the instructions, going seamlessly between the different lists
and avoiding the non-assembly instructions.

@author David Saxton
 */
class CodeIterator
{
	public:
		bool operator != ( const CodeIterator & i ) const { return it != i.it; }
		bool operator == ( const CodeIterator & i ) const { return it == i.it; }
		CodeIterator & operator ++ ();
		Instruction * & operator * () { return *it; }
		/**
		 * Deletes the instruction that this iterator is currently pointing at
		 * (removing it from any lists), and increments the iterator to the next
		 * instruction.
		 */
		CodeIterator & removeAndIncrement();
		/**
		 * Inserts the given instruction before the instruction pointed at by
		 * this iterator.
		 */
		void insertBefore( Instruction * ins );
		
		InstructionList::iterator it;
		InstructionList::iterator listEnd;
		Code::InstructionPosition pos;
		Code * code;
		InstructionList * list;
};


/**
A const version of CodeIterator (cannot change instructions).

@author David Saxton
 */
class CodeConstIterator
{
	public:
		bool operator != ( const CodeConstIterator & i ) const { return it != i.it; }
		bool operator == ( const CodeConstIterator & i ) const { return it == i.it; }
		CodeConstIterator & operator ++ ();
		const Instruction * operator * () const { return *it; }
		
		InstructionList::const_iterator it;
		InstructionList::const_iterator listEnd;
		Code::InstructionPosition pos;
		const Code * code;
		const InstructionList * list;
};


/**
@author Daniel Clarke
@author David Saxton
*/
class Instruction
{
	public:
		enum InstructionType
		{
			Assembly,
			Raw, // User-inserted assembly
			Comment,
		};
		/**
		 * Used in optimization. Note that this follows roughly, but not
		 * exactly, the Microchip classifications of similar categories.
		 */
		enum AssemblyType
		{
			/**
			 * Writes to a file (which can be obtained by calling outputReg().
			 */
			FileOriented,
			
			/**
			 * Writes to a file bit (so BCF or BSF).
			 */
			BitOriented,
			
			/**
			 * Affects the working register via a literal operation, with no
			 * branching (so excludes retlw).
			 */
			WorkingOriented,
			
			/**
			 * Assembly instructions that don't come under the above categories
			 * (so control and branching instructions).
			 */
			Other,
			
			/**
			 * The Instruction is not of Assembly InstructionType.
			 */
			None,
		};

		Instruction();
		virtual ~Instruction();
		void setCode( Code * code ) { m_pCode = code; }
		
		/**
		 * This is used to decide how to output the instruction, and which
		 * instructions to avoid while optimizing.
		 */
		virtual InstructionType type() const { return Assembly; }
		/**
		 * @return the AssemblyType (None for non-Assembly instructions).
		 */
		virtual AssemblyType assemblyType() const = 0;
		/**
		 * The text to output to the generated assembly.
		 */
		virtual QString code() const = 0;
		/**
		 * The input processor state is used to generate the outputlinks and the
		 * output processor state.
		 */
		void setInputState( const ProcessorState & processorState ) { m_inputState = processorState; }
		/**
		 * By using the ProcessorState, the Instruction should:
		 * * Find all instructions that could be executed after this instruction.
		 * * Generate the output ProcessorState.
		 * The default behaviour of this function is to link to the next
		 * sequential instruction, and to generate an unknown ProcessorState.
		 * @warning if your instruction depends on any bits, then it must
		 * reinherit this function and say so.
		 * @param instruction points at this instruction
		 */
		virtual void generateLinksAndStates( Code::iterator instruction );
		/**
		 * @return the processor behaviour for this instruction.
		 */
		virtual ProcessorBehaviour behaviour() const;
		/**
		 * An input link is an instruction that might be executed immediately
		 * before this Instruction.
		 */
		void addInputLink( Instruction * inputLink );
		/**
		 * An output link is an instruction that might be executed immediately
		 * after this Instruction.
		 */
		void addOutputLink( Instruction * inputLink );
		/**
		 * The list of instructions that might be executed immediately before
		 * this instruction.
		 * @see addInputLink
		 */
		InstructionList inputLinks() const { return m_inputLinks; }
		/**
		 * The list of instructions that might be executed immediately after
		 * this instruction. Instruction does not generate these links; instead
		 * the list is generated Code::generateLinksAndStates function.
		 */
		InstructionList outputLinks() const { return m_outputLinks; }
		/**
		 * Remove the given input link from the instruction.
		 */
		void removeInputLink( Instruction * ins );
		/**
		 * Remove the given output link from the instruction.
		 */
		void removeOutputLink( Instruction * ins );
		/**
		 * Clears all input and output links from this instruction. This does
		 * not remove references to this instruction from other instructions.
		 */
		void clearLinks();
		/**
		 * An instruction may have zero, or more than zero labels associated
		 * with it - these will be printed before the instruction in the
		 * assembly output.
		 */
		QStringList labels() const { return m_labels; }
		/**
		 * @see labels
		 */
		void addLabels( const QStringList & labels );
		/**
		 * @see labels
		 */
		void setLabels( const QStringList & labels );
		/**
		 * @see used
		 */
		void setUsed( bool used ) { m_bUsed = used; }
		/**
		 * Used for optimization purposes in determining whether the instruction
		 * has been examined yet (to avoid infinite loops).
		 */
		bool isUsed() const { return m_bUsed; }
		/**
		 * Set by the optimizer to indicate whether this instruction or any of
		 * its outputs overwrite any of the bits of the given register.
		 */
		void setRegisterDepends( uchar depends, const Register & reg ) { m_registerDepends.reg(reg) = depends; }
		/**
		 * @see setOutputsOverwriteWorking
		 */
		uchar registerDepends( const Register & reg ) { return m_registerDepends.reg(reg); }
		/**
		 * Resets the overwrites.
		 */
		void resetRegisterDepends() { m_registerDepends.reset(); }
		/**
		 * @return the input processor state to this instruction.
		 * @see setInputState
		 */
		ProcessorState inputState() const { return m_inputState; }
		/**
		 * @return the output processor state from this instruction.
		 * @see generateLinksAndStates.
		 */
		ProcessorState outputState() const { return m_outputState; }
		/**
		 * Only applicable to Instructions that refer to a file.
		 */
		Register file() const { return m_file; }
		/**
		 * Only applicable to Instructions that refer to a bit (such as BCF).
		 */
		RegisterBit bit() const { return m_bit; }
		/**
		 * Only applicable to instructions that refer to a literal (such as
		 * XORLW).
		 */
		uchar literal() const { return m_literal; }
		/**
		 * Applicable only to instructions that save a result to working or file
		 * depending on the destination bit.
		 */
		Register outputReg() const { return (m_dest == 0) ? Register::WORKING : m_file; }
		/**
		 * Applicable only to instructions that use the destination flag.
		 */
		unsigned dest() const { return m_dest; }
		
	protected:
		/**
		 * This function is provided for convenience; it creates links to the
		 * first or second instructions after this one, depending on the value
		 * of firstOutput and secondOutput.
		 * @see generateOutputLinks
		 */
		void makeOutputLinks( Code::iterator current, bool firstOutput = true, bool secondOutput = false );
		/**
		 * This function is provided for instructions that jump to a label (i.e.
		 * call and goto).
		 */
		void makeLabelOutputLink( const QString & label );
		
		RegisterDepends m_registerDepends;
		bool m_bInputStateChanged;
		bool m_bUsed;
		bool m_bPositionAffectsBranching;
		InstructionList m_inputLinks;
		InstructionList m_outputLinks;
		QStringList m_labels;
		Code * m_pCode;
		
		// Commonly needed member variables for assembly instructions
		Register m_file;
		RegisterBit m_bit;
		QString m_raw; // Used by source code, raw asm, etc
		uchar m_literal;
		unsigned m_dest:1; // is 0 (W) or 1 (file).
		ProcessorState m_inputState;
		ProcessorState m_outputState;
		
	private: // Disable copy constructor and operator=
		Instruction( const Instruction & );
		Instruction &operator=( const Instruction & );
};



//BEGIN Byte-Oriented File Register Operations
class Instr_addwf : public Instruction
{
	public:
		Instr_addwf( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


class Instr_andwf : public Instruction
{
	public:
		Instr_andwf( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


class Instr_clrf : public Instruction
{
	public:
		Instr_clrf( const Register & file ) { m_file = file; m_dest = 1; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


//TODO CLRW
//TODO COMF


class Instr_decf : public Instruction
{
	public:
		Instr_decf( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


class Instr_decfsz : public Instruction
{
	public:
		Instr_decfsz( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


class Instr_incf : public Instruction
{
	public:
		Instr_incf( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


//TODO INCFSZ


class Instr_iorwf : public Instruction
{
	public:
		Instr_iorwf( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


class Instr_movf : public Instruction
{
	public:
		Instr_movf( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


class Instr_movwf : public Instruction
{
	public:
		Instr_movwf( const Register & file ) { m_file = file; m_dest = 1; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


//TODO NOP


class Instr_rlf : public Instruction
{
	public:
		Instr_rlf( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


class Instr_rrf : public Instruction
{
	public:
		Instr_rrf( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


class Instr_subwf : public Instruction
{
	public:
		Instr_subwf( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


class Instr_swapf : public Instruction
{
	public:
		Instr_swapf( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};


class Instr_xorwf : public Instruction
{
	public:
		Instr_xorwf( const Register & file, int dest ) { m_file = file; m_dest = dest; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return FileOriented; }
};
//END Byte-Oriented File Register Operations



//BEGIN Bit-Oriented File Register Operations
class Instr_bcf : public Instruction
{
	public:
		Instr_bcf( const Register & file, const RegisterBit & bit ) { m_file = file; m_bit = bit; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return BitOriented; }
};


class Instr_bsf : public Instruction
{
	public:
		Instr_bsf( const Register & file, const RegisterBit & bit ) { m_file = file; m_bit = bit; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return BitOriented; }
};


class Instr_btfsc : public Instruction
{
	public:
		Instr_btfsc( const Register & file, const RegisterBit & bit ) { m_file = file; m_bit = bit; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return Other; }
};


class Instr_btfss : public Instruction
{
	public:
		Instr_btfss( const Register & file, const RegisterBit & bit ) { m_file = file; m_bit = bit; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return Other; }
};
//END Bit-Oriented File Register Operations



//BEGIN Literal and Control Operations
class Instr_addlw : public Instruction
{
	public:
		Instr_addlw( int literal ) { m_literal = literal; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return WorkingOriented; }
};



class Instr_andlw : public Instruction
{
	public:
		Instr_andlw( int literal ) { m_literal = literal; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return WorkingOriented; }
};


class Instr_call : public Instruction
{
	public:
		Instr_call( const QString & label ) { m_label = label; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return Other; }
		/**
		 * Called from Code after all the output links have been generated. The
		 * instruction that is called has its output links followed, and any
		 * returns encountered are linked back to the instruction after this
		 * one.
		 * @param next the instruction after this one which the return points
		 * will be linked to.
		 */
		void makeReturnLinks( Instruction * next );
		
		QString label() const { return m_label; }
		void setLabel( const QString & label ) { m_label = label; }
		
	protected:
		/**
		 * Used by makeReturnLinks. Recursively follows the instruction's output
		 * links, until a return is found - then, link the return point back to
		 * the instruction after this one. Call instructions found while
		 * following the output are ignored.
		 * @param returnPoint the instruction to link back to on finding a
		 * return.
		 */
		void linkReturns( Instruction * current, Instruction * returnPoint );
		
		QString m_label;
};


//TODO CLRWDT


class Instr_goto : public Instruction
{
	public:
		Instr_goto( const QString & label ) { m_label = label; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return Other; }
		
		QString label() const { return m_label; }
		void setLabel( const QString & label ) { m_label = label; }
		
	protected:
		QString m_label;
};


class Instr_iorlw : public Instruction
{
	public:
		Instr_iorlw( int literal ) { m_literal = literal; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return WorkingOriented; }
};


class Instr_movlw : public Instruction
{
	public:
		Instr_movlw( int literal ) { m_literal = literal; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return WorkingOriented; }
};


class Instr_retfie : public Instruction
{
	public:
		Instr_retfie() {};
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return Other; }
};


class Instr_retlw : public Instruction
{
	public:
		Instr_retlw( int literal ) { m_literal = literal; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return Other; }
};


class Instr_return : public Instruction
{
	public:
		Instr_return() {};
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return Other; }
};


class Instr_sleep : public Instruction
{
	public:
		Instr_sleep() {};
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return Other; }
};


class Instr_sublw : public Instruction
{
	public:
		Instr_sublw( int literal ) { m_literal = literal; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return WorkingOriented; }
};


class Instr_xorlw : public Instruction
{
	public:
		Instr_xorlw( int literal ) { m_literal = literal; }
		virtual QString code() const;
		virtual void generateLinksAndStates( Code::iterator current );
		virtual ProcessorBehaviour behaviour() const;
		virtual AssemblyType assemblyType() const { return WorkingOriented; }
};
//END Literal and Control Operations



//BEGIN Microbe (non-assembly) Operations
class Instr_sourceCode : public Instruction
{
	public:
		Instr_sourceCode( const QString & source ) { m_raw = source; }
		virtual QString code() const;
		virtual InstructionType type() const { return Comment; }
		virtual AssemblyType assemblyType() const { return None; }
};


class Instr_asm : public Instruction
{
	public:
		Instr_asm( const QString & raw ) { m_raw = raw; }
		virtual QString code() const;
		virtual InstructionType type() const { return Raw; }
		virtual AssemblyType assemblyType() const { return None; }
};


// Like Instr_asm, but does not put ;asm {} in, used
// for internal things like gpasm directives etc...
class Instr_raw : public Instruction
{
	public:
		Instr_raw( const QString & raw ) { m_raw = raw; }
		virtual QString code() const;
		virtual InstructionType type() const { return Raw; }
		virtual AssemblyType assemblyType() const { return None; }
};
//END Microbe (non-assembly) Operations



#endif
