Ejemplo n.º 1
0
void CompileInterpreted(char *outFile)
{
    FILE *f = fopen(outFile, "w");
    if(!f) {
        Error(_("Couldn't write to '%s'"), outFile);
        return;
    }

    InternalRelaysCount = 0;
    VariablesCount = 0;

    fprintf(f, "$$LDcode\n");

    int ipc;
    int outPc;
    BinOp op;

    // Convert the if/else structures in the intermediate code to absolute
    // conditional jumps, to make life a bit easier for the interpreter.
#define MAX_IF_NESTING      32
    int ifDepth = 0;
    // PC for the if(...) instruction, which we will complete with the
    // 'jump to if false' address (which is either the ELSE+1 or the ENDIF+1)
    int ifOpIf[MAX_IF_NESTING];
    // PC for the else instruction, which we will complete with the
    // 'jump to if reached' address (which is the ENDIF+1)
    int ifOpElse[MAX_IF_NESTING];

    outPc = 0;
    for(ipc = 0; ipc < IntCodeLen; ipc++) {
        memset(&op, 0, sizeof(op));
        op.op = IntCode[ipc].op;

        switch(IntCode[ipc].op) {
            case INT_CLEAR_BIT:
            case INT_SET_BIT:
                op.name1 = AddrForInternalRelay(IntCode[ipc].name1);
                break;

            case INT_COPY_BIT_TO_BIT:
                op.name1 = AddrForInternalRelay(IntCode[ipc].name1);
                op.name2 = AddrForInternalRelay(IntCode[ipc].name2);
                break;

            case INT_SET_VARIABLE_TO_LITERAL:
                op.name1 = AddrForVariable(IntCode[ipc].name1);
                op.literal = IntCode[ipc].literal;
                break;

            case INT_SET_VARIABLE_TO_VARIABLE:
                op.name1 = AddrForVariable(IntCode[ipc].name1);
                op.name2 = AddrForVariable(IntCode[ipc].name2);
                break;

            case INT_INCREMENT_VARIABLE:
                op.name1 = AddrForVariable(IntCode[ipc].name1);
                break;

            case INT_SET_VARIABLE_ADD:
            case INT_SET_VARIABLE_SUBTRACT:
            case INT_SET_VARIABLE_MULTIPLY:
            case INT_SET_VARIABLE_DIVIDE:
                op.name1 = AddrForVariable(IntCode[ipc].name1);
                op.name2 = AddrForVariable(IntCode[ipc].name2);
                op.name3 = AddrForVariable(IntCode[ipc].name3);
                break;

            case INT_IF_BIT_SET:
            case INT_IF_BIT_CLEAR:
                op.name1 = AddrForInternalRelay(IntCode[ipc].name1);
                goto finishIf;
            case INT_IF_VARIABLE_LES_LITERAL:
                op.name1 = AddrForVariable(IntCode[ipc].name1);
                op.literal = IntCode[ipc].literal;
                goto finishIf;
            case INT_IF_VARIABLE_EQUALS_VARIABLE:
            case INT_IF_VARIABLE_GRT_VARIABLE:
                op.name1 = AddrForVariable(IntCode[ipc].name1);
                op.name2 = AddrForVariable(IntCode[ipc].name2);
                goto finishIf;
finishIf:
                ifOpIf[ifDepth] = outPc;
                ifOpElse[ifDepth] = 0;
                ifDepth++;
                // jump target will be filled in later
                break;

            case INT_ELSE:
                ifOpElse[ifDepth-1] = outPc;
                // jump target will be filled in later
                break;

            case INT_END_IF:
                --ifDepth;
                if(ifOpElse[ifDepth] == 0) {
                    // There is no else; if should jump straight to the
                    // instruction after this one if the condition is false.
                    OutProg[ifOpIf[ifDepth]].name3 = outPc-1;
                } else {
                    // There is an else clause; if the if is false then jump
                    // just past the else, and if the else is reached then
                    // jump to the endif.
                    OutProg[ifOpIf[ifDepth]].name3 = ifOpElse[ifDepth];
                    OutProg[ifOpElse[ifDepth]].name3 = outPc-1;
                }
                // But don't generate an instruction for this.
                continue;

            case INT_SIMULATE_NODE_STATE:
            case INT_COMMENT:
                // Don't care; ignore, and don't generate an instruction.
                continue;

            case  INT_READ_SFR_LITERAL:
            case  INT_WRITE_SFR_LITERAL:
            case  INT_SET_SFR_LITERAL:
            case  INT_CLEAR_SFR_LITERAL:
            case  INT_TEST_SFR_LITERAL:
            case  INT_READ_SFR_VARIABLE:
            case  INT_WRITE_SFR_VARIABLE:
            case  INT_SET_SFR_VARIABLE:
            case  INT_CLEAR_SFR_VARIABLE:
            case  INT_TEST_SFR_VARIABLE:
            case  INT_TEST_C_SFR_LITERAL:
            case  INT_WRITE_SFR_LITERAL_L:
            case  INT_WRITE_SFR_VARIABLE_L:
            case  INT_SET_SFR_LITERAL_L:
            case  INT_SET_SFR_VARIABLE_L:
            case  INT_CLEAR_SFR_LITERAL_L:
            case  INT_CLEAR_SFR_VARIABLE_L:
            case  INT_TEST_SFR_LITERAL_L:
            case  INT_TEST_SFR_VARIABLE_L:
            case  INT_TEST_C_SFR_VARIABLE:
            case  INT_TEST_C_SFR_LITERAL_L:
            case  INT_TEST_C_SFR_VARIABLE_L:

            case INT_EEPROM_BUSY_CHECK:
            case INT_EEPROM_READ:
            case INT_EEPROM_WRITE:
            case INT_READ_ADC:
            case INT_SET_PWM:
            case INT_UART_SEND:
            case INT_UART_RECV:
            default:
                Error(_("Unsupported op (anything ADC, PWM, UART, EEPROM, SFR..) for "
                    "interpretable target."));
                fclose(f);
                return;
        }

        memcpy(&OutProg[outPc], &op, sizeof(op));
        outPc++;
    }

    int i;
    for(i = 0; i < outPc; i++) {
        Write(f, &OutProg[i]);
    }
    memset(&op, 0, sizeof(op));
    op.op = INT_END_OF_PROGRAM;
    Write(f, &op);


    fprintf(f, "$$bits\n");
    for(i = 0; i < InternalRelaysCount; i++) {
        if(InternalRelays[i][0] != '$') {
            fprintf(f, "%s,%d\n", InternalRelays[i], i);
        }
    }
    fprintf(f, "$$int16s\n");
    for(i = 0; i < VariablesCount; i++) {
        if(Variables[i][0] != '$') {
            fprintf(f, "%s,%d\n", Variables[i], i);
        }
    }

    fprintf(f, "$$cycle %d us\n", Prog.cycleTime);

    fclose(f);

    char str[MAX_PATH+500];
    sprintf(str,
      _("Compile successful; wrote interpretable code to '%s'.\r\n\r\n"
        "You probably have to adapt the interpreter to your application. See "
        "the documentation."), outFile);
    CompileSuccessfulMessage(str);
}
Ejemplo n.º 2
0
void CompileAnsiC(char *dest)
{
    SeenVariablesCount = 0;

    FILE *f = fopen(dest, "w");
    if(!f) {
        Error(_("Couldn't open file '%s'"), dest);
        return;
    }

    fprintf(f,
"/* This is auto-generated code from LDmicro. Do not edit this file! Go\n"
"   back to the ladder diagram source for changes in the logic, and make\n"
"   any C additions either in ladder.h or in additional .c files linked\n"
"   against this one. */\n"
"\n"
"/* You must provide ladder.h; there you must provide:\n"
"      * a typedef for SWORD and BOOL, signed 16 bit and boolean types\n"
"        (probably typedef signed short SWORD; typedef unsigned char BOOL;)\n"
"\n"
"   You must also provide implementations of all the I/O read/write\n"
"   either as inlines in the header file or in another source file. (The\n"
"   I/O functions are all declared extern.)\n"
"\n"
"   See the generated source code (below) for function names. */\n"
"#include \"ladder.h\"\n"
"\n"
"/* Define EXTERN_EVERYTHING in ladder.h if you want all symbols extern.\n"
"   This could be useful to implement `magic variables,' so that for\n"
"   example when you write to the ladder variable duty_cycle, your PLC\n"
"   runtime can look at the C variable U_duty_cycle and use that to set\n"
"   the PWM duty cycle on the micro. That way you can add support for\n"
"   peripherals that LDmicro doesn't know about. */\n"
"#ifdef EXTERN_EVERYTHING\n"
"#define STATIC \n"
"#else\n"
"#define STATIC static\n"
"#endif\n"
"\n"
"/* Define NO_PROTOTYPES if you don't want LDmicro to provide prototypes for\n"
"   all the I/O functions (Read_U_xxx, Write_U_xxx) that you must provide.\n"
"   If you define this then you must provide your own prototypes for these\n"
"   functions in ladder.h, or provide definitions (e.g. as inlines or macros)\n"
"   for them in ladder.h. */\n"
"#ifdef NO_PROTOTYPES\n"
"#define PROTO(x)\n"
"#else\n"
"#define PROTO(x) x\n"
"#endif\n"
"\n"
"/* U_xxx symbols correspond to user-defined names. There is such a symbol\n"
"   for every internal relay, variable, timer, and so on in the ladder\n"
"   program. I_xxx symbols are internally generated. */\n"
        );

    // now generate declarations for all variables
    GenerateDeclarations(f);

    fprintf(f,
"\n"
"\n"
"/* Call this function once per PLC cycle. You are responsible for calling\n"
"   it at the interval that you specified in the MCU configuration when you\n"
"   generated this code. */\n"
"void PlcCycle(void)\n"
"{\n"
        );

    GenerateAnsiC(f);

    fprintf(f, "}\n");
    fclose(f);

    char str[MAX_PATH+500];
    sprintf(str, _("Compile successful; wrote C source code to '%s'.\r\n\r\n"
        "This is not a complete C program. You have to provide the runtime "
        "and all the I/O routines. See the comments in the source code for "
        "information about how to do this."), dest);
    CompileSuccessfulMessage(str);
}