/*************************************************************************** * Copyright (C) 2004-2005 by Daniel Clarke * * daniel.jc@gmail.com * * * * 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 #include #include 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 TQString & portPinString ) { TQString port; int pin = -1; // In form e.g. RB3 if ( portPinString.length() == 3 ) { port = TQString("PORT%1").arg( portPinString[1].upper() ); pin = TQString( 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 TQString & _text ) { TQString 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 << TQString("%1 is not a known PIC identifier\n").arg(_text).local8Bit(); return unknown; } TQString 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 TQStringList &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); TQStringList::ConstIterator interruptsEnd = interrupts.end(); for( TQStringList::ConstIterator it = interrupts.begin(); it != interruptsEnd; ++it ) { // Is the interrupt's flag bit set? m_pCode->append(new Instr_btfsc("INTCON",TQString::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 TQString &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 TQString & 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 TQString & trisName ) const { return ( trisName == "TRISA" || trisName == "trisa" || trisName == "TRISB" || trisName == "trisb" ); } bool PIC14::isValidInterrupt( const TQString & 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 TQString &label) { m_pCode->append( new Instr_goto(label) ); } void PIC14::Slabel(const TQString &label) { // std::cout << k_funcinfo << "label="<queueLabel( label, Code::Middle ); } void PIC14::Send() { m_pCode->append( new Instr_sleep() ); } void PIC14::Ssubroutine( const TQString &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 TQString &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",TQString::number(interruptNameToBit(procName,true))) ); m_pCode->merge( subCode, Code::Subroutine ); m_pCode->append( new Instr_goto("_interrupt_end"), Code::Subroutine ); } void PIC14::Scall(const TQString &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(),TQString::number(portPin.pin()) ) ); else m_pCode->append( new Instr_bcf( portPin.port(), TQString::number(portPin.pin()) ) ); } void PIC14::rearrangeOpArguments( TQString * val1, TQString * val2, LocationType * val1Type, LocationType * val2Type) { if( *val2Type == work && *val1Type != work ) { LocationType tempType = *val2Type; TQString tempVal = *val2; *val2Type = *val1Type; *val2 = *val1; *val1Type = tempType; *val1 = tempVal; } } void PIC14::add( TQString val1, TQString 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 TQString & val1, const TQString & 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 TQString & val) { m_pCode->append(new Instr_movlw(val.toInt( 0, 0 ))); } void PIC14::assignVar(const TQString &val) { m_pCode->append(new Instr_movf(val,0)); } void PIC14::saveToReg(const TQString &dest) { m_pCode->append(new Instr_movwf(dest)); } void PIC14::saveResultToVar( const TQString & var ) { m_pCode->append( new Instr_movwf( var ) ); } void PIC14::mul(TQString val1, TQString 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 TQString & val1, const TQString & 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 TQString &val1, const TQString &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 TQString &val1, const TQString &val2, LocationType val1Type, LocationType val2Type ) { ifInitCode( val1, val2, val1Type, val2Type ); const TQString labelEnd = mb->uniqueLabel()+"_endif"; const TQString 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 TQString &val1, const TQString &val2, LocationType val1Type, LocationType val2Type ) { ifInitCode( val1, val2, val1Type, val2Type ); const TQString labelEnd = mb->uniqueLabel()+"_endif"; const TQString 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 TQString &val1, const TQString &val2, LocationType val1Type, LocationType val2Type ) { ifInitCode( val1, val2, val1Type, val2Type ); const TQString labelEnd = mb->uniqueLabel()+"_endif"; const TQString 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 TQString &val1, const TQString &val2, LocationType val1Type, LocationType val2Type ) { cout << k_funcinfo << endl; ifInitCode( val1, val2, val1Type, val2Type ); const TQString labelEnd = mb->uniqueLabel()+"_endif"; const TQString 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 TQString &val1, const TQString &val2, LocationType val1Type, LocationType val2Type ) { ifInitCode( val1, val2, val1Type, val2Type ); const TQString labelEnd = mb->uniqueLabel()+"_endif"; const TQString 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 TQString &val1, const TQString &val2, LocationType val1Type, LocationType val2Type ) { ifInitCode( val1, val2, val1Type, val2Type ); const TQString labelEnd = mb->uniqueLabel()+"_endif"; const TQString 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 TQString &expression) { TQString result; TQString 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 TQString &expression) { TQString result; TQString 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 TQString &expression) { m_parser->compileConditionalExpression( expression, ifCode, elseCode ); } void PIC14::Sfor( Code * forCode, Code * initCode, const TQString &expression, const TQString &variable, const TQString &step, bool stepPositive) { TQString 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) { TQString 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(), TQString::number( portPin.pin() ) )); //result +=instruction((TQString)(NOT?"btfsc":"btfss")+"\t"+port+","+pin); else m_pCode->append(new Instr_btfss( portPin.port(), TQString::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 ) { TQString 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 ); TQString subName = TQString("__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; TQString portName = TQString("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 + TQString("_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 + TQString("_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 TQString subName = TQString("__wait_read_keypad_%1").arg( pinMap.name() ); TQString waitName = TQString("__wait_keypad_%1").arg( pinMap.name() ); TQString readName = TQString("__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\")="<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(), TQString::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(), TQString::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(), TQString::number( colPin.pin() ) ), Code::Subroutine ); m_pCode->append( new Instr_retlw( mb->alias( TQString("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(), TQString::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 TQString &r_val1, const TQString &val2, bool val1IsNum, bool val2IsNum ) { TQString 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"); TQString 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 TQString &var ) { m_pCode->append(new Instr_incf(var,1) ); } void PIC14::SdecVar( const TQString &var ) { m_pCode->append(new Instr_decf(var,1) ); } void PIC14::SrotlVar( const TQString &var ) { m_pCode->append(new Instr_rlf(var,1)); } void PIC14::SrotrVar( const TQString &var ) { m_pCode->append(new Instr_rrf(var,1)); } void PIC14::Stristate(const TQString &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 TQString &raw) { m_pCode->append(new Instr_asm(raw)); } //BEGIN class PortPin PortPin::PortPin( const TQString & 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