/*
   Copyright (C) 1998-2003 Scott Dattalo
                 2003 Mike Durian

This file is part of gpsim.

gpsim 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 2, or (at your option)
any later version.

gpsim 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 gpsim; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

#ifndef PIR_H
#define PIR_H

#include "assert.h"

#include "pie.h"

class INTCON;

//---------------------------------------------------------
// PIR Peripheral Interrupt register base class for PIR1 & PIR2

class PIR : public sfr_register
{
protected:
  INTCON  *intcon;
  PIE     *pie;
public:
  int valid_bits;
  int writable_bits;
 
  PIR(INTCON *, PIE *, int _valid_bits);
  // The PIR base class supports no PIR bits directly
  virtual void clear_sspif(){}
  virtual void clear_rcif(){}
  virtual void clear_txif(){}
  virtual void set_adif(){}
  virtual void set_bclif(){}
  virtual void set_ccpif(){}
  virtual void set_cmif(){}
  virtual void set_eccp1if(){}
  virtual void set_eeif(){}
  virtual void set_errif(){}
  virtual void set_irxif(){}
  virtual void set_lvdif(){}
  virtual void set_pspif(){}
  virtual void set_rcif(){}
  virtual void set_rxb0if(){}
  virtual void set_rxb1if(){}
  virtual void set_sspif(){}
  virtual void set_tmr1if(){}
  virtual void set_tmr2if(){}
  virtual void set_tmr3if(){}
  virtual void set_txb0if(){}
  virtual void set_txb1if(){}
  virtual void set_txb2if(){}
  virtual void set_txif(){}
  virtual void set_wakif(){}

  virtual unsigned int get_txif() { return 0;}
  virtual unsigned int get_rcif() { return 0;}
  virtual unsigned int get_sspif() { return 0;}

  virtual bool interrupt_status();
  virtual void put(unsigned int new_value);

  virtual void setInterrupt(unsigned int bitMask);
  virtual void setPeripheralInterrupt();

  void set_intcon(INTCON *);
  void set_pie(PIE *);

};
//---------------------------------------------------------
// InterruptSource

class InterruptSource
{
public:
  InterruptSource(PIR *_pir, unsigned int bitMask);
  void Trigger();
private:
  PIR *m_pir;
  unsigned int m_bitMask;
};
//---------------------------------------------------------
// PIR1 Peripheral Interrupt register # 1
//
// This is version 1 of the PIR1 register - as seen on the 16f62x

class PIR1v1 : public PIR
{
public:

  enum {
    TMR1IF  = 1<<0,
    TMR2IF  = 1<<1,
    CCP1IF  = 1<<2,
    SSPIF   = 1<<3,
    TXIF    = 1<<4,
    RCIF    = 1<<5,
    CMIF    = 1<<6,     // 16f62x
    EEIF    = 1<<7      // 16f62x
  };

  virtual void set_tmr1if()
  {
    put(get() | TMR1IF);
  }

  virtual void set_tmr2if()
  {
    put(get() | TMR2IF);
  }

  virtual void set_ccpif()
  {
    put(get() | CCP1IF);
  }

  virtual void set_sspif()
  {
    put(get() | SSPIF);
  }

  virtual void set_txif();
  virtual void set_rcif();

  virtual void set_cmif();

  virtual void set_eeif();

  virtual unsigned int get_sspif()
  {
    return value.get() & SSPIF;
  }
  void clear_sspif();

  unsigned int get_txif()
  {
    return value.get() & TXIF;
  }
  void clear_txif();

  unsigned int get_rcif()
  {
    return value.get() & RCIF;
  }
  virtual void clear_rcif();
 

  PIR1v1(INTCON *, PIE *);
};


//---------------------------------------------------------
// PIR1 Peripheral Interrupt register # 1
//
// This is version 2 of the PIR1 register - as seen on the 18xxxx devices
// and devices like the 16c63a.

class PIR1v2 : public PIR
{
public:

  enum {
    TMR1IF  = 1<<0,
    TMR2IF  = 1<<1,
    CCP1IF  = 1<<2,
    SSPIF   = 1<<3,
    TXIF    = 1<<4,
    RCIF    = 1<<5,
    ADIF    = 1<<6,     // 18cxxx
    PSPIF   = 1<<7
  };
 
  virtual void set_tmr1if()
  {
    put(get() | TMR1IF);
  }

  virtual void set_tmr2if()
  {
    put(get() | TMR2IF);
  }

  virtual void set_ccpif()
  {
    put(get() | CCP1IF);
  }

  virtual void set_sspif();

  unsigned int get_sspif()
  {
    return value.get() & SSPIF;
  }
  virtual void clear_sspif();

  virtual void set_txif();
  virtual void set_rcif();

  virtual void set_adif()
  {
    put(get() | ADIF);
  }

  virtual void set_pspif();

  virtual unsigned int get_txif()
  {
    return value.get() & TXIF;
  }
  virtual void clear_txif();
  unsigned int get_rcif()
  {
    return value.get() & RCIF;
  }
  virtual void clear_rcif();
 
  PIR1v2(INTCON *, PIE *);
};



//---------------------------------------------------------
// PIR2 Peripheral Interrupt register # 2
//
// This is version 1 of the PIR1 register - as seen on the 16f62x

class PIR2v1 : public PIR
{
public:

enum
{
    CCP2IF  = 1<<0
};

  virtual void set_ccpif()
    {
      put(get() | CCP2IF);
    }

  PIR2v1(INTCON *, PIE *);
};

//---------------------------------------------------------
// PIR2 Peripheral Interrupt register # 2
//
// This is version 2 of the PIR2 register - as seen on the 18xxxx devices
// and devices like the 16c63a.

class PIR2v2 : public PIR
{
public:

enum
{
    ECCP1IF = 1<<0,		/* only on the PIC18F4xx devices */
    TMR3IF  = 1<<1,
    LVDIF   = 1<<2,
    BCLIF   = 1<<3,
    EEIF    = 1<<4,
    CMIF    = 1<<6		/* PIC16F87xA, PIC18F4xx devices */
};

  virtual void set_eccp1if()
    {
      put(get() | ECCP1IF);
    }

  virtual void set_tmr3if()
    {
      put(get() | TMR3IF);
    }

  virtual void set_lvdif()
    {
      put(get() | LVDIF);
    }

  virtual void set_bclif();
  virtual void set_eeif();
  virtual void set_cmif();

  PIR2v2(INTCON *, PIE *);
};


//---------------------------------------------------------
// PIR2 Peripheral Interrupt register # 3
//
// This is version 2 of the PIR3 register - as seen on the 18F248 devices
// Perhaps other devices too - it contains bits for the CAN device

class PIR3v2 : public PIR
{
public:

enum
{
    RXB0IF  = 1<<0,
    RXB1IF  = 1<<1,
    TXB0IF  = 1<<2,
    TXB1IF  = 1<<3,
    TXB2IF  = 1<<4,
    ERRIF   = 1<<5,
    WAKIF   = 1<<6,
    IRXIF   = 1<<7
};

  virtual void set_rxb0if()
    {
      put(get() | RXB0IF);
    }

  virtual void set_rxb1if()
    {
      put(get() | RXB1IF);
    }

  virtual void set_txb0if()
    {
      put(get() | TXB0IF);
    }

  virtual void set_txb1if()
    {
      put(get() | TXB1IF);
    }

  virtual void set_txb2if()
    {
      put(get() | TXB2IF);
    }

  virtual void set_errif()
    {
      put(get() | ERRIF);
    }

  virtual void set_wakif()
    {
      put(get() | WAKIF);
    }

  virtual void set_irxif()
    {
      put(get() | IRXIF);
    }

  PIR3v2(INTCON *, PIE *);
};


/*
 * PIR_SET defines and interface to some common interrupt capabilities.
 * PIR_SET is a pure virtual class - you must instantiate a more specific
 * version of PIR_SET.
 *
 * The idea behind PIR_SET is to hide the location of the interrupt bits.
 * in some cases, a bit might be in PIR1, in others it might be in PIR2.
 * Instead of accessing the register directly, you go through PIR_SET
 * and it will find the proper PIR register.
 */

class PIR_SET
{
public:
  virtual bool interrupt_status()
  {
    return false;
  }

  // uart stuff
  virtual bool get_txif()
  {
    return false;
  }
  virtual void set_txif() {}
  virtual void clear_txif() {}
  virtual bool get_rcif()
  {
    return false;
  }
  virtual void set_rcif() {}
  virtual void clear_rcif() {}
	
  // ssp stuff
  virtual bool get_sspif()
  {
    return false;
  }
  virtual void clear_sspif() {}
  virtual void set_sspif() {}
  virtual void set_bclif() {}
 

  virtual void set_pspif() {}
  virtual void set_cmif() {}

  // eeprom stuff
  virtual void set_eeif() {}

  // CCP stuff
  virtual void set_ccpif() {}

  // Timer stuff
  virtual void set_tmr1if() {}
  virtual void set_tmr2if() {}
  virtual void set_adif() {}
};


//----------------------------------------
// Supports 1 or 2 Pir version 1 registers

class PIR_SET_1 : public PIR_SET
{
 public:
  PIR_SET_1() { pir1 = 0; pir2 = 0; }
  void set_pir1(PIR *p1) { pir1 = p1; }
  void set_pir2(PIR *p2) { pir2 = p2; }

  virtual bool interrupt_status() {
    assert(pir1 != 0);
    if (pir2 != 0)
      return (pir1->interrupt_status() ||
	      pir2->interrupt_status());
    else
      return (pir1->interrupt_status());
  }

  // uart stuff
  virtual bool get_txif() {
    assert(pir1 != 0);
    return (pir1->get_txif() != 0);
  }
  virtual void set_txif() {
    assert(pir1 != 0);
    pir1->set_txif();
  }
  virtual void clear_txif() {
    assert(pir1 != 0);
    pir1->clear_txif();
  }
  virtual bool get_rcif() {
    assert(pir1 != 0);
    return (pir1->get_rcif() != 0);
  }
  virtual void set_rcif() {
    assert(pir1 != 0);
    pir1->set_rcif();
  }
  virtual void clear_rcif() {
    assert(pir1 != 0);
    pir1->clear_rcif();
  }
	
  // ssp stuff
  virtual bool get_sspif() {
    assert(pir1 != 0);
    return (pir1->get_sspif() != 0);
  }
  virtual void set_sspif() {
    assert(pir1 != 0);
    pir1->set_sspif();
  }
  virtual void clear_sspif() {
    assert(pir1 != 0);
    pir1->clear_sspif();
  }

  // eeprom stuff
  virtual void set_eeif() {
    assert(pir1 != 0);
    pir1->set_eeif();
  }

  // CCP stuff
  virtual void set_ccpif() {
    assert(pir1 != 0);
    pir1->set_ccpif();
  }

  // Timer stuff
  virtual void set_tmr1if() {
    assert(pir1 != 0);
    pir1->set_tmr1if();
  }
  virtual void set_tmr2if() {
    assert(pir1 != 0);
    pir1->set_tmr2if();
  }

  // A/D stuff - not part of base PIR_SET class
  virtual void set_adif() {
    assert(pir1 != 0);
    pir1->set_adif();
  }
  // Comparator
  virtual void set_cmif() {
    assert(pir1 != 0);
    pir1->set_cmif();
  }

private:
  PIR	*pir1;
  PIR	*pir2;
};


// Supports 1, 2 or 3 version 2 Pir registers

class PIR_SET_2 : public PIR_SET
{
 public:
  PIR_SET_2() { pir1 = 0; pir2 = 0; pir3 = 0; }

  void set_pir1(PIR *p1) { pir1 = p1; }
  void set_pir2(PIR *p2) { pir2 = p2; }
  void set_pir3(PIR *p3) { pir3 = p3; }

  virtual bool interrupt_status() {
    assert(pir1 != 0);
    if (pir1 != 0 && pir1->interrupt_status())
	return(true);
    else if (pir2 != 0 && pir2->interrupt_status())
	return(true);
    else if (pir3 != 0 && pir3->interrupt_status())
	return(true);
    return(false);   
  }

  // uart stuff
  virtual bool get_txif() {
    assert(pir1 != 0);
    return (pir1->get_txif() != 0);
  }
  virtual void set_txif() {
    assert(pir1 != 0);
    pir1->set_txif();
  }
  virtual void clear_txif() {
    assert(pir1 != 0);
    pir1->clear_txif();
  }
  virtual bool get_rcif() {
    assert(pir1 != 0);
    return (pir1->get_rcif() != 0);
  }
  virtual void set_rcif() {
    assert(pir1 != 0);
    pir1->set_rcif();
  }
  virtual void clear_rcif() {
    assert(pir1 != 0);
    pir1->clear_rcif();
  }
	
  // ssp stuff
  virtual bool get_sspif() {
    assert(pir1 != 0);
    return (pir1->get_sspif() != 0);
  }
  virtual void set_sspif() {
    assert(pir1 != 0);
    pir1->set_sspif();
  }
  virtual void clear_sspif() {
    assert(pir1 != 0);
    pir1->clear_sspif();
  }


  // eeprom stuff
  virtual void set_eeif() {
    assert(pir2 != 0);
    pir2->set_eeif();
  }

  // CCP stuff
  virtual void set_ccpif() {
    assert(pir1 != 0);
    pir1->set_ccpif();
  }

  // Timer stuff
  virtual void set_tmr1if() {
    assert(pir1 != 0);
    pir1->set_tmr1if();
  }
  virtual void set_tmr2if() {
    assert(pir1 != 0);
    pir1->set_tmr2if();
  }

  // A/D stuff - not part of base PIR_SET class
  virtual void set_adif() {
    assert(pir1 != 0);
    pir1->set_adif();
  }
  // Comparator
  virtual void set_cmif() {
    assert(pir2 != 0);
    pir2->set_cmif();
  }

  // I2C master
  virtual void set_bclif() {
    assert(pir2 != 0);
    pir2->set_bclif();
  }

  // Parallel Slave Port
  virtual void set_pspif() {
    assert(pir1 != 0);
    pir1->set_pspif();
  }

private:
  PIR	*pir1;
  PIR	*pir2;
  PIR	*pir3;
};


#endif /* PIR_H */
