File indexing completed on 2024-04-21 05:43:20

0001 /***************************************************************************
0002  *   Copyright (C) 2004-2005 by Daniel Clarke                              *
0003  *   daniel.jc@gmail.com                           *
0004  *                                     *
0005  *   24-04-2007                                                            *
0006  *   Modified to add pic 16f877,16f627 and 16f628              *
0007  *   by george john george@space-kerala.org                    *
0008  *   supported by SPACE www.space-kerala.org                   *
0009  *                                                                         *
0010  *   This program is free software; you can redistribute it and/or modify  *
0011  *   it under the terms of the GNU General Public License as published by  *
0012  *   the Free Software Foundation; either version 2 of the License, or     *
0013  *   (at your option) any later version.                                   *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program; if not, write to the                         *
0022  *   Free Software Foundation, Inc.,                                       *
0023  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0024  ***************************************************************************/
0025 
0026 
0027 #include "instruction.h"
0028 #include "parser.h"
0029 #include "pic14.h"
0030 
0031 #include <QDebug>
0032 
0033 #include <cassert>
0034 #include <iostream>
0035 using namespace std;
0036 QString pic_type;
0037 bool LEDSegTable[][7] = {
0038 { 1, 1, 1, 1, 1, 1, 0 },
0039 { 0, 1, 1, 0, 0, 0, 0 }, // 1
0040 { 1, 1, 0, 1, 1, 0, 1 }, // 2
0041 { 1, 1, 1, 1, 0, 0, 1 }, // 3
0042 { 0, 1, 1, 0 ,0, 1, 1 }, // 4
0043 { 1, 0, 1, 1, 0, 1, 1 }, // 5
0044 { 1, 0, 1, 1, 1, 1, 1 }, // 6
0045 { 1, 1, 1, 0, 0, 0, 0 }, // 7
0046 { 1, 1, 1, 1, 1, 1, 1 }, // 8
0047 { 1, 1, 1, 0, 0, 1, 1 }, // 9
0048 { 1, 1, 1, 0, 1, 1, 1 }, // A
0049 { 0, 0, 1, 1, 1, 1, 1 }, // b
0050 { 1, 0, 0, 1, 1, 1, 0 }, // C
0051 { 0, 1, 1, 1, 1, 0, 1 }, // d
0052 { 1, 0, 0, 1, 1, 1, 1 }, // E
0053 { 1, 0, 0, 0, 1, 1, 1 }  // F
0054 };
0055 
0056 
0057 
0058 PIC14::PIC14( MicrobeApp * master, Type type )
0059 {
0060     mb = master;
0061     m_pCode = nullptr;
0062     m_type = type;
0063 
0064 }
0065 
0066 
0067 PIC14::~PIC14()
0068 {
0069 }
0070 
0071 PortPin PIC14::toPortPin( const QString & portPinString )
0072 {
0073     QString port,holdport;
0074     int pin = -1;
0075 /*****************************modified *********************************************/
0076 //inorder to support RB.3=high/1
0077 
0078     if ( portPinString.length()  == 3 )
0079     {
0080         port = QString("PORT%1").arg( portPinString[1].toUpper() );
0081         pin = QString( portPinString[2] ).toInt();
0082     }
0083     // In form e.g. RB.3
0084     else if ( portPinString.length()  == 4 )//modification change ==3 to ==4
0085     {
0086         port = QString("PORT%1").arg( portPinString[1].toUpper() );
0087         pin = QString( portPinString[3] ).toInt();//modification change 2 to 3
0088     }
0089     else
0090     {
0091         int dotpos = portPinString.indexOf(".");
0092         if ( dotpos == -1 )
0093             return PortPin();
0094 
0095         port = portPinString.left(dotpos);
0096 //modified checking is added in the case of Register also
0097 //now INTCON.GIE is high ,and INTCON.GIE=1/high works
0098         if(isValidRegister( port))
0099         {
0100 
0101             RegisterBit REG(portPinString.mid(dotpos+1));
0102             pin=REG.bitPos();
0103             Register Reg(REG.registerType());
0104             holdport=Reg.name();
0105             if(holdport!=port)
0106                  cerr << QString(" ERROR: %1 is not a Register bit\n").arg(portPinString ).toStdString();
0107         }
0108         else
0109             pin = portPinString.mid(dotpos+1).toInt();
0110 
0111 
0112 //***************************Modification ends********************************
0113     }
0114 
0115     PortPin portPin( port, pin );
0116 
0117     if ( isValidPortPin( portPin ) )
0118         return portPin;
0119 //**************************Modification start ********************************
0120     else if(isValidRegister(port))
0121         return portPin;
0122 //**************************Modification ends ********************************
0123     else
0124     {
0125         cerr << QString("ERROR: %1 is not a Port/Register bit\n").arg(portPinString ).toStdString();
0126         return PortPin();
0127     }
0128 }
0129 
0130 
0131 void PIC14::mergeCode( Code * code )
0132 {
0133     m_pCode->merge( code );
0134 }
0135 
0136 
0137 uchar PIC14::gprStart() const
0138 {
0139     switch ( m_type )
0140     {
0141         case P16C84:
0142         case P16F84:
0143             return 0xc;
0144 
0145         case P16F627:
0146         case P16F628:
0147         case P16F877:
0148             return 0x20;
0149 
0150         case unknown:
0151             break;
0152     }
0153 
0154     qCritical() << Q_FUNC_INFO << "Unknown PIC type = " << m_type;
0155     return 0xc;
0156 }
0157 
0158 
0159 PIC14::Type PIC14::toType( const QString & _text )
0160 {
0161     QString text = _text.toUpper().simplified().remove('P');
0162 
0163     if ( text == "16C84" )
0164     {
0165         pic_type="P16C84";
0166         return P16C84;
0167     }
0168     if ( text == "16F84" )
0169     {
0170         pic_type="P16F84";
0171         return P16F84;
0172     }
0173     if ( text == "16F627" )
0174     {
0175         pic_type="P16F627";
0176         return P16F627;
0177     }
0178 
0179     if ( text == "16F628" )
0180     {
0181         pic_type="P16F627";
0182         return P16F628;
0183     }
0184 //modified checking of 16F877 is included
0185     if ( text == "16F877" )
0186     {
0187         pic_type="P16F877";
0188         return P16F877;
0189     }
0190 
0191     cerr << QString("%1 is not a known PIC identifier\n").arg(_text).toStdString();
0192     return unknown;
0193 }
0194 
0195 
0196 QString PIC14::minimalTypeString() const
0197 {
0198     switch ( m_type )
0199     {
0200         case P16C84:
0201             return "16C84";
0202 
0203         case P16F84:
0204             return "16F84";
0205 
0206         case P16F627:
0207             return "16F627";
0208 
0209         case P16F628:
0210             return "16F628";
0211 
0212 //modified checking of 16F877 is included
0213 
0214         case P16F877:
0215             return "16F877";
0216 
0217         case unknown:
0218             break;
0219     }
0220 
0221     qCritical() << Q_FUNC_INFO << "Unknown PIC type = " << m_type;
0222     return nullptr;;
0223 }
0224 
0225 
0226 void PIC14::postCompileConstruct( const QStringList &interrupts )
0227 {
0228     m_pCode->append( new Instr_raw("\n\tEND\n"), Code::Subroutine );
0229 
0230     if ( interrupts.isEmpty() )
0231     {
0232         // If there are no ISRs then we don't need to put in any handler code.
0233         // Instead, just insert the goto start instruction in case we need to
0234         // jump past any lookup tabes (and if there are none, then the optimizer
0235         // will remove the goto instruction).
0236         m_pCode->append(new Instr_goto("_start"), Code::InterruptHandler);
0237         m_pCode->queueLabel( "_start", Code::LookupTable );
0238         return;
0239     }
0240 
0241     /*
0242         INTCON register:
0243         7 --- GIE EEIE T0IE INTE RBIE T0IF INTF RBIF --- 0
0244 
0245         E: enable
0246         F: flag
0247         Flag bits must be cleared manually before reactivating GIE,
0248         but we do this in each individual interrupt handler
0249     */
0250 
0251     // The bizarre dance with swap is to ensure the status bits
0252     // are preserved properly
0253     m_pCode->append(new Instr_goto("_start"), Code::InterruptHandler);
0254 
0255     m_pCode->append(new Instr_raw("ORG 0x4"), Code::InterruptHandler);
0256     // When we arrive here:
0257     // Return address on stack,
0258     // GIE flag cleared (globally interrupts disabled)
0259     // W or STATUS not preserved by processor.
0260     m_pCode->append(new Instr_movwf("W_TEMP"), Code::InterruptHandler);
0261     m_pCode->append(new Instr_swapf("STATUS",0), Code::InterruptHandler);
0262     m_pCode->append(new Instr_movwf("STATUS_TEMP"), Code::InterruptHandler);
0263 
0264     QStringList::ConstIterator interruptsEnd = interrupts.end();
0265     for( QStringList::ConstIterator it = interrupts.begin(); it != interruptsEnd; ++it )
0266     {
0267         // Is the interrupt's flag bit set?
0268         m_pCode->append(new Instr_btfsc("INTCON",QString::number(interruptNameToBit((*it), true))), Code::InterruptHandler);
0269         m_pCode->append(new Instr_goto("_interrupt_" + (*it)), Code::InterruptHandler); // Yes, do its handler routine
0270         // Otherwise fall through to the next.
0271     }
0272 
0273     // If there was "somehow" a suprious interrupt there isn't really
0274     // much we can do about that (??) so just fall through and hope for the worst.
0275 
0276     m_pCode->queueLabel( "_interrupt_end", Code::InterruptHandler );
0277     m_pCode->append(new Instr_swapf("STATUS_TEMP",0), Code::InterruptHandler );
0278     m_pCode->append(new Instr_movwf("STATUS"), Code::InterruptHandler );
0279     m_pCode->append(new Instr_swapf("W_TEMP",1), Code::InterruptHandler );
0280     m_pCode->append(new Instr_swapf("W_TEMP",0), Code::InterruptHandler );
0281     m_pCode->append(new Instr_retfie()); // Returns and renables globally interrupts.
0282 
0283     m_pCode->queueLabel( "_start", Code::LookupTable );
0284 }
0285 
0286 int PIC14::interruptNameToBit(const QString &name, bool flag)
0287 {
0288     // 7 --- GIE EEIE T0IE INTE RBIE T0IF INTF RBIF --- 0
0289 
0290     if( name == "change" ) // RB
0291     {
0292         if(flag) return 0;
0293         else return 3;
0294     }
0295     else if( name == "timer" )
0296     {
0297         if(flag) return 2;
0298         else return 5;
0299     }
0300     else if( name == "external" )
0301     {
0302         if(flag) return 1;
0303         else return 4;
0304     }
0305 
0306     return -1;
0307 }
0308 
0309 
0310 bool PIC14::isValidPort( const QString & portName ) const
0311 {
0312 
0313     if(pic_type =="P16F84"||pic_type =="P16C84"||pic_type =="P16F627"||pic_type =="P16F628")
0314         return ( portName == "PORTA" || portName == "PORTB");
0315 
0316     if(pic_type=="P16F877")
0317         return ( portName == "PORTA" ||portName == "PORTB"||portName == "PORTC" ||portName == "PORTD"||portName == "PORTE");
0318 
0319     return false;
0320 }
0321 
0322 
0323 bool PIC14::isValidPortPin( const PortPin & portPin ) const
0324 {
0325 
0326     if(pic_type == "P16F84" ||pic_type =="P16C84")
0327     {
0328         if ( portPin.port() == "PORTA" )
0329             return (portPin.pin() >= 0) && (portPin.pin() <= 4);
0330 
0331         if ( portPin.port() == "PORTB" )
0332             return (portPin.pin() >= 0) && (portPin.pin() <= 7);
0333     }
0334     if(pic_type == "P16F627" ||pic_type =="P16F628")
0335     {
0336         if ( portPin.port() == "PORTA" )
0337             return (portPin.pin() >= 0) && (portPin.pin() <= 7);
0338 
0339         if ( portPin.port() == "PORTB" )
0340             return (portPin.pin() >= 0) && (portPin.pin() <= 7);
0341     }
0342 
0343     if(pic_type=="P16F877")
0344     {
0345         if ( portPin.port() == "PORTA" )
0346             return (portPin.pin() >= 0) && (portPin.pin() <= 5);
0347 
0348         if ( portPin.port() == "PORTB" )
0349             return (portPin.pin() >= 0) && (portPin.pin() <= 7);
0350         if ( portPin.port() == "PORTC" )
0351             return (portPin.pin() >= 0) && (portPin.pin() <= 7);
0352 
0353         if ( portPin.port() == "PORTD" )
0354             return (portPin.pin() >= 0) && (portPin.pin() <= 7);
0355 
0356         if ( portPin.port() == "PORTE" )
0357             return (portPin.pin() >= 0) && (portPin.pin() <= 2);
0358     }
0359 
0360     return false;
0361 }
0362 
0363 
0364 bool PIC14::isValidTris( const QString & trisName ) const
0365 {
0366     if(pic_type =="P16F84"||pic_type =="P16C84"||pic_type =="P16F627"||pic_type =="P16F628")
0367         return ( trisName == "TRISA" || trisName == "TRISB");
0368 
0369     if(pic_type=="P16F877")
0370         return ( trisName =="TRISA"|| trisName =="TRISB"||trisName =="TRISC"||trisName == "TRISD"||trisName == "TRISE" );
0371 
0372     return false;
0373 }
0374 
0375 //*****************Modified ****************************//
0376 //New function isValiedRegister is added to check whether a register is valied or not
0377 bool PIC14::isValidRegister( const QString & registerName)const
0378 {
0379     if(pic_type=="P16F84"||pic_type=="P16C84")
0380         return ( registerName == "TMR0"
0381             || registerName == "PCL"
0382             || registerName == "STATUS"
0383             || registerName == "FSR"
0384             || registerName == "EEDATH"
0385             || registerName == "EEADR"
0386             || registerName == "PCLATH"
0387             || registerName == "INTCON"
0388             || registerName == "EECON1"
0389             || registerName == "EECON2"
0390             || registerName == "OPTION_REG");
0391 
0392     if(pic_type=="P16F877")
0393         return ( registerName == "TMR0"
0394             || registerName == "PCL"
0395             || registerName == "STATUS"
0396             || registerName == "FSR"
0397             || registerName == "PCLATH"
0398             || registerName == "INTCON"
0399             || registerName == "PIR1"
0400             || registerName == "PIR2"
0401             || registerName == "TMR1L"
0402             || registerName == "TMR1H"
0403             || registerName == "T1CON"
0404             || registerName == "TMR2"
0405             || registerName == "T2CON"
0406             || registerName == "SSPBUF"
0407             || registerName == "SSPCON"
0408             || registerName == "CCPR1L"
0409             || registerName == "CCPR1H"
0410             || registerName == "CCP1CON"
0411             || registerName == "RCSTA"
0412             || registerName == "TXREG"
0413             || registerName == "RCREG"
0414             || registerName == "CCPR2L"
0415             || registerName == "CCPR2H"
0416             || registerName == "CCP2CON"
0417             || registerName == "ADRESH"
0418             || registerName == "ADCON0" /*bank0ends*/
0419             || registerName == "OPTION_REG"
0420             || registerName == "PIE1"
0421             || registerName == "PIE2"
0422             || registerName == "PCON"
0423             || registerName == "SSPCON2"
0424             || registerName == "PR2"
0425             || registerName == "SSPADD"
0426             || registerName == "SSPSTAT"
0427             || registerName == "TXSTA"
0428             || registerName == "SPBRG"
0429             || registerName == "ADRESL"
0430             || registerName == "ADCON1" /*bank1ends*/
0431             || registerName == "EEDATA"
0432             || registerName == "EEADR"
0433             || registerName == "EEDATH"
0434             || registerName == "EEADRH" /*bank2ends*/
0435             || registerName == "EECON1"
0436             || registerName == "EECON2" /*bank3ends*/   );
0437 
0438     if(pic_type=="P16F627"||pic_type=="P16F628")
0439         return ( registerName == "TMR0"
0440             || registerName == "PCL"
0441             || registerName == "STATUS"
0442             || registerName == "FSR"
0443             || registerName == "PCLATH"
0444             || registerName == "INTCON"
0445             || registerName == "PIR1"
0446             || registerName == "TMR1L"
0447             || registerName == "TMR1H"
0448             || registerName == "T1CON"
0449             || registerName == "TMR2"
0450             || registerName == "T2CON"
0451             || registerName == "CCPR1L"
0452             || registerName == "CCPR1H"
0453             || registerName == "CCP1CON"
0454             || registerName == "RCSTA"
0455             || registerName == "TXREG"
0456             || registerName == "RCREG"
0457             || registerName == "CMCON"/*bank0ends*/
0458             || registerName == "OPTION_REG"
0459             || registerName == "PIE1"
0460             || registerName == "PCON"
0461             || registerName == "PR2"
0462             || registerName == "TXSTA"
0463             || registerName == "SPBRG"
0464             || registerName == "EEDATA"
0465             || registerName == "EEADR"
0466             || registerName == "EECON1"
0467             || registerName == "EECON2"
0468             || registerName == "VRCON"/*bank1ends*/ );
0469 
0470     return false;
0471 }
0472 
0473 //****************************modifications ends********************************************
0474 
0475 bool PIC14::isValidInterrupt( const QString & interruptName ) const
0476 {
0477     if(pic_type == "P16F84" ||pic_type =="P16C84"||pic_type =="P16F877"||pic_type=="P16F627"||pic_type=="P16F628")
0478         return ( interruptName == "change" ||
0479                  interruptName == "timer" ||
0480                  interruptName == "external" );
0481 
0482     return false;
0483 }
0484 
0485 
0486 void PIC14::setConditionalCode( Code * ifCode, Code * elseCode )
0487 {
0488     m_ifCode = ifCode;
0489     m_elseCode = elseCode;
0490 }
0491 
0492 void PIC14::Sgoto(const QString &label)
0493 {
0494     m_pCode->append( new Instr_goto(label) );
0495 }
0496 
0497 void PIC14::Slabel(const QString &label)
0498 {
0499 //  std::cout << Q_FUNC_INFO << "label="<<label<<'\n';
0500     m_pCode->queueLabel( label, Code::Middle );
0501 }
0502 
0503 void PIC14::Send()
0504 {
0505     m_pCode->append( new Instr_sleep() );
0506 }
0507 
0508 void PIC14::Ssubroutine( const QString &procName, Code * subCode )
0509 {
0510     m_pCode->queueLabel( procName, Code::Subroutine );
0511     m_pCode->merge( subCode, Code::Subroutine );
0512     m_pCode->append( new Instr_return(), Code::Subroutine );
0513 }
0514 
0515 void PIC14::Sinterrupt( const QString &procName, Code * subCode )
0516 {
0517     m_pCode->queueLabel( "_interrupt_" + procName, Code::Subroutine );
0518 
0519     // Clear the interrupt flag for this particular interrupt source
0520     m_pCode->append( new Instr_bcf("INTCON",QString::number(interruptNameToBit(procName,true))) );
0521     m_pCode->merge( subCode, Code::Subroutine );
0522 
0523     m_pCode->append( new Instr_goto("_interrupt_end"), Code::Subroutine );
0524 }
0525 
0526 
0527 void PIC14::Scall(const QString &name)
0528 {
0529     m_pCode->append( new Instr_call(name) );
0530 }
0531 
0532 
0533 void PIC14::Ssetlh( const PortPin & portPin, bool high)
0534 {
0535     if(high)
0536         m_pCode->append( new Instr_bsf( portPin.port(),QString::number(portPin.pin()) ) );
0537     else
0538         m_pCode->append( new Instr_bcf( portPin.port(), QString::number(portPin.pin()) ) );
0539 }
0540 
0541 void PIC14::rearrangeOpArguments( QString * val1, QString * val2, LocationType * val1Type, LocationType * val2Type)
0542 {
0543     if( *val2Type == work && *val1Type != work )
0544     {
0545         LocationType tempType = *val2Type;
0546         QString tempVal = *val2;
0547 
0548         *val2Type = *val1Type;
0549         *val2 = *val1;
0550 
0551         *val1Type = tempType;
0552         *val1 = tempVal;
0553     }
0554 }
0555 
0556 void PIC14::add( QString val1, QString val2, LocationType val1Type, LocationType val2Type )
0557 {
0558     rearrangeOpArguments( &val1, &val2, &val1Type, &val2Type );
0559 
0560     switch(val1Type)
0561     {
0562         case num:  m_pCode->append(new Instr_movlw( val1.toInt( nullptr, 0 ) )); break;
0563         case work: break;
0564         case var: m_pCode->append(new Instr_movf(val1,0)); break;
0565     }
0566 
0567     switch(val2Type)
0568     {
0569         case num: m_pCode->append(new Instr_addlw(val2.toInt( nullptr, 0 ))); break;
0570         case work: break;
0571         case var: m_pCode->append(new Instr_addwf(val2,0)); break;
0572     }
0573 }
0574 
0575 void PIC14::subtract( const QString & val1, const QString & val2, LocationType val1Type, LocationType val2Type )
0576 {
0577     switch(val2Type)
0578     {
0579         case num:  m_pCode->append(new Instr_movlw( val2.toInt( nullptr, 0 ) )); break;
0580         case work: break;
0581         case var: m_pCode->append(new Instr_movf(val2,0)); break;
0582     }
0583     switch(val1Type)
0584     {
0585         case num: m_pCode->append(new Instr_sublw(val1.toInt( nullptr, 0 ))); break;
0586         case work: break;
0587         case var: m_pCode->append(new Instr_subwf(val1,0)); break;
0588     }
0589 }
0590 
0591 void PIC14::assignNum(const QString & val)
0592 {
0593     m_pCode->append(new Instr_movlw(val.toInt( nullptr, 0 )));
0594 }
0595 
0596 void PIC14::assignVar(const QString &val)
0597 {
0598     m_pCode->append(new Instr_movf(val,0));
0599 }
0600 
0601 void PIC14::saveToReg(const QString &dest)
0602 {
0603     m_pCode->append(new Instr_movwf(dest));
0604 }
0605 
0606 void PIC14::saveResultToVar( const QString & var )
0607 {
0608     m_pCode->append( new Instr_movwf( var ) );
0609 }
0610 
0611 void PIC14::mul(QString val1, QString val2, LocationType val1Type, LocationType val2Type)
0612 {
0613     multiply();
0614 
0615     rearrangeOpArguments( &val1, &val2, &val1Type, &val2Type );
0616 
0617     // First, set _i argument
0618     switch(val1Type)
0619     {
0620         case num: m_pCode->append(new Instr_movlw(val1.toInt( nullptr, 0 ))); break;
0621         case work: break;
0622         case var: m_pCode->append(new Instr_movf(val1,0)); break;
0623     }
0624 
0625     m_pCode->append(new Instr_movwf("__i"));
0626 
0627     // Then set _j argument
0628     switch(val2Type)
0629     {
0630         case num: m_pCode->append(new Instr_movlw(val2.toInt( nullptr, 0 ))); break;
0631         case work: break;
0632         case var: m_pCode->append(new Instr_movf(val2,0)); break;
0633     }
0634 
0635     m_pCode->append(new Instr_movwf("__j"));
0636     m_pCode->append(new Instr_call("__picfunc_multiply"));
0637     m_pCode->append(new Instr_movf("__result",0));
0638 }
0639 
0640 
0641 void PIC14::multiply()
0642 {
0643     if ( m_pCode->instruction("__picfunc_multiply") )
0644         return;
0645 
0646     m_pCode->queueLabel( "__picfunc_multiply", Code::Subroutine );
0647     m_pCode->append(new Instr_clrf("__result"), Code::Subroutine ); //result+=m_pCode->appenduction("clrf __result");
0648 
0649     m_pCode->queueLabel( "__picfunc_multiply_loop", Code::Subroutine );
0650     m_pCode->append(new Instr_movf("__i",0), Code::Subroutine ); //result+=m_pCode->appenduction("movf __i,0");
0651     m_pCode->append(new Instr_btfsc("__j","0"), Code::Subroutine ); //result+=m_pCode->appenduction("btfsc __j,0");
0652     m_pCode->append(new Instr_addwf("__result",1), Code::Subroutine ); //result+=m_pCode->appenduction("addwf __result,1");
0653     m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine ); //result+=m_pCode->appenduction("bcf STATUS,C");
0654     m_pCode->append(new Instr_rrf("__j",1), Code::Subroutine ); //result+=m_pCode->appenduction("rrf __j,1");
0655     m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine ); //result+=m_pCode->appenduction("bcf STATUS,C");
0656     m_pCode->append(new Instr_rlf("__i",1), Code::Subroutine ); //result+=m_pCode->appenduction("rlf __i,1");
0657     m_pCode->append(new Instr_movf("__j",1), Code::Subroutine ); //result+=m_pCode->appenduction("movf __j,1");
0658     m_pCode->append(new Instr_btfss("STATUS","Z"), Code::Subroutine ); //result+=m_pCode->appenduction("btfss STATUS,Z");
0659     m_pCode->append(new Instr_goto("__picfunc_multiply_loop"), Code::Subroutine ); //result+=m_pCode->appenduction("goto __picfunc_multiply_loop");
0660     m_pCode->append(new Instr_return(), Code::Subroutine ); //result+=m_pCode->appenduction("return");
0661 }
0662 
0663 
0664 void PIC14::div( const QString & val1, const QString & val2, LocationType val1Type, LocationType val2Type)
0665 {
0666     divide();
0667 
0668     // NOO - "x / 2" is NOT the same as "2 / x"
0669 //  rearrangeOpArguments( val1, val2, val1Type, val2Type );
0670 
0671     // First, set _i argument
0672     switch(val1Type)
0673     {
0674         case num: m_pCode->append(new Instr_movlw(val1.toInt( nullptr, 0 ))); break;
0675         case work: break;
0676         case var: m_pCode->append(new Instr_movf(val1,0)); break;
0677     }
0678 
0679     m_pCode->append(new Instr_movwf("__i"));
0680 
0681     // Then set _j argument
0682     switch(val2Type)
0683     {
0684         case num: m_pCode->append(new Instr_movlw(val2.toInt( nullptr, 0 ))); break;
0685         case work: break;
0686         case var: m_pCode->append(new Instr_movf(val2,0)); break;
0687     }
0688 
0689     m_pCode->append(new Instr_movwf("__j"));
0690 
0691     m_pCode->append(new Instr_call("__picfunc_divide"));//result+=instruction("call __picfunc_divide");
0692     m_pCode->append(new Instr_movf("__result",0));//result+=instruction("movf __result,0");
0693 }
0694 
0695 void PIC14::divide()
0696 {
0697     m_pCode->queueLabel( "__picfunc_divide", Code::Subroutine );
0698     m_pCode->append(new Instr_movf("__j",1), Code::Subroutine );
0699     m_pCode->append(new Instr_btfsc("STATUS","2"), Code::Subroutine );
0700     m_pCode->append(new Instr_return(), Code::Subroutine );
0701     m_pCode->append(new Instr_clrf("__result"), Code::Subroutine );
0702     m_pCode->append(new Instr_movlw(1), Code::Subroutine );
0703     m_pCode->append(new Instr_movwf("__k"), Code::Subroutine );
0704 
0705     m_pCode->queueLabel( "__divide_shift", Code::Subroutine );
0706     m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine );
0707     m_pCode->append(new Instr_rlf("__k",1), Code::Subroutine );
0708     m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine );
0709     m_pCode->append(new Instr_rlf("__j",1), Code::Subroutine );
0710     m_pCode->append(new Instr_btfss("__j","7"), Code::Subroutine );
0711     m_pCode->append(new Instr_goto("__divide_shift"), Code::Subroutine );
0712 
0713     m_pCode->queueLabel( "__divide_loop", Code::Subroutine );
0714     m_pCode->append(new Instr_movf("__j",0), Code::Subroutine );
0715     m_pCode->append(new Instr_subwf("__i",1), Code::Subroutine );
0716     m_pCode->append(new Instr_btfsc("STATUS","C"), Code::Subroutine );
0717     m_pCode->append(new Instr_goto("__divide_count"), Code::Subroutine );
0718     m_pCode->append(new Instr_addwf("__i",1), Code::Subroutine );
0719     m_pCode->append(new Instr_goto("__divide_final"), Code::Subroutine );
0720 
0721     m_pCode->queueLabel( "__divide_count", Code::Subroutine );
0722     m_pCode->append(new Instr_movf("__k",0), Code::Subroutine );
0723     m_pCode->append(new Instr_addwf("__result",1), Code::Subroutine );
0724 
0725     m_pCode->queueLabel( "__divide_final", Code::Subroutine );
0726     m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine );
0727     m_pCode->append(new Instr_rrf("__j",1), Code::Subroutine );
0728     m_pCode->append(new Instr_bcf("STATUS","C"), Code::Subroutine );
0729     m_pCode->append(new Instr_rrf("__k",1), Code::Subroutine );
0730     m_pCode->append(new Instr_btfss("STATUS","C"), Code::Subroutine );
0731     m_pCode->append(new Instr_goto("__divide_loop"), Code::Subroutine );
0732     m_pCode->append(new Instr_return(), Code::Subroutine );
0733 }
0734 
0735 
0736 Code * PIC14::ifCode()
0737 {
0738     return m_ifCode;
0739 }
0740 
0741 
0742 Code * PIC14::elseCode()
0743 {
0744     return m_elseCode;
0745 }
0746 
0747 
0748 void PIC14::ifInitCode( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
0749 {
0750     // NOO - "x < 2" is NOT the same as "2 < x"
0751 //  rearrangeOpArguments( val1, val2, val1Type, val2Type );
0752 
0753     switch(val1Type)
0754     {
0755         case num:
0756             m_pCode->append(new Instr_movlw(val1.toInt( nullptr, 0 )));
0757             break;
0758 
0759         case work:
0760             break; // Nothing to do
0761 
0762         case var:
0763             m_pCode->append(new Instr_movf(val1,0));
0764             break;
0765     }
0766 
0767     switch(val2Type)
0768     {
0769         case num:
0770             m_pCode->append(new Instr_sublw(val2.toInt( nullptr, 0 )));
0771             break;
0772 
0773         case work:
0774             qCritical() << Q_FUNC_INFO << "Cannot subtract working from working!";
0775             break;
0776 
0777         case var:
0778             m_pCode->append(new Instr_subwf(val2,0));
0779             break;
0780     }
0781 }
0782 
0783 void PIC14::equal( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
0784 {
0785     ifInitCode( val1, val2, val1Type, val2Type );
0786     const QString labelEnd = mb->uniqueLabel()+"_endif";
0787     const QString labelFalse = mb->uniqueLabel()+"_case_false";
0788 
0789     m_pCode->append(new Instr_btfss("STATUS","2"));
0790     m_pCode->append(new Instr_goto(labelFalse));
0791 
0792     mergeCode( ifCode() );
0793 
0794     m_pCode->append(new Instr_goto(labelEnd));
0795 
0796     m_pCode->queueLabel( labelFalse );
0797     mergeCode( elseCode() );
0798     m_pCode->queueLabel( labelEnd );
0799 }
0800 
0801 void PIC14::notEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
0802 {
0803     ifInitCode( val1, val2, val1Type, val2Type );
0804     const QString labelEnd = mb->uniqueLabel()+"_endif";
0805     const QString labelFalse = mb->uniqueLabel()+"_case_false";
0806 
0807     m_pCode->append(new Instr_btfsc("STATUS","2"));
0808     m_pCode->append(new Instr_goto(labelFalse));
0809 
0810     mergeCode( ifCode() );
0811 
0812     m_pCode->append(new Instr_goto(labelEnd));
0813 
0814     m_pCode->queueLabel( labelFalse );
0815     mergeCode( elseCode() );
0816     m_pCode->queueLabel( labelEnd );
0817 }
0818 
0819 void PIC14::greaterThan( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
0820 {
0821     ifInitCode( val1, val2, val1Type, val2Type );
0822     const QString labelEnd = mb->uniqueLabel()+"_endif";
0823     const QString labelFalse = mb->uniqueLabel()+"_case_false";
0824 
0825     m_pCode->append(new Instr_btfsc("STATUS","0"));
0826     m_pCode->append(new Instr_goto(labelFalse));
0827 
0828     mergeCode( ifCode() );
0829     m_pCode->append(new Instr_goto(labelEnd));
0830 
0831     m_pCode->queueLabel( labelFalse );
0832     mergeCode( elseCode() );
0833     m_pCode->queueLabel( labelEnd );
0834 }
0835 
0836 void PIC14::lessThan( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
0837 {
0838     cout << Q_FUNC_INFO << endl;
0839     ifInitCode( val1, val2, val1Type, val2Type );
0840     const QString labelEnd = mb->uniqueLabel()+"_endif";
0841     const QString labelFalse = mb->uniqueLabel()+"_case_false";
0842 
0843     m_pCode->append(new Instr_btfss("STATUS","0"));
0844     m_pCode->append(new Instr_goto(labelFalse));
0845     m_pCode->append(new Instr_btfsc("STATUS","2"));
0846     m_pCode->append(new Instr_goto(labelFalse));
0847 
0848     mergeCode( ifCode() );
0849 
0850     m_pCode->append(new Instr_goto(labelEnd));
0851 
0852     m_pCode->queueLabel( labelFalse );
0853     mergeCode( elseCode() );
0854     m_pCode->queueLabel( labelEnd );
0855 }
0856 
0857 void PIC14::greaterOrEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
0858 {
0859     ifInitCode( val1, val2, val1Type, val2Type );
0860     const QString labelEnd = mb->uniqueLabel()+"_endif";
0861     const QString labelTrue = mb->uniqueLabel()+"_case_true"; // Note that unlike the others, this is labelTrue, not labelFalse
0862 
0863     m_pCode->append(new Instr_btfsc("STATUS","2"));
0864     m_pCode->append(new Instr_goto(labelTrue));
0865     m_pCode->append(new Instr_btfss("STATUS","0"));
0866     m_pCode->append(new Instr_goto(labelTrue));
0867 
0868     mergeCode( elseCode() );
0869 
0870     m_pCode->append(new Instr_goto(labelEnd));
0871 
0872     m_pCode->queueLabel( labelTrue );
0873     mergeCode( ifCode() );
0874     m_pCode->queueLabel( labelEnd );
0875 }
0876 
0877 void PIC14::lessOrEqual( const QString &val1, const QString &val2, LocationType val1Type, LocationType val2Type )
0878 {
0879     ifInitCode( val1, val2, val1Type, val2Type );
0880     const QString labelEnd = mb->uniqueLabel()+"_endif";
0881     const QString labelFalse = mb->uniqueLabel()+"_case_false";
0882 
0883     m_pCode->append(new Instr_btfss("STATUS","0"));
0884     m_pCode->append(new Instr_goto(labelFalse));
0885 
0886     mergeCode( ifCode() );
0887     m_pCode->append(new Instr_goto(labelEnd));
0888 
0889     m_pCode->queueLabel( labelFalse );
0890     mergeCode( elseCode() );
0891     m_pCode->queueLabel( labelEnd );
0892 }
0893 
0894 
0895 void PIC14::Swhile( Code * whileCode, const QString &expression)
0896 {
0897     QString result;
0898     QString ul = mb->uniqueLabel();
0899 
0900     whileCode->append( new Instr_goto(ul) );
0901 
0902     m_pCode->queueLabel( ul, Code::Middle );
0903 
0904     // If the condition is not true, just fall through
0905     m_parser->compileConditionalExpression( expression, whileCode, nullptr );
0906 }
0907 
0908 
0909 void PIC14::Srepeat( Code * repeatCode, const QString &expression)
0910 {
0911     QString result;
0912     QString ul = mb->uniqueLabel();
0913 
0914     Code * elseCode = new Code;
0915     elseCode->append( new Instr_goto(ul) );
0916 
0917     m_pCode->queueLabel( ul );
0918     m_pCode->merge( repeatCode );
0919 
0920     // If the condition is true, just fall through
0921     m_parser->compileConditionalExpression( expression, nullptr, elseCode );
0922 }
0923 
0924 void PIC14::Sif( Code * ifCode, Code * elseCode, const QString &expression)
0925 {
0926     m_parser->compileConditionalExpression( expression, ifCode, elseCode );
0927 }
0928 
0929 
0930 void PIC14::Sfor( Code * forCode, Code * initCode, const QString &expression, const QString &variable, const QString &step, bool stepPositive)
0931 {
0932     QString ul = mb->uniqueLabel();
0933 
0934     if ( step == "1" )
0935     {
0936         if (stepPositive)
0937             forCode->append(new Instr_incf(variable,1));
0938         else
0939             forCode->append(new Instr_decf(variable,1));
0940     }
0941     else
0942     {
0943         forCode->append(new Instr_movlw(step.toInt( nullptr, 0 )));
0944         if (stepPositive)
0945             forCode->append(new Instr_addwf(variable,1));
0946         else
0947             forCode->append(new Instr_subwf(variable,1));
0948     }
0949     forCode->append(new Instr_goto(ul));
0950 
0951     m_pCode->merge( initCode );
0952 
0953     m_pCode->queueLabel( ul );
0954 
0955     m_parser->compileConditionalExpression( expression, forCode, nullptr );
0956 }
0957 
0958 
0959 void PIC14::Spin( const PortPin & portPin, bool NOT)
0960 {
0961     QString lowLabel, highLabel, postLabel;
0962     lowLabel = mb->uniqueLabel();
0963     highLabel = mb->uniqueLabel();
0964     postLabel = mb->uniqueLabel();
0965     /*result += indent + "goto\t" + lowLabel;
0966     result += indent + "movlw\t1" + "goto\t"+postLabel+;
0967     result += lowLabel +  + indent + "movlw\t0" + indent;
0968     result += postLabel + ;*/
0969 
0970     if(NOT)
0971         m_pCode->append(new Instr_btfsc( portPin.port(), QString::number( portPin.pin() ) ));
0972     //result +=instruction((QString)(NOT?"btfsc":"btfss")+"\t"+port+","+pin);
0973     else
0974         m_pCode->append(new Instr_btfss( portPin.port(), QString::number( portPin.pin() ) ));
0975 
0976     m_pCode->append(new Instr_goto(lowLabel));//result += instruction("goto\t" + lowLabel);
0977     mergeCode( ifCode() );
0978     m_pCode->append(new Instr_goto(postLabel));//result += instruction("goto\t"+postLabel);
0979 
0980     m_pCode->queueLabel( lowLabel );
0981     mergeCode( elseCode() );
0982 
0983     m_pCode->queueLabel( postLabel );
0984 }
0985 
0986 
0987 void PIC14::Sdelay( unsigned length_us, Code::InstructionPosition pos )
0988 {
0989     if ( length_us == 0 )
0990         return;
0991 
0992     if ( length_us > 50070524 )
0993     {
0994         length_us += 50267642;
0995         int l = length_us/50070530;
0996         length_us -= l * 50070530;
0997         int k = length_us/196355;
0998 
0999         m_pCode->append( new Instr_movlw( l ), pos );
1000         m_pCode->append( new Instr_movwf( "__l" ), pos );
1001         m_pCode->append( new Instr_movlw( k ), pos );
1002         m_pCode->append( new Instr_movwf( "__k" ), pos );
1003 
1004         mb->addDelayRoutineWanted( Delay_50S );
1005     }
1006 
1007     else if ( length_us > 196350 )
1008     {
1009         length_us += 197116;
1010         int k = length_us/196355;
1011         length_us -= k * 196355;
1012         int j = length_us/770;
1013 
1014         m_pCode->append( new Instr_incf( "__l", 1 ), pos );
1015         m_pCode->append( new Instr_movlw( k ), pos );
1016         m_pCode->append( new Instr_movwf( "__k" ), pos );
1017         m_pCode->append( new Instr_movlw( j ), pos );
1018         m_pCode->append( new Instr_movwf( "__j" ), pos );
1019 
1020         mb->addDelayRoutineWanted( Delay_200mS );
1021     }
1022 
1023     else if ( length_us > 766 )
1024     {
1025         length_us += 765;
1026         int j = length_us/770;
1027         length_us -= j * 770;
1028         int i = length_us/3;
1029 
1030         m_pCode->append( new Instr_incf( "__l", 1 ), pos );
1031         m_pCode->append( new Instr_incf( "__k", 1 ), pos );
1032         m_pCode->append( new Instr_movlw( j ), pos );
1033         m_pCode->append( new Instr_movwf( "__j" ), pos );
1034         m_pCode->append( new Instr_movlw( i ), pos );
1035         m_pCode->append( new Instr_movwf( "__i" ), pos );
1036 
1037         mb->addDelayRoutineWanted( Delay_768uS );
1038     }
1039 
1040     else
1041     {
1042         length_us += -1;
1043         int i = length_us/3;
1044 
1045         m_pCode->append( new Instr_incf( "__l", 1 ), pos );
1046         m_pCode->append( new Instr_incf( "__k", 1 ), pos );
1047         m_pCode->append( new Instr_incf( "__j", 1 ), pos );
1048         m_pCode->append( new Instr_movlw( i ), pos );
1049         m_pCode->append( new Instr_movwf( "__i" ), pos );
1050 
1051         mb->addDelayRoutineWanted( Delay_3uS );
1052     }
1053 
1054     m_pCode->append( new Instr_call( "__delay_subroutine"), pos );
1055 }
1056 
1057 
1058 void PIC14::addCommonFunctions( DelaySubroutine delay )
1059 {
1060     if ( delay != Delay_None )
1061     {
1062         QString subName = "__delay_subroutine";
1063         m_pCode->queueLabel( subName, Code::Subroutine );
1064 
1065         m_pCode->append( new Instr_decfsz( "__i", 1 ), Code::Subroutine );
1066         m_pCode->append( new Instr_goto( subName ), Code::Subroutine );
1067 
1068         if ( delay > Delay_3uS )
1069         {
1070             m_pCode->append( new Instr_decfsz( "__j", 1 ), Code::Subroutine );
1071             m_pCode->append( new Instr_goto( subName ), Code::Subroutine );
1072         }
1073 
1074         if ( delay > Delay_768uS )
1075         {
1076             m_pCode->append( new Instr_decfsz( "__k", 1 ), Code::Subroutine );
1077             m_pCode->append( new Instr_goto( subName ), Code::Subroutine );
1078         }
1079 
1080         if ( delay > Delay_200mS )
1081         {
1082             m_pCode->append( new Instr_decfsz( "__l", 1 ), Code::Subroutine );
1083             m_pCode->append( new Instr_goto( subName ), Code::Subroutine );
1084         }
1085 
1086         m_pCode->append( new Instr_return(), Code::Subroutine );
1087     }
1088 }
1089 
1090 
1091 void PIC14::SsevenSegment( const Variable & pinMap )
1092 {
1093     assert( pinMap.type() == Variable::sevenSegmentType );
1094     assert( pinMap.portPinList().size() == 7 );
1095 
1096     QString subName = QString("__output_seven_segment_%1").arg( pinMap.name() );
1097 
1098     m_pCode->append( new Instr_call( subName ) );
1099 
1100     if ( m_pCode->instruction(subName) )
1101         return;
1102 
1103     // Build up what are going to write to each port from the pin map
1104     struct SSPortOutput
1105     {
1106         bool used; // Wheter we use this port at all
1107         bool use[8]; // Whether or not we use each pin.
1108         bool out[16][8]; // The bit to write to each pin for each value.
1109         uchar useMask; // The bits of use[8] - this is generated later from use[8]
1110     };
1111 
1112     unsigned numPorts = 2;
1113     SSPortOutput portOutput[ 2 ];  // numPorts
1114     memset( portOutput, 0, numPorts * sizeof(SSPortOutput) );
1115 
1116     for ( unsigned i = 0; i < 7; ++i )
1117     {
1118         PortPin portPin = pinMap.portPinList()[i];
1119 
1120         unsigned port = unsigned( portPin.portPosition() );
1121         unsigned pin = unsigned( portPin.pin() );
1122 
1123         portOutput[ port ].used = true;
1124         portOutput[ port ].use[ pin ] = true;
1125 
1126         for ( unsigned num = 0; num < 16; ++num )
1127         {
1128             portOutput[ port ].out[ num ][ pin ] = LEDSegTable[num][ i ];
1129         }
1130     }
1131 
1132 
1133     // See if we've used more than one port
1134     unsigned portsUsed = 0;
1135     for ( unsigned port = 0; port < numPorts; ++port )
1136     {
1137         if ( portOutput[port].used )
1138             portsUsed++;
1139     }
1140 
1141 
1142     // Generate the useMasks
1143     for ( unsigned port = 0; port < numPorts; ++port )
1144     {
1145         portOutput[port].useMask = 0;
1146         for ( unsigned pin = 0; pin < 8; ++pin )
1147             portOutput[port].useMask |= portOutput[port].use[pin] ? (1 << pin) : 0;
1148     }
1149 
1150 
1151     //BEGIN Generate [subName] Subroutine
1152     m_pCode->queueLabel( subName, Code::Subroutine );
1153 //  if ( portsUsed > 1 )
1154     {
1155         m_pCode->append( new Instr_movwf("__i"), Code::Subroutine );
1156     }
1157 
1158 //  bool overwrittenW = false;
1159     bool overwrittenW = true;
1160 
1161     for ( unsigned port = 0; port < numPorts; ++port )
1162     {
1163         if ( !portOutput[port].used )
1164             continue;
1165 
1166         QString portName = QString("PORT%1").arg( char('A'+port) );
1167 
1168         // Save the current value of the port pins that we should not be writing to
1169         m_pCode->append( new Instr_movf( portName, 0 ), Code::Subroutine );
1170         m_pCode->append( new Instr_andlw( ~portOutput[port].useMask ), Code::Subroutine );
1171         m_pCode->append( new Instr_movwf( "__j" ), Code::Subroutine );
1172 
1173         if ( overwrittenW )
1174             m_pCode->append( new Instr_movf("__i",0), Code::Subroutine );
1175 
1176         m_pCode->append( new Instr_call( subName + QString("_lookup_%1").arg(port) ), Code::Subroutine );
1177         overwrittenW = true;
1178 
1179         // Restore the state of the pins which aren't used
1180         m_pCode->append( new Instr_iorwf( "__j", 0 ), Code::Subroutine );
1181 
1182         // And write the result to the port
1183         m_pCode->append( new Instr_movwf( portName ), Code::Subroutine );
1184     }
1185 
1186     m_pCode->append( new Instr_return(), Code::Subroutine );
1187     //END Generate [subName] Subroutine
1188 
1189     // For each port, generate code for looking up the value for writing to it
1190     for ( unsigned port = 0; port < numPorts; ++port )
1191     {
1192         if ( !portOutput[port].used )
1193             continue;
1194 
1195         m_pCode->queueLabel( subName + QString("_lookup_%1").arg(port), Code::LookupTable );
1196         m_pCode->append( new Instr_andlw(15), Code::LookupTable );
1197 
1198         // Generate the lookup table
1199         m_pCode->append( new Instr_addwf( "pcl", 1 ), Code::LookupTable );
1200         for ( unsigned num = 0; num < 16; ++num )
1201         {
1202             unsigned literal = 0;
1203             for ( unsigned bit = 0; bit < 8; ++bit )
1204                 literal += ( portOutput[port].out[num][bit] ? 1 : 0 ) << bit;
1205 
1206             m_pCode->append( new Instr_retlw( literal ), Code::LookupTable );
1207         }
1208     }
1209 }
1210 
1211 
1212 void PIC14::Skeypad( const Variable & pinMap )
1213 {
1214     // pinMap = 4 rows, n columns
1215 
1216     assert( pinMap.type() == Variable::keypadType );
1217     assert( pinMap.portPinList().size() >= 7 ); // 4 rows, at least 3 columns
1218 
1219     QString subName = QString("__wait_read_keypad_%1").arg( pinMap.name() );
1220     QString waitName = QString("__wait_keypad_%1").arg( pinMap.name() );
1221     QString readName = QString("__read_keypad_%1").arg( pinMap.name() );
1222 
1223     m_pCode->append( new Instr_call( subName ) );
1224 
1225     if ( m_pCode->instruction( subName ) )
1226         return;
1227 
1228     //BEGIN Wait until read subroutine
1229     m_pCode->queueLabel( subName, Code::Subroutine );
1230 
1231     // Read current key (if any) from keypad and save to temporary variable
1232     m_pCode->append( new Instr_call( readName ), Code::Subroutine );
1233     m_pCode->append( new Instr_movwf( "__m" ), Code::Subroutine );
1234 
1235     // Test if any key was pressed; if not, then start again
1236 //  std::cout << "mb->alias(\"Keypad_None\")="<<mb->alias("Keypad_None") << std::endl;
1237     m_pCode->append( new Instr_sublw( mb->alias("Keypad_None").toInt( nullptr, 0 ) ), Code::Subroutine );
1238     m_pCode->append( new Instr_btfsc( "STATUS","Z" ), Code::Subroutine );
1239     m_pCode->append( new Instr_goto( subName ), Code::Subroutine );
1240     m_pCode->append( new Instr_goto( waitName ), Code::Subroutine );
1241     //END Wait until read subroutine
1242 
1243 
1244     //BEGIN Wait until released subroutine
1245     m_pCode->queueLabel( waitName, Code::Subroutine );
1246 
1247     Sdelay( 10000, Code::Subroutine ); // 10 milliseconds for debouncing
1248 
1249     // Key was pressed; now we wait until the key is released again
1250     m_pCode->append( new Instr_call( readName ), Code::Subroutine );
1251     m_pCode->append( new Instr_sublw( mb->alias("Keypad_None").toInt( nullptr, 0 ) ), Code::Subroutine );
1252     m_pCode->append( new Instr_btfss( "STATUS","Z" ), Code::Subroutine );
1253     m_pCode->append( new Instr_goto( waitName ), Code::Subroutine );
1254     m_pCode->append( new Instr_movf( "__m", 0 ), Code::Subroutine );
1255     m_pCode->append( new Instr_return(), Code::Subroutine );
1256     //END Wait until released subroutine
1257 
1258 
1259     if ( m_pCode->instruction( readName ) )
1260         return;
1261 
1262     //BEGIN Read current value of keypad subroutine
1263     m_pCode->queueLabel( readName, Code::Subroutine );
1264 
1265     // Make the four row lines low
1266     for ( unsigned row = 0; row < 4; ++ row )
1267     {
1268         PortPin rowPin = pinMap.portPinList()[row];
1269         m_pCode->append( new Instr_bcf( rowPin.port(), QString::number( rowPin.pin() ) ), Code::Subroutine );
1270     }
1271 
1272     // Test each row in turn
1273     for ( unsigned row = 0; row < 4; ++ row )
1274     {
1275         // Make the high low
1276         PortPin rowPin = pinMap.portPinList()[row];
1277         m_pCode->append( new Instr_bsf( rowPin.port(), QString::number( rowPin.pin() ) ), Code::Subroutine );
1278 
1279         for ( unsigned col = 0; col < 3; ++ col )
1280         {
1281             PortPin colPin = pinMap.portPinList()[4+col];
1282             m_pCode->append( new Instr_btfsc( colPin.port(), QString::number( colPin.pin() ) ), Code::Subroutine );
1283             m_pCode->append( new Instr_retlw( mb->alias( QString("Keypad_%1_%2").arg(row+1).arg(col+1) ).toInt( nullptr, 0 ) ), Code::Subroutine );
1284         }
1285 
1286         // Make the low again
1287         m_pCode->append( new Instr_bcf( rowPin.port(), QString::number( rowPin.pin() ) ), Code::Subroutine );
1288     }
1289 
1290     // No key was pressed
1291     m_pCode->append( new Instr_retlw( mb->alias("Keypad_None").toInt( nullptr, 0 ) ), Code::Subroutine );
1292     //END Read current value of keypad subroutine
1293 }
1294 
1295 /*****************************commented for modification *******************************
1296 
1297 void PIC14::bitwise( Expression::Operation op, const QString &r_val1, const QString &val2, bool val1IsNum, bool val2IsNum )
1298 {
1299     QString val1 = r_val1;
1300     // There is no instruction for notting a literal,
1301     // so instead I am going to XOR with 0xFF
1302     if( op == Expression::bwnot ) val1 = "0xFF";
1303     if( val1IsNum ) m_pCode->append(new Instr_movlw(val1.toInt( 0, 0 )));// result += instruction("movlw\t"+val1);
1304     else m_pCode->append(new Instr_movf(val1,0));//result += instruction("movf\t"+val1+",0");
1305 
1306     QString opString;
1307     if( val2IsNum )
1308     {
1309         switch(op)
1310         {
1311             case Expression::bwand: m_pCode->append(new Instr_andlw(val2.toInt( 0, 0 ))); break;
1312             case Expression::bwor: m_pCode->append(new Instr_iorlw(val2.toInt( 0, 0 ))); break;
1313             case Expression::bwxor: m_pCode->append(new Instr_xorlw(val2.toInt( 0, 0 ))); break;
1314             case Expression::bwnot: m_pCode->append(new Instr_xorlw(val2.toInt( 0, 0 ))); break;
1315             default: break;
1316         }
1317     }
1318     else
1319     {
1320         switch(op)
1321         {
1322             case Expression::bwand: m_pCode->append(new Instr_andwf(val2,0)); break;
1323             case Expression::bwor: m_pCode->append(new Instr_iorwf(val2,0)); break;
1324             case Expression::bwxor: m_pCode->append(new Instr_xorwf(val2,0)); break;
1325             case Expression::bwnot: m_pCode->append(new Instr_xorwf(val2,0)); break;
1326             default: break;
1327         }
1328 
1329     }
1330 }*/
1331 ///comment end and the new function is given bellow -- new code is working well
1332 // TODO - One error with OR operation if A OR 255 result in segebentation fault
1333 //*****************modified to make the bit operation works***************************/
1334 void PIC14::bitwise( Expression::Operation op,const QString & r_val1, const QString & val2, LocationType val1Type, LocationType val2Type)
1335 {
1336     QString val1 = r_val1;
1337     if( op == Expression::bwnot ) val1 = "0xFF";
1338     switch(val1Type)
1339     {
1340         case num: m_pCode->append(new Instr_movlw(val1.toInt( nullptr, 0 ))); break;
1341         case work: break;
1342         case var: m_pCode->append(new Instr_movf(val1,0)); break;
1343     }
1344     switch(val2Type)
1345     {
1346         case num:
1347         {
1348             switch(op)
1349             {
1350                 case Expression::bwand: m_pCode->append(new Instr_andlw(val2.toInt( nullptr, 0 ))); break;
1351                 case Expression::bwor:  m_pCode->append(new Instr_iorlw(val2.toInt( nullptr, 0 ))); break;
1352                 case Expression::bwxor: m_pCode->append(new Instr_xorlw(val2.toInt( nullptr, 0 ))); break;
1353                 case Expression::bwnot: m_pCode->append(new Instr_xorlw(val2.toInt( nullptr, 0 ))); break;
1354                 default: break;
1355         }
1356         }
1357         case work: break;
1358         case var:
1359         {
1360             switch(op)
1361             {
1362                 case Expression::bwand: m_pCode->append(new Instr_andwf(val2,0)); break;
1363                 case Expression::bwor:  m_pCode->append(new Instr_iorwf(val2,0)); break;
1364                 case Expression::bwxor: m_pCode->append(new Instr_xorwf(val2,0)); break;
1365                 case Expression::bwnot: m_pCode->append(new Instr_xorwf(val2,0)); break;
1366                 default: break;
1367             }
1368 
1369         }
1370     }
1371 
1372 }//***************************************modification ends*****************************
1373 void PIC14::SincVar( const QString &var )
1374 {
1375     m_pCode->append(new Instr_incf(var,1) );
1376 }
1377 
1378 void PIC14::SdecVar( const QString &var )
1379 {
1380     m_pCode->append(new Instr_decf(var,1) );
1381 }
1382 
1383 void PIC14::SrotlVar( const QString &var )
1384 {
1385     m_pCode->append(new Instr_rlf(var,1));
1386 }
1387 
1388 void PIC14::SrotrVar( const QString &var )
1389 {
1390     m_pCode->append(new Instr_rrf(var,1));
1391 }
1392 
1393 void PIC14::Stristate(const QString &port)
1394 {
1395 //modification pic type is checked here
1396     m_pCode->append( new Instr_bsf("STATUS","5") );//commented
1397     if(pic_type== "P16C84" || pic_type =="P16F84"||pic_type =="P16F627")
1398     {
1399         if( port == "trisa" || port == "TRISA" )
1400             saveResultToVar( "TRISA" );
1401         else    saveResultToVar( "TRISB" );
1402     }
1403     if(pic_type =="P16F877")
1404     {
1405         if( port == "trisa" || port == "TRISA" )
1406             saveResultToVar( "TRISA" );
1407         else if( port == "trisb" || port == "TRISB" )
1408             saveResultToVar( "TRISB" );
1409         else if( port == "trisc" || port == "TRISC" )
1410             saveResultToVar( "TRISC" );
1411         else if( port == "trisd" || port == "TRISD" )
1412             saveResultToVar( "TRISD" );
1413         else    saveResultToVar( "TRISE" );
1414 
1415     }
1416     m_pCode->append( new Instr_bcf(Register("STATUS"),"5") );//commented
1417 }
1418 
1419 void PIC14::Sasm(const QString &raw)
1420 {
1421     m_pCode->append(new Instr_asm(raw));
1422 }
1423 
1424 //BEGIN class PortPin
1425 PortPin::PortPin( const QString & port, int pin )
1426 {
1427     m_port = port.toUpper();
1428     m_pin = pin;
1429 }
1430 
1431 
1432 PortPin::PortPin()
1433 {
1434     m_port = ' ';
1435     m_pin = -1;
1436 }
1437 
1438 
1439 int PortPin::portPosition() const
1440 {
1441     if ( m_port.isEmpty() )
1442         return 0;
1443     return uchar( m_port[ m_port.length() - 1 ].toLatin1() ) - 'A';
1444 }
1445 
1446 //END class PortPin
1447