/* logical.c - logical operations.
 *  Copyright (C) 2022 by Jed Marti
 *   This program 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.
 *
 *  This program 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 this program.  If not, see https://www.gnu.org/licenses/.
 */


#include <C8051F380.h>
#include <stdint.h>

#include "config.h"
#include "lfxmit.h"
#include "serial.h"
#include "storage.h"

extern __xdata uint16_t   ST[];
extern uint16_t           DREG;
extern __xdata floatOrInt IACC;
extern __xdata floatOrInt IACCB;
extern __xdata floatOrInt FACC;
extern __xdata floatOrInt FACCB;
extern __xdata uint16_t   iONE;
extern __xdata uint16_t   iZERO;

extern __bit            errorThrown;
extern __bit            doit;


/*
__bit logiccalValue(void)
{
  if (!doit) return;
  DREG = popST();
  switch (tag()) {
  case DESC_IINT:
    getIACC();
    if (IACC.i == 0) return 0;
    else return 1;
    break;
  default:
    badType("??? logical");
  }
}
*/


void and(void)
// Logical AND operation from && operator. Works with floats and ints where 0 or 0.0 means
// false. If not executing, don't do anything. Returns 0 for false, 1 for true.
{
  // Not executing, just return.
  if (!doit) return;
  
  // RHS value.
  DREG = popST();
  switch (tag()) {

  // ??? >= Integer.
  case DESC_INT:
    getIACC();

    DREG = popST();
    switch (tag()) {
    case DESC_INT:
      getIACCB();
      if (IACCB.i == 0 || IACC.i == 0) pushST(iZERO);
      else pushST(iONE);
      break;

    case DESC_FLOAT:
      getFACC();
      if (FACC.f == 0.0f || IACC.i == 0) pushST(iZERO);
      else pushST(iONE);
      break;
      
    default:
      badType("??? && Int ");
    }
    break;

  case DESC_FLOAT:
    getFACC();
    DREG = popST();
    switch (tag()) {
    case DESC_INT:
      getIACC;
      if (IACC.i == 0 || FACC.f == 0.0f) pushST(iZERO);
      else pushST(iONE);
      break;
      
    case DESC_FLOAT:
      getFACCB();
      if (FACCB.f == 0.0f || FACC.f == 0.0f) pushST(iZERO);
      else pushST(iONE);
      break;
    default:
      badType("??? && float");
    }
    break;

  default:
    badType("??? && ???");
  }
}



void or(void)
// Logical OR operation from || operator. Works with floats and ints as above. If not executing,
// then just return. Returns 0 for false, 1 for true.
{
  // Not executing, just return.
  if (!doit) return;
  
  // RHS value.
  DREG = popST();
  switch (tag()) {

  // ??? >= Integer.
  case DESC_INT:
    getIACC();

    DREG = popST();
    switch (tag()) {
    case DESC_INT:
      getIACCB();
      if (IACCB.i == 0 && IACC.i == 0) pushST(iZERO);
      else pushST(iONE);
      break;

    case DESC_FLOAT:
      getFACC();
      if (FACC.f == 0.0f && IACC.i == 0) pushST(iZERO);
      else pushST(iONE);
      break;
      
    default:
      badType("??? || Int ");
    }
    break;

  case DESC_FLOAT:
    getFACC();
    DREG = popST();
    switch (tag()) {
    case DESC_INT:
      getIACC;
      if (IACC.i == 0 && FACC.f == 0.0f) pushST(iZERO);
      else pushST(iONE);
      break;
      
    case DESC_FLOAT:
      getFACCB();
      if (FACCB.f == 0.0f && FACC.f == 0.0f) pushST(iZERO);
      else pushST(iONE);
      break;
    default:
      badType("??? || float");
    }
    break;

  default:
    badType("??? || ???");
  }
}



void not(void)
// Logical inversion fromm ! operatopr. Works with floats and ints. If not executing, just
// return. Returns 0 for false, 1 for true.
{
  // Not executing, just return.
  if (!doit) return;
  
  DREG = popST();
  switch (tag()) {
  case DESC_INT:
    getIACC();
    if (IACC.i == 0) pushST(iONE);
    else pushST(iZERO);
    break;

  case DESC_FLOAT:
    getFACC();
    if (FACC.f == 0.0f) pushST(iONE);
    else pushST(iZERO);
    break;

  default:
    badType("! ???");
  }
}



// EOF
