|
|
|
/***************************************************************************
|
|
|
|
* 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 <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 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="<<label<<'\n';
|
|
|
|
m_pCode->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\")="<<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(), 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
|