diff options
Diffstat (limited to 'ldmicro/interpreted.cpp')
-rw-r--r-- | ldmicro/interpreted.cpp | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/ldmicro/interpreted.cpp b/ldmicro/interpreted.cpp new file mode 100644 index 0000000..2295f90 --- /dev/null +++ b/ldmicro/interpreted.cpp @@ -0,0 +1,248 @@ +//----------------------------------------------------------------------------- +// 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 crunched-down version of the intermediate code (e.g. assigning addresses +// to all the variables instead of just working with their names), suitable +// for interpretation. +// Jonathan Westhues, Aug 2005 +//----------------------------------------------------------------------------- +#include "linuxUI.h" +#include <stdio.h> +#include <setjmp.h> +#include <stdlib.h> + +#include "ldmicro.h" +#include "intcode.h" + +static char Variables[MAX_IO][MAX_NAME_LEN]; +static int VariablesCount; + +static char InternalRelays[MAX_IO][MAX_NAME_LEN]; +static int InternalRelaysCount; + +typedef struct { + WORD op; + WORD name1; + WORD name2; + WORD name3; + SWORD literal; +} BinOp; + +static BinOp OutProg[MAX_INT_OPS]; + +static WORD AddrForInternalRelay(char *name) +{ + int i; + for(i = 0; i < InternalRelaysCount; i++) { + if(strcmp(InternalRelays[i], name)==0) { + return i; + } + } + strcpy(InternalRelays[i], name); + InternalRelaysCount++; + return i; +} + +static WORD AddrForVariable(char *name) +{ + int i; + for(i = 0; i < VariablesCount; i++) { + if(strcmp(Variables[i], name)==0) { + return i; + } + } + strcpy(Variables[i], name); + VariablesCount++; + return i; +} + +static void Write(FILE *f, BinOp *op) +{ + BYTE *b = (BYTE *)op; + int i; + for(i = 0; i < sizeof(*op); i++) { + fprintf(f, "%02x", b[i]); + } + fprintf(f, "\n"); +} + +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_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) 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); +} |