/*
   Copyright (C) 1998 T. Scott Dattalo

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 __14_BIT_TMRS_H__
#define __14_BIT_TMRS_H__

#include "gpsim_classes.h"
#include "registers.h"
#include "breakpoints.h"
#include "ioports.h"
#include "ssp.h"

class TMRL;
class TMRH;
class TMR2;
class CCPRL;
class ADCON0;
class PIR_SET;
class InterruptSource;

class _14bit_processor;

//---------------------------------------------------------
// Todo
// 
// The timer base classes need to be abstracted one more 
// layer. The 18fxxx parts have a new timer, TMR3, that's
// almost but not quite, identical to the 16fxx's TMR1.


//---------------------------------------------------------
// CCPCON - Capture and Compare registers
//---------------------------------------------------------
class CCPRH : public sfr_register
{
public:

  CCPRL *ccprl;
  bool  pwm_mode;
  unsigned int pwm_value;

  CCPRH();
  void put(unsigned int new_value);
  void put_value(unsigned int new_value);
  unsigned int get();

};


class CCPRL : public sfr_register
{
public:

  CCPRH  *ccprh;
  TMRL   *tmrl;

  void put(unsigned int new_value);
  void capture_tmr();
  void start_compare_mode();
  void stop_compare_mode();
  void start_pwm_mode();
  void stop_pwm_mode();
  void assign_tmr(TMRL *ptmr);
  CCPRL();
};


//---------------------------------------------------------
// CCPCON - Capture and Compare Control register
//---------------------------------------------------------
class CCPSignalSource;  // I/O pin interface
class CCPSignalSink;    // I/O pin interface
class PinModule;

class CCPCON : public sfr_register
{
public:

  /* Bit definitions for the register */
  enum {
    CCPM0 = 1 << 0,
    CCPM1 = 1 << 1,
    CCPM2 = 1 << 2,
    CCPM3 = 1 << 3,
    CCPY  = 1 << 4,
    CCPX  = 1 << 5
  };

  /* Define the Modes (based on the CCPM bits) */
  enum {
    ALL_OFF0 = 0,
    ALL_OFF1 = 1,
    ALL_OFF2 = 2,
    ALL_OFF3 = 3,
    CAP_FALLING_EDGE = 4,
    CAP_RISING_EDGE  = 5,
    CAP_RISING_EDGE4 = 6,
    CAP_RISING_EDGE16 = 7,
    COM_SET_OUT = 8,
    COM_CLEAR_OUT = 9,
    COM_INTERRUPT = 10,
    COM_TRIGGER = 11,
    PWM0 = 12,
    PWM1 = 13,
    PWM2 = 14,
    PWM3 = 15
  };

  void new_edge(unsigned int level);
  void compare_match();
  void pwm_match(int new_state);
  void put(unsigned int new_value);
  char getState();

  void setCrosslinks(CCPRL *, PIR_SET *, TMR2 *);
  void setADCON(ADCON0 *);
  CCPCON();

  void setIOpin(PinModule *);
private:
  PinModule *m_PinModule;
  CCPSignalSource *m_source;
  CCPSignalSink   *m_sink;
  bool  m_bInputEnabled;    // Input mode for capture/compare
  bool  m_bOutputEnabled;   // Output mode for PWM
  char  m_cOutputState;
  int   edges;

  CCPRL   *ccprl;
  PIR_SET *pir_set;
  TMR2    *tmr2;
  ADCON0  *adcon0;



};
//---------------------------------------------------------
// T1CON - Timer 1 control register

class T1CON : public sfr_register
{
public:

enum
{
  TMR1ON  = 1<<0,
  TMR1CS  = 1<<1,
  T1SYNC  = 1<<2,
  T1OSCEN = 1<<3,
  T1CKPS0 = 1<<4,
  T1CKPS1 = 1<<5,
  T1RD16  = 1<<6
};

  TMRL  *tmrl;

  T1CON();

  unsigned int get();

  // For (at least) the 18f family, there's a 4X PLL that effects the
  // the relative timing between gpsim's cycle counter (which is equivalent
  // to the cumulative instruction count) and the external oscillator. In
  // all parts, the clock source for the timer is fosc, the external oscillator.
  // However, for the 18f parts, the instructions execute 4 times faster when
  // the PLL is selected.

  virtual unsigned int get_prescale();

  unsigned int get_tmr1cs()
    {
      return(value.get() & TMR1CS);
    }
  unsigned int get_tmr1on()
    {
      return(value.get() & TMR1ON);
    }
  virtual void put(unsigned int new_value);

};


//---------------------------------------------------------
// TMRL & TMRH - Timer 1
class TMRH : public sfr_register
{
public:

  TMRL *tmrl;

  void put(unsigned int new_value);
  unsigned int get();
  virtual unsigned int get_value();

  TMRH();

};

class TMRL : public sfr_register, public TriggerObject, public SignalSink
{
public:

  TMRH  *tmrh;
  T1CON *t1con;
  CCPCON *ccpcon;

  unsigned int 
    prescale,
    prescale_counter,
    break_value,
    compare_value,
    value_16bit;         /* Low and high concatenated */

  guint64
    synchronized_cycle,
    last_cycle,
    future_cycle;

  bool compare_mode;

  virtual void callback();
  virtual void callback_print();

  TMRL();

  virtual void put(unsigned int new_value);
  virtual unsigned int get();
  virtual unsigned int get_value();
  virtual unsigned int get_low_and_high();
  virtual void on_or_off(int new_state);
  virtual void current_value();
  virtual void new_clock_source();
  virtual void update();
  virtual void clear_timer();
  virtual void setSinkState(char);
  virtual void setIOpin(PinModule *);
  virtual void setInterruptSource(InterruptSource *);
protected:
  virtual void increment();   // Used when TMR1 is attached to an external clock
private:
  char m_cState;
  bool m_bExtClkEnabled;
  InterruptSource *m_Interrupt;
};






class PR2 : public sfr_register
{
public:

  TMR2 *tmr2;

  PR2();
  void put(unsigned int new_value);

};

//---------------------------------------------------------
// T2CON - Timer 2 control register

class T2CON : public sfr_register
{
public:

enum
{
  T2CKPS0 = 1<<0,
  T2CKPS1 = 1<<1,
  TMR2ON  = 1<<2,
  TOUTPS0 = 1<<3,
  TOUTPS1 = 1<<4,
  TOUTPS2 = 1<<5,
  TOUTPS3 = 1<<6
};

  TMR2 *tmr2;

  T2CON();

  inline unsigned int get_t2ckps0()
    {
      return(value.get() & T2CKPS0);
    }

  inline unsigned int get_t2ckps1()
    {
      return(value.get() & T2CKPS1);
    }

  inline unsigned int get_tmr2on()
    {
      return(value.get() & TMR2ON);
    }

  inline unsigned int get_post_scale()
    {
      return( (value.get() & (TOUTPS0 | TOUTPS1 | TOUTPS2 | TOUTPS3)) >> 3 );
    }

  inline unsigned int get_pre_scale()
    {
      //  ps1:ps0 prescale
      //   0   0     1
      //   0   1     4
      //   1   x     16

      if(value.get() & T2CKPS1)
	return 16;
      else
	if(value.get() & T2CKPS0)
	  return 4;
	else
	  return 1;

    }

  void put(unsigned int new_value);

};



//---------------------------------------------------------
// TMR2 - Timer
class TMR2 : public sfr_register, public TriggerObject
{
public:
  /* Define the way in which the tmr2 callback function may be updated. */
  enum TMR2_UPDATE_TYPES
  {
    TMR2_PWM1_UPDATE = 1<<0,       // wrt ccp1
    TMR2_PWM2_UPDATE = 1<<1,       // wrt ccp2
    TMR2_PR2_UPDATE  = 1<<2,       // update pr2 match
    TMR2_WRAP        = 1<<3,	   // wrap TMR2
    TMR2_DONTCARE_UPDATE = 0xf     // whatever comes next
  };

  int pwm_mode;
  int update_state;
  int last_update;

  unsigned int 
    prescale,
    prescale_counter,
    break_value,
    duty_cycle1,     /* for ccp1 */
    duty_cycle2;     /* for ccp2 */
  int
    post_scale;
  guint64
    last_cycle,
    future_cycle;

  PR2  *pr2;
  PIR_SET *pir_set;
  T2CON *t2con;
  CCPCON *ccp1con;
  CCPCON *ccp2con;
  SSP_MODULE *ssp_module;

  virtual void callback();
  virtual void callback_print();
  TMR2();

  void put(unsigned int new_value);
  unsigned int get();
  void on_or_off(int new_state);
  void start();
  void new_pre_post_scale();
  void new_pr2(unsigned int new_value);
  void current_value();
  void update(int ut = TMR2_DONTCARE_UPDATE);
  void pwm_dc(unsigned int dc, unsigned int ccp_address);
  void stop_pwm(unsigned int ccp_address);
  virtual unsigned int get_value();

};


//---------------------------------------------------------
//
// TMR2_MODULE
//
// 

class TMR2_MODULE
{
public:

  _14bit_processor *cpu;
  char * name_str;


  T2CON *t2con;
  PR2   *pr2;
  TMR2  *tmr2;

  TMR2_MODULE();
  void initialize(T2CON *t2con, PR2 *pr2, TMR2  *tmr2);

};

//---------------------------------------------------------
//
// TMR1_MODULE
//
// 

class TMR1_MODULE
{
public:

  _14bit_processor *cpu;
  char * name_str;

  T1CON *t1con;
  PIR_SET  *pir_set;

  TMR1_MODULE();
  void initialize(T1CON *t1con, PIR_SET *pir_set);

};

#endif
