summaryrefslogtreecommitdiffstats
path: root/microbe/instruction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'microbe/instruction.cpp')
-rw-r--r--microbe/instruction.cpp2309
1 files changed, 2309 insertions, 0 deletions
diff --git a/microbe/instruction.cpp b/microbe/instruction.cpp
new file mode 100644
index 0000000..b2b02b4
--- /dev/null
+++ b/microbe/instruction.cpp
@@ -0,0 +1,2309 @@
+/***************************************************************************
+ * Copyright (C) 2004-2005 by Daniel Clarke <[email protected]> *
+ * 2005 by David Saxton <[email protected]> *
+ * *
+ * 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., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "instruction.h"
+#include "optimizer.h"
+#include "pic14.h"
+
+#include <kdebug.h>
+#include <qstringlist.h>
+
+#include <assert.h>
+#include <iostream>
+using namespace std;
+
+
+//BEGIN class Register
+Register::Register( Type type )
+{
+ m_type = type;
+
+ switch ( m_type )
+ {
+ case TMR0:
+ m_name = "TMR0";
+ break;
+ case OPTION_REG:
+ m_name = "OPTION_REG";
+ break;
+ case PCL:
+ m_name = "PCL";
+ break;
+ case STATUS:
+ m_name = "STATUS";
+ break;
+ case FSR:
+ m_name = "FSR";
+ break;
+ case PORTA:
+ m_name = "PORTA";
+ break;
+ case TRISA:
+ m_name = "TRISA";
+ break;
+ case PORTB:
+ m_name = "PORTB";
+ break;
+ case TRISB:
+ m_name = "TRISB";
+ break;
+ case EEDATA:
+ m_name = "EEDATA";
+ break;
+ case EECON1:
+ m_name = "EECON1";
+ break;
+ case EEADR:
+ m_name = "EEADR";
+ break;
+ case EECON2:
+ m_name = "EECON2";
+ break;
+ case PCLATH:
+ m_name = "PCLATH";
+ break;
+ case INTCON:
+ m_name = "INTCON";
+ break;
+ case WORKING:
+ m_name = "<working>";
+ break;
+ case GPR:
+ case none:
+ break;
+ }
+}
+
+
+Register::Register( const QString & name )
+{
+ m_name = name.stripWhiteSpace();
+ QString upper = m_name.upper();
+
+ if ( upper == "TMR0" )
+ m_type = TMR0;
+ else if ( upper == "OPTION_REG" )
+ m_type = OPTION_REG;
+ else if ( upper == "PCL" )
+ m_type = PCL;
+ else if ( upper == "STATUS")
+ m_type = STATUS;
+ else if ( upper == "FSR")
+ m_type = FSR;
+ else if ( upper == "PORTA")
+ m_type = PORTA;
+ else if ( upper == "TRISA")
+ m_type = TRISA;
+ else if ( upper == "PORTB")
+ m_type = PORTB;
+ else if ( upper == "TRISB")
+ m_type = TRISB;
+ else if ( upper == "EEDATA")
+ m_type = EEDATA;
+ else if ( upper == "EECON1")
+ m_type = EECON1;
+ else if ( upper == "EEADR")
+ m_type = EEADR;
+ else if ( upper == "EECON2")
+ m_type = EECON2;
+ else if ( upper == "PCLATH")
+ m_type = PCLATH;
+ else if ( upper == "INTCON")
+ m_type = INTCON;
+ else
+ m_type = GPR;
+}
+
+
+Register::Register( const char * name )
+{
+ *this = Register( QString(name) );
+}
+
+
+bool Register::operator < ( const Register & reg ) const
+{
+ if ( (type() != GPR) || (reg.type() != GPR) )
+ return type() < reg.type();
+
+ return name() < reg.name();
+}
+
+
+bool Register::operator == ( const Register & reg ) const
+{
+ if ( type() != reg.type() )
+ return false;
+
+ return name() == reg.name();
+}
+
+
+uchar Register::banks() const
+{
+ switch ( m_type )
+ {
+ case TMR0: return Bank0;
+ case OPTION_REG: return Bank1;
+ case PCL: return Bank0 | Bank1;
+ case STATUS: return Bank0 | Bank1;
+ case FSR: return Bank0 | Bank1;
+ case PORTA: return Bank0;
+ case TRISA: return Bank1;
+ case PORTB: return Bank0;
+ case TRISB: return Bank1;
+ case EEDATA: return Bank0;
+ case EECON1: return Bank1;
+ case EEADR: return Bank0;
+ case EECON2: return Bank1;
+ case PCLATH: return Bank0 | Bank1;
+ case INTCON: return Bank0 | Bank1;
+
+ case GPR: return Bank0 | Bank1;
+ case WORKING: return Bank0 | Bank1;
+ case none: return Bank0 | Bank1;
+ }
+
+ return Bank0 | Bank1; // Vacously true (and useful too) - a non-existent bank can be accessed anywhere
+}
+
+
+bool Register::bankDependent() const
+{
+ return ( banks() != (Bank0 | Bank1) );
+}
+
+
+bool Register::affectsExternal() const
+{
+ switch ( m_type )
+ {
+ case PORTA:
+ case TRISA:
+ case PORTB:
+ case TRISB:
+ return true;
+
+ case TMR0:
+ case OPTION_REG:
+ case PCL:
+ case STATUS:
+ case FSR:
+ case EEDATA:
+ case EECON1:
+ case EEADR:
+ case EECON2:
+ case PCLATH:
+ case INTCON:
+ case GPR:
+ case WORKING:
+ case none:
+ return false;
+ }
+ return false;
+}
+//END class Register
+
+
+
+//BEGIN class RegisterBit
+RegisterBit::RegisterBit( uchar bitPos, Register::Type reg )
+{
+ m_bitPos = bitPos;
+ m_registerType = reg;
+
+ switch ( m_registerType )
+ {
+ case Register::STATUS:
+ {
+ switch ( m_bitPos )
+ {
+ case 0: m_name = "C"; break;
+ case 1: m_name = "DC"; break;
+ case 2: m_name = "Z"; break;
+ case 3: m_name = "NOT_PD"; break;
+ case 4: m_name = "NOT_TO"; break;
+ case 5: m_name = "RP0"; break;
+ case 6: m_name = "RP1"; break;
+ case 7: m_name = "IRP"; break;
+ }
+ break;
+ }
+ case Register::INTCON:
+ {
+ switch ( m_bitPos )
+ {
+ case 0: m_name = "RBIF"; break;
+ case 1: m_name = "INTF"; break;
+ case 2: m_name = "T0IF"; break;
+ case 3: m_name = "RBIE"; break;
+ case 4: m_name = "INTE"; break;
+ case 5: m_name = "T0IE"; break;
+ case 6: m_name = "EEIE"; break;
+ case 7: m_name = "GIE"; break;
+ }
+ break;
+ }
+ case Register::OPTION_REG:
+ {
+ switch ( m_bitPos )
+ {
+ case 0: m_name = "PS0"; break;
+ case 1: m_name = "PS1"; break;
+ case 2: m_name = "PS2"; break;
+ case 3: m_name = "PSa"; break;
+ case 4: m_name = "T0SE"; break;
+ case 5: m_name = "T0CS"; break;
+ case 6: m_name = "INTEDG"; break;
+ case 7: m_name = "NOT_RBPU"; break;
+ }
+ break;
+ }
+ case Register::EECON1:
+ {
+ switch ( m_bitPos )
+ {
+ case 0: m_name = "RD"; break;
+ case 1: m_name = "WR"; break;
+ case 2: m_name = "WREN"; break;
+ case 3: m_name = "WRERR"; break;
+ case 4: m_name = "EEIF"; break;
+ }
+ break;
+ }
+
+ case Register::TMR0:
+ case Register::PCL:
+ case Register::FSR:
+ case Register::PORTA:
+ case Register::TRISA:
+ case Register::PORTB:
+ case Register::TRISB:
+ case Register::EEDATA:
+ case Register::EEADR:
+ case Register::EECON2:
+ case Register::PCLATH:
+ case Register::GPR:
+ case Register::WORKING:
+ case Register::none:
+ {
+// kdError() << k_funcinfo << "Bad register: " << reg << endl;
+ }
+ }
+}
+
+
+RegisterBit::RegisterBit( const QString & name )
+{
+ m_name = name.upper().stripWhiteSpace();
+ initFromName();
+}
+
+
+RegisterBit::RegisterBit( const char * name )
+{
+ m_name = QString(name).upper().stripWhiteSpace();
+ initFromName();
+}
+
+
+void RegisterBit::initFromName()
+{
+ bool ok;
+ m_bitPos = m_name.toInt( & ok, 0 );
+ if ( ok )
+ m_registerType = Register::none; // hmm it should be unknown - not none.
+
+ else if ( m_name == "C" )
+ {
+ m_registerType = Register::STATUS;
+ m_bitPos = 0;
+ }
+ else if ( m_name == "DC" )
+ {
+ m_registerType = Register::STATUS;
+ m_bitPos = 1;
+ }
+ else if ( m_name == "Z" )
+ {
+ m_registerType = Register::STATUS;
+ m_bitPos = 2;
+ }
+ else if ( m_name == "NOT_PD" )
+ {
+ m_registerType = Register::STATUS;
+ m_bitPos = 3;
+ }
+ else if ( m_name == "NOT_TO" )
+ {
+ m_registerType = Register::STATUS;
+ m_bitPos = 4;
+ }
+ else if ( m_name == "RP0" )
+ {
+ m_registerType = Register::STATUS;
+ m_bitPos = 5;
+ }
+ else if ( m_name == "RP1" )
+ {
+ m_registerType = Register::STATUS;
+ m_bitPos = 6;
+ }
+ else if ( m_name == "IRP" )
+ {
+ m_registerType = Register::STATUS;
+ m_bitPos = 7;
+ }
+ else if ( m_name == "RBIF" )
+ {
+ m_registerType = Register::INTCON;
+ m_bitPos = 0;
+ }
+ else if ( m_name == "INTF" )
+ {
+ m_registerType = Register::INTCON;
+ m_bitPos = 1;
+ }
+ else if ( m_name == "T0IF" )
+ {
+ m_registerType = Register::INTCON;
+ m_bitPos = 2;
+ }
+ else if ( m_name == "RBIE" )
+ {
+ m_registerType = Register::INTCON;
+ m_bitPos = 3;
+ }
+ else if ( m_name == "INTE" )
+ {
+ m_registerType = Register::INTCON;
+ m_bitPos = 4;
+ }
+ else if ( m_name == "T0IE" )
+ {
+ m_registerType = Register::INTCON;
+ m_bitPos = 5;
+ }
+ else if ( m_name == "EEIE" )
+ {
+ m_registerType = Register::INTCON;
+ m_bitPos = 6;
+ }
+ else if ( m_name == "GIE" )
+ {
+ m_registerType = Register::INTCON;
+ m_bitPos = 7;
+ }
+ else if ( m_name == "PS0" )
+ {
+ m_registerType = Register::OPTION_REG;
+ m_bitPos = 0;
+ }
+ else if ( m_name == "PS1" )
+ {
+ m_registerType = Register::OPTION_REG;
+ m_bitPos = 1;
+ }
+ else if ( m_name == "PS2" )
+ {
+ m_registerType = Register::OPTION_REG;
+ m_bitPos = 2;
+ }
+ else if ( m_name == "PSA" )
+ {
+ m_registerType = Register::OPTION_REG;
+ m_bitPos = 3;
+ }
+ else if ( m_name == "T0SE" )
+ {
+ m_registerType = Register::OPTION_REG;
+ m_bitPos = 4;
+ }
+ else if ( m_name == "T0CS" )
+ {
+ m_registerType = Register::OPTION_REG;
+ m_bitPos = 5;
+ }
+ else if ( m_name == "INTEDG" )
+ {
+ m_registerType = Register::OPTION_REG;
+ m_bitPos = 6;
+ }
+ else if ( m_name == "NOT_RBPU" )
+ {
+ m_registerType = Register::OPTION_REG;
+ m_bitPos = 7;
+ }
+ else if ( m_name == "RD" )
+ {
+ m_registerType = Register::EECON1;
+ m_bitPos = 0;
+ }
+ else if ( m_name == "WR" )
+ {
+ m_registerType = Register::EECON1;
+ m_bitPos = 1;
+ }
+ else if ( m_name == "WREN" )
+ {
+ m_registerType = Register::EECON1;
+ m_bitPos = 2;
+ }
+ else if ( m_name == "WRERR" )
+ {
+ m_registerType = Register::EECON1;
+ m_bitPos = 3;
+ }
+ else if ( m_name == "EEIF" )
+ {
+ m_registerType = Register::EECON1;
+ m_bitPos = 4;
+ }
+ else
+ {
+ m_registerType = Register::none;
+ m_bitPos = 0;
+ kdError() << k_funcinfo << "Unknown bit: " << m_name << endl;
+ }
+}
+//END class RegisterBit
+
+
+
+
+//BEGIN class RegisterState
+RegisterState::RegisterState()
+{
+ reset();
+}
+
+
+void RegisterState::reset()
+{
+ known = 0x0;
+ value = 0x0;
+}
+
+
+void RegisterState::merge( const RegisterState & state )
+{
+ known &= state.known;
+ known &= ~( value ^ state.value );
+}
+
+
+bool RegisterState::operator == ( const RegisterState & state ) const
+{
+ return (known == state.known) && (value == state.value);
+}
+
+
+void RegisterState::print()
+{
+ cout << " known="<<binary(known)<<endl;
+ cout << " value="<<binary(value)<<endl;
+}
+//END class RegisterState
+
+
+
+//BEGIN class RegisterBehaviour
+RegisterBehaviour::RegisterBehaviour()
+{
+ reset();
+}
+
+
+void RegisterBehaviour::reset()
+{
+ depends = 0x0;
+ indep = 0x0;
+}
+//END class RegisterBehaviour
+
+
+
+//BEGIN class ProcessorState
+ProcessorState::ProcessorState()
+{
+}
+
+
+void ProcessorState::reset()
+{
+ working.reset();
+ status.reset();
+
+ RegisterMap::iterator end = m_registers.end();
+ for ( RegisterMap::iterator it = m_registers.begin(); it != end; ++it )
+ (*it).reset();
+}
+
+
+void ProcessorState::merge( const ProcessorState & state )
+{
+ working.merge( state.working );
+ status.merge( state.status );
+
+ RegisterMap::iterator this_it = m_registers.begin();
+ RegisterMap::const_iterator other_it = state.m_registers.begin();
+
+ RegisterMap::iterator this_end = m_registers.end();
+ RegisterMap::const_iterator other_end = state.m_registers.end();
+
+ while ( true )
+ {
+ if ( this_it == this_end )
+ {
+ // So remaining registers of this are default
+ while ( other_it != other_end )
+ {
+ m_registers[ other_it.key() ].merge( *other_it );
+ ++other_it;
+ }
+ return;
+ }
+
+ if ( other_it == other_end )
+ {
+ // So remaining registers of other are default
+ while ( this_it != this_end )
+ {
+ (*this_it).merge( RegisterState() );
+ ++this_it;
+ }
+ return;
+ }
+
+ RegisterState thisReg = *this_it;
+ RegisterState otherReg = *other_it;
+
+ if ( this_it.key() == other_it.key() )
+ {
+ (*this_it).merge( *other_it );
+ ++this_it;
+ ++other_it;
+ }
+ else if ( this_it.key() < other_it.key() )
+ {
+ (*this_it).merge( RegisterState() );
+ ++this_it;
+ }
+ else // other_it.key() < this_it.key()
+ {
+ m_registers[ other_it.key() ].merge( *other_it );
+ ++other_it;
+ }
+ }
+}
+
+
+RegisterState & ProcessorState::reg( const Register & reg )
+{
+ if ( reg.type() == Register::WORKING )
+ return working;
+
+ if ( reg.type() == Register::STATUS )
+ return status;
+
+ return m_registers[ reg ];
+}
+
+
+RegisterState ProcessorState::reg( const Register & reg ) const
+{
+ if ( reg.type() == Register::WORKING )
+ return working;
+
+ if ( reg.type() == Register::STATUS )
+ return status;
+
+ return m_registers[ reg ];
+}
+
+
+bool ProcessorState::operator == ( const ProcessorState & state ) const
+{
+ if ( working != state.working )
+ return false;
+
+ if ( status != state.status )
+ return false;
+
+ RegisterMap::const_iterator this_it = m_registers.begin();
+ RegisterMap::const_iterator other_it = state.m_registers.begin();
+
+ RegisterMap::const_iterator this_end = m_registers.end();
+ RegisterMap::const_iterator other_end = state.m_registers.end();
+
+ while ( true )
+ {
+ if ( this_it == this_end )
+ {
+ // So remaining registers of this are default
+ while ( other_it != other_end )
+ {
+ if ( *other_it != RegisterState() )
+ return false;
+ ++other_it;
+ }
+ return true;
+ }
+
+ if ( other_it == other_end )
+ {
+ // So remaining registers of other are default
+ while ( this_it != this_end )
+ {
+ if ( *this_it != RegisterState() )
+ return false;
+ ++this_it;
+ }
+ return true;
+ }
+
+ RegisterState thisReg = *this_it;
+ RegisterState otherReg = *other_it;
+
+ if ( this_it.key() == other_it.key() )
+ {
+ if ( *this_it != *other_it )
+ return false;
+ ++this_it;
+ ++other_it;
+ }
+ else if ( this_it.key() < other_it.key() )
+ {
+ if ( *this_it != RegisterState() )
+ return false;
+ ++this_it;
+ }
+ else // other_it.key() < this_it.key()
+ {
+ if ( *other_it != RegisterState() )
+ return false;
+ ++other_it;
+ }
+ }
+}
+
+
+void ProcessorState::print()
+{
+ cout << " WORKING:\n";
+ working.print();
+ cout << " STATUS:\n";
+ working.print();
+ RegisterMap::iterator end = m_registers.end();
+ for ( RegisterMap::iterator it = m_registers.begin(); it != end; ++it )
+ {
+ cout << " " << it.key().name() << ":\n";
+ it.data().print();
+ }
+}
+//END class ProcessorState
+
+
+
+//BEGIN class ProcessorBehaviour
+ProcessorBehaviour::ProcessorBehaviour()
+{
+}
+
+
+void ProcessorBehaviour::reset()
+{
+ working.reset();
+ status.reset();
+
+ RegisterMap::iterator end = m_registers.end();
+ for ( RegisterMap::iterator it = m_registers.begin(); it != end; ++it )
+ (*it).reset();
+}
+
+
+RegisterBehaviour & ProcessorBehaviour::reg( const Register & reg )
+{
+ if ( reg.type() == Register::WORKING )
+ return working;
+
+ if ( reg.type() == Register::STATUS )
+ return status;
+
+ return m_registers[ reg ];
+}
+//END class ProcessorBehaviour
+
+
+
+//BEGIN class RegisterDepends
+RegisterDepends::RegisterDepends()
+{
+ reset();
+}
+
+
+void RegisterDepends::reset()
+{
+ working = 0x0;
+ status = 0x0;
+
+ RegisterMap::iterator end = m_registers.end();
+ for ( RegisterMap::iterator it = m_registers.begin(); it != end; ++it )
+ (*it) = 0x0;
+}
+
+
+uchar & RegisterDepends::reg( const Register & reg )
+{
+ if ( reg.type() == Register::WORKING )
+ return working;
+
+ if ( reg.type() == Register::STATUS )
+ return status;
+
+ // If we don't already have the register, we need to reset it first
+ if ( !m_registers.contains( reg.name() ) )
+ m_registers[ reg ] = 0xff;
+
+ return m_registers[ reg ];
+}
+//END class RegisterDepends
+
+
+
+//BEGIN clas Code
+Code::Code()
+{
+}
+
+
+void Code::merge( Code * code, InstructionPosition middleInsertionPosition )
+{
+ if ( code == this )
+ {
+ cout << k_funcinfo << "identical\n";
+ return;
+ }
+
+ if ( !code )
+ return;
+
+ // Reparent instructions
+ for ( unsigned i = 0; i < PositionCount; ++i )
+ {
+ InstructionList * list = code->instructionList( (InstructionPosition)i );
+ InstructionList::const_iterator end = list->end();
+ for ( InstructionList::const_iterator it = list->begin(); it != end; ++it )
+ append( *it, ( (i == Middle) ? middleInsertionPosition : (InstructionPosition)i ) );
+
+ // Queue any labels that the other code has queued
+ m_queuedLabels[i] += code->queuedLabels( (InstructionPosition)i );
+ }
+}
+
+
+void Code::queueLabel( const QString & label, InstructionPosition position )
+{
+// cout << k_funcinfo << "label="<<label<<" position="<<position<<'\n';
+ m_queuedLabels[ position ] << label;
+}
+
+
+void Code::removeInstruction( Instruction * instruction )
+{
+ if ( !instruction )
+ return;
+
+ // If the instruction could potentially be jumped over by a BTFSS or a
+ // BTFSC intsruction, then we must also remove the bit test instruction,
+ // else the next instruction will be jumped over instead after removal.
+ // Removing the bit test instruction is perfectly safe as it only does
+ // branching (not setting of any bits, etc).
+
+ // Any labels that the instruction has must be given to the next
+ // instruction.
+
+ iterator e = end();
+ iterator previous = e; // Refers to the previous instruction if it was a bit test instruction
+ for ( iterator i = begin(); i != e; ++i )
+ {
+ if ( *i != instruction )
+ {
+ if ( dynamic_cast<Instr_btfss*>(*i) || dynamic_cast<Instr_btfsc*>(*i) )
+ previous = i;
+ else
+ previous = e;
+ continue;
+ }
+
+ iterator next = ++iterator(i);
+
+ QStringList labels = instruction->labels();
+ i.list->remove( i.it );
+
+ if ( previous != e )
+ {
+ labels += (*previous)->labels();
+ previous.list->remove( previous.it );
+ }
+
+ if ( next != e )
+ (*next)->addLabels( labels );
+
+ break;
+ }
+
+// instruction->removeOutputs();
+}
+
+
+void Code::append( Instruction * instruction, InstructionPosition position )
+{
+ if ( !instruction )
+ return;
+
+// cout << k_funcinfo << instruction->code() << '\n';
+
+ removeInstruction( instruction );
+ m_instructionLists[position].append( instruction );
+
+ instruction->setCode( this );
+
+ if ( instruction->type() == Instruction::Assembly /*||
+ instruction->type() == Instruction::Raw*/ )
+ {
+// if ( (position == Middle) && !m_queuedLabels[position].isEmpty() )
+// cout << "adding queued labels for 1: " << m_queuedLabels[position].join(",") << '\n';
+ instruction->addLabels( m_queuedLabels[position] );
+ m_queuedLabels[position].clear();
+ }
+}
+
+
+Instruction * Code::instruction( const QString & label ) const
+{
+ for ( unsigned i = 0; i < PositionCount; ++i )
+ {
+ InstructionList::const_iterator end = m_instructionLists[i].end();
+ for ( InstructionList::const_iterator it = m_instructionLists[i].begin(); it != end; ++it )
+ {
+ if ( (*it)->labels().contains( label ) )
+ return *it;
+ }
+ }
+ return 0l;
+}
+
+
+Code::iterator Code::find( Instruction * instruction )
+{
+ iterator e = end();
+ iterator i = begin();
+ for ( ; i != e; ++i )
+ {
+ if ( *i == instruction )
+ break;
+ }
+ return i;
+}
+
+
+void Code::postCompileConstruct()
+{
+ // Give any queued labels to the instructions in the subsequent code block
+ for ( unsigned i = 0; i < PositionCount; ++i )
+ {
+ if ( m_queuedLabels[i].isEmpty() )
+ continue;
+
+ QStringList labels = m_queuedLabels[i];
+ m_queuedLabels[i].clear();
+
+ // Find an instruction to dump them onto
+ for ( unsigned block = i+1; block < PositionCount; ++block )
+ {
+ bool added = false;
+
+ InstructionList::iterator end = m_instructionLists[block].end();
+ for ( InstructionList::iterator it = m_instructionLists[block].begin(); it != end; ++it )
+ {
+ if ( (*it)->type() == Instruction::Assembly )
+ {
+ (*it)->addLabels( labels );
+ added = true;
+ break;
+ }
+ }
+
+ if ( added )
+ break;
+ }
+ }
+}
+
+
+QString Code::generateCode( PIC14 * pic ) const
+{
+ QString code;
+
+ const QStringList variables = findVariables();
+ if ( !variables.isEmpty() )
+ {
+ code += "; Variables\n";
+ uchar reg = pic->gprStart();
+ QStringList::const_iterator end = variables.end();
+ for ( QStringList::const_iterator it = variables.begin(); it != end; ++it )
+ code += QString("%1\tequ\t0x%2\n").arg( *it ).arg( QString::number( reg++, 16 ) );
+
+ code += "\n";
+ }
+
+ QString picString = pic->minimalTypeString();
+ code += QString("list p=%1\n").arg( picString );
+ code += QString("include \"p%2.inc\"\n\n").arg( picString.lower() );
+
+ code += "; Config options\n";
+ code += " __config _WDT_OFF\n\n";
+
+ code += "START\n\n";
+
+ for ( unsigned i = 0; i < PositionCount; ++i )
+ {
+ InstructionList::const_iterator end = m_instructionLists[i].end();
+ for ( InstructionList::const_iterator it = m_instructionLists[i].begin(); it != end; ++it )
+ {
+ const QStringList labels = (*it)->labels();
+ if ( !labels.isEmpty() )
+ {
+ code += '\n';
+ QStringList::const_iterator labelsEnd = labels.end();
+ for ( QStringList::const_iterator labelsIt = labels.begin(); labelsIt != labelsEnd; ++labelsIt )
+ code += *labelsIt + '\n';
+ }
+
+ if ( (*it)->type() == Instruction::Assembly )
+ code += '\t';
+ code += (*it)->code() + '\n';
+ }
+ }
+
+ return code;
+}
+
+
+QStringList Code::findVariables() const
+{
+ QStringList variables;
+
+ const_iterator e = end();
+ for ( const_iterator i = begin(); i != e; ++i )
+ {
+ if ( (*i)->file().type() != Register::GPR )
+ continue;
+
+ QString alias = (*i)->file().name();
+ if ( !variables.contains( alias ) )
+ variables << alias;
+ }
+
+ return variables;
+}
+
+
+void Code::generateLinksAndStates()
+{
+ CodeIterator e = end();
+
+ for ( CodeIterator it = begin(); it != e; ++it )
+ (*it)->clearLinks();
+
+ for ( CodeIterator it = begin(); it != e; ++it )
+ (*it)->generateLinksAndStates( it );
+
+ // Generate return links for call instructions
+ // This cannot be done from the call instructions as we need to have
+ // generated the links first.
+ for ( CodeIterator it = begin(); it != e; ++it )
+ {
+ Instr_call * ins = dynamic_cast<Instr_call*>(*it);
+ if ( !ins )
+ continue;
+
+ Instruction * next = *(++Code::iterator(it));
+ ins->makeReturnLinks( next );
+ }
+}
+
+
+void Code::setAllUnused()
+{
+ CodeIterator e = end();
+ for ( CodeIterator it = begin(); it != e; ++it )
+ {
+ (*it)->setUsed( false );
+ (*it)->resetRegisterDepends();
+ }
+}
+
+
+CodeIterator Code::begin()
+{
+ // Following code is very similar to the version of this function.
+ // Make sure any changes are applied to both (when applicable).
+
+ for ( unsigned i = 0; i < PositionCount; ++i )
+ {
+ if ( m_instructionLists[i].isEmpty() )
+ continue;
+
+ CodeIterator codeIterator;
+ codeIterator.code = this;
+ codeIterator.it = m_instructionLists[i].begin();
+ codeIterator.pos = (Code::InstructionPosition)i;
+ codeIterator.list = & m_instructionLists[i];
+ codeIterator.listEnd = m_instructionLists[i].end();
+
+ return codeIterator;
+ }
+
+ return end();
+}
+
+
+CodeIterator Code::end()
+{
+ // Following code is very similar to the version of this function.
+ // Make sure any changes are applied to both (when applicable).
+
+ CodeIterator codeIterator;
+ codeIterator.code = this;
+ codeIterator.it = m_instructionLists[ PositionCount - 1 ].end();
+ codeIterator.pos = (Code::InstructionPosition)(Code::PositionCount - 1);
+ codeIterator.list = & m_instructionLists[ PositionCount - 1 ];
+ codeIterator.listEnd = m_instructionLists[ PositionCount - 1 ].end();
+ return codeIterator;
+}
+
+
+CodeConstIterator Code::begin() const
+{
+ // Following code is very similar to the non-const version of this function.
+ // Make sure any changes are applied to both (when applicable).
+
+ for ( unsigned i = 0; i < PositionCount; ++i )
+ {
+ if ( m_instructionLists[i].isEmpty() )
+ continue;
+
+ CodeConstIterator codeIterator;
+ codeIterator.code = this;
+ codeIterator.it = m_instructionLists[i].begin();
+ codeIterator.pos = (Code::InstructionPosition)i;
+ codeIterator.list = & m_instructionLists[i];
+ codeIterator.listEnd = m_instructionLists[i].end();
+
+ return codeIterator;
+ }
+
+ return end();
+}
+
+
+CodeConstIterator Code::end() const
+{
+ // Following code is very similar to the non-const version of this function.
+ // Make sure any changes are applied to both (when applicable).
+
+ CodeConstIterator codeIterator;
+ codeIterator.code = this;
+ codeIterator.it = m_instructionLists[ PositionCount - 1 ].end();
+ codeIterator.pos = (Code::InstructionPosition)(Code::PositionCount - 1);
+ codeIterator.list = & m_instructionLists[ PositionCount - 1 ];
+ codeIterator.listEnd = m_instructionLists[ PositionCount - 1 ].end();
+ return codeIterator;
+}
+//END class Code
+
+
+
+//BEGIN class CodeIterator
+CodeIterator & CodeIterator::operator ++ ()
+{
+ // NOTE: This code is very similar to the const version.
+ // Any changes to thsi code should be applied there as well (when applicable).
+
+ do
+ {
+ if ( ++it == listEnd && pos < (Code::PositionCount - 1) )
+ {
+ bool found = false;
+ for ( pos = (Code::InstructionPosition)(pos+1); pos < Code::PositionCount; pos = (Code::InstructionPosition)(pos+1) )
+ {
+ list = code->instructionList( pos );
+ listEnd = list->end();
+ if ( list->isEmpty() )
+ continue;
+
+ it = list->begin();
+ found = true;
+ break;
+ }
+
+ if ( !found )
+ it = listEnd;
+ }
+ }
+ while ( (it != listEnd) && ((*it)->type() != Instruction::Assembly) );
+
+ return *this;
+}
+
+
+CodeIterator & CodeIterator::removeAndIncrement()
+{
+ Instruction * i = *it;
+ ++(*this);
+ code->removeInstruction( i );
+ return *this;
+}
+
+
+void CodeIterator::insertBefore( Instruction * ins )
+{
+ list->insert( it, ins );
+}
+//END class CodeIterator
+
+
+
+//BEGIN class CodeConstIterator
+CodeConstIterator & CodeConstIterator::operator ++ ()
+{
+ // NOTE: This code is very similar to the non-const version.
+ // Any changes to thsi code should be applied there as well (when applicable).
+
+ do
+ {
+ if ( ++it == listEnd && pos < (Code::PositionCount - 1) )
+ {
+ bool found = false;
+ for ( pos = (Code::InstructionPosition)(pos+1); pos < Code::PositionCount; pos = (Code::InstructionPosition)(pos+1) )
+ {
+ list = code->instructionList( pos );
+ listEnd = list->end();
+ if ( list->isEmpty() )
+ continue;
+
+ it = list->begin();
+ found = true;
+ break;
+ }
+
+ if ( !found )
+ it = listEnd;
+ }
+ }
+ while ( (it != listEnd) && ((*it)->type() != Instruction::Assembly) );
+
+ return *this;
+}
+//END class CodeConstIterator
+
+
+
+
+//BEGIN class Instruction
+Instruction::Instruction()
+{
+ m_bInputStateChanged = true;
+ m_bPositionAffectsBranching = false;
+ m_bUsed = false;
+ m_literal = 0;
+ m_dest = 0;
+}
+
+
+Instruction::~ Instruction()
+{
+}
+
+
+void Instruction::addLabels( const QStringList & labels )
+{
+ m_labels += labels;
+}
+
+
+void Instruction::setLabels( const QStringList & labels )
+{
+ m_labels = labels;
+}
+
+
+void Instruction::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+ m_outputState.reset();
+}
+
+
+ProcessorBehaviour Instruction::behaviour() const
+{
+ return ProcessorBehaviour();
+}
+
+
+void Instruction::makeOutputLinks( Code::iterator current, bool firstOutput, bool secondOutput )
+{
+ if ( !firstOutput && !secondOutput )
+ return;
+
+ ++current;
+ if ( !*current )
+ {
+ kdWarning() << k_funcinfo << "current+1 is null"<<endl;
+ return;
+ }
+ if ( firstOutput )
+ (*current)->addInputLink( this );
+
+ if ( !secondOutput )
+ return;
+
+ ++current;
+ (*current)->addInputLink( this );
+}
+
+
+void Instruction::makeLabelOutputLink( const QString & label )
+{
+ Instruction * output = m_pCode->instruction( label );
+ if ( output )
+ output->addInputLink( this );
+}
+
+
+void Instruction::addInputLink( Instruction * instruction )
+{
+ // Don't forget that a link to ourself is valid!
+ if ( !instruction || m_inputLinks.contains( instruction ) )
+ return;
+
+ m_inputLinks << instruction;
+ instruction->addOutputLink( this );
+}
+
+
+void Instruction::addOutputLink( Instruction * instruction )
+{
+ // Don't forget that a link to ourself is valid!
+ if ( !instruction || m_outputLinks.contains( instruction ) )
+ return;
+
+ m_outputLinks << instruction;
+ instruction->addInputLink( this );
+}
+
+
+void Instruction::removeInputLink( Instruction * instruction )
+{
+ m_inputLinks.remove( instruction );
+}
+
+
+void Instruction::removeOutputLink( Instruction * instruction )
+{
+ m_outputLinks.remove( instruction );
+}
+
+
+void Instruction::clearLinks()
+{
+ m_inputLinks.clear();
+ m_outputLinks.clear();
+}
+//END class Instruction
+
+
+
+//BEGIN Byte-Oriented File Register Operations
+QString Instr_addwf::code() const
+{
+ return QString("addwf\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_addwf::generateLinksAndStates( Code::iterator current )
+{
+ m_outputState = m_inputState;
+
+ m_outputState.reg( outputReg() ).value = (m_inputState.working.value + m_inputState.reg( m_file ).value) & 0xff;
+ m_outputState.reg( outputReg() ).known = ((m_inputState.working.known == 0xff) && (m_inputState.reg( m_file ).known == 0xff)) ? 0xff : 0x0;
+
+ m_outputState.status.known &= ~( (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z) );
+
+ if ( m_file.type() != Register::PCL || m_dest == 0 )
+ {
+ makeOutputLinks( current );
+ return;
+ }
+
+ ++current; // Don't have a link to ourself
+
+ // maxInc is the greatest possibly value that we might have incremented the program counter by.
+ // It is generated by ORing the known bits of the working register with the greatest value
+ // of the unknown bits;
+ uchar maxInc = m_inputState.working.maxValue();
+ if ( maxInc < 0xff )
+ maxInc++;
+// cout << "m_inputState.working.known="<<int(m_inputState.working.known)<<" maxInc="<<int(maxInc)<<'\n';
+ Code::iterator end = m_pCode->end();
+ for ( int i = 0; current != end && i < maxInc; ++i, ++current )
+ {
+ (*current)->addInputLink( this );
+// if ( i != maxInc-1 )
+// (*current)->setPositionAffectsBranching( true );
+ }
+}
+
+ProcessorBehaviour Instr_addwf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ // Depend on W and f
+ behaviour.working.depends = 0xff;
+ behaviour.reg( m_file ).depends = 0xff;
+
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ behaviour.status.indep = (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z);
+ return behaviour;
+}
+
+
+
+QString Instr_andwf::code() const
+{
+ return QString("andwf\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_andwf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+ m_outputState = m_inputState;
+
+ uchar definiteOnes = m_inputState.reg( m_file ).definiteOnes() & m_outputState.working.definiteOnes();
+ m_outputState.reg( outputReg() ).value = definiteOnes;
+ m_outputState.reg( outputReg() ).known = m_inputState.reg( m_file ).definiteZeros() | m_inputState.working.definiteZeros() | definiteOnes;
+
+ m_outputState.status.known &= ~(1 << RegisterBit::Z);
+}
+
+ProcessorBehaviour Instr_andwf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ // Depend on W and f
+ behaviour.working.depends = 0xff;
+ behaviour.reg( m_file ).depends = 0xff;
+
+ if ( m_dest == 0 )
+ behaviour.working.indep = m_inputState.reg( m_file ).known & ~( m_inputState.reg( m_file ).value);
+
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ behaviour.status.indep = (1 << RegisterBit::Z);
+ return behaviour;
+}
+
+
+QString Instr_clrf::code() const
+{
+ return QString("clrf\t%1").arg( m_file.name() );
+}
+
+void Instr_clrf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.reg( m_file ).known = 0xff;
+ m_outputState.reg( m_file ).value = 0x0;
+
+ m_outputState.status.known |= (1 << RegisterBit::Z);
+ m_outputState.status.value |= (1 << RegisterBit::Z);
+}
+
+ProcessorBehaviour Instr_clrf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ behaviour.reg( m_file ).indep = 0xff;
+
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ behaviour.status.indep = (1 << RegisterBit::Z);
+
+ return behaviour;
+}
+
+
+//TODO CLRW
+//TODO COMF
+
+
+QString Instr_decf::code() const
+{
+ return QString("decf\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_decf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.status.known &= ~(1 << RegisterBit::Z);
+
+ m_outputState.reg( outputReg() ).known = 0x0;
+}
+
+ProcessorBehaviour Instr_decf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ behaviour.reg( m_file ).depends = 0xff;
+
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ behaviour.status.indep = (1 << RegisterBit::Z);
+
+ return behaviour;
+}
+
+
+QString Instr_decfsz::code() const
+{
+ return QString("decfsz\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_decfsz::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current, true, true );
+
+ m_outputState = m_inputState;
+ m_outputState.reg( outputReg() ).known = 0x0;
+}
+
+ProcessorBehaviour Instr_decfsz::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ behaviour.reg( m_file ).depends = 0xff;
+
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ return behaviour;
+}
+
+
+QString Instr_incf::code() const
+{
+ return QString("incf\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_incf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.status.known &= ~(1 << RegisterBit::Z);
+
+ m_outputState.reg( outputReg() ).known = 0x0;
+}
+
+ProcessorBehaviour Instr_incf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ behaviour.reg( m_file ).depends = 0xff;
+
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ behaviour.status.indep = (1 << RegisterBit::Z);
+ return behaviour;
+}
+
+
+//TODO INCFSZ
+
+
+QString Instr_iorwf::code() const
+{
+ return QString("iorwf\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_iorwf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.status.known &= ~(1 << RegisterBit::Z);
+
+ m_outputState.reg( outputReg() ).known = 0x0;
+}
+
+ProcessorBehaviour Instr_iorwf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ // Depend on W and f
+ behaviour.working.depends = 0xff;
+ behaviour.reg( m_file ).depends = 0xff;
+
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ behaviour.status.indep = (1 << RegisterBit::Z);
+ return behaviour;
+}
+
+
+QString Instr_movf::code() const
+{
+ return QString("movf\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_movf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+
+ if ( m_inputState.reg( m_file ).known == 0xff )
+ {
+ m_outputState.status.known |= (1 << RegisterBit::Z);
+ bool isZero = (m_inputState.reg( m_file ).value == 0x0);
+ if ( isZero )
+ m_outputState.status.value |= (1 << RegisterBit::Z);
+ else
+ m_outputState.status.value &= ~(1 << RegisterBit::Z);
+ }
+ else
+ m_outputState.status.known &= ~(1 << RegisterBit::Z);
+
+ if ( m_dest == 0 )
+ {
+ // Writing to the working register
+ m_outputState.working.known = m_inputState.reg( m_file ).known;
+ m_outputState.working.value = m_inputState.reg( m_file ).value;
+ }
+}
+
+ProcessorBehaviour Instr_movf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ if ( m_dest == 0 )
+ behaviour.working.indep = 0xff;
+
+ behaviour.reg( m_file ).depends = 0xff;
+
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ behaviour.status.indep = (1 << RegisterBit::Z);
+ return behaviour;
+}
+
+
+QString Instr_movwf::code() const
+{
+ return QString("movwf\t%1").arg( m_file.name() );
+}
+
+void Instr_movwf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.reg( m_file ).known = m_inputState.working.known;
+ m_outputState.reg( m_file ).value = m_inputState.working.value;
+}
+
+ProcessorBehaviour Instr_movwf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ behaviour.reg( m_file ).indep = 0xff;
+ behaviour.working.depends = 0xff;
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+
+ return behaviour;
+}
+
+
+//TODO NOP
+
+
+
+QString Instr_rlf::code() const
+{
+ return QString("rlf\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_rlf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.status.known &= ~(1 << RegisterBit::C);
+
+ m_outputState.reg( outputReg() ).known = 0x0;
+}
+
+ProcessorBehaviour Instr_rlf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ // Is the value written to W or f?
+ if ( m_dest == 0 )
+ behaviour.working.indep = 0xff;
+
+ behaviour.reg( m_file ).depends = 0xff;
+
+ behaviour.status.depends = (1 << RegisterBit::C) | (m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0);
+ behaviour.status.indep = (1 << RegisterBit::C);
+ return behaviour;
+}
+
+
+QString Instr_rrf::code() const
+{
+ return QString("rrf\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_rrf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.status.known &= ~(1 << RegisterBit::C);
+
+ m_outputState.reg( outputReg() ).known = 0x0;
+}
+
+ProcessorBehaviour Instr_rrf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ if ( m_dest == 0 )
+ behaviour.working.indep = 0xff;
+
+ behaviour.reg( m_file ).depends = 0xff;
+
+ behaviour.status.depends = (1 << RegisterBit::C) | (m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0);
+ behaviour.status.indep = (1 << RegisterBit::C);
+ return behaviour;
+}
+
+
+QString Instr_subwf::code() const
+{
+ return QString("subwf\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_subwf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+
+ if ( (m_inputState.working.known == 0xff) && (m_inputState.reg( m_file ).known == 0xff) )
+ {
+ m_outputState.reg( outputReg() ).known = 0xff;
+ m_outputState.reg( outputReg() ).value = (m_inputState.reg( m_file ).value - m_inputState.working.value) & 0xff;
+ }
+ else
+ m_outputState.reg( outputReg() ).known = 0x0;
+
+
+ m_outputState.status.known &= ~( (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z) );
+
+ if ( m_inputState.working.minValue() > m_inputState.reg( m_file ).maxValue() )
+ {
+ m_outputState.status.value &= ~(1 << RegisterBit::C);
+ m_outputState.status.known |= (1 << RegisterBit::C);
+ }
+ else if ( m_inputState.working.maxValue() <= m_inputState.reg( m_file ).minValue() )
+ {
+ m_outputState.status.value |= (1 << RegisterBit::C);
+ m_outputState.status.known |= (1 << RegisterBit::C);
+ }
+
+ if ( (m_inputState.working.known == 0xff) && (m_inputState.reg( m_file ).known == 0xff) )
+ {
+ bool isZero = (m_inputState.working.value == m_inputState.reg( m_file ).value);
+ if ( isZero )
+ m_outputState.status.value |= (1 << RegisterBit::Z);
+ else
+ m_outputState.status.value &= ~(1 << RegisterBit::Z);
+ m_outputState.status.known |= (1 << RegisterBit::Z);
+ }
+}
+
+ProcessorBehaviour Instr_subwf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ // Depend on W and f
+ behaviour.working.depends = 0xff;
+ behaviour.reg( m_file ).depends = 0xff;
+
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ behaviour.status.indep = (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z);
+ return behaviour;
+}
+
+
+QString Instr_swapf::code() const
+{
+ return QString("swapf\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_swapf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ if ( m_dest == 0 )
+ {
+ // Writing to the working register
+ m_outputState.working.known = 0x0;
+ }
+}
+
+ProcessorBehaviour Instr_swapf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ behaviour.reg( m_file ).depends = 0xff;
+ behaviour.working.indep = ( m_dest == 0 ) ? 0xff : 0x0;
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ return behaviour;
+}
+
+
+QString Instr_xorwf::code() const
+{
+ return QString("xorwf\t%1,%2").arg( m_file.name() ).arg( m_dest );
+}
+
+void Instr_xorwf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.status.known &= ~(1 << RegisterBit::Z);
+
+ m_outputState.reg( outputReg() ).known = 0x0;
+}
+
+ProcessorBehaviour Instr_xorwf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ // Depend on W and f
+ behaviour.working.depends = 0xff;
+ behaviour.reg( m_file ).depends = 0xff;
+
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ behaviour.status.indep = (1 << RegisterBit::Z);
+ return behaviour;
+}
+//END Byte-Oriented File Register Operations
+
+
+
+//BEGIN Bit-Oriented File Register Operations
+QString Instr_bcf::code() const
+{
+ return QString("bcf\t\t%1,%2").arg( m_file.name() ).arg( m_bit.name() );
+}
+
+void Instr_bcf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.reg( m_file ).value &= ~uchar(1 << m_bit.bitPos());
+ m_outputState.reg( m_file ).known |= uchar(1 << m_bit.bitPos());
+}
+
+ProcessorBehaviour Instr_bcf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ behaviour.reg( m_file ).indep = 1 << m_bit.bitPos();
+ return behaviour;
+}
+
+
+QString Instr_bsf::code() const
+{
+ return QString("bsf\t\t%1,%2").arg( m_file.name() ).arg( m_bit.name() );
+}
+
+void Instr_bsf::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.reg( m_file ).value |= uchar(1 << m_bit.bitPos());
+ m_outputState.reg( m_file ).known |= uchar(1 << m_bit.bitPos());
+}
+
+ProcessorBehaviour Instr_bsf::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ behaviour.status.depends = m_file.bankDependent() ? (1 << RegisterBit::RP0) : 0x0;
+ behaviour.reg( m_file ).indep = 1 << m_bit.bitPos();
+ return behaviour;
+}
+
+
+QString Instr_btfsc::code() const
+{
+ return QString("btfsc\t%1,%2").arg( m_file.name() ).arg( m_bit.name() );
+}
+
+void Instr_btfsc::generateLinksAndStates( Code::iterator current )
+{
+ m_outputState = m_inputState;
+
+ if ( m_inputState.reg( m_file ).known & (1 << m_bit.bitPos()) )
+ {
+ bool bit = m_inputState.reg( m_file ).value & (1 << m_bit.bitPos());
+ makeOutputLinks( current, bit, !bit );
+ }
+ else
+ makeOutputLinks( current, true, true );
+}
+
+ProcessorBehaviour Instr_btfsc::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ behaviour.reg( m_file ).depends = 1 << m_bit.bitPos();
+ behaviour.status.depends = (m_file.type() == Register::STATUS) ? m_bit.bit() : 0x0;
+ return behaviour;
+}
+
+
+QString Instr_btfss::code() const
+{
+ return QString("btfss\t%1,%2").arg( m_file.name() ).arg( m_bit.name() );
+}
+
+void Instr_btfss::generateLinksAndStates( Code::iterator current )
+{
+ m_outputState = m_inputState;
+
+ if ( m_inputState.reg( m_file ).known & (1 << m_bit.bitPos()) )
+ {
+ bool bit = m_inputState.reg( m_file ).value & (1 << m_bit.bitPos());
+ makeOutputLinks( current, !bit, bit );
+ }
+ else
+ makeOutputLinks( current, true, true );
+}
+
+ProcessorBehaviour Instr_btfss::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ behaviour.reg( m_file ).depends = 1 << m_bit.bitPos();
+ behaviour.status.depends = (m_file.type() == Register::STATUS) ? m_bit.bit() : 0x0;
+ return behaviour;
+}
+//END Bit-Oriented File Register Operations
+
+
+
+//BEGIN Literal and Control Operations
+QString Instr_addlw::code() const
+{
+ return QString("addlw\t%1").arg( m_literal );
+}
+
+void Instr_addlw::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.working.value = (m_inputState.working.value + m_literal) & 0xff;
+ m_outputState.working.known = (m_inputState.working.known == 0xff) ? 0xff : 0x0;
+ m_outputState.status.known &= ~( (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z) );
+}
+
+ProcessorBehaviour Instr_addlw::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ behaviour.working.depends = 0xff;
+
+ behaviour.status.indep = (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z);
+
+ return behaviour;
+}
+
+
+QString Instr_andlw::code() const
+{
+ return QString("andlw\t%1").arg( m_literal );
+}
+
+void Instr_andlw::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.working.value = (m_inputState.working.value & m_literal) & 0xff;
+ m_outputState.working.known |= ~m_literal; // Now know any bits that are zero in value
+ m_outputState.status.known &= ~(1 << RegisterBit::Z);
+}
+
+ProcessorBehaviour Instr_andlw::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ behaviour.working.indep = ~m_literal;
+ behaviour.working.depends = m_literal;
+
+ behaviour.status.indep = (1 << RegisterBit::Z);
+ return behaviour;
+}
+
+
+QString Instr_call::code() const
+{
+ return QString("call\t%1").arg( m_label );
+}
+
+void Instr_call::generateLinksAndStates( Code::iterator current )
+{
+ (void)current;
+ makeLabelOutputLink( m_label );
+
+ m_outputState = m_inputState;
+}
+
+ProcessorBehaviour Instr_call::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ return behaviour;
+}
+
+void Instr_call::makeReturnLinks( Instruction * next )
+{
+ m_pCode->setAllUnused();
+ linkReturns( m_pCode->instruction( m_label ), next );
+}
+
+
+void Instr_call::linkReturns( Instruction * current, Instruction * returnPoint )
+{
+ while (true)
+ {
+ if ( !current || current->isUsed() )
+ return;
+
+ current->setUsed( true );
+ if ( dynamic_cast<Instr_return*>(current) || dynamic_cast<Instr_retlw*>(current) )
+ {
+// cout << "Added return link" << endl;
+// cout << " FROM: " << current->code() << endl;
+// cout << " TO: " << returnPoint->code() << endl;
+ returnPoint->addInputLink( current );
+ return;
+ }
+ if ( dynamic_cast<Instr_call*>(current) )
+ {
+ // Jump over the call instruction to its return point,
+ // which will be the instruction after current.
+ current = *(++m_pCode->find( current ));
+ continue;
+ }
+
+ const InstructionList outputs = current->outputLinks();
+
+ if ( outputs.isEmpty() )
+ return;
+
+ if ( outputs.size() == 1 )
+ current = outputs.first();
+
+ else
+ {
+ // Can't avoid function recursion now.
+ InstructionList::const_iterator end = outputs.end();
+ for ( InstructionList::const_iterator it = outputs.begin(); it != end; ++it )
+ linkReturns( *it, returnPoint );
+ return;
+ }
+ };
+}
+
+
+//TODO CLRWDT
+
+
+QString Instr_goto::code() const
+{
+ return QString("goto\t%1").arg( m_label );
+}
+
+void Instr_goto::generateLinksAndStates( Code::iterator current )
+{
+ (void)current;
+
+ makeLabelOutputLink( m_label );
+
+ m_outputState = m_inputState;
+}
+
+ProcessorBehaviour Instr_goto::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ return behaviour;
+}
+
+
+QString Instr_iorlw::code() const
+{
+ return QString("iorlw\t%1").arg( m_literal );
+}
+
+void Instr_iorlw::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.working.value = (m_inputState.working.value | m_literal) & 0xff;
+ m_outputState.working.known |= m_literal; // Now know any bits that are one in value
+ m_outputState.status.known &= ~(1 << RegisterBit::Z);
+}
+
+ProcessorBehaviour Instr_iorlw::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+
+ behaviour.working.indep = m_literal;
+ behaviour.working.depends = ~m_literal;
+
+ behaviour.status.indep = (1 << RegisterBit::Z);;
+ return behaviour;
+}
+
+
+QString Instr_movlw::code() const
+{
+ return QString("movlw\t%1").arg( m_literal );
+}
+
+void Instr_movlw::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+ m_outputState = m_inputState;
+ m_outputState.working.known = 0xff;
+ m_outputState.working.value = m_literal;
+}
+
+ProcessorBehaviour Instr_movlw::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ behaviour.working.indep = 0xff;
+ return behaviour;
+}
+
+
+QString Instr_retfie::code() const
+{
+ return "retfie";
+}
+
+void Instr_retfie::generateLinksAndStates( Code::iterator current )
+{
+ // Don't generate any output links
+ (void)current;
+
+ m_inputState = m_outputState;
+}
+
+ProcessorBehaviour Instr_retfie::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ return behaviour;
+}
+
+
+QString Instr_retlw::code() const
+{
+ return QString("retlw\t%1").arg( m_literal );
+}
+
+void Instr_retlw::generateLinksAndStates( Code::iterator current )
+{
+ (void)current;
+
+ m_outputState = m_inputState;
+ m_outputState.working.known = 0xff;
+ m_outputState.working.value = m_literal;
+}
+
+ProcessorBehaviour Instr_retlw::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ behaviour.working.indep = 0xff;
+ return behaviour;
+}
+
+
+
+QString Instr_return::code() const
+{
+ return "return";
+}
+
+void Instr_return::generateLinksAndStates( Code::iterator current )
+{
+ (void)current;
+
+ m_outputState = m_inputState;
+}
+
+ProcessorBehaviour Instr_return::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ return behaviour;
+}
+
+
+QString Instr_sleep::code() const
+{
+ return "sleep";
+}
+
+void Instr_sleep::generateLinksAndStates( Code::iterator current )
+{
+ // Don't generate any output links
+ (void)current;
+
+ m_outputState = m_inputState;
+ m_outputState.status.value &= ~(1 << RegisterBit::NOT_PD);
+ m_outputState.status.value |= (1 << RegisterBit::NOT_TO);
+ m_outputState.status.known |= (1 << RegisterBit::NOT_TO) | (1 << RegisterBit::NOT_PD);
+}
+
+ProcessorBehaviour Instr_sleep::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ behaviour.status.indep = (1 << RegisterBit::NOT_TO) | (1 << RegisterBit::NOT_PD);
+ return behaviour;
+}
+
+
+QString Instr_sublw::code() const
+{
+ return QString("sublw\t%1").arg( m_literal );
+}
+
+void Instr_sublw::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+
+ m_outputState = m_inputState;
+ m_outputState.working.value = (m_literal - m_inputState.working.value) & 0xff;
+ m_outputState.working.known = (m_inputState.working.known == 0xff) ? 0xff : 0x00;
+ m_outputState.status.known &= ~( (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z) );
+
+ if ( m_inputState.working.minValue() > m_literal )
+ {
+ m_outputState.status.value &= ~(1 << RegisterBit::C);
+ m_outputState.status.known |= (1 << RegisterBit::C);
+ }
+ else if ( m_inputState.working.maxValue() <= m_literal )
+ {
+ m_outputState.status.value |= (1 << RegisterBit::C);
+ m_outputState.status.known |= (1 << RegisterBit::C);
+ }
+
+ if ( m_inputState.working.known == 0xff )
+ {
+ bool isZero = (m_inputState.working.value == m_literal);
+ if ( isZero )
+ m_outputState.status.value |= (1 << RegisterBit::Z);
+ else
+ m_outputState.status.value &= ~(1 << RegisterBit::Z);
+ m_outputState.status.known |= (1 << RegisterBit::Z);
+ }
+}
+
+ProcessorBehaviour Instr_sublw::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ behaviour.working.depends = 0xff;
+ behaviour.status.indep = (1 << RegisterBit::C) | (1 << RegisterBit::DC) | (1 << RegisterBit::Z);
+ return behaviour;
+}
+
+
+QString Instr_xorlw::code() const
+{
+ return QString("xorlw\t%1").arg( m_literal );
+}
+
+void Instr_xorlw::generateLinksAndStates( Code::iterator current )
+{
+ makeOutputLinks( current );
+ m_outputState = m_inputState;
+ m_outputState.working.value = (m_inputState.working.value ^ m_literal) & 0xff;
+ m_outputState.working.known = m_inputState.working.known;
+ m_outputState.status.known &= ~(1 << RegisterBit::Z);
+}
+
+ProcessorBehaviour Instr_xorlw::behaviour() const
+{
+ ProcessorBehaviour behaviour;
+ behaviour.working.depends = 0xff;
+ behaviour.status.indep = (1 << RegisterBit::Z);
+ return behaviour;
+}
+//END Literal and Control Operations
+
+
+
+//BEGIN Microbe (non-assembly) Operations
+QString Instr_sourceCode::code() const
+{
+ QStringList sourceLines = QStringList::split("\n",m_raw);
+ return ";" + sourceLines.join("\n;");
+}
+
+
+QString Instr_asm::code() const
+{
+ return "; asm {\n" + m_raw + "\n; }";
+}
+
+
+QString Instr_raw::code() const
+{
+ return m_raw;
+}
+//END Microbe (non-assembly) Operations
+