summaryrefslogtreecommitdiffstats
path: root/microbe/pic14.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'microbe/pic14.cpp')
-rw-r--r--microbe/pic14.cpp1196
1 files changed, 1196 insertions, 0 deletions
diff --git a/microbe/pic14.cpp b/microbe/pic14.cpp
new file mode 100644
index 0000000..7785afb
--- /dev/null
+++ b/microbe/pic14.cpp
@@ -0,0 +1,1196 @@
+/***************************************************************************
+ * Copyright (C) 2004-2005 by Daniel Clarke *
+ * *
+ * 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 "parser.h"
+#include "pic14.h"
+
+#include <assert.h>
+#include <kdebug.h>
+#include <iostream>
+using namespace std;
+
+bool LEDSegTable[][7] = {
+{ 1, 1, 1, 1, 1, 1, 0 },
+{ 0, 1, 1, 0, 0, 0, 0 }, // 1
+{ 1, 1, 0, 1, 1, 0, 1 }, // 2
+{ 1, 1, 1, 1, 0, 0, 1 }, // 3
+{ 0, 1, 1, 0 ,0, 1, 1 }, // 4
+{ 1, 0, 1, 1, 0, 1, 1 }, // 5
+{ 1, 0, 1, 1, 1, 1, 1 }, // 6
+{ 1, 1, 1, 0, 0, 0, 0 }, // 7
+{ 1, 1, 1, 1, 1, 1, 1 }, // 8
+{ 1, 1, 1, 0, 0, 1, 1 }, // 9
+{ 1, 1, 1, 0, 1, 1, 1 }, // A
+{ 0, 0, 1, 1, 1, 1, 1 }, // b
+{ 1, 0, 0, 1, 1, 1, 0 }, // C
+{ 0, 1, 1, 1, 1, 0, 1 }, // d
+{ 1, 0, 0, 1, 1, 1, 1 }, // E
+{ 1, 0, 0, 0, 1, 1, 1 } // F
+};
+
+
+
+PIC14::PIC14( Microbe * master, Type type )
+{
+ mb = master;
+ m_pCode = 0l;
+ m_type = type;
+
+}
+
+
+PIC14::~PIC14()
+{
+}
+
+PortPin PIC14::toPortPin( const QString & portPinString )
+{
+ QString port;
+ int pin = -1;
+
+ // In form e.g. RB3
+ if ( portPinString.length() == 3 )
+ {
+ port = QString("PORT%1").arg( portPinString[1].upper() );
+ pin = QString( portPinString[2] ).toInt();
+ }
+ else
+ {
+ int dotpos = portPinString.find(".");
+ if ( dotpos == -1 )
+ return PortPin();
+
+ port = portPinString.left(dotpos);
+ pin = portPinString.mid(dotpos+1).toInt();
+ }
+
+ PortPin portPin( port, pin );
+
+ if ( isValidPortPin( portPin ) )
+ return portPin;
+ else
+ return PortPin();
+}
+
+
+void PIC14::mergeCode( Code * code )
+{
+ m_pCode->merge( code );
+}
+
+
+uchar PIC14::gprStart() const
+{
+ switch ( m_type )
+ {
+ case P16C84:
+ case P16F84:
+ return 0xc;
+
+ case P16F627:
+ case P16F628:
+ return 0x20;
+
+ case unknown:
+ break;
+ }
+
+ kdError() << k_funcinfo << "Unknown PIC type = " << m_type << endl;
+ return 0xc;
+}
+
+
+PIC14::Type PIC14::toType( const QString & _text )
+{
+ QString text = _text.upper().simplifyWhiteSpace().remove('P');
+
+ if ( text == "16C84" )
+ return P16C84;
+
+ if ( text == "16F84" )
+ return P16F84;
+
+ if ( text == "16F627" )
+ return P16F627;
+
+ if ( text == "16F628" )
+ return P16F628;
+
+ cerr << QString("%1 is not a known PIC identifier\n").arg(_text);
+ return unknown;
+}
+
+
+QString PIC14::minimalTypeString() const
+{
+ switch ( m_type )
+ {
+ case P16C84:
+ return "16C84";
+
+ case P16F84:
+ return "16F84";
+
+ case P16F627:
+ return "16F627";
+
+ case P16F628:
+ return "16F628";
+
+ case unknown:
+ break;
+ }
+
+ kdError() << k_funcinfo << "Unknown PIC type = " << m_type << endl;
+ return 0;;
+}
+
+
+void PIC14::postCompileConstruct( const QStringList &interrupts )
+{
+ m_pCode->append( new Instr_raw("\n\tEND\n"), Code::Subroutine );
+
+ if ( interrupts.isEmpty() )
+ {
+ // If there are no ISRs then we don't need to put in any handler code.
+ // Instead, just insert the goto start instruction in case we need to
+ // jump past any lookup tabes (and if there are none, then the optimizer
+ // will remove the goto instruction).
+ m_pCode->append(new Instr_goto("_start"), Code::InterruptHandler);
+ m_pCode->queueLabel( "_start", Code::LookupTable );
+ return;
+ }
+
+ /*
+ INTCON register:
+ 7 --- GIE EEIE T0IE INTE RBIE T0IF INTF RBIF --- 0
+
+ E: enable
+ F: flag
+ Flag bits must be cleared manually before reactivating GIE,
+ but we do this in each individual interrupt handler
+ */
+
+ // The bizarre dance with swap is to ensure the status bits
+ // are preserved properly
+ m_pCode->append(new Instr_goto("_start"), Code::InterruptHandler);
+
+ m_pCode->append(new Instr_raw("ORG 0x4"), Code::InterruptHandler);
+ // When we arrive here:
+ // Return address on stack,
+ // GIE flag cleared (globally interrupts disabled)
+ // W or STATUS not preserved by processor.
+ m_pCode->append(new Instr_movwf("W_TEMP"), Code::InterruptHandler);
+ m_pCode->append(new Instr_swapf("STATUS",0), Code::InterruptHandler);
+ m_pCode->append(new Instr_movwf("STATUS_TEMP"), Code::InterruptHandler);
+
+ QStringList::ConstIterator interruptsEnd = interrupts.end();
+ for( QStringList::ConstIterator it = interrupts.begin(); it != interruptsEnd; ++it )
+ {
+ // Is the interrupt's flag bit set?
+ m_pCode->append(new Instr_btfsc("INTCON",QString::number(interruptNameToBit((*it), true))), Code::InterruptHandler);
+ m_pCode->append(new Instr_goto("_interrupt_" + (*it)), Code::InterruptHandler); // Yes, do its handler routine
+ // Otherwise fall through to the next.
+ }
+
+ // If there was "somehow" a suprious interrupt there isn't really
+ // much we can do about that (??) so just fall through and hope for the worst.
+
+ m_pCode->queueLabel( "_interrupt_end", Code::InterruptHandler );
+ m_pCode->append(new Instr_swapf("STATUS_TEMP",0), Code::InterruptHandler );
+ m_pCode->append(new Instr_movwf("STATUS"), Code::InterruptHandler );
+ m_pCode->append(new Instr_swapf("W_TEMP",1), Code::InterruptHandler );
+ m_pCode->append(new Instr_swapf("W_TEMP",0), Code::InterruptHandler );
+ m_pCode->append(new Instr_retfie()); // Returns and renables globally interrupts.
+
+ m_pCode->queueLabel( "_start", Code::LookupTable );
+}
+
+int PIC14::interruptNameToBit(const QString &name, bool flag)
+{
+ // 7 --- GIE EEIE T0IE INTE RBIE T0IF INTF RBIF --- 0
+
+ if( name == "change" ) // RB
+ {
+ if(flag) return 0;
+ else return 3;
+ }
+ else if( name == "timer" )
+ {
+ if(flag) return 2;
+ else return 5;
+ }
+ else if( name == "external" )
+ {
+ if(flag) return 1;
+ else return 4;
+ }
+
+ return -1;
+}
+
+
+bool PIC14::isValidPort( const QString & portName ) const
+{
+ return ( portName == "PORTA" || portName == "porta" ||
+ portName == "PORTB" || portName == "portb" );
+}
+
+
+bool PIC14::isValidPortPin( const PortPin & portPin ) const
+{
+ if ( portPin.port() == "PORTA" )
+ return (portPin.pin() >= 0) && (portPin.pin() <= 4);
+
+ if ( portPin.port() == "PORTB" )
+ return (portPin.pin() >= 0) && (portPin.pin() <= 7);
+
+ return false;
+}
+
+
+bool PIC14::isValidTris( const QString & trisName ) const
+{
+ return ( trisName == "TRISA" || trisName == "trisa" ||
+ trisName == "TRISB" || trisName == "trisb" );
+}
+
+
+bool PIC14::isValidInterrupt( const QString & interruptName ) const
+{
+ if(m_type == "P16F84" || m_type =="P16C84")
+ {
+ return ( interruptName == "change" ||
+ interruptName == "timer" ||
+ interruptName == "external" );
+ }
+ return false;
+}
+
+
+void PIC14::setConditionalCode( Code * ifCode, Code * elseCode )
+{
+ m_ifCode = ifCode;
+ m_elseCode = elseCode;
+}
+
+void PIC14::Sgoto(const QString &label)
+{
+ m_pCode->append( new Instr_goto(label) );
+}
+
+void PIC14::Slabel(const QString &label)
+{
+// std::cout << k_funcinfo << "label="<<label<<'\n';
+ m_pCode->queueLabel( label, Code::Middle );
+}
+
+void PIC14::Send()
+{
+ m_pCode->append( new Instr_sleep() );
+}
+
+void PIC14::Ssubroutine( const QString &procName, Code * subCode )
+{
+ m_pCode->queueLabel( procName, Code::Subroutine );
+ m_pCode->merge( subCode, Code::Subroutine );
+ m_pCode->append( new Instr_return(), Code::Subroutine );
+}
+
+void PIC14::Sinterrupt( const QString &procName, Code * subCode )
+{
+ m_pCode->queueLabel( "_interrupt_" + procName, Code::Subroutine );
+
+ // Clear the interrupt flag for this particular interrupt source
+ m_pCode->append( new Instr_bcf("INTCON",QString::number(interruptNameToBit(procName,true))) );
+ m_pCode->merge( subCode, Code::Subroutine );
+
+ m_pCode->append( new Instr_goto("_interrupt_end"), Code::Subroutine );
+}
+
+
+void PIC14::Scall(const QString &name)
+{
+ m_pCode->append( new Instr_call(name) );
+}
+
+
+void PIC14::Ssetlh( const PortPin & portPin, bool high)
+{
+ if(high)
+ m_pCode->append( new Instr_bsf( portPin.port(),QString::number(portPin.pin()) ) );
+ else
+ m_pCode->append( new Instr_bcf( portPin.port(), QString::number(portPin.pin()) ) );
+}
+
+void PIC14::rearrangeOpArguments( QString * val1, QString * val2, LocationType * val1Type, LocationType * val2Type)
+{
+ if( *val2Type == work && *val1Type != work )
+ {
+ LocationType tempType = *val2Type;
+ QString tempVal = *val2;
+
+ *val2Type = *val1Type;
+ *val2 = *val1;
+
+ *val1Type = tempType;
+ *val1 = tempVal;
+ }
+}
+
+void PIC14::add( QString val1, QString val2, LocationType val1Type, LocationType val2Type )
+{
+ rearrangeOpArguments( &val1, &val2, &val1Type, &val2Type );
+
+ switch(val1Type)
+ {
+ case num: m_pCode->append(new Instr_movlw( val1.toInt( 0, 0 ) )); break;
+ case work: break;
+ case var: m_pCode->append(new Instr_movf(val1,0)); break;
+ }
+
+ switch(val2Type)
+ {
+ case num: m_pCode->append(new Instr_addlw(val2.toInt( 0, 0 ))); break;
+ case work: break;
+ case var: m_pCode->append(new Instr_addwf(val2,0)); break;
+ }
+}
+
+void PIC14::subtract( const QString & val1, const QString & val2, LocationType val1Type, LocationType val2Type )
+{
+ switch(val2Type)
+ {
+ case num: m_pCode->append(new Instr_movlw( val2.toInt( 0, 0 ) )); break;
+ case work: break;
+ case var: m_pCode->append(new Instr_movf(val2,0)); break;
+ }
+ switch(val1Type)
+ {
+ case num: m_pCode->append(new Instr_sublw(val1.toInt( 0, 0 ))); break;
+ case work: break;
+ case var: m_pCode->append(new Instr_subwf(val1,0)); break;
+ }
+}
+
+void PIC14::assignNum(const QString & val)
+{
+ m_pCode->append(new Instr_movlw(val.toInt( 0, 0 )));
+}
+
+void PIC14::assignVar(const QString &val)
+{
+ m_pCode->append(new Instr_movf(val,0));
+}
+
+void PIC14::saveToReg(const QString &dest)
+{
+ m_pCode->append(new Instr_movwf(dest));
+}
+
+void PIC14::saveResultToVar( const QString & var )
+{
+ m_pCode->append( new Instr_movwf( var ) );
+}
+
+void PIC14::mul(QString val1, QString val2, LocationType val1Type, LocationType val2Type)
+{
+ multiply();
+
+ rearrangeOpArguments( &val1, &val2, &val1Type, &val2Type );
+
+ // First, set _i argument
+ switch(val1Type)
+ {
+ case num: m_pCode->append(new Instr_movlw(val1.toInt( 0, 0 ))); break;
+ case work: break;
+ case var: m_pCode->append(new Instr_movf(val1,0)); break;
+ }
+
+ m_pCode->append(new Instr_movwf("__i"));
+
+ // Then set _j argument
+ switch(val2Type)
+ {
+ case num: m_pCode->append(new Instr_movlw(val2.toInt( 0, 0 ))); break;
+ case work: break;
+ case var: m_pCode->append(new Instr_movf(val2,0)); break;
+ }
+
+ m_pCode->append(new Instr_movwf("__j"));
+ m_pCode->append(new Instr_call("__picfunc_multiply"));
+ m_pCode->append(new Instr_movf("__result",0));
+}
+
+
+void PIC14::multiply()
+{
+ if ( m_pCode->instruction("__picfunc_multiply") )
+ return;
+
+ m_pCode->queueLabel( "__picfunc_multiply", Code::Subroutine );
+ m_pCode->append(new Instr_clrf("__result"), Code::Subroutine ); //result+=m_pCode->appenduction("clrf __result");
+
+ m_pCode->queueLabel( "__picfunc_multiply_loop", Code::Subroutine );
+ m_pCode->append(new Instr_movf("__i",0), Code::Subroutine ); //result+=m_pCode->appenduction("movf __i,0");
+ m_pCode->append(new Instr_btfsc("__j","0"), Code::Subroutine ); //result+=m_pCode->appenduction("btfsc __j,0");
+ m_pCode->append(new Instr_addwf("__result",1), Code::Subroutine ); //result+=m_pCode->appenduction("addwf __result,1");
+ m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine ); //result+=m_pCode->appenduction("bcf STATUS,C");
+ m_pCode->append(new Instr_rrf("__j",1), Code::Subroutine ); //result+=m_pCode->appenduction("rrf __j,1");
+ m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine ); //result+=m_pCode->appenduction("bcf STATUS,C");
+ m_pCode->append(new Instr_rlf("__i",1), Code::Subroutine ); //result+=m_pCode->appenduction("rlf __i,1");
+ m_pCode->append(new Instr_movf("__j",1), Code::Subroutine ); //result+=m_pCode->appenduction("movf __j,1");
+ m_pCode->append(new Instr_btfss("STATUS","Z"), Code::Subroutine ); //result+=m_pCode->appenduction("btfss STATUS,Z");
+ m_pCode->append(new Instr_goto("__picfunc_multiply_loop"), Code::Subroutine ); //result+=m_pCode->appenduction("goto __picfunc_multiply_loop");
+ m_pCode->append(new Instr_return(), Code::Subroutine ); //result+=m_pCode->appenduction("return");
+}
+
+
+void PIC14::div( const QString & val1, const QString & val2, LocationType val1Type, LocationType val2Type)
+{
+ divide();
+
+ // NOO - "x / 2" is NOT the same as "2 / x"
+// rearrangeOpArguments( val1, val2, val1Type, val2Type );
+
+ // First, set _i argument
+ switch(val1Type)
+ {
+ case num: m_pCode->append(new Instr_movlw(val1.toInt( 0, 0 ))); break;
+ case work: break;
+ case var: m_pCode->append(new Instr_movf(val1,0)); break;
+ }
+
+ m_pCode->append(new Instr_movwf("__i"));
+
+ // Then set _j argument
+ switch(val2Type)
+ {
+ case num: m_pCode->append(new Instr_movlw(val2.toInt( 0, 0 ))); break;
+ case work: break;
+ case var: m_pCode->append(new Instr_movf(val2,0)); break;
+ }
+
+ m_pCode->append(new Instr_movwf("__j"));
+
+ m_pCode->append(new Instr_call("__picfunc_divide"));//result+=instruction("call __picfunc_divide");
+ m_pCode->append(new Instr_movf("__result",0));//result+=instruction("movf __result,0");
+}
+
+void PIC14::divide()
+{
+ m_pCode->queueLabel( "__picfunc_divide", Code::Subroutine );
+ m_pCode->append(new Instr_movf("__j",1), Code::Subroutine );
+ m_pCode->append(new Instr_btfsc("STATUS","2"), Code::Subroutine );
+ m_pCode->append(new Instr_return(), Code::Subroutine );
+ m_pCode->append(new Instr_clrf("__result"), Code::Subroutine );
+ m_pCode->append(new Instr_movlw(1), Code::Subroutine );
+ m_pCode->append(new Instr_movwf("__k"), Code::Subroutine );
+
+ m_pCode->queueLabel( "__divide_shift", Code::Subroutine );
+ m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine );
+ m_pCode->append(new Instr_rlf("__k",1), Code::Subroutine );
+ m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine );
+ m_pCode->append(new Instr_rlf("__j",1), Code::Subroutine );
+ m_pCode->append(new Instr_btfss("__j","7"), Code::Subroutine );
+ m_pCode->append(new Instr_goto("__divide_shift"), Code::Subroutine );
+
+ m_pCode->queueLabel( "__divide_loop", Code::Subroutine );
+ m_pCode->append(new Instr_movf("__j",0), Code::Subroutine );
+ m_pCode->append(new Instr_subwf("__i",1), Code::Subroutine );
+ m_pCode->append(new Instr_btfsc("STATUS","C"), Code::Subroutine );
+ m_pCode->append(new Instr_goto("__divide_count"), Code::Subroutine );
+ m_pCode->append(new Instr_addwf("__i",1), Code::Subroutine );
+ m_pCode->append(new Instr_goto("__divide_final"), Code::Subroutine );
+
+ m_pCode->queueLabel( "__divide_count", Code::Subroutine );
+ m_pCode->append(new Instr_movf("__k",0), Code::Subroutine );
+ m_pCode->append(new Instr_addwf("__result",1), Code::Subroutine );
+
+ m_pCode->queueLabel( "__divide_final", Code::Subroutine );
+ m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine );
+ m_pCode->append(new Instr_rrf("__j",1), Code::Subroutine );
+ m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine );
+ m_pCode->append(new Instr_rrf("__k",1), Code::Subroutine );
+ m_pCode->append(new Instr_btfss("STATUS","C"), Code::Subroutine );
+ m_pCode->append(new Instr_goto("__divide_loop"), Code::Subroutine );
+ m_pCode->append(new Instr_return(), Code::Subroutine );
+}
+
+
+Code * PIC14::ifCode()
+{
+ return m_ifCode;
+}
+
+
+Code * PIC14::elseCode()
+{
+ return m_elseCode;
+}
+
+
+void PIC14::ifInitCode( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
+{
+ // NOO - "x < 2" is NOT the same as "2 < x"
+// rearrangeOpArguments( val1, val2, val1Type, val2Type );
+
+ switch(val1Type)
+ {
+ case num:
+ m_pCode->append(new Instr_movlw(val1.toInt( 0, 0 )));
+ break;
+
+ case work:
+ break; // Nothing to do
+
+ case var:
+ m_pCode->append(new Instr_movf(val1,0));
+ break;
+ }
+
+ switch(val2Type)
+ {
+ case num:
+ m_pCode->append(new Instr_sublw(val2.toInt( 0, 0 )));
+ break;
+
+ case work:
+ kdError() << k_funcinfo << "Cannot subtract working from working!" << endl;
+ break;
+
+ case var:
+ m_pCode->append(new Instr_subwf(val2,0));
+ break;
+ }
+}
+
+void PIC14::equal( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
+{
+ ifInitCode( val1, val2, val1Type, val2Type );
+ const QString labelEnd = mb->uniqueLabel()+"_endif";
+ const QString labelFalse = mb->uniqueLabel()+"_case_false";
+
+ m_pCode->append(new Instr_btfss("STATUS","2"));
+ m_pCode->append(new Instr_goto(labelFalse));
+
+ mergeCode( ifCode() );
+
+ m_pCode->append(new Instr_goto(labelEnd));
+
+ m_pCode->queueLabel( labelFalse );
+ mergeCode( elseCode() );
+ m_pCode->queueLabel( labelEnd );
+}
+
+void PIC14::notEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
+{
+ ifInitCode( val1, val2, val1Type, val2Type );
+ const QString labelEnd = mb->uniqueLabel()+"_endif";
+ const QString labelFalse = mb->uniqueLabel()+"_case_false";
+
+ m_pCode->append(new Instr_btfsc("STATUS","2"));
+ m_pCode->append(new Instr_goto(labelFalse));
+
+ mergeCode( ifCode() );
+
+ m_pCode->append(new Instr_goto(labelEnd));
+
+ m_pCode->queueLabel( labelFalse );
+ mergeCode( elseCode() );
+ m_pCode->queueLabel( labelEnd );
+}
+
+void PIC14::greaterThan( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
+{
+ ifInitCode( val1, val2, val1Type, val2Type );
+ const QString labelEnd = mb->uniqueLabel()+"_endif";
+ const QString labelFalse = mb->uniqueLabel()+"_case_false";
+
+ m_pCode->append(new Instr_btfsc("STATUS","0"));
+ m_pCode->append(new Instr_goto(labelFalse));
+
+ mergeCode( ifCode() );
+ m_pCode->append(new Instr_goto(labelEnd));
+
+ m_pCode->queueLabel( labelFalse );
+ mergeCode( elseCode() );
+ m_pCode->queueLabel( labelEnd );
+}
+
+void PIC14::lessThan( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
+{
+ cout << k_funcinfo << endl;
+ ifInitCode( val1, val2, val1Type, val2Type );
+ const QString labelEnd = mb->uniqueLabel()+"_endif";
+ const QString labelFalse = mb->uniqueLabel()+"_case_false";
+
+ m_pCode->append(new Instr_btfss("STATUS","0"));
+ m_pCode->append(new Instr_goto(labelFalse));
+ m_pCode->append(new Instr_btfsc("STATUS","2"));
+ m_pCode->append(new Instr_goto(labelFalse));
+
+ mergeCode( ifCode() );
+
+ m_pCode->append(new Instr_goto(labelEnd));
+
+ m_pCode->queueLabel( labelFalse );
+ mergeCode( elseCode() );
+ m_pCode->queueLabel( labelEnd );
+}
+
+void PIC14::greaterOrEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
+{
+ ifInitCode( val1, val2, val1Type, val2Type );
+ const QString labelEnd = mb->uniqueLabel()+"_endif";
+ const QString labelTrue = mb->uniqueLabel()+"_case_true"; // Note that unlike the others, this is labelTrue, not labelFalse
+
+ m_pCode->append(new Instr_btfsc("STATUS","2"));
+ m_pCode->append(new Instr_goto(labelTrue));
+ m_pCode->append(new Instr_btfss("STATUS","0"));
+ m_pCode->append(new Instr_goto(labelTrue));
+
+ mergeCode( elseCode() );
+
+ m_pCode->append(new Instr_goto(labelEnd));
+
+ m_pCode->queueLabel( labelTrue );
+ mergeCode( ifCode() );
+ m_pCode->queueLabel( labelEnd );
+}
+
+void PIC14::lessOrEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
+{
+ ifInitCode( val1, val2, val1Type, val2Type );
+ const QString labelEnd = mb->uniqueLabel()+"_endif";
+ const QString labelFalse = mb->uniqueLabel()+"_case_false";
+
+ m_pCode->append(new Instr_btfss("STATUS","0"));
+ m_pCode->append(new Instr_goto(labelFalse));
+
+ mergeCode( ifCode() );
+ m_pCode->append(new Instr_goto(labelEnd));
+
+ m_pCode->queueLabel( labelFalse );
+ mergeCode( elseCode() );
+ m_pCode->queueLabel( labelEnd );
+}
+
+
+void PIC14::Swhile( Code * whileCode, const QString &expression)
+{
+ QString result;
+ QString ul = mb->uniqueLabel();
+
+ whileCode->append( new Instr_goto(ul) );
+
+ m_pCode->queueLabel( ul, Code::Middle );
+
+ // If the condition is not true, just fall through
+ m_parser->compileConditionalExpression( expression, whileCode, 0 );
+}
+
+
+void PIC14::Srepeat( Code * repeatCode, const QString &expression)
+{
+ QString result;
+ QString ul = mb->uniqueLabel();
+
+ Code * elseCode = new Code;
+ elseCode->append( new Instr_goto(ul) );
+
+ m_pCode->queueLabel( ul );
+ m_pCode->merge( repeatCode );
+
+ // If the condition is true, just fall through
+ m_parser->compileConditionalExpression( expression, 0, elseCode );
+}
+
+void PIC14::Sif( Code * ifCode, Code * elseCode, const QString &expression)
+{
+ m_parser->compileConditionalExpression( expression, ifCode, elseCode );
+}
+
+
+void PIC14::Sfor( Code * forCode, Code * initCode, const QString &expression, const QString &variable, const QString &step, bool stepPositive)
+{
+ QString ul = mb->uniqueLabel();
+
+ if ( step == "1" )
+ {
+ if (stepPositive)
+ forCode->append(new Instr_incf(variable,1));
+ else
+ forCode->append(new Instr_decf(variable,1));
+ }
+ else
+ {
+ forCode->append(new Instr_movlw(step.toInt( 0, 0 )));
+ if (stepPositive)
+ forCode->append(new Instr_addwf(variable,1));
+ else
+ forCode->append(new Instr_subwf(variable,1));
+ }
+ forCode->append(new Instr_goto(ul));
+
+ m_pCode->merge( initCode );
+
+ m_pCode->queueLabel( ul );
+
+ m_parser->compileConditionalExpression( expression, forCode, 0 );
+}
+
+
+void PIC14::Spin( const PortPin & portPin, bool NOT)
+{
+ QString lowLabel, highLabel, postLabel;
+ lowLabel = mb->uniqueLabel();
+ highLabel = mb->uniqueLabel();
+ postLabel = mb->uniqueLabel();
+ /*result += indent + "goto\t" + lowLabel;
+ result += indent + "movlw\t1" + "goto\t"+postLabel+;
+ result += lowLabel + + indent + "movlw\t0" + indent;
+ result += postLabel + ;*/
+
+ if(NOT)
+ m_pCode->append(new Instr_btfsc( portPin.port(), QString::number( portPin.pin() ) ));
+ //result +=instruction((QString)(NOT?"btfsc":"btfss")+"\t"+port+","+pin);
+ else
+ m_pCode->append(new Instr_btfss( portPin.port(), QString::number( portPin.pin() ) ));
+
+ m_pCode->append(new Instr_goto(lowLabel));//result += instruction("goto\t" + lowLabel);
+ mergeCode( ifCode() );
+ m_pCode->append(new Instr_goto(postLabel));//result += instruction("goto\t"+postLabel);
+
+ m_pCode->queueLabel( lowLabel );
+ mergeCode( elseCode() );
+
+ m_pCode->queueLabel( postLabel );
+}
+
+
+void PIC14::Sdelay( unsigned length_us, Code::InstructionPosition pos )
+{
+ if ( length_us == 0 )
+ return;
+
+ if ( length_us > 50070524 )
+ {
+ length_us += 50267642;
+ int l = length_us/50070530;
+ length_us -= l * 50070530;
+ int k = length_us/196355;
+
+ m_pCode->append( new Instr_movlw( l ), pos );
+ m_pCode->append( new Instr_movwf( "__l" ), pos );
+ m_pCode->append( new Instr_movlw( k ), pos );
+ m_pCode->append( new Instr_movwf( "__k" ), pos );
+
+ mb->addDelayRoutineWanted( Delay_50S );
+ }
+
+ else if ( length_us > 196350 )
+ {
+ length_us += 197116;
+ int k = length_us/196355;
+ length_us -= k * 196355;
+ int j = length_us/770;
+
+ m_pCode->append( new Instr_incf( "__l", 1 ), pos );
+ m_pCode->append( new Instr_movlw( k ), pos );
+ m_pCode->append( new Instr_movwf( "__k" ), pos );
+ m_pCode->append( new Instr_movlw( j ), pos );
+ m_pCode->append( new Instr_movwf( "__j" ), pos );
+
+ mb->addDelayRoutineWanted( Delay_200mS );
+ }
+
+ else if ( length_us > 766 )
+ {
+ length_us += 765;
+ int j = length_us/770;
+ length_us -= j * 770;
+ int i = length_us/3;
+
+ m_pCode->append( new Instr_incf( "__l", 1 ), pos );
+ m_pCode->append( new Instr_incf( "__k", 1 ), pos );
+ m_pCode->append( new Instr_movlw( j ), pos );
+ m_pCode->append( new Instr_movwf( "__j" ), pos );
+ m_pCode->append( new Instr_movlw( i ), pos );
+ m_pCode->append( new Instr_movwf( "__i" ), pos );
+
+ mb->addDelayRoutineWanted( Delay_768uS );
+ }
+
+ else
+ {
+ length_us += -1;
+ int i = length_us/3;
+
+ m_pCode->append( new Instr_incf( "__l", 1 ), pos );
+ m_pCode->append( new Instr_incf( "__k", 1 ), pos );
+ m_pCode->append( new Instr_incf( "__j", 1 ), pos );
+ m_pCode->append( new Instr_movlw( i ), pos );
+ m_pCode->append( new Instr_movwf( "__i" ), pos );
+
+ mb->addDelayRoutineWanted( Delay_3uS );
+ }
+
+ m_pCode->append( new Instr_call( "__delay_subroutine"), pos );
+}
+
+
+void PIC14::addCommonFunctions( DelaySubroutine delay )
+{
+ if ( delay != Delay_None )
+ {
+ QString subName = "__delay_subroutine";
+ m_pCode->queueLabel( subName, Code::Subroutine );
+
+ m_pCode->append( new Instr_decfsz( "__i", 1 ), Code::Subroutine );
+ m_pCode->append( new Instr_goto( subName ), Code::Subroutine );
+
+ if ( delay > Delay_3uS )
+ {
+ m_pCode->append( new Instr_decfsz( "__j", 1 ), Code::Subroutine );
+ m_pCode->append( new Instr_goto( subName ), Code::Subroutine );
+ }
+
+ if ( delay > Delay_768uS )
+ {
+ m_pCode->append( new Instr_decfsz( "__k", 1 ), Code::Subroutine );
+ m_pCode->append( new Instr_goto( subName ), Code::Subroutine );
+ }
+
+ if ( delay > Delay_200mS )
+ {
+ m_pCode->append( new Instr_decfsz( "__l", 1 ), Code::Subroutine );
+ m_pCode->append( new Instr_goto( subName ), Code::Subroutine );
+ }
+
+ m_pCode->append( new Instr_return(), Code::Subroutine );
+ }
+}
+
+
+void PIC14::SsevenSegment( const Variable & pinMap )
+{
+ assert( pinMap.type() == Variable::sevenSegmentType );
+ assert( pinMap.portPinList().size() == 7 );
+
+ QString subName = QString("__output_seven_segment_%1").arg( pinMap.name() );
+
+ m_pCode->append( new Instr_call( subName ) );
+
+ if ( m_pCode->instruction(subName) )
+ return;
+
+ // Build up what are going to write to each port from the pin map
+ struct SSPortOutput
+ {
+ bool used; // Wheter we use this port at all
+ bool use[8]; // Whether or not we use each pin.
+ bool out[16][8]; // The bit to write to each pin for each value.
+ uchar useMask; // The bits of use[8] - this is generated later from use[8]
+ };
+
+ unsigned numPorts = 2;
+ SSPortOutput portOutput[ numPorts ];
+ memset( portOutput, 0, numPorts * sizeof(SSPortOutput) );
+
+ for ( unsigned i = 0; i < 7; ++i )
+ {
+ PortPin portPin = pinMap.portPinList()[i];
+
+ unsigned port = unsigned( portPin.portPosition() );
+ unsigned pin = unsigned( portPin.pin() );
+
+ portOutput[ port ].used = true;
+ portOutput[ port ].use[ pin ] = true;
+
+ for ( unsigned num = 0; num < 16; ++num )
+ {
+ portOutput[ port ].out[ num ][ pin ] = LEDSegTable[num][ i ];
+ }
+ }
+
+
+ // See if we've used more than one port
+ unsigned portsUsed = 0;
+ for ( unsigned port = 0; port < numPorts; ++port )
+ {
+ if ( portOutput[port].used )
+ portsUsed++;
+ }
+
+
+ // Generate the useMasks
+ for ( unsigned port = 0; port < numPorts; ++port )
+ {
+ portOutput[port].useMask = 0;
+ for ( unsigned pin = 0; pin < 8; ++pin )
+ portOutput[port].useMask |= portOutput[port].use[pin] ? (1 << pin) : 0;
+ }
+
+
+ //BEGIN Generate [subName] Subroutine
+ m_pCode->queueLabel( subName, Code::Subroutine );
+// if ( portsUsed > 1 )
+ {
+ m_pCode->append( new Instr_movwf("__i"), Code::Subroutine );
+ }
+
+// bool overwrittenW = false;
+ bool overwrittenW = true;
+
+ for ( unsigned port = 0; port < numPorts; ++port )
+ {
+ if ( !portOutput[port].used )
+ continue;
+
+ QString portName = QString("PORT%1").arg( char('A'+port) );
+
+ // Save the current value of the port pins that we should not be writing to
+ m_pCode->append( new Instr_movf( portName, 0 ), Code::Subroutine );
+ m_pCode->append( new Instr_andlw( ~portOutput[port].useMask ), Code::Subroutine );
+ m_pCode->append( new Instr_movwf( "__j" ), Code::Subroutine );
+
+ if ( overwrittenW )
+ m_pCode->append( new Instr_movf("__i",0), Code::Subroutine );
+
+ m_pCode->append( new Instr_call( subName + QString("_lookup_%1").arg(port) ), Code::Subroutine );
+ overwrittenW = true;
+
+ // Restore the state of the pins which aren't used
+ m_pCode->append( new Instr_iorwf( "__j", 0 ), Code::Subroutine );
+
+ // And write the result to the port
+ m_pCode->append( new Instr_movwf( portName ), Code::Subroutine );
+ }
+
+ m_pCode->append( new Instr_return(), Code::Subroutine );
+ //END Generate [subName] Subroutine
+
+ // For each port, generate code for looking up the value for writing to it
+ for ( unsigned port = 0; port < numPorts; ++port )
+ {
+ if ( !portOutput[port].used )
+ continue;
+
+ m_pCode->queueLabel( subName + QString("_lookup_%1").arg(port), Code::LookupTable );
+ m_pCode->append( new Instr_andlw(15), Code::LookupTable );
+
+ // Generate the lookup table
+ m_pCode->append( new Instr_addwf( "pcl", 1 ), Code::LookupTable );
+ for ( unsigned num = 0; num < 16; ++num )
+ {
+ unsigned literal = 0;
+ for ( unsigned bit = 0; bit < 8; ++bit )
+ literal += ( portOutput[port].out[num][bit] ? 1 : 0 ) << bit;
+
+ m_pCode->append( new Instr_retlw( literal ), Code::LookupTable );
+ }
+ }
+}
+
+
+void PIC14::Skeypad( const Variable & pinMap )
+{
+ // pinMap = 4 rows, n columns
+
+ assert( pinMap.type() == Variable::keypadType );
+ assert( pinMap.portPinList().size() >= 7 ); // 4 rows, at least 3 columns
+
+ QString subName = QString("__wait_read_keypad_%1").arg( pinMap.name() );
+ QString waitName = QString("__wait_keypad_%1").arg( pinMap.name() );
+ QString readName = QString("__read_keypad_%1").arg( pinMap.name() );
+
+ m_pCode->append( new Instr_call( subName ) );
+
+ if ( m_pCode->instruction( subName ) )
+ return;
+
+ //BEGIN Wait until read subroutine
+ m_pCode->queueLabel( subName, Code::Subroutine );
+
+ // Read current key (if any) from keypad and save to temporary variable
+ m_pCode->append( new Instr_call( readName ), Code::Subroutine );
+ m_pCode->append( new Instr_movwf( "__m" ), Code::Subroutine );
+
+ // Test if any key was pressed; if not, then start again
+// std::cout << "mb->alias(\"Keypad_None\")="<<mb->alias("Keypad_None") << std::endl;
+ m_pCode->append( new Instr_sublw( mb->alias("Keypad_None").toInt( 0, 0 ) ), Code::Subroutine );
+ m_pCode->append( new Instr_btfsc( "STATUS","Z" ), Code::Subroutine );
+ m_pCode->append( new Instr_goto( subName ), Code::Subroutine );
+ m_pCode->append( new Instr_goto( waitName ), Code::Subroutine );
+ //END Wait until read subroutine
+
+
+ //BEGIN Wait until released subroutine
+ m_pCode->queueLabel( waitName, Code::Subroutine );
+
+ Sdelay( 10000, Code::Subroutine ); // 10 milliseconds for debouncing
+
+ // Key was pressed; now we wait until the key is released again
+ m_pCode->append( new Instr_call( readName ), Code::Subroutine );
+ m_pCode->append( new Instr_sublw( mb->alias("Keypad_None").toInt( 0, 0 ) ), Code::Subroutine );
+ m_pCode->append( new Instr_btfss( "STATUS","Z" ), Code::Subroutine );
+ m_pCode->append( new Instr_goto( waitName ), Code::Subroutine );
+ m_pCode->append( new Instr_movf( "__m", 0 ), Code::Subroutine );
+ m_pCode->append( new Instr_return(), Code::Subroutine );
+ //END Wait until released subroutine
+
+
+ if ( m_pCode->instruction( readName ) )
+ return;
+
+ //BEGIN Read current value of keypad subroutine
+ m_pCode->queueLabel( readName, Code::Subroutine );
+
+ // Make the four row lines low
+ for ( unsigned row = 0; row < 4; ++ row )
+ {
+ PortPin rowPin = pinMap.portPinList()[row];
+ m_pCode->append( new Instr_bcf( rowPin.port(), QString::number( rowPin.pin() ) ), Code::Subroutine );
+ }
+
+ // Test each row in turn
+ for ( unsigned row = 0; row < 4; ++ row )
+ {
+ // Make the high low
+ PortPin rowPin = pinMap.portPinList()[row];
+ m_pCode->append( new Instr_bsf( rowPin.port(), QString::number( rowPin.pin() ) ), Code::Subroutine );
+
+ for ( unsigned col = 0; col < 3; ++ col )
+ {
+ PortPin colPin = pinMap.portPinList()[4+col];
+ m_pCode->append( new Instr_btfsc( colPin.port(), QString::number( colPin.pin() ) ), Code::Subroutine );
+ m_pCode->append( new Instr_retlw( mb->alias( QString("Keypad_%1_%2").arg(row+1).arg(col+1) ).toInt( 0, 0 ) ), Code::Subroutine );
+ }
+
+ // Make the low again
+ m_pCode->append( new Instr_bcf( rowPin.port(), QString::number( rowPin.pin() ) ), Code::Subroutine );
+ }
+
+ // No key was pressed
+ m_pCode->append( new Instr_retlw( mb->alias("Keypad_None").toInt( 0, 0 ) ), Code::Subroutine );
+ //END Read current value of keypad subroutine
+}
+
+
+void PIC14::bitwise( Expression::Operation op, const QString &r_val1, const QString &val2, bool val1IsNum, bool val2IsNum )
+{
+ QString val1 = r_val1;
+ // There is no instruction for notting a literal,
+ // so instead I am going to XOR with 0xFF
+ if( op == Expression::bwnot ) val1 = "0xFF";
+ if( val1IsNum ) m_pCode->append(new Instr_movlw(val1.toInt( 0, 0 )));// result += instruction("movlw\t"+val1);
+ else m_pCode->append(new Instr_movf(val1,0));//result += instruction("movf\t"+val1+",0");
+
+ QString opString;
+ if( val2IsNum )
+ {
+ switch(op)
+ {
+ case Expression::bwand: m_pCode->append(new Instr_andlw(val2.toInt( 0, 0 ))); break;
+ case Expression::bwor: m_pCode->append(new Instr_iorlw(val2.toInt( 0, 0 ))); break;
+ case Expression::bwxor: m_pCode->append(new Instr_xorlw(val2.toInt( 0, 0 ))); break;
+ case Expression::bwnot: m_pCode->append(new Instr_xorlw(val2.toInt( 0, 0 ))); break;
+ default: break;
+ }
+ }
+ else
+ {
+ switch(op)
+ {
+ case Expression::bwand: m_pCode->append(new Instr_andwf(val2,0)); break;
+ case Expression::bwor: m_pCode->append(new Instr_iorwf(val2,0)); break;
+ case Expression::bwxor: m_pCode->append(new Instr_xorwf(val2,0)); break;
+ case Expression::bwnot: m_pCode->append(new Instr_xorwf(val2,0)); break;
+ default: break;
+ }
+
+ }
+}
+
+void PIC14::SincVar( const QString &var )
+{
+ m_pCode->append(new Instr_incf(var,1) );
+}
+
+void PIC14::SdecVar( const QString &var )
+{
+ m_pCode->append(new Instr_decf(var,1) );
+}
+
+void PIC14::SrotlVar( const QString &var )
+{
+ m_pCode->append(new Instr_rlf(var,1));
+}
+
+void PIC14::SrotrVar( const QString &var )
+{
+ m_pCode->append(new Instr_rrf(var,1));
+}
+
+void PIC14::Stristate(const QString &port)
+{
+ m_pCode->append( new Instr_bsf("STATUS","5") );
+
+ if( port == "trisa" || port == "TRISA" )
+ saveResultToVar( "TRISA" );
+ else
+ saveResultToVar( "TRISB" );
+
+ m_pCode->append( new Instr_bcf(Register("STATUS"),"5") );
+}
+
+void PIC14::Sasm(const QString &raw)
+{
+ m_pCode->append(new Instr_asm(raw));
+}
+
+
+
+
+//BEGIN class PortPin
+PortPin::PortPin( const QString & port, int pin )
+{
+ m_port = port.upper();
+ m_pin = pin;
+}
+
+
+PortPin::PortPin()
+{
+ m_port = ' ';
+ m_pin = -1;
+}
+
+
+int PortPin::portPosition() const
+{
+ if ( m_port.isEmpty() )
+ return 0;
+ return uchar( m_port[ m_port.length() - 1 ] ) - 'A';
+}
+//END class PortPin