📄 pic16.cpp
字号:
WriteIhex(f, 0x00);
WriteIhex(f, Prog.mcu->configurationWord & 0xff);
WriteIhex(f, Prog.mcu->configurationWord >> 8);
FinishIhex(f);
// end of file record
fprintf(f, ":00000001FF\n");
}
//-----------------------------------------------------------------------------
// Generate code to write an 8-bit value to a particular register. Takes care
// of the bank switching if necessary; assumes that code is called in bank
// 0.
//-----------------------------------------------------------------------------
static void WriteRegister(DWORD reg, BYTE val)
{
if(reg & 0x080) Instruction(OP_BSF, REG_STATUS, STATUS_RP0);
if(reg & 0x100) Instruction(OP_BSF, REG_STATUS, STATUS_RP1);
Instruction(OP_MOVLW, val, 0);
Instruction(OP_MOVWF, (reg & 0x7f), 0);
if(reg & 0x080) Instruction(OP_BCF, REG_STATUS, STATUS_RP0);
if(reg & 0x100) Instruction(OP_BCF, REG_STATUS, STATUS_RP1);
}
//-----------------------------------------------------------------------------
// Call a subroutine, that might be in an arbitrary page, and then put
// PCLATH back where we want it.
//-----------------------------------------------------------------------------
static void CallWithPclath(DWORD addr)
{
// Set up PCLATH for the jump, and then do it.
Instruction(OP_MOVLW, FWD_HI(addr), 0);
Instruction(OP_MOVWF, REG_PCLATH, 0);
Instruction(OP_CALL, FWD_LO(addr), 0);
// Restore PCLATH to something appropriate for our page. (We have
// already made fairly sure that we will never try to compile across
// a page boundary.)
Instruction(OP_MOVLW, (PicProgWriteP >> 8), 0);
Instruction(OP_MOVWF, REG_PCLATH, 0);
}
// Note that all of these are single instructions on the PIC; this is not the
// case for their equivalents on the AVR!
#define SetBit(reg, b) Instruction(OP_BSF, reg, b)
#define ClearBit(reg, b) Instruction(OP_BCF, reg, b)
#define IfBitClear(reg, b) Instruction(OP_BTFSS, reg, b)
#define IfBitSet(reg, b) Instruction(OP_BTFSC, reg, b)
static void CopyBit(DWORD addrDest, int bitDest, DWORD addrSrc, int bitSrc)
{
IfBitSet(addrSrc, bitSrc);
SetBit(addrDest, bitDest);
IfBitClear(addrSrc, bitSrc);
ClearBit(addrDest, bitDest);
}
//-----------------------------------------------------------------------------
// Handle an IF statement. Flow continues to the first instruction generated
// by this function if the condition is true, else it jumps to the given
// address (which is an FwdAddress, so not yet assigned). Called with IntPc
// on the IF statement, returns with IntPc on the END IF.
//-----------------------------------------------------------------------------
static void CompileIfBody(DWORD condFalse)
{
IntPc++;
CompileFromIntermediate(FALSE);
if(IntCode[IntPc].op == INT_ELSE) {
IntPc++;
DWORD endBlock = AllocFwdAddr();
Instruction(OP_GOTO, endBlock, 0);
FwdAddrIsNow(condFalse);
CompileFromIntermediate(FALSE);
FwdAddrIsNow(endBlock);
} else {
FwdAddrIsNow(condFalse);
}
if(IntCode[IntPc].op != INT_END_IF) oops();
}
//-----------------------------------------------------------------------------
// Compile the intermediate code to PIC16 native code.
//-----------------------------------------------------------------------------
static void CompileFromIntermediate(BOOL topLevel)
{
DWORD addr, addr2;
int bit, bit2;
DWORD addrl, addrh;
DWORD addrl2, addrh2;
DWORD addrl3, addrh3;
// Keep track of which 2k section we are using. When it looks like we
// are about to run out, fill with nops and move on to the next one.
DWORD section = 0;
for(; IntPc < IntCodeLen; IntPc++) {
// Try for a margin of about 400 words, which is a little bit
// wasteful but considering that the formatted output commands
// are huge, probably necessary. Of course if we are in our
// last section then it is silly to do that, either we make it
// or we're screwed...
if(topLevel && (((PicProgWriteP + 400) >> 11) != section) &&
((PicProgWriteP + 400) < Prog.mcu->flashWords))
{
// Jump to the beginning of the next section
Instruction(OP_MOVLW, (PicProgWriteP >> 8) + (1<<3), 0);
Instruction(OP_MOVWF, REG_PCLATH, 0);
Instruction(OP_GOTO, 0, 0);
// Then, just burn the last of this section with NOPs.
while((PicProgWriteP >> 11) == section) {
Instruction(OP_MOVLW, 0xab, 0);
}
section = (PicProgWriteP >> 11);
// And now PCLATH is set up, so everything in our new section
// should just work
}
IntOp *a = &IntCode[IntPc];
switch(a->op) {
case INT_SET_BIT:
MemForSingleBit(a->name1, FALSE, &addr, &bit);
SetBit(addr, bit);
break;
case INT_CLEAR_BIT:
MemForSingleBit(a->name1, FALSE, &addr, &bit);
ClearBit(addr, bit);
break;
case INT_COPY_BIT_TO_BIT:
MemForSingleBit(a->name1, FALSE, &addr, &bit);
MemForSingleBit(a->name2, FALSE, &addr2, &bit2);
CopyBit(addr, bit, addr2, bit2);
break;
case INT_SET_VARIABLE_TO_LITERAL:
MemForVariable(a->name1, &addrl, &addrh);
WriteRegister(addrl, a->literal & 0xff);
WriteRegister(addrh, a->literal >> 8);
break;
case INT_INCREMENT_VARIABLE: {
MemForVariable(a->name1, &addrl, &addrh);
DWORD noCarry = AllocFwdAddr();
Instruction(OP_INCFSZ, addrl, DEST_F);
Instruction(OP_GOTO, noCarry, 0);
Instruction(OP_INCF, addrh, DEST_F);
FwdAddrIsNow(noCarry);
break;
}
case INT_IF_BIT_SET: {
DWORD condFalse = AllocFwdAddr();
MemForSingleBit(a->name1, TRUE, &addr, &bit);
IfBitClear(addr, bit);
Instruction(OP_GOTO, condFalse, 0);
CompileIfBody(condFalse);
break;
}
case INT_IF_BIT_CLEAR: {
DWORD condFalse = AllocFwdAddr();
MemForSingleBit(a->name1, TRUE, &addr, &bit);
IfBitSet(addr, bit);
Instruction(OP_GOTO, condFalse, 0);
CompileIfBody(condFalse);
break;
}
case INT_IF_VARIABLE_LES_LITERAL: {
DWORD notTrue = AllocFwdAddr();
DWORD isTrue = AllocFwdAddr();
DWORD lsbDecides = AllocFwdAddr();
// V = Rd7*(Rr7')*(R7') + (Rd7')*Rr7*R7 ; but only one of the
// product terms can be true, and we know which at compile
// time
BYTE litH = (a->literal >> 8);
BYTE litL = (a->literal & 0xff);
MemForVariable(a->name1, &addrl, &addrh);
// var - lit
Instruction(OP_MOVLW, litH, 0);
Instruction(OP_SUBWF, addrh, DEST_W);
IfBitSet(REG_STATUS, STATUS_Z);
Instruction(OP_GOTO, lsbDecides, 0);
Instruction(OP_MOVWF, Scratch0, 0);
if(litH & 0x80) {
Instruction(OP_COMF, addrh, DEST_W);
Instruction(OP_ANDWF, Scratch0, DEST_W);
Instruction(OP_XORWF, Scratch0, DEST_F);
} else {
Instruction(OP_COMF, Scratch0, DEST_W);
Instruction(OP_ANDWF, addrh, DEST_W);
Instruction(OP_XORWF, Scratch0, DEST_F);
}
IfBitSet(Scratch0, 7); // var - lit < 0, var < lit
Instruction(OP_GOTO, isTrue, 0);
Instruction(OP_GOTO, notTrue, 0);
FwdAddrIsNow(lsbDecides);
// var - lit < 0
// var < lit
Instruction(OP_MOVLW, litL, 0);
Instruction(OP_SUBWF, addrl, DEST_W);
IfBitClear(REG_STATUS, STATUS_C);
Instruction(OP_GOTO, isTrue, 0);
Instruction(OP_GOTO, notTrue, 0);
FwdAddrIsNow(isTrue);
CompileIfBody(notTrue);
break;
}
case INT_IF_VARIABLE_EQUALS_VARIABLE: {
DWORD notEqual = AllocFwdAddr();
MemForVariable(a->name1, &addrl, &addrh);
MemForVariable(a->name2, &addrl2, &addrh2);
Instruction(OP_MOVF, addrl, DEST_W);
Instruction(OP_SUBWF, addrl2, DEST_W);
IfBitClear(REG_STATUS, STATUS_Z);
Instruction(OP_GOTO, notEqual, 0);
Instruction(OP_MOVF, addrh, DEST_W);
Instruction(OP_SUBWF, addrh2, DEST_W);
IfBitClear(REG_STATUS, STATUS_Z);
Instruction(OP_GOTO, notEqual, 0);
CompileIfBody(notEqual);
break;
}
case INT_IF_VARIABLE_GRT_VARIABLE: {
DWORD notTrue = AllocFwdAddr();
DWORD isTrue = AllocFwdAddr();
DWORD lsbDecides = AllocFwdAddr();
MemForVariable(a->name1, &addrl, &addrh);
MemForVariable(a->name2, &addrl2, &addrh2);
// first, a signed comparison of the high octets, which is
// a huge pain on the PIC16
DWORD iu = addrh2, ju = addrh;
DWORD signa = Scratch0;
DWORD signb = Scratch1;
Instruction(OP_COMF, ju, DEST_W);
Instruction(OP_MOVWF, signb, 0);
Instruction(OP_ANDWF, iu, DEST_W);
Instruction(OP_MOVWF, signa, 0);
Instruction(OP_MOVF, iu, DEST_W);
Instruction(OP_IORWF, signb, DEST_F);
Instruction(OP_COMF, signb, DEST_F);
Instruction(OP_MOVF, ju, DEST_W);
Instruction(OP_SUBWF, iu, DEST_W);
IfBitSet(REG_STATUS, STATUS_Z);
Instruction(OP_GOTO, lsbDecides, 0);
Instruction(OP_ANDWF, signb, DEST_F);
Instruction(OP_MOVWF, Scratch2, 0);
Instruction(OP_COMF, Scratch2, DEST_W);
Instruction(OP_ANDWF, signa, DEST_W);
Instruction(OP_IORWF, signb, DEST_W);
Instruction(OP_XORWF, Scratch2, DEST_F);
IfBitSet(Scratch2, 7);
Instruction(OP_GOTO, isTrue, 0);
Instruction(OP_GOTO, notTrue, 0);
FwdAddrIsNow(lsbDecides);
Instruction(OP_MOVF, addrl, DEST_W);
Instruction(OP_SUBWF, addrl2, DEST_W);
IfBitClear(REG_STATUS, STATUS_C);
Instruction(OP_GOTO, isTrue, 0);
Instruction(OP_GOTO, notTrue, 0);
FwdAddrIsNow(isTrue);
CompileIfBody(notTrue);
break;
}
case INT_SET_VARIABLE_TO_VARIABLE:
MemForVariable(a->name1, &addrl, &addrh);
MemForVariable(a->name2, &addrl2, &addrh2);
Instruction(OP_MOVF, addrl2, DEST_W);
Instruction(OP_MOVWF, addrl, 0);
Instruction(OP_MOVF, addrh2, DEST_W);
Instruction(OP_MOVWF, addrh, 0);
break;
case INT_SET_VARIABLE_ADD:
MemForVariable(a->name1, &addrl, &addrh);
MemForVariable(a->name2, &addrl2, &addrh2);
MemForVariable(a->name3, &addrl3, &addrh3);
Instruction(OP_MOVF, addrl2, DEST_W);
Instruction(OP_ADDWF, addrl3, DEST_W);
Instruction(OP_MOVWF, addrl, 0);
Instruction(OP_MOVF, addrh2, DEST_W);
Instruction(OP_MOVWF, addrh, 0);
IfBitSet(REG_STATUS, STATUS_C);
Instruction(OP_INCF, addrh, DEST_F);
Instruction(OP_MOVF, addrh3, DEST_W);
Instruction(OP_ADDWF, addrh, DEST_F);
break;
case INT_SET_VARIABLE_SUBTRACT:
MemForVariable(a->name1, &addrl, &addrh);
MemForVariable(a->name2, &addrl2, &addrh2);
MemForVariable(a->name3, &addrl3, &addrh3);
Instruction(OP_MOVF, addrl3, DEST_W);
Instruction(OP_SUBWF, addrl2, DEST_W);
Instruction(OP_MOVWF, addrl, 0);
Instruction(OP_MOVF, addrh2, DEST_W);
Instruction(OP_MOVWF, addrh, 0);
IfBitClear(REG_STATUS, STATUS_C);
Instruction(OP_DECF, addrh, DEST_F);
Instruction(OP_MOVF, addrh3, DEST_W);
Instruction(OP_SUBWF, addrh, DEST_F);
break;
case INT_SET_VARIABLE_MULTIPLY:
MultiplyNeeded = TRUE;
MemForVariable(a->name1, &addrl, &addrh);
MemForVariable(a->name2, &addrl2, &addrh2);
MemForVariable(a->name3, &addrl3, &addrh3);
Instruction(OP_MOVF, addrl2, DEST_W);
Instruction(OP_MOVWF, Scratch0, 0);
Instruction(OP_MOVF, addrh2, DEST_W);
Instruction(OP_MOVWF, Scratch1, 0);
Instruction(OP_MOVF, addrl3, DEST_W);
Instruction(OP_MOVWF, Scratch2, 0);
Instruction(OP_MOVF, addrh3, DEST_W);
Instruction(OP_MOVWF, Scratch3, 0);
CallWithPclath(MultiplyRoutineAddress);
Instruction(OP_MOVF, Scratch2, DEST_W);
Instruction(OP_MOVWF, addrl, 0);
Instruction(OP_MOVF, Scratch3, DEST_W);
Instruction(OP_MOVWF, addrh, 0);
break;
case INT_SET_VARIABLE_DIVIDE:
DivideNeeded = TRUE;
MemForVariable(a->name1, &addrl, &addrh);
MemForVariable(a->name2, &addrl2, &addrh2);
MemForVariable(a->name3, &addrl3, &addrh3);
Instruction(OP_MOVF, addrl2, DEST_W);
Instruction(OP_MOVWF, Scratch0, 0);
Instruction(OP_MOVF, addrh2, DEST_W);
Instruction(OP_MOVWF, Scratch1, 0);
Instruction(OP_MOVF, addrl3, DEST_W);
Instruction(OP_MOVWF, Scratch2, 0);
Instruction(OP_MOVF, addrh3, DEST_W);
Instruction(OP_MOVWF, Scratch3, 0);
CallWithPclath(DivideRoutineAddress);
Instruction(OP_MOVF, Scratch0, DEST_W);
Instruction(OP_MOVWF, addrl, 0);
Instruction(OP_MOVF, Scratch1, DEST_W);
Instruction(OP_MOVWF, addrh, 0);
break;
case INT_UART_SEND: {
MemForVariable(a->name1, &addrl, &addrh);
MemForSingleBit(a->name2, TRUE, &addr, &bit);
DWORD noSend = AllocFwdAddr();
IfBitClear(addr, bit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -