QuakeGod
2023-02-01 4392349b649164f2b498ca5157ecd141631ea96f
Src/PLCfunctions.c
@@ -36,23 +36,23 @@
int InitTimer(int nIndex, int nType)
{
   if (nIndex >= TOTALTIMERS) return -1;
   PLCMem.Timers[nIndex].StatByte = 0x0010 | nType;
   KMem.Timers[nIndex].StatByte = 0x0010 | nType;
//   Timers[nIndex].nType = 0;
   PLCMem.Timers[nIndex].SV = 0;
   PLCMem.Timers[nIndex].EV = 0;
   PLCMem.Timers[nIndex].LastActTime = GetTick();
   KMem.SV[nIndex] = 0;
   KMem.EV[nIndex] = 0;
   KMem.Timers[nIndex].LastActTime = GetTick();
   return 0;
}
int StartTimer(int nIndex , int SV)
int RunTimer(int nIndex , int SV)
{
   if (nIndex >= TOTALTIMERS) return -1;   
   if (!PLCMem.Timers[nIndex].bSet)
   if (!KMem.Timers[nIndex].bSet)
   {
      PLCMem.Timers[nIndex].SV = SV;
      PLCMem.Timers[nIndex].EV = 0;
      PLCMem.Timers[nIndex].LastActTime = GetTick();
      PLCMem.Timers[nIndex].bSet = 1;
      KMem.SV[nIndex] = SV;
      KMem.EV[nIndex]= 0;
      KMem.Timers[nIndex].LastActTime = GetTick();
      KMem.Timers[nIndex].bSet = 1;
   }
   return 0;
}
@@ -60,48 +60,48 @@
int StopTimer(int nIndex)
{
   if (nIndex >= TOTALTIMERS) return -1;   
   if (PLCMem.Timers[nIndex].bSet)
   if (KMem.Timers[nIndex].bSet)
   {
      PLCMem.Timers[nIndex].EV = 0;
      PLCMem.Timers[nIndex].LastActTime = GetTick();
      PLCMem.Timers[nIndex].bSet = 0;
      KMem.EV[nIndex] = 0;
      KMem.Timers[nIndex].LastActTime = GetTick();
      KMem.Timers[nIndex].bSet = 0;
   }
   return 0;
}
int ResetTimer(int nIndex)
{
   if (nIndex >= TOTALTIMERS) return -1;
   PLCMem.Timers[nIndex].EV = 0;
   PLCMem.Timers[nIndex].bTon = 0;
   PLCMem.Timers[nIndex].LastActTime=GetTick();
   KMem.EV[nIndex] = 0;
   KMem.Timers[nIndex].bTon = 0;
   KMem.Timers[nIndex].LastActTime=GetTick();
   return 0;
}
int SetTimerValue(int nIndex, int bSet, int SV)
{
   if (nIndex >= TOTALTIMERS) return -1;   
   if (bSet) {StartTimer(nIndex, SV);}
   if (bSet) {RunTimer(nIndex, SV);}
   else {StopTimer(nIndex);}
   return PLCMem.Timers[nIndex].bTon;
   return KMem.Timers[nIndex].bTon;
}
int ProcessTimer(int nIndex)
{
   if (nIndex >= TOTALTIMERS) return -1;
   if (!PLCMem.Timers[nIndex].nInited) return 0;
   if (PLCMem.Timers[nIndex].bSet)      // bSet =1;
   if (!KMem.Timers[nIndex].nInited) return 0;
   if (KMem.Timers[nIndex].bSet)      // bSet =1;
   {
      if (!PLCMem.Timers[nIndex].bTon)
      if (!KMem.Timers[nIndex].bTon)
      {
         int TimeDiff = GetTick() - PLCMem.Timers[nIndex].LastActTime;
         int TimeDiff = GetTick() - KMem.Timers[nIndex].LastActTime;
         int nScale = TICK_OF_MS;
         if (PLCMem.Timers[nIndex].nScale == 0)
         if (KMem.Timers[nIndex].nScale == 0)
         {nScale = TICK_OF_MS;
         }else if (PLCMem.Timers[nIndex].nScale == 1)
         }else if (KMem.Timers[nIndex].nScale == 1)
         {nScale = TICK_OF_RS;
         }else if (PLCMem.Timers[nIndex].nScale == 2)
         }else if (KMem.Timers[nIndex].nScale == 2)
         {nScale = TICK_OF_XS;
         }else if (PLCMem.Timers[nIndex].nScale == 3)
         }else if (KMem.Timers[nIndex].nScale == 3)
         {nScale = TICK_OF_YS;
         }else {}
         
@@ -109,32 +109,33 @@
         if (TimeDiff >= nScale)
         {
            int TimeDiffmS = TimeDiff / nScale;
            unsigned short NextEV = PLCMem.Timers[nIndex].EV + TimeDiffmS;
            PLCMem.Timers[nIndex].LastActTime += TimeDiffmS*nScale;
            unsigned short NextEV = KMem.EV[nIndex] + TimeDiffmS;
            KMem.Timers[nIndex].LastActTime += TimeDiffmS*nScale;
            
            if (NextEV >= PLCMem.Timers[nIndex].SV)
            if (NextEV >= KMem.SV[nIndex])
            {
               NextEV = PLCMem.Timers[nIndex].SV;
               PLCMem.Timers[nIndex].bTon =1;
               NextEV = KMem.SV[nIndex];
               KMem.Timers[nIndex].bTon =1;
            }
            PLCMem.Timers[nIndex].EV = NextEV;
            KMem.EV[nIndex] = NextEV;
         }
      }
   }else       //bSet=0;
   {
      if(PLCMem.Timers[nIndex].bTon)
      if(KMem.Timers[nIndex].bTon)
      {
         PLCMem.Timers[nIndex].bTon =   0;
         KMem.Timers[nIndex].bTon =   0;
      }
   }
   return PLCMem.Timers[nIndex].bTon;
   SetCoilValue(KLCoilTypeT, nIndex, KMem.Timers[nIndex].bTon);
   return KMem.Timers[nIndex].bTon;
}
int IsTimerOn(int nIndex)
{
   if (nIndex >= TOTALTIMERS) return 0;
   ProcessTimer(nIndex);
   return PLCMem.Timers[nIndex].bTon;
   return KMem.Timers[nIndex].bTon;
}
@@ -142,164 +143,185 @@
{
   if (nIndex >= TOTALTIMERS) return 0;
//   ProcessTimer(nIndex);   
   return PLCMem.Timers[nIndex].SV;
   return KMem.SV[nIndex];
//   return 0;   
}
int GetTimerEV(int nIndex)
{
   if (nIndex >= TOTALTIMERS) return 0;
//   ProcessTimer(nIndex);   
   return PLCMem.Timers[nIndex].EV;
   return KMem.EV[nIndex];
//   return 0;
}
const unsigned short bitMasks[16]=
{
   0x1<<0,
   0x1<<1,
   0x1<<2,
   0x1<<3,
   0x1<<4,
   0x1<<5,
   0x1<<6,
   0x1<<7,
   0x1<<8,
   0x1<<9,
   0x1<<10,
   0x1<<11,
   0x1<<12,
   0x1<<13,
   0x1<<14,
   0x1<<15,
};
inline void SetAddrBit(unsigned short * pW, unsigned char bitAddr)
{
   (*pW)|=bitMasks[bitAddr&0xf];
}
inline void ResetBit(unsigned short * pW, unsigned char bitAddr)
{
   (*pW)&=~bitMasks[bitAddr&0xf];
}
static inline void SetBitValue(unsigned short * pW, unsigned char bitAddr, unsigned char Value)
{
   if (Value)   {   SetAddrBit(pW, bitAddr);}
   else {ResetBit(pW, bitAddr);}
}
static inline unsigned char GetBitValue(unsigned short W, unsigned char bitAddr)
{
   if (W&bitMasks[bitAddr&0xf]) return 1;
   else return 0;
}
int InitAllDFs()
{
   for (int i=0;i<TOTAL_WDFS;i++)
   {
      PLCMem.WDFs[i]=0;
   }
   return TOTAL_WDFS;
}
int IsDF(int nIndex, int bSet)
{
   unsigned short addr1 = (nIndex&0xff0)>>4;
   unsigned char bitAddr=nIndex&0xf;
   if (addr1 >= TOTAL_WDFS) return 0;
   if (!GetBitValue( PLCMem.WDFs[addr1],bitAddr) && bSet)
   {
      SetBitValue(&PLCMem.WDFs[addr1],bitAddr,1);
      return 1;
   }else
   {
      SetBitValue(&PLCMem.WDFs[addr1],bitAddr,bSet);
   }
   return 0;
}
int PushInVal(void)
{
   for (int i=TOTAL_CurVAL;i>0;i--)
   for (int i=TOTAL_CurVAL -1 ;i>0;i--)
   {
      PLCMem.CurVALs[i]=PLCMem.CurVALs[i-1];
      KMem.CurVALs[i]=KMem.CurVALs[i-1];
   }
   PLCMem.CurVALs[0]=PLCMem.CurVAL;
   return PLCMem.CurVAL;
   KMem.CurVALs[0]=KMem.CurVAL;
   return KMem.CurVAL;
}
int PopOutVal(void)
{
   unsigned char theVAL=PLCMem.CurVALs[0];
   unsigned char theVAL=KMem.CurVALs[0];
   for (int i=0;i<TOTAL_CurVAL-1;i++)
   {
      PLCMem.CurVALs[i]=PLCMem.CurVALs[i+1];
      KMem.CurVALs[i]=KMem.CurVALs[i+1];
   }
   return theVAL;
}
int ANS(int bValue)
stBinProg1 const  prog1[]= //__attribute__((at(0X8008000)))
{
   return PLCMem.CurVAL;
}
int ORS(int bValue)
{
   return PLCMem.CurVAL;
}
int ST(int nAddr)
{
   return 0;
}
int AN(int nAddr)
{
   return 0;
}
int OR(int nAddr)
{
   return 0;
}
int AN_(int nAddr)
{
   return 0;
}
int OR_(int nAddr)
{
   return 0;
}
stPLCPROG const  prog1[]= //__attribute__((at(0X8008000)))
{
   {OP_ST,Addr_X,0},
   {OP_OR,Addr_Y,0},
   {OP_AN_,Addr_X,1},
   {OP_OUT,Addr_Y,0},
   {OP_ST,KLCoilTypeSR,13},
   {OP_MV,0,50},   {KLDataTypeDEC,KLDataTypeDT,1},
   {OP_MV,0,20},   {KLDataTypeDEC,KLDataTypeDT,2},
   {OP_MV,0,30},   {KLDataTypeDEC,KLDataTypeDT,3},
   {OP_MV,0,40},   {KLDataTypeDEC,KLDataTypeDT,4},
   {OP_SET,KLCoilTypeR,0},
//   {OP_SET,KLCoilTypeY,0},
   
   {OP_ST,Addr_X,2},
   {OP_SET,Addr_R,1},
   {OP_ST,Addr_X,3},
   {OP_RESET,Addr_R,1},
   {OP_ST,Addr_R,1},
   {OP_PSHS,0,0},
   {OP_AN_,Addr_Y,1},
   {OP_TML,5,25},
   {OP_SET,Addr_Y,1},
   {OP_RESET,Addr_Y,2},
   {OP_ST,KLCoilTypeR,0},
      {OP_TMX,1,1},   {KLDataTypeDT,0,0},
      {OP_DF},
      {OP_SET,KLCoilTypeR,10},
   {OP_ST,KLCoilTypeX,0},
   {OP_DF},
   {OP_SET,KLCoilTypeR,10},
   {OP_POPS,0,0},
   {OP_AN,Addr_Y,1},
   {OP_TML,6,25},
   {OP_RESET,Addr_Y,1},
   {OP_SET,Addr_Y,2},
   {OP_ST,KLCoilTypeX,1},
   {OP_DF},
   {OP_RESET,KLCoilTypeR,10},
/*
   {OP_ST,KLCoilTypeR,10},
   {OP_AN,KLCoilTypeR,51},
   {OP_AN,KLCoilTypeR,52},
   {OP_AN,KLCoilTypeR,53},
   {OP_ADD3,0,21},      {KLDataTypeDT,KLDataTypeDT,31},      {0,KLDataTypeDT,32},
   {OP_ST,KLCoilTypeR,10},
   {OP_AN,KLCoilTypeR,54},
   {OP_AN,KLCoilTypeR,55},
   {OP_AN,KLCoilTypeR,56},
   {OP_ADD3,0,23},      {KLDataTypeDT,KLDataTypeDT,33},      {0,KLDataTypeDT,34},
*/
   {OP_ST,KLCoilTypeSR,1},
   {OP_PSHS},
   {OP_AN,KLCoilTypeR,51},
   {OP_OUT,KLCoilTypeY,1},
   {OP_RDS},
   {OP_AN,KLCoilTypeR,52},
   {OP_OUT,KLCoilTypeY,2},
   {OP_RDS},
   {OP_AN,KLCoilTypeR,53},
   {OP_OUT,KLCoilTypeY,3},
   {OP_RDS},
   {OP_AN,KLCoilTypeR,54},
   {OP_OUT,KLCoilTypeY,4},
   {OP_RDS},
   {OP_AN,KLCoilTypeR,55},
   {OP_OUT,KLCoilTypeY,5},
   {OP_POPS},
   {OP_AN,KLCoilTypeR,56},
   {OP_OUT,KLCoilTypeY,6},
   {OP_ST,KLCoilTypeR,10},
   {OP_DF},
   {OP_PSHS},
   {OP_MV,0,150},   {KLDataTypeDEC,KLDataTypeDT,11},
   {OP_MV,0,30},   {KLDataTypeDEC,KLDataTypeDT,12},
   {OP_RDS},
   {OP_MV,0,150},   {KLDataTypeDEC,KLDataTypeDT,13},
   {OP_MV,0,30},   {KLDataTypeDEC,KLDataTypeDT,14},
   {OP_POPS},
   {OP_AN_,KLCoilTypeR,11},
   {OP_AN_,KLCoilTypeR,12},
   {OP_AN_,KLCoilTypeR,13},
   {OP_AN_,KLCoilTypeR,14},
   {OP_SET,KLCoilTypeR,14},
   {OP_ST,KLCoilTypeR,10},
   {OP_PSHS},
   {OP_AN,KLCoilTypeR,11},
   {OP_DF},
   {OP_SET,KLCoilTypeR,51},
   {OP_RESET,KLCoilTypeR,52},
   {OP_RESET,KLCoilTypeR,53},
   {OP_RESET,KLCoilTypeR,54},
   {OP_RESET,KLCoilTypeR,55},
   {OP_SET,KLCoilTypeR,56},
   {OP_RDS},
   {OP_AN,KLCoilTypeR,11},
      {OP_PSHS},
      {OP_TMX,11,11},   {KLDataTypeDT,0,0},
         {OP_RESET,KLCoilTypeR,11},
         {OP_SET,KLCoilTypeR,12},
      {OP_POPS},
         {OP_SUB3,0,11},      {KLDataTypeSV,KLDataTypeEV,11},      {0,KLDataTypeDT,21},
         {OP_AN_LE,0,21},{KLDataTypeDT,KLDataTypeDEC,30},
         {OP_PSHS},
            {OP_DIV,0,21},      {KLDataTypeDT,KLDataTypeDEC,10},      {0,KLDataTypeDT,31},
         {OP_RDS},
            {OP_AN_GE,0,32},{KLDataTypeDT,KLDataTypeDEC,5},
            {OP_SET,KLCoilTypeR,51},
         {OP_POPS},
            {OP_AN_LT,0,32},{KLDataTypeDT,KLDataTypeDEC,5},
            {OP_RESET,KLCoilTypeR,51},
   {OP_RDS},
   {OP_AN,KLCoilTypeR,12},
   {OP_DF},
   {OP_RESET,KLCoilTypeR,51},
   {OP_SET,KLCoilTypeR,52},
   {OP_RDS},
   {OP_AN,KLCoilTypeR,12},
      {OP_TMX,12,12},   {KLDataTypeDT,0,0},
         {OP_RESET,KLCoilTypeR,12},
         {OP_SET,KLCoilTypeR,13},
   {OP_POPS},
   {OP_AN,KLCoilTypeR,12},
   {OP_OUT,KLCoilTypeR,52},
   
   {OP_ST,KLCoilTypeR,10},
   {OP_PSHS},
   {OP_AN,KLCoilTypeR,13},
   {OP_DF},
   {OP_RESET,KLCoilTypeR,52},
   {OP_SET,KLCoilTypeR,53},
   {OP_SET,KLCoilTypeR,54},
   {OP_RESET,KLCoilTypeR,56},
   {OP_RDS},
   {OP_AN,KLCoilTypeR,13},
      {OP_TMX,13,13},   {KLDataTypeDT,0,0},
         {OP_RESET,KLCoilTypeR,13},
         {OP_SET,KLCoilTypeR,14},
   {OP_RDS},
   {OP_AN,KLCoilTypeR,13},
         {OP_SUB3,0,13},      {KLDataTypeSV,KLDataTypeEV,13},      {0,KLDataTypeDT,23},
         {OP_AN_LE,0,23},{KLDataTypeDT,KLDataTypeDEC,30},
         {OP_PSHS},
            {OP_DIV,0,23},      {KLDataTypeDT,KLDataTypeDEC,10},      {0,KLDataTypeDT,33},
         {OP_RDS},
            {OP_AN_GE,0,34},{KLDataTypeDT,KLDataTypeDEC,5},
            {OP_SET,KLCoilTypeR,54},
         {OP_POPS},
            {OP_AN_LT,0,34},{KLDataTypeDT,KLDataTypeDEC,5},
            {OP_RESET,KLCoilTypeR,54},
   {OP_RDS},
   {OP_AN,KLCoilTypeR,14},
   {OP_DF},
   {OP_RESET,KLCoilTypeR,54},
   {OP_SET,KLCoilTypeR,55},
   {OP_POPS},
   {OP_AN,KLCoilTypeR,14},
      {OP_TMX,14,14},   {KLDataTypeDT,0,0},
         {OP_RESET,KLCoilTypeR,14},
         {OP_SET,KLCoilTypeR,11},
};
/*
@@ -315,159 +337,439 @@
   {OP_RESET,Addr_Y,1},
*/
int nSizeProg1=sizeof(prog1)/sizeof(stPLCPROG);
int nSizeProg1=sizeof(prog1)/sizeof(stBinProg1);
char * PLCPRG=
int InitPLC()
{
   "ST X0\n\
   AN X1\n\
   ST Y0\n\
   AN Y1\n\
   ORS\n\
   AN/ X2\n\
   AN/ X3\n\
   OT Y0\n\
   OT Y1\n\
   "
};
int InitPLCPROGStat()
{
   PLCMem.nScanCount=0;
   for (int i=0;i<1024;i++){PLCMem.ProgTrace[i]=0;}
   for (int i=0;i<16;i++)   {
      KMem.WR[i]=0;
   }
   for (int i=0;i<256;i++)   {
      KMem.DT[i]=0;
   }
   return 0;
}
unsigned char GetAddrValue(unsigned char AddrType, unsigned short Addr)
int StartPLC()
{
      unsigned char thisValue;
      unsigned short Addr1=(Addr&0xff0)>>4;
      unsigned char bitAddr=Addr&0xf;
      switch(AddrType)
      {
         case Addr_None:
            break;
         case Addr_X:
            thisValue=GetBitValue( KMem.WX[Addr1],bitAddr);
            break;
         case Addr_Y:
            thisValue=GetBitValue( KMem.WY[Addr1],bitAddr);
            break;
         case Addr_R:
            thisValue=GetBitValue( KMem.WR[Addr1],bitAddr);
            break;
         case Addr_T:
            thisValue=PLCMem.Timers[Addr].bTon;
            break;
         case Addr_L:
            break;
         default:
            break;
      }
      return thisValue;
   PLCMem.nScanCount = 0;
   for (int i=0;i<1024;i++){PLCMem.ProgTrace[i]=0;}
   for (int i=0;i<16;i++)   {
      KMem.WR[i]=0;
   }
   for (int i=0;i<256;i++)   {
      KMem.DT[i]=0;
   }
   PLCMem.bPLCRunning=1;
   return 0;
}
int SetAddrValue(unsigned char AddrType, unsigned short Addr, unsigned char Value)
int StopPLC()
{
      unsigned short Addr1=(Addr&0xff0)>>4;
      unsigned char bitAddr=Addr&0xf;
      switch(AddrType)
      {
         case Addr_None:
            break;
         case Addr_X:
            SetBitValue(&KMem.WX[Addr1],bitAddr,Value);
            break;
         case Addr_Y:
            SetBitValue(&KMem.WY[Addr1],bitAddr,Value);
         break;
         case Addr_R:
            SetBitValue(&KMem.WR[Addr1],bitAddr,Value);
         break;
         case Addr_T:
            PLCMem.Timers[Addr].bTon=Value;
            break;
         case Addr_L:
            break;
         default:
            break;
      }
      return Value;
   PLCMem.bPLCRunning=0;
   return 0;
}
int ProcessPLCPROG(const stPLCPROG * prog,int nSize)
inline void SetAddrBit(unsigned short * pW, unsigned char bitAddr)
{
   for (int i=0;i<nSize;i++)
   (*pW)|=1<<(bitAddr&0xf);
}
inline void ResetBit(unsigned short * pW, unsigned char bitAddr)
{
   (*pW)&=~(1<<(bitAddr&0xf));
}
static inline void SetBitValue(unsigned short * pW, unsigned char bitAddr, unsigned char Value)
{
   if (Value)   {   SetAddrBit(pW, bitAddr);}
   else {ResetBit(pW, bitAddr);}
}
static inline unsigned char GetBitValue(unsigned short W, unsigned char bitAddr)
{
   if (W&(1<<(bitAddr&0xf))) return 1;
   else return 0;
}
int ProcessPLCBinProg(const stBinProg1 * pBinprog, int nStepSize)
{
   if (!PLCMem.bPLCRunning) return 0;
   if (PLCMem.nScanCount == 0) {
      SetCoilValue(KLCoilTypeSR, 13, 1);
      SetCoilValue(KLCoilTypeSR, 0, 0);
      SetCoilValue(KLCoilTypeSR, 1, 1);
   }
   else
   {
      unsigned char thisOP=prog[i].OP;
      unsigned char thisAddrType=prog[i].AddrType;
      unsigned short thisAddr=prog[i].Addr;
      SetCoilValue(KLCoilTypeSR, 13, 0);
      SetCoilValue(KLCoilTypeSR, 0, 0);
      SetCoilValue(KLCoilTypeSR, 1, 1);
   }
   for (int i = 0; i < TOTAL_CurVAL; i++) {
      KMem.CurVALs[i] = 0;
   }
   int CurPos = 0;
//   stBinProg1 * pBinProg1;
   stBinProg15 * pBinProg15;
   stBinProg2 * pBinProg2;
   stBinProg3 * pBinProg3;
   int lastScanInputVal = 1;//??????,????????,? ?? ???
   while (CurPos < nStepSize)
   {
      unsigned int nNextPos = 1;
      unsigned int thisOP = pBinprog[CurPos].nOp;
//      unsigned int nParamCount = 0
      unsigned char thisAddrType = pBinprog[CurPos].nParamType;
      unsigned short thisAddr = pBinprog[CurPos].nParamAddr;
      switch (thisOP)
      {
         case OP_None:
            break;
         case OP_ST:
            PushInVal();
            PLCMem.CurVAL=GetAddrValue(thisAddrType, thisAddr);
            break;
         case OP_ST_:
            PushInVal();
            PLCMem.CurVAL=!GetAddrValue(thisAddrType, thisAddr);
            break;
         case OP_AN:
           PLCMem.CurVAL = PLCMem.CurVAL&&GetAddrValue(thisAddrType, thisAddr);
            break;
         case OP_AN_:
            PLCMem.CurVAL = PLCMem.CurVAL && (!GetAddrValue(thisAddrType, thisAddr));
            break;
         case OP_OR:
            PLCMem.CurVAL = PLCMem.CurVAL || GetAddrValue(thisAddrType, thisAddr);
            break;
         case OP_OR_:
            PLCMem.CurVAL = PLCMem.CurVAL || (!GetAddrValue(thisAddrType, thisAddr));
            break;
//      case OP_NONE:
//         break;
      case OP_NOP:
         break;
         //??? ??
      case OP_NOT:
      case OP_ANS:
      case OP_ORS:
      case OP_PSHS:
      case OP_RDS:
      case OP_POPS:
      case OP_DF:
      case OP_DF_:
         switch (thisOP)
         {
         case OP_NOT:
            PLCMem.CurVAL = ! PLCMem.CurVAL;
            KMem.CurVAL = !KMem.CurVAL;
            break;
         case OP_ANS:
            KMem.CurVAL = PopOutVal() && KMem.CurVAL;
            break;
         case OP_ORS:
            KMem.CurVAL = PopOutVal() || KMem.CurVAL;
            break;
         case OP_PSHS:
            PushInVal();
            break;
         case OP_RDS:
            KMem.CurVAL = KMem.CurVALs[0] != 0;
            break;
         case OP_POPS:
            PLCMem.CurVAL = PopOutVal();
            KMem.CurVAL = PopOutVal();
            break;
         case OP_ANS:
            PLCMem.CurVAL = PLCMem.CurVAL && PopOutVal();
         case OP_DF:
            KMem.CurVAL = KMem.CurVAL && !lastScanInputVal;
            break;
         case OP_ORS:
            PLCMem.CurVAL = PLCMem.CurVAL || PopOutVal();
         case OP_DF_:
            KMem.CurVAL = !KMem.CurVAL && lastScanInputVal;
            break;
         case OP_OUT:
            SetAddrValue(thisAddrType,thisAddr,PLCMem.CurVAL);
            break;
         case OP_SET:
            if (PLCMem.CurVAL) SetAddrValue(thisAddrType,thisAddr,1);
            break;
         case OP_RESET:
            if (PLCMem.CurVAL) SetAddrValue(thisAddrType,thisAddr,0);
            break;
         case OP_DF:
            break;
         case OP_TML:
            if (!PLCMem.Timers[thisAddrType].nInited) InitTimer(thisAddrType,0);
            if (PLCMem.CurVAL) StartTimer(thisAddrType,thisAddr);
            else StopTimer(thisAddrType);
            PLCMem.CurVAL = ProcessTimer(thisAddrType);
            break;
         case OP_TMR:
            if (!PLCMem.Timers[thisAddrType].nInited) InitTimer(thisAddrType,1);
            if (PLCMem.CurVAL) StartTimer(thisAddrType,thisAddr);
            else StopTimer(thisAddrType);
            PLCMem.CurVAL = ProcessTimer(thisAddrType);
            break;
         default:
            break;
         }
         break;
         // 1????
      case OP_ST:
      case OP_ST_:
      case OP_AN:
      case OP_AN_:
      case OP_OR:
      case OP_OR_:
         switch (thisOP)
         {
         case OP_ST:
            PushInVal();
            KMem.CurVAL = GetCoilValue(thisAddrType, thisAddr);
            break;
         case OP_ST_:
            PushInVal();
            KMem.CurVAL = !GetCoilValue(thisAddrType, thisAddr);
            break;
         case OP_AN:
            KMem.CurVAL = KMem.CurVAL&&GetCoilValue(thisAddrType, thisAddr);
            break;
         case OP_AN_:
            KMem.CurVAL = KMem.CurVAL && (!GetCoilValue(thisAddrType, thisAddr));
            break;
         case OP_OR:
            KMem.CurVAL = KMem.CurVAL || GetCoilValue(thisAddrType, thisAddr);
            break;
         case OP_OR_:
            KMem.CurVAL = KMem.CurVAL || (!GetCoilValue(thisAddrType, thisAddr));
            break;
         default:
            break;
         }
         break;
         // 1 ?? ??
      case OP_OUT:
      case OP_SET:
      case OP_RESET:
         switch (thisOP)
         {
         case OP_OUT:
            SetCoilValue(thisAddrType, thisAddr, KMem.CurVAL);
            break;
         case OP_SET:
            if (KMem.CurVAL) SetCoilValue(thisAddrType, thisAddr, 1);
            break;
         case OP_RESET:
            if (KMem.CurVAL) SetCoilValue(thisAddrType, thisAddr, 0);
            break;
         default:
            break;
         }
         break;
         // ????
      case OP_ST_EQ:
      case OP_ST_NE:
      case OP_ST_LT:
      case OP_ST_GT:
      case OP_ST_LE:
      case OP_ST_GE:
      case OP_AN_EQ:
      case OP_AN_NE:
      case OP_AN_LT:
      case OP_AN_GT:
      case OP_AN_LE:
      case OP_AN_GE:
      case OP_OR_EQ:
      case OP_OR_NE:
      case OP_OR_LT:
      case OP_OR_GT:
      case OP_OR_LE:
      case OP_OR_GE:
         pBinProg2 = (stBinProg2 *)&pBinprog[CurPos];
         thisAddrType = pBinProg2->nParamType1;
         switch (thisOP)
         {
         case OP_ST_EQ:
            PushInVal();
            KMem.CurVAL = (GetVarData(thisAddrType, thisAddr) == GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_ST_NE:
            PushInVal();
            KMem.CurVAL = (GetVarData(thisAddrType, thisAddr) != GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_ST_LT:
            PushInVal();
            KMem.CurVAL = (GetVarData(thisAddrType, thisAddr) < GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_ST_GT:
            PushInVal();
            KMem.CurVAL = (GetVarData(thisAddrType, thisAddr) > GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_ST_LE:
            PushInVal();
            KMem.CurVAL = (GetVarData(thisAddrType, thisAddr) <= GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_ST_GE:
            PushInVal();
            KMem.CurVAL = (GetVarData(thisAddrType, thisAddr) >= GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_AN_EQ:
            KMem.CurVAL = KMem.CurVAL && (GetVarData(thisAddrType, thisAddr) == GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_AN_NE:
            KMem.CurVAL = KMem.CurVAL && (GetVarData(thisAddrType, thisAddr) != GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_AN_LT:
            KMem.CurVAL = KMem.CurVAL && (GetVarData(thisAddrType, thisAddr) < GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_AN_GT:
            KMem.CurVAL = KMem.CurVAL && (GetVarData(thisAddrType, thisAddr) > GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_AN_LE:
            KMem.CurVAL = KMem.CurVAL && (GetVarData(thisAddrType, thisAddr) <= GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_AN_GE:
            KMem.CurVAL = KMem.CurVAL && (GetVarData(thisAddrType, thisAddr) >= GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_OR_EQ:
            KMem.CurVAL = KMem.CurVAL || (GetVarData(thisAddrType, thisAddr) == GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_OR_NE:
            KMem.CurVAL = KMem.CurVAL || (GetVarData(thisAddrType, thisAddr) != GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_OR_LT:
            KMem.CurVAL = KMem.CurVAL || (GetVarData(thisAddrType, thisAddr) < GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_OR_GT:
            KMem.CurVAL = KMem.CurVAL || (GetVarData(thisAddrType, thisAddr) > GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_OR_LE:
            KMem.CurVAL = KMem.CurVAL || (GetVarData(thisAddrType, thisAddr) <= GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         case OP_OR_GE:
            KMem.CurVAL = KMem.CurVAL || (GetVarData(thisAddrType, thisAddr) >= GetVarData(pBinProg2->nParamType2, pBinProg2->nParamAddr2));
            break;
         default:
            break;
         }
         nNextPos = 2;
         break;
         // ???
      case OP_TML:
      case OP_TMR:
      case OP_TMX:
      case OP_TMY:
         pBinProg15 = (stBinProg15 *)(&pBinprog[CurPos]);
         {
            unsigned char thisNum= pBinProg15->nOpNum;
            thisAddrType = pBinProg15->nParamType1;
            thisAddr = pBinProg15->nParamAddr1;
            switch (thisOP)
            {
            case OP_TML:
               if (!KMem.Timers[thisNum].nInited) InitTimer(thisNum, 0);
               if (KMem.CurVAL) RunTimer(thisNum, GetVarData(thisAddrType, thisAddr));
               else StopTimer(thisNum);
               KMem.CurVAL = ProcessTimer(thisNum);
               break;
            case OP_TMR:
               if (!KMem.Timers[thisNum].nInited) InitTimer(thisNum, 1);
               if (KMem.CurVAL) RunTimer(thisNum, GetVarData(thisAddrType, thisAddr));
               else StopTimer(thisNum);
               KMem.CurVAL = ProcessTimer(thisNum);
               break;
            case OP_TMX:
               if (!KMem.Timers[thisNum].nInited) InitTimer(thisNum, 2);
               if (KMem.CurVAL) RunTimer(thisNum, GetVarData(thisAddrType, thisAddr));
               else StopTimer(thisNum);
               KMem.CurVAL = ProcessTimer(thisNum);
               break;
            case OP_TMY:
               if (!KMem.Timers[thisNum].nInited) InitTimer(thisNum, 3);
               if (KMem.CurVAL) RunTimer(thisNum, GetVarData(thisAddrType, thisAddr));
               else StopTimer(thisNum);
               KMem.CurVAL = ProcessTimer(thisNum);
               break;
            default:
               break;
            }
         }
         nNextPos = 2;
         break;
         // 1 ??????
      case OP_INC:
      case OP_DEC:
         pBinProg15 = (stBinProg15 *)(&pBinprog[CurPos]);
         thisAddrType = pBinProg15->nParamType1;
         thisAddr = pBinProg15->nParamAddr1;
         nNextPos = 2;
         switch (thisOP)
         {
         case OP_INC:
            if (KMem.CurVAL) SetVarData(thisAddrType, thisAddr, GetVarData(thisAddrType, thisAddr) + 1);
            break;
         case OP_DEC:
            if (KMem.CurVAL) SetVarData(thisAddrType, thisAddr, GetVarData(thisAddrType, thisAddr) - 1);
            break;
         default:
            break;
         }
         break;
         // 2??????
      case OP_MV:
      case OP_ADD2:
      case OP_SUB2:
         pBinProg2 = (stBinProg2 *)(&pBinprog[CurPos]);
         {
            int nParamType2, nParamAddr2;
            thisAddrType = pBinProg2->nParamType1;
            thisAddr = pBinProg2->nParamAddr1;
            nParamType2 = pBinProg2->nParamType2;
            nParamAddr2 = pBinProg2->nParamAddr2;
            switch (thisOP)
            {
            case OP_MV:
               if (KMem.CurVAL) SetVarData(nParamType2, nParamAddr2, GetVarData(thisAddrType, thisAddr));
               break;
            case OP_ADD2:
               if (KMem.CurVAL) SetVarData(nParamType2, nParamAddr2, GetVarData(thisAddrType, thisAddr) + GetVarData(nParamType2, nParamAddr2));
               break;
            case OP_SUB2:
               if (KMem.CurVAL) SetVarData(nParamType2, nParamAddr2, GetVarData(nParamType2, nParamAddr2) - GetVarData(thisAddrType, thisAddr));
               break;
            default:
               break;
            }
         }
         nNextPos = 2;
         break;
         // 3 ??????
      case OP_ADD3:
      case OP_SUB3:
      case OP_MUL:
      case OP_DIV:
         pBinProg3 = (stBinProg3 *)(&pBinprog[CurPos]);
         int nParamType2, nParamAddr2;
         int nParamType3, nParamAddr3;
         thisAddrType = pBinProg3->nParamType1;
         thisAddr = pBinProg3->nParamAddr1;
         nParamType2 = pBinProg3->nParamType2;
         nParamAddr2 = pBinProg3->nParamAddr2;
         nParamType3 = pBinProg3->nParamType3;
         nParamAddr3 = pBinProg3->nParamAddr3;
         switch (thisOP)
         {
         case OP_ADD3:
            if (KMem.CurVAL) SetVarData(nParamType3, nParamAddr3, GetVarData(thisAddrType, thisAddr) + GetVarData(nParamType2, nParamAddr2));
            break;
         case OP_SUB3:
            if (KMem.CurVAL) SetVarData(nParamType3, nParamAddr3, GetVarData(thisAddrType, thisAddr) - GetVarData(nParamType2, nParamAddr2));
            break;
         case OP_MUL:
            if (KMem.CurVAL) {
               short multiplicand = GetVarData(thisAddrType, thisAddr);
               short multiplier = GetVarData(nParamType2, nParamAddr2);
               int product = multiplicand * multiplier;
               SetVarData(nParamType3, nParamAddr3, product);
               SetVarData(nParamType3, nParamAddr3 + 1, product >> 16);
            }
            break;
         case OP_DIV:
            if (KMem.CurVAL) {
               short dividend = GetVarData(thisAddrType, thisAddr);
               short divisor = GetVarData(nParamType2, nParamAddr2);
               short quotient = dividend / divisor;
               short remainder = dividend % divisor;
               SetVarData(nParamType3, nParamAddr3, quotient);
               SetVarData(nParamType3, nParamAddr3 + 1, remainder);
            }
            break;
         default:
            break;
         }
         nNextPos = 3;
         break;
      default:
         break;
      }
      lastScanInputVal =  PLCMem.ProgTrace[CurPos]; //GetBitValue(KMem.WDFs);
      PLCMem.ProgTrace[CurPos] = KMem.CurVAL;
      CurPos += nNextPos;
   }
   PLCMem.nScanCount++;
   return 0;
}