summaryrefslogtreecommitdiff
path: root/ldmicro/compilecommon.cpp
diff options
context:
space:
mode:
authorakshay-c2019-01-30 12:23:44 +0530
committerakshay-c2019-01-30 12:23:44 +0530
commit4196481f74afb84e5cc59cdf00c06c1ca1becab7 (patch)
treeb531deb0466897691f08f9076b7012592f026664 /ldmicro/compilecommon.cpp
downloadLDmicroQt-4196481f74afb84e5cc59cdf00c06c1ca1becab7.tar.gz
LDmicroQt-4196481f74afb84e5cc59cdf00c06c1ca1becab7.tar.bz2
LDmicroQt-4196481f74afb84e5cc59cdf00c06c1ca1becab7.zip
First commit
Diffstat (limited to 'ldmicro/compilecommon.cpp')
-rw-r--r--ldmicro/compilecommon.cpp373
1 files changed, 373 insertions, 0 deletions
diff --git a/ldmicro/compilecommon.cpp b/ldmicro/compilecommon.cpp
new file mode 100644
index 0000000..f66e7f9
--- /dev/null
+++ b/ldmicro/compilecommon.cpp
@@ -0,0 +1,373 @@
+//-----------------------------------------------------------------------------
+// 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/>.
+//------
+//
+// Routines common to the code generators for all processor architectures.
+// Jonathan Westhues, Nov 2004
+//-----------------------------------------------------------------------------
+#include <linuxUI.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ldmicro.h"
+
+// If we encounter an error while compiling then it's convenient to break
+// out of the possibly-deeply-recursed function we're in.
+jmp_buf CompileErrorBuf;
+
+// Assignment of the internal relays to memory, efficient, one bit per
+// relay.
+static struct {
+ char name[MAX_NAME_LEN];
+ DWORD addr;
+ int bit;
+ BOOL assignedTo;
+} InternalRelays[MAX_IO];
+static int InternalRelayCount;
+
+// Assignment of the `variables,' used for timers, counters, arithmetic, and
+// other more general things. Allocate 2 octets (16 bits) per.
+static struct {
+ char name[MAX_NAME_LEN];
+ DWORD addrl;
+ DWORD addrh;
+} Variables[MAX_IO];
+static int VariableCount;
+
+#define NO_MEMORY 0xffffffff
+static DWORD NextBitwiseAllocAddr;
+static int NextBitwiseAllocBit;
+static int MemOffset;
+
+//-----------------------------------------------------------------------------
+// Forget what memory has been allocated on the target, so we start from
+// everything free.
+//-----------------------------------------------------------------------------
+void AllocStart(void)
+{
+ NextBitwiseAllocAddr = NO_MEMORY;
+ MemOffset = 0;
+ InternalRelayCount = 0;
+ VariableCount = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Return the address of a previously unused octet of RAM on the target, or
+// signal an error if there is no more available.
+//-----------------------------------------------------------------------------
+DWORD AllocOctetRam(void)
+{
+ if(MemOffset >= Prog.mcu->ram[0].len) {
+ Error(_("Out of memory; simplify program or choose "
+ "microcontroller with more memory."));
+ CompileError();
+ }
+
+ MemOffset++;
+ return Prog.mcu->ram[0].start + MemOffset - 1;
+}
+
+//-----------------------------------------------------------------------------
+// Return the address (octet address) and bit of a previously unused bit of
+// RAM on the target.
+//-----------------------------------------------------------------------------
+void AllocBitRam(DWORD *addr, int *bit)
+{
+ if(NextBitwiseAllocAddr != NO_MEMORY) {
+ *addr = NextBitwiseAllocAddr;
+ *bit = NextBitwiseAllocBit;
+ NextBitwiseAllocBit++;
+ if(NextBitwiseAllocBit > 7) {
+ NextBitwiseAllocAddr = NO_MEMORY;
+ }
+ return;
+ }
+
+ *addr = AllocOctetRam();
+ *bit = 0;
+ NextBitwiseAllocAddr = *addr;
+ NextBitwiseAllocBit = 1;
+}
+
+//-----------------------------------------------------------------------------
+// Return the address (octet) and bit of the bit in memory that represents the
+// given input or output pin. Raises an internal error if the specified name
+// is not present in the I/O list or a user error if a pin has not been
+// assigned to that I/O name. Will allocate if it no memory allocated for it
+// yet, else will return the previously allocated bit.
+//-----------------------------------------------------------------------------
+static void MemForPin(char *name, DWORD *addr, int *bit, BOOL asInput)
+{
+ int i;
+ for(i = 0; i < Prog.io.count; i++) {
+ if(strcmp(Prog.io.assignment[i].name, name)==0)
+ break;
+ }
+
+ if(i >= Prog.io.count) oops();
+ if(asInput && Prog.io.assignment[i].type == IO_TYPE_DIG_OUTPUT) oops();
+ if(!asInput && Prog.io.assignment[i].type == IO_TYPE_DIG_INPUT) oops();
+
+ int pin = Prog.io.assignment[i].pin;
+ for(i = 0; i < Prog.mcu->pinCount; i++) {
+ if(Prog.mcu->pinInfo[i].pin == pin)
+ break;
+ }
+ if(i >= Prog.mcu->pinCount) {
+ Error(_("Must assign pins for all I/O.\r\n\r\n"
+ "'%s' is not assigned."), name);
+ CompileError();
+ }
+ McuIoPinInfo *iop = &Prog.mcu->pinInfo[i];
+
+ if(asInput) {
+ *addr = Prog.mcu->inputRegs[iop->port - 'A'];
+ } else {
+ *addr = Prog.mcu->outputRegs[iop->port - 'A'];
+ }
+ *bit = iop->bit;
+}
+
+//-----------------------------------------------------------------------------
+// Determine the mux register settings to read a particular ADC channel.
+//-----------------------------------------------------------------------------
+BYTE MuxForAdcVariable(char *name)
+{
+ int i;
+ for(i = 0; i < Prog.io.count; i++) {
+ if(strcmp(Prog.io.assignment[i].name, name)==0)
+ break;
+ }
+ if(i >= Prog.io.count) oops();
+
+ int j;
+ for(j = 0; j < Prog.mcu->adcCount; j++) {
+ if(Prog.mcu->adcInfo[j].pin == Prog.io.assignment[i].pin) {
+ break;
+ }
+ }
+ if(j == Prog.mcu->adcCount) {
+ Error(_("Must assign pins for all ADC inputs (name '%s')."), name);
+ CompileError();
+ }
+
+ return Prog.mcu->adcInfo[j].muxRegValue;
+}
+
+//-----------------------------------------------------------------------------
+// Allocate the two octets (16-bit count) for a variable, used for a variety
+// of purposes.
+//-----------------------------------------------------------------------------
+void MemForVariable(char *name, DWORD *addrl, DWORD *addrh)
+{
+ int i;
+ for(i = 0; i < VariableCount; i++) {
+ if(strcmp(name, Variables[i].name)==0) break;
+ }
+ if(i >= MAX_IO) {
+ Error(_("Internal limit exceeded (number of vars)"));
+ CompileError();
+ }
+ if(i == VariableCount) {
+ VariableCount++;
+ strcpy(Variables[i].name, name);
+ Variables[i].addrl = AllocOctetRam();
+ Variables[i].addrh = AllocOctetRam();
+ }
+ *addrl = Variables[i].addrl;
+ *addrh = Variables[i].addrh;
+}
+
+//-----------------------------------------------------------------------------
+// Allocate or retrieve the bit of memory assigned to an internal relay or
+// other thing that requires a single bit of storage.
+//-----------------------------------------------------------------------------
+static void MemForBitInternal(char *name, DWORD *addr, int *bit, BOOL writeTo)
+{
+ int i;
+ for(i = 0; i < InternalRelayCount; i++) {
+ if(strcmp(name, InternalRelays[i].name)==0)
+ break;
+ }
+ if(i >= MAX_IO) {
+ Error(_("Internal limit exceeded (number of vars)"));
+ CompileError();
+ }
+ if(i == InternalRelayCount) {
+ InternalRelayCount++;
+ strcpy(InternalRelays[i].name, name);
+ AllocBitRam(&InternalRelays[i].addr, &InternalRelays[i].bit);
+ InternalRelays[i].assignedTo = FALSE;
+ }
+
+ *addr = InternalRelays[i].addr;
+ *bit = InternalRelays[i].bit;
+ if(writeTo) {
+ InternalRelays[i].assignedTo = TRUE;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Retrieve the bit to read to determine whether a set of contacts is open
+// or closed. Contacts could be internal relay, output pin, or input pin,
+// or one of the internal state variables ($xxx) from the int code generator.
+//-----------------------------------------------------------------------------
+void MemForSingleBit(char *name, BOOL forRead, DWORD *addr, int *bit)
+{
+ switch(name[0]) {
+ case 'X':
+ if(!forRead) oops();
+ MemForPin(name, addr, bit, TRUE);
+ break;
+
+ case 'Y':
+ MemForPin(name, addr, bit, FALSE);
+ break;
+
+ case 'R':
+ case '$':
+ MemForBitInternal(name, addr, bit, !forRead);
+ break;
+
+ default:
+ oops();
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Retrieve the bit to write to set the state of an output.
+//-----------------------------------------------------------------------------
+void MemForCoil(char *name, DWORD *addr, int *bit)
+{
+ switch(name[0]) {
+ case 'Y':
+ MemForPin(name, addr, bit, FALSE);
+ break;
+
+ case 'R':
+ MemForBitInternal(name, addr, bit, TRUE);
+ break;
+
+ default:
+ oops();
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Do any post-compilation sanity checks necessary.
+//-----------------------------------------------------------------------------
+void MemCheckForErrorsPostCompile(void)
+{
+ int i;
+ for(i = 0; i < InternalRelayCount; i++) {
+ if(!InternalRelays[i].assignedTo) {
+ Error(
+ _("Internal relay '%s' never assigned; add its coil somewhere."),
+ InternalRelays[i].name);
+ CompileError();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// From the I/O list, determine which pins are inputs and which pins are
+// outputs, and pack that in 8-bit format as we will need to write to the
+// TRIS or DDR registers. ADC pins are neither inputs nor outputs.
+//-----------------------------------------------------------------------------
+void BuildDirectionRegisters(BYTE *isInput, BYTE *isOutput)
+{
+ memset(isOutput, 0x00, MAX_IO_PORTS);
+ memset(isInput, 0x00, MAX_IO_PORTS);
+
+ BOOL usedUart = UartFunctionUsed();
+ BOOL usedPwm = PwmFunctionUsed();
+
+ int i;
+ for(i = 0; i < Prog.io.count; i++) {
+ int pin = Prog.io.assignment[i].pin;
+
+ if(Prog.io.assignment[i].type == IO_TYPE_DIG_OUTPUT ||
+ Prog.io.assignment[i].type == IO_TYPE_DIG_INPUT)
+ {
+ int j;
+ for(j = 0; j < Prog.mcu->pinCount; j++) {
+ McuIoPinInfo *iop = &Prog.mcu->pinInfo[j];
+ if(iop->pin == pin) {
+ if(Prog.io.assignment[i].type == IO_TYPE_DIG_INPUT) {
+ isInput[iop->port - 'A'] |= (1 << iop->bit);
+ } else {
+ isOutput[iop->port - 'A'] |= (1 << iop->bit);
+ }
+ break;
+ }
+ }
+ if(j >= Prog.mcu->pinCount) {
+ Error(_("Must assign pins for all I/O.\r\n\r\n"
+ "'%s' is not assigned."),
+ Prog.io.assignment[i].name);
+ CompileError();
+ }
+
+ if(usedUart &&
+ (pin == Prog.mcu->uartNeeds.rxPin ||
+ pin == Prog.mcu->uartNeeds.txPin))
+ {
+ Error(_("UART in use; pins %d and %d reserved for that."),
+ Prog.mcu->uartNeeds.rxPin, Prog.mcu->uartNeeds.txPin);
+ CompileError();
+ }
+
+ if(usedPwm && pin == Prog.mcu->pwmNeedsPin) {
+ Error(_("PWM in use; pin %d reserved for that."),
+ Prog.mcu->pwmNeedsPin);
+ CompileError();
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Display our boilerplate warning that the baud rate error is too high.
+//-----------------------------------------------------------------------------
+void ComplainAboutBaudRateError(int divisor, double actual, double err)
+{
+ Error(_("UART baud rate generator: divisor=%d actual=%.4f for %.2f%% "
+ "error.\r\n"
+ "\r\n"
+ "This is too large; try a different baud rate (slower "
+ "probably), or a crystal frequency chosen to be divisible "
+ "by many common baud rates (e.g. 3.6864 MHz, 14.7456 MHz).\r\n"
+ "\r\n"
+ "Code will be generated anyways but serial may be "
+ "unreliable or completely broken."), divisor, actual, err);
+}
+
+//-----------------------------------------------------------------------------
+// Display our boilerplate warning that the baud rate is too slow (making
+// for an overflowed divisor).
+//-----------------------------------------------------------------------------
+void ComplainAboutBaudRateOverflow(void)
+{
+ Error(_("UART baud rate generator: too slow, divisor overflows. "
+ "Use a slower crystal or a faster baud rate.\r\n"
+ "\r\n"
+ "Code will be generated anyways but serial will likely be "
+ "completely broken."));
+}