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

📄 simulate.cpp

📁 plc软件的源代码 支持PIC ATMEGA单片机
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//-----------------------------------------------------------------------------
// 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 to simulate the logic interactively, for testing purposes. We can
// simulate in real time, triggering off a Windows timer, or we can 
// single-cycle it. The GUI acts differently in simulation mode, to show the
// status of all the signals graphically, show how much time is left on the
// timers, etc.
// Jonathan Westhues, Nov 2004
//-----------------------------------------------------------------------------
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

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

static struct {
    char name[MAX_NAME_LEN];
    BOOL powered;
} SingleBitItems[MAX_IO];
static int SingleBitItemsCount;

static struct {
    char    name[MAX_NAME_LEN];
    SWORD   val;
    DWORD   usedFlags;
} Variables[MAX_IO];
static int VariablesCount;

static struct {
    char    name[MAX_NAME_LEN];
    SWORD   val;
} AdcShadows[MAX_IO];
static int AdcShadowsCount;

#define VAR_FLAG_TON  0x00000001
#define VAR_FLAG_TOF  0x00000002
#define VAR_FLAG_RTO  0x00000004
#define VAR_FLAG_CTU  0x00000008
#define VAR_FLAG_CTD  0x00000010
#define VAR_FLAG_CTC  0x00000020
#define VAR_FLAG_RES  0x00000040
#define VAR_FLAG_ANY  0x00000080

#define VAR_FLAG_OTHERWISE_FORGOTTEN  0x80000000


// Schematic-drawing code needs to know whether we're in simulation mode or
// note, as that changes how everything is drawn; also UI code, to disable
// editing during simulation.
BOOL InSimulationMode;

// Don't want to redraw the screen unless necessary; track whether a coil
// changed state or a timer output switched to see if anything could have
// changed (not just coil, as we show the intermediate steps too).
static BOOL NeedRedraw;
// Have to let the effects of a coil change in cycle k appear in cycle k+1,
// or set by the UI code to indicate that user manually changed an Xfoo
// input.
BOOL SimulateRedrawAfterNextCycle;

// Don't want to set a timer every 100 us to simulate a 100 us cycle
// time...but we can cycle multiple times per timer interrupt and it will
// be almost as good, as long as everything runs fast.
static int CyclesPerTimerTick;

// Program counter as we evaluate the intermediate code.
static int IntPc;

// A window to allow simulation with the UART stuff (insert keystrokes into
// the program, view the output, like a terminal window).
static HWND UartSimulationWindow;
static HWND UartSimulationTextControl;
static LONG_PTR PrevTextProc;

static int QueuedUartCharacter = -1;
static int SimulateUartTxCountdown = 0;

static void AppendToUartSimulationTextControl(BYTE b);

static void SimulateIntCode(void);
static char *MarkUsedVariable(char *name, DWORD flag);

//-----------------------------------------------------------------------------
// Query the state of a single-bit element (relay, digital in, digital out).
// Looks in the SingleBitItems list; if an item is not present then it is
// FALSE by default.
//-----------------------------------------------------------------------------
static BOOL SingleBitOn(char *name)
{
    int i;
    for(i = 0; i < SingleBitItemsCount; i++) {
        if(strcmp(SingleBitItems[i].name, name)==0) {
            return SingleBitItems[i].powered;
        }
    }
    return FALSE;
}

//-----------------------------------------------------------------------------
// Set the state of a single-bit item. Adds it to the list if it is not there
// already.
//-----------------------------------------------------------------------------
static void SetSingleBit(char *name, BOOL state)
{
    int i;
    for(i = 0; i < SingleBitItemsCount; i++) {
        if(strcmp(SingleBitItems[i].name, name)==0) {
            SingleBitItems[i].powered = state;
            return;
        }
    }
    if(i < MAX_IO) {
        strcpy(SingleBitItems[i].name, name);
        SingleBitItems[i].powered = state;
        SingleBitItemsCount++;
    }
}

//-----------------------------------------------------------------------------
// Count a timer up (i.e. increment its associated count by 1). Must already
// exist in the table.
//-----------------------------------------------------------------------------
static void IncrementVariable(char *name)
{
    int i;
    for(i = 0; i < VariablesCount; i++) {
        if(strcmp(Variables[i].name, name)==0) {
            (Variables[i].val)++;
            return;
        }
    }
    oops();
}

//-----------------------------------------------------------------------------
// Set a variable to a value.
//-----------------------------------------------------------------------------
static void SetSimulationVariable(char *name, SWORD val)
{
    int i;
    for(i = 0; i < VariablesCount; i++) {
        if(strcmp(Variables[i].name, name)==0) {
            Variables[i].val = val;
            return;
        }
    }
    MarkUsedVariable(name, VAR_FLAG_OTHERWISE_FORGOTTEN);
    SetSimulationVariable(name, val);
}

//-----------------------------------------------------------------------------
// Read a variable's value.
//-----------------------------------------------------------------------------
SWORD GetSimulationVariable(char *name)
{
    int i;
    for(i = 0; i < VariablesCount; i++) {
        if(strcmp(Variables[i].name, name)==0) {
            return Variables[i].val;
        }
    }
    MarkUsedVariable(name, VAR_FLAG_OTHERWISE_FORGOTTEN);
    return GetSimulationVariable(name);
}

//-----------------------------------------------------------------------------
// Set the shadow copy of a variable associated with a READ ADC operation. This
// will get committed to the real copy when the rung-in condition to the
// READ ADC is true.
//-----------------------------------------------------------------------------
void SetAdcShadow(char *name, SWORD val)
{
    int i;
    for(i = 0; i < AdcShadowsCount; i++) {
        if(strcmp(AdcShadows[i].name, name)==0) {
            AdcShadows[i].val = val;
            return;
        }
    }
    strcpy(AdcShadows[i].name, name);
    AdcShadows[i].val = val;
    AdcShadowsCount++;
}

//-----------------------------------------------------------------------------
// Return the shadow value of a variable associated with a READ ADC. This is
// what gets copied into the real variable when an ADC read is simulated.
//-----------------------------------------------------------------------------
SWORD GetAdcShadow(char *name)
{
    int i;
    for(i = 0; i < AdcShadowsCount; i++) {
        if(strcmp(AdcShadows[i].name, name)==0) {
            return AdcShadows[i].val;
        }
    }
    return 0;
}

//-----------------------------------------------------------------------------
// Mark how a variable is used; a series of flags that we can OR together,
// then we can check to make sure that only valid combinations have been used
// (e.g. just a TON, an RTO with its reset, etc.). Returns NULL for success,
// else an error string.
//-----------------------------------------------------------------------------
static char *MarkUsedVariable(char *name, DWORD flag)
{
    int i;
    for(i = 0; i < VariablesCount; i++) {
        if(strcmp(Variables[i].name, name)==0) {
            break;
        }
    }
    if(i >= MAX_IO) return "";

    if(i == VariablesCount) {
        strcpy(Variables[i].name, name);
        Variables[i].usedFlags = 0;
        Variables[i].val = 0;
        VariablesCount++;
    }

    switch(flag) {
        case VAR_FLAG_TOF:
            if(Variables[i].usedFlags != 0) 
                return _("TOF: variable cannot be used elsewhere");
            break;

        case VAR_FLAG_TON:
            if(Variables[i].usedFlags != 0)
                return _("TON: variable cannot be used elsewhere");
            break;
        
        case VAR_FLAG_RTO:
            if(Variables[i].usedFlags & ~VAR_FLAG_RES)
                return _("RTO: variable can only be used for RES elsewhere");
            break;

        case VAR_FLAG_CTU:
        case VAR_FLAG_CTD:
        case VAR_FLAG_CTC:
        case VAR_FLAG_RES:
        case VAR_FLAG_ANY:
            break;

        case VAR_FLAG_OTHERWISE_FORGOTTEN:
            if(name[0] != '$') {
                Error(_("Variable '%s' not assigned to, e.g. with a "
                    "MOV statement, an ADD statement, etc.\r\n\r\n"
                    "This is probably a programming error; now it "
                    "will always be zero."), name);
            }
            break;

        default:
            oops();
    }

    Variables[i].usedFlags |= flag;
    return NULL;
}

//-----------------------------------------------------------------------------
// Check for duplicate uses of a single variable. For example, there should
// not be two TONs with the same name. On the other hand, it would be okay
// to have an RTO with the same name as its reset; in fact, verify that
// there must be a reset for each RTO.
//-----------------------------------------------------------------------------
static void MarkWithCheck(char *name, int flag)
{
    char *s = MarkUsedVariable(name, flag);
    if(s) {
        Error(_("Variable for '%s' incorrectly assigned: %s."), name, s);
    }
}
static void CheckVariableNamesCircuit(int which, void *elem)
{
    ElemLeaf *l = (ElemLeaf *)elem;
    char *name = NULL;
    DWORD flag;

    switch(which) {
        case ELEM_SERIES_SUBCKT: {
            int i;
            ElemSubcktSeries *s = (ElemSubcktSeries *)elem;
            for(i = 0; i < s->count; i++) {
                CheckVariableNamesCircuit(s->contents[i].which,
                    s->contents[i].d.any);
            }
            break;
        }

        case ELEM_PARALLEL_SUBCKT: {
            int i;
            ElemSubcktParallel *p = (ElemSubcktParallel *)elem;
            for(i = 0; i < p->count; i++) {
                CheckVariableNamesCircuit(p->contents[i].which,
                    p->contents[i].d.any);
            }
            break;
        }
        
        case ELEM_RTO:
        case ELEM_TOF:

⌨️ 快捷键说明

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