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

📄 pic16.cpp

📁 plc软件的源代码 支持PIC ATMEGA单片机
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//-----------------------------------------------------------------------------
// Copyright 2007 Jonathan Westhues
//
// This file is part of LDmicro.
// 
// LDmicro 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 3 of the License, or
// (at your option) any later version.
// 
// LDmicro 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 LDmicro.  If not, see <http://www.gnu.org/licenses/>.
//------
//
// A PIC16... assembler, for our own internal use, plus routines to generate
// code from the ladder logic structure, plus routines to generate the
// runtime needed to schedule the cycles.
// Jonathan Westhues, Oct 2004
//-----------------------------------------------------------------------------
#include <windows.h>
#include <math.h>
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>

#include "ldmicro.h"
#include "intcode.h"

// not complete; just what I need
typedef enum Pic16OpTag {
    OP_VACANT,
    OP_ADDWF,
    OP_ANDWF,
    OP_CALL,
    OP_BSF,
    OP_BCF,
    OP_BTFSC,
    OP_BTFSS,
    OP_GOTO,
    OP_CLRF,
    OP_CLRWDT,
    OP_COMF,
    OP_DECF,
    OP_DECFSZ,
    OP_INCF,
    OP_INCFSZ,
    OP_IORWF,
    OP_MOVLW,
    OP_MOVF,
    OP_MOVWF,
    OP_RETFIE,
    OP_RETURN,
    OP_RLF,
    OP_RRF,
    OP_SUBLW,
    OP_SUBWF,
    OP_XORWF,
} Pic16Op;

#define DEST_F 1
#define DEST_W 0

#define STATUS_RP1  6
#define STATUS_RP0  5
#define STATUS_Z    2
#define STATUS_C    0

typedef struct Pic16InstructionTag {
    Pic16Op     op;
    DWORD       arg1;
    DWORD       arg2;
} Pic16Instruction;

#define MAX_PROGRAM_LEN 128*1024
static Pic16Instruction PicProg[MAX_PROGRAM_LEN];
static DWORD PicProgWriteP;

// Scratch variables, for temporaries
static DWORD Scratch0;
static DWORD Scratch1;
static DWORD Scratch2;
static DWORD Scratch3;
static DWORD Scratch4;
static DWORD Scratch5;
static DWORD Scratch6;
static DWORD Scratch7;

// The extra byte to program, for the EEPROM (because we can only set
// up one byte to program at a time, and we will be writing two-byte
// variables, in general).
static DWORD EepromHighByte;
static DWORD EepromHighByteWaitingAddr;
static int EepromHighByteWaitingBit;

// Subroutines to do multiply/divide
static DWORD MultiplyRoutineAddress;
static DWORD DivideRoutineAddress;
static BOOL MultiplyNeeded;
static BOOL DivideNeeded;

// For yet unresolved references in jumps
static DWORD FwdAddrCount;

// As I start to support the paging; it is sometimes necessary to pick
// out the high vs. low portions of the address, so that the high portion
// goes in PCLATH, and the low portion is just used for the jump.
#define FWD_LO(x)   ((x) | 0x20000000)
#define FWD_HI(x)   ((x) | 0x40000000)

// Some useful registers, which I think are mostly in the same place on
// all the PIC16... devices.
#define REG_INDF      0x00
#define REG_STATUS    0x03
#define REG_FSR       0x04
#define REG_PCLATH    0x0a
#define REG_INTCON    0x0b
#define REG_PIR1      0x0c
#define REG_PIE1      0x8c
#define REG_TMR1L     0x0e
#define REG_TMR1H     0x0f
#define REG_T1CON     0x10
#define REG_CCPR1L    0x15
#define REG_CCPR1H    0x16
#define REG_CCP1CON   0x17
#define REG_CMCON     0x1f

#define REG_TXSTA     0x98
#define REG_RCSTA     0x18
#define REG_SPBRG     0x99
#define REG_TXREG     0x19
#define REG_RCREG     0x1a

#define REG_ADRESH    0x1e
#define REG_ADRESL    0x9e
#define REG_ADCON0    0x1f
#define REG_ADCON1    0x9f
#define REG_ANSEL     0x9b

#define REG_T2CON     0x12
#define REG_CCPR2L    0x1b
#define REG_CCP2CON   0x1d
#define REG_PR2       0x92

// These move around from device to device.
static DWORD REG_EECON1;
static DWORD REG_EECON2;
static DWORD REG_EEDATA;
static DWORD REG_EEADR;

static int IntPc;

static void CompileFromIntermediate(BOOL topLevel);

//-----------------------------------------------------------------------------
// Wipe the program and set the write pointer back to the beginning.
//-----------------------------------------------------------------------------
static void WipeMemory(void)
{
    memset(PicProg, 0, sizeof(PicProg));
    PicProgWriteP = 0;
}

//-----------------------------------------------------------------------------
// Store an instruction at the next spot in program memory.  Error condition
// if this spot is already filled. We don't actually assemble to binary yet;
// there may be references to resolve.
//-----------------------------------------------------------------------------
static void Instruction(Pic16Op op, DWORD arg1, DWORD arg2)
{
    if(PicProg[PicProgWriteP].op != OP_VACANT) oops();

    PicProg[PicProgWriteP].op = op;
    PicProg[PicProgWriteP].arg1 = arg1;
    PicProg[PicProgWriteP].arg2 = arg2;
    PicProgWriteP++;
}

//-----------------------------------------------------------------------------
// Allocate a unique descriptor for a forward reference. Later that forward
// reference gets assigned to an absolute address, and we can go back and
// fix up the reference.
//-----------------------------------------------------------------------------
static DWORD AllocFwdAddr(void)
{
    FwdAddrCount++;
    return 0x80000000 | FwdAddrCount;
}

//-----------------------------------------------------------------------------
// Go back and fix up the program given that the provided forward address
// corresponds to the next instruction to be assembled.
//-----------------------------------------------------------------------------
static void FwdAddrIsNow(DWORD addr)
{
    if(!(addr & 0x80000000)) oops();

    BOOL seen = FALSE;
    DWORD i;
    for(i = 0; i < PicProgWriteP; i++) {
        if(PicProg[i].arg1 == addr) {
            // Insist that they be in the same page, but otherwise assume
            // that PCLATH has already been set up appropriately.
            if((i >> 11) != (PicProgWriteP >> 11)) {
                Error(_("Internal error relating to PIC paging; make program "
                    "smaller or reshuffle it."));
                CompileError();
            }
            PicProg[i].arg1 = PicProgWriteP;
            seen = TRUE;
        } else if(PicProg[i].arg1 == FWD_LO(addr)) {
            PicProg[i].arg1 = (PicProgWriteP & 0x7ff);
            seen = TRUE;
        } else if(PicProg[i].arg1 == FWD_HI(addr)) {
            PicProg[i].arg1 = (PicProgWriteP >> 8);
        }
    }
    if(!seen) oops();
}

//-----------------------------------------------------------------------------
// Given an opcode and its operands, assemble the 14-bit instruction for the
// PIC. Check that the operands do not have more bits set than is meaningful;
// it is an internal error if they do.
//-----------------------------------------------------------------------------
static DWORD Assemble(Pic16Op op, DWORD arg1, DWORD arg2)
{
#define CHECK(v, bits) if((v) != ((v) & ((1 << (bits))-1))) oops()
    switch(op) {
        case OP_ADDWF:
            CHECK(arg2, 1); CHECK(arg1, 7);
            return (7 << 8) | (arg2 << 7) | arg1;

        case OP_ANDWF:
            CHECK(arg2, 1); CHECK(arg1, 7);
            return (5 << 8) | (arg2 << 7) | arg1;

        case OP_BSF:
            CHECK(arg2, 3); CHECK(arg1, 7);
            return (5 << 10) | (arg2 << 7) | arg1;

        case OP_BCF:
            CHECK(arg2, 3); CHECK(arg1, 7);
            return (4 << 10) | (arg2 << 7) | arg1;

        case OP_BTFSC:
            CHECK(arg2, 3); CHECK(arg1, 7);
            return (6 << 10) | (arg2 << 7) | arg1;

        case OP_BTFSS:
            CHECK(arg2, 3); CHECK(arg1, 7);
            return (7 << 10) | (arg2 << 7) | arg1;

        case OP_CLRF:
            CHECK(arg1, 7); CHECK(arg2, 0);
            return (3 << 7) | arg1;

        case OP_CLRWDT:
            return 0x0064;

        case OP_COMF:
            CHECK(arg2, 1); CHECK(arg1, 7);
            return (9 << 8) | (arg2 << 7) | arg1;

        case OP_DECF:
            CHECK(arg1, 7); CHECK(arg2, 1);
            return (3 << 8) | (arg2 << 7) | arg1;

        case OP_DECFSZ:
            CHECK(arg1, 7); CHECK(arg2, 1);
            return (11 << 8) | (arg2 << 7) | arg1;

        case OP_GOTO:
            // Very special case: we will assume that the PCLATH stuff has
            // been taken care of already.
            arg1 &= 0x7ff;
            CHECK(arg1, 11); CHECK(arg2, 0);
            return (5 << 11) | arg1;

        case OP_CALL:
            CHECK(arg1, 11); CHECK(arg2, 0);
            return (4 << 11) | arg1;

        case OP_INCF:
            CHECK(arg1, 7); CHECK(arg2, 1);
            return (10 << 8) | (arg2 << 7) | arg1;

        case OP_INCFSZ:
            CHECK(arg1, 7); CHECK(arg2, 1);
            return (15 << 8) | (arg2 << 7) | arg1;

        case OP_IORWF:
            CHECK(arg2, 1); CHECK(arg1, 7);
            return (4 << 8) | (arg2 << 7) | arg1;

        case OP_MOVLW:
            CHECK(arg1, 8); CHECK(arg2, 0);
            return (3 << 12) | arg1;

        case OP_MOVF:
            CHECK(arg1, 7); CHECK(arg2, 1);
            return (8 << 8) | (arg2 << 7) | arg1;

        case OP_MOVWF:
            CHECK(arg1, 7); CHECK(arg2, 0);
            return (1 << 7) | arg1;

        case OP_RETURN:
            return 0x0008;

        case OP_RETFIE:
            return 0x0009;

        case OP_RLF:
            CHECK(arg1, 7); CHECK(arg2, 1);
            return (13 << 8) | (arg2 << 7) | arg1;

        case OP_RRF:
            CHECK(arg1, 7); CHECK(arg2, 1);
            return (12 << 8) | (arg2 << 7) | arg1;

        case OP_SUBLW:
            CHECK(arg1, 8); CHECK(arg2, 0);
            return (15 << 9) | arg1;

        case OP_SUBWF:
            CHECK(arg1, 7); CHECK(arg2, 1);
            return (2 << 8) | (arg2 << 7) | arg1;

        case OP_XORWF:
            CHECK(arg1, 7); CHECK(arg2, 1);
            return (6 << 8) | (arg2 << 7) | arg1;

        default:
            oops();
            break;
    }
}

//-----------------------------------------------------------------------------
// Write an intel IHEX format description of the program assembled so far.
// This is where we actually do the assembly to binary format.
//-----------------------------------------------------------------------------
static void WriteHexFile(FILE *f)
{
    BYTE soFar[16];
    int soFarCount = 0;
    DWORD soFarStart = 0;

    // always start from address 0
    fprintf(f, ":020000040000FA\n");

    DWORD i;
    for(i = 0; i < PicProgWriteP; i++) {
        DWORD w = Assemble(PicProg[i].op, PicProg[i].arg1, PicProg[i].arg2);

        if(soFarCount == 0) soFarStart = i;
        soFar[soFarCount++] = (BYTE)(w & 0xff);
        soFar[soFarCount++] = (BYTE)(w >> 8);

        if(soFarCount >= 0x10 || i == (PicProgWriteP-1)) {
            StartIhex(f);
            WriteIhex(f, soFarCount);
            WriteIhex(f, (BYTE)((soFarStart*2) >> 8));
            WriteIhex(f, (BYTE)((soFarStart*2) & 0xff));
            WriteIhex(f, 0x00);
            int j;
            for(j = 0; j < soFarCount; j++) {
                WriteIhex(f, soFar[j]);
            }
            FinishIhex(f);
            soFarCount = 0;
        }
    }

    StartIhex(f);
    WriteIhex(f, 0x02);
    WriteIhex(f, 0x40);
    WriteIhex(f, 0x0E);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -