⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pic16.cpp

📁 plc软件的源代码 支持PIC ATMEGA单片机
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    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 + -