/*
   Copyright (C) 1998,1999,2000,2001,2002 Scott Dattalo
	         2006 Roy R Rankin

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.  */

#include <stdio.h>
#include <iostream>

#include "../config.h"
#include "ssp.h"
#include "pic-ioports.h"
#include "stimuli.h"
#include "14bit-processors.h"
#include "14bit-tmrs.h"

#include "xref.h"

//#warning only supports SPI mode.
//-----------------------------------------------------------
// SSPSTAT - Synchronous Serial Port Status register.


/*
	only CKE and SMP is writable
*/
void _SSPSTAT::put(unsigned int new_value)
{
  unsigned int old6 = value.get() & ~(CKE|SMP);

  // For BSSP register is read only otherwise
  // only CKE and SMP are writable

  if (!m_sspmod || m_sspmod->ssp_type() == SSP_TYPE_BSSP)
	return;

  put_value(old6 | (new_value & (CKE|SMP)));


}

void _SSPSTAT::put_value(unsigned int new_value)
{

  trace.raw(write_trace.get() | value.get());
  value.put(new_value);

}
/*
	register pointer to SSPMOD
*/
void _SSPSTAT::setSSPMODULE(SSP_MODULE *sspmod)
{
  m_sspmod = sspmod;
}

class SDI_SignalSink : public SignalSink
{
public:
  SDI_SignalSink(SSP_MODULE *_ssp_mod)
    : m_ssp_mod(_ssp_mod)
  {
    assert(_ssp_mod);
  }
  virtual ~SDI_SignalSink(){}

  void setSinkState(char new3State)
  {
    m_ssp_mod->SDI_SinkState(new3State);
  }
private:
  SSP_MODULE *m_ssp_mod;
};

class SCL_SignalSink : public SignalSink
{
public:
  SCL_SignalSink(SSP_MODULE *_ssp_mod)
    : m_ssp_mod(_ssp_mod)
  {
    assert(_ssp_mod);
  }
  virtual ~SCL_SignalSink(){}

  void setSinkState(char new3State)
  {
    m_ssp_mod->SCL_SinkState(new3State);
  }
private:
  SSP_MODULE *m_ssp_mod;
};
class SS_SignalSink : public SignalSink
{
public:
  SS_SignalSink(SSP_MODULE *_ssp_mod)
    : m_ssp_mod(_ssp_mod)
  {
    assert(_ssp_mod);
  }
  virtual ~SS_SignalSink(){}

  void setSinkState(char new3State)
  {
    m_ssp_mod->SS_SinkState(new3State);
  }
private:
  SSP_MODULE *m_ssp_mod;
};


//-----------------------------------------------------------
// SSPCON - Synchronous Serial Port Control register.
//-----------------------------------------------------------

_SSPCON::_SSPCON()
{
}
/*
	register pointer to SSPMOD
*/
void _SSPCON::setSSPMODULE(SSP_MODULE *sspmod)
{
  m_sspmod = sspmod;
}

/*
	return true if an SPI mode is enabled
*/
bool _SSPCON::isSPIActive(unsigned int value)
{
    if (value & SSPEN)
    {
      switch(value & SSPM_mask)
      {
	case SSPM_SPImaster4:
	case SSPM_SPImaster16:
	case SSPM_SPImaster64:
	case SSPM_SPImasterTMR2:
	case SSPM_SPIslaveSS:
	case SSPM_SPIslave:
	    return(true);
      }
    }
    return(false);
}
/*
	process write to SSPCON
*/
void _SSPCON::put(unsigned int new_value)
{
  unsigned int old_value = value.get();

  put_value(new_value);

  if ((new_value & SSPEN) && ! (old_value & SSPEN)) // Turn on SSP
       m_sspmod->startSSP(new_value);
  else if (!(new_value & SSPEN) &&  (old_value & SSPEN)) // Turn off SSP
       m_sspmod->stopSSP(old_value);
  else if ((new_value & SSPEN) &&  (old_value & SSPEN)) // change while active
      m_sspmod->changeSSP(new_value, old_value);
}

/*
	update SSPCON without action
*/
void _SSPCON::put_value(unsigned int new_value)
{

  trace.raw(write_trace.get() | value.get());
  value.put(new_value & 0xff);

}

/*
	Set WCOL bit of SSPCON
*/
void _SSPCON::setWCOL()
{
  if (value.get() & WCOL)
    return;
  put_value(value.get() | WCOL);

}
/*
	return true if a I2C mode is enabled in SSPCON
*/

bool _SSPCON::isI2CActive(unsigned int val) 
{
    if ( (val & SSPEN) != SSPEN)
	return(false);
    switch(val & SSPM_mask)
    {
      case SSPM_I2Cslave_7bitaddr:
      case SSPM_I2Cslave_10bitaddr:
      case SSPM_MSSPI2Cmaster:
      case SSPM_I2Cfirmwaremaster:
      case SSPM_I2Cslave_7bitaddr_ints:
      case SSPM_I2Cslave_10bitaddr_ints:
	return(true);
	break;
    }
    return(false);
}
bool _SSPCON::isI2CMaster(unsigned int val) 
{
    if ( (val & SSPEN) != SSPEN)
	return(false);
    switch(val & SSPM_mask)
    {
      case SSPM_MSSPI2Cmaster:
      case SSPM_I2Cfirmwaremaster:
	return(true);
	break;
    }
    return(false);
}
/*
	return true if an I2C slave mode is enabled in SSPCON
*/
bool _SSPCON::isI2CSlave(unsigned int val) 
{
    if ( (val & SSPEN) != SSPEN)
	return(false);
    switch(val & SSPM_mask)
    {
      case SSPM_I2Cslave_7bitaddr:
      case SSPM_I2Cslave_10bitaddr:
      case SSPM_I2Cslave_7bitaddr_ints:
      case SSPM_I2Cslave_10bitaddr_ints:
	return(true);
	break;
    }
    return(false);
}

//-----------------------------------------------------------
// SSPBUF - Synchronous Serial Port Control register.
//-----------------------------------------------------------

_SSPBUF::_SSPBUF()
  :  m_sspmod(0), m_bIsFull(false)
{
}

/*
	process write to SSPBUF
*/
void _SSPBUF::put(unsigned int new_value)
{
  put_value(new_value);
  m_sspmod->newSSPBUF(value.get());
}

/*
	update SSPBUF without processing data
*/
void _SSPBUF::put_value(unsigned int new_value)
{

  trace.raw(write_trace.get() | value.get());
  value.put(new_value & 0xff);
}

void _SSPBUF::setSSPMODULE( SSP_MODULE *_sspmod)
{
  m_sspmod = _sspmod;
}

unsigned int _SSPBUF::get()
{
  if( m_sspmod )
	m_sspmod->rdSSPBUF();

  trace.raw(read_trace.get() | value.get());
  m_bIsFull = false;

  return value.get();
}
  
unsigned int _SSPBUF::get_value()
{
  return value.get();
}


//-----------------------------------------------------------
// SSPADD - Synchronous Serial Port Address (for I2C)
//-----------------------------------------------------------


void _SSPADD::setSSPMODULE( SSP_MODULE *_sspmod)
{
  m_sspmod = _sspmod;
}
void _SSPADD::put(unsigned int new_value)
{
  trace.raw(write_trace.get() | value.get());
  put_value(new_value);

  if( m_sspmod )
	m_sspmod->newSSPADD(new_value);

}

void _SSPADD::put_value(unsigned int new_value)
{
  value.put(new_value & 0xff);
}
SPI::SPI(SSP_MODULE *_ssp_mod, _SSPCON *_sspcon, _SSPSTAT *_sspstat, _SSPBUF *_sspbuf)
{
    m_sspmod = _ssp_mod;
    m_sspcon = _sspcon;
    m_sspstat = _sspstat;
    m_sspbuf = _sspbuf;
}

void SPI::clock( bool ClockState )
{
  // A clock has happened. Either we sent one or we recieved one.
  bool onbeat;
  if( !m_sspstat || ! m_sspcon)
    return;
  unsigned int sspstat_val = m_sspstat->value.get();
  unsigned int sspcon_val = m_sspcon->value.get();

cout << "SPi clock " << ClockState << " m_state=" << m_state << endl;

  if( ClockState ) // rising edge
  {
    if( ( (sspcon_val & _SSPCON::CKP) && !(sspstat_val & _SSPSTAT::CKE) )
	|| ( !(sspcon_val & _SSPCON::CKP) && (sspstat_val & _SSPSTAT::CKE) ) )
      onbeat = true;
    else
      onbeat = false;
  } 
  else // falling edge
  {
    if( ( !(sspcon_val & _SSPCON::CKP) && !(sspstat_val & _SSPSTAT::CKE) )
	|| ( (sspcon_val & _SSPCON::CKP) && (sspstat_val & _SSPSTAT::CKE)))
      onbeat = true;
    else
      onbeat = false;
  }

  if( m_state == eIDLE ){
    if( sspstat_val & _SSPSTAT::CKE ) 
    {
      // FIX: I have NOT verified that PICs actually behave like this.
      cout << "SSP: I can't handle a non-started transfer with CKE = 1." << endl;
      return;
    } 
    else if( onbeat ) 
    {
      // FIX: I have NOT verified that PICs actually behave like this.
      cout << "SSP: Ignoring clock transition to neutral in state IDLE." << endl;
      return;
    }
    else 
    {
      if (verbose)
      	cout << "SPI clock called start_transfer\n";
      start_transfer();
    }

  }
 
  if (!m_sspmod)
    return;

  if( onbeat ) {
    // on beat: data is read in if SMP = 0
    if( !(sspstat_val & _SSPSTAT::SMP) ) {
      m_SSPsr <<= 1;
      if (m_sspmod->get_SDI_State())
	m_SSPsr |= 1;
      if (verbose)
      	cout << "SSP: SPI Received bit = " << (m_SSPsr & 1) << ". (SMP=0)" << endl;
    }
  } else {
    // off beat: data is shifted out, data is read in if SMP = 1

    if( sspstat_val & _SSPSTAT::SMP ) {
      m_SSPsr <<= 1;
      if (m_sspmod->get_SDI_State())
	m_SSPsr |= 1;
      if (verbose)
      	cout << "SSP: SPI Received bit = " << (m_SSPsr & 1) << ". (SMP=1)" << endl;
    }
	
    char nextSDO = (m_SSPsr&(1<<7)) ? '1' : '0';
    m_sspmod->putStateSDO(nextSDO);
    if (verbose)
      cout << "SSP: SPI Sent bit = " << nextSDO << "."  << endl;
  }

  bool bSSPCONValue = (sspcon_val & _SSPCON::CKP) ? true : false;
  if(bSSPCONValue == ClockState) {
    bits_transfered++;
    if( bits_transfered == 8 ) 
    {
      if( (sspstat_val & _SSPSTAT::SMP) && !(sspstat_val & _SSPSTAT::CKE) ) 
      {
	m_state = eWAITING_FOR_LAST_SMP;
	set_halfclock_break();
      } 
      else 
      {
	stop_transfer();
      }
    }
  }
}
void SPI::set_halfclock_break()
{
  int clock_in_cycles = 1;

  if( !m_sspstat || ! m_sspcon)
    return;

  unsigned int sspcon_val = m_sspcon->value.get();

  switch( sspcon_val & _SSPCON::SSPM_mask ) {
  // Simulation requires Fosc/4 to be run at Fosc/8
  case _SSPCON::SSPM_SPImaster4: 
    clock_in_cycles = 1;
    break;
  case _SSPCON::SSPM_SPImaster16:
    clock_in_cycles = 2;
    break;
  case _SSPCON::SSPM_SPImaster64:
    clock_in_cycles = 8;
    break;
  case _SSPCON::SSPM_SPImasterTMR2:
    break;
  }
  
  get_cycles().set_break(get_cycles().value + clock_in_cycles, this);
}
void SPI::callback()
{
  if (!m_sspmod)
    return;

  cout << "SPI callback m_state=" << m_state << endl;

  switch( m_state ) {
  case eIDLE:
    break;
  case eACTIVE:
    m_sspmod->Sck_toggle();
    clock( m_sspmod->get_SCL_State() );
    set_halfclock_break();
    break;
  case eWAITING_FOR_LAST_SMP:
    if( m_sspstat && m_sspstat->value.get() & _SSPSTAT::SMP ) {
      m_SSPsr <<= 1;
      if (m_sspmod->get_SDI_State())
	m_SSPsr |= 1;

      if (verbose)
      	cout << "SSP: Received bit = " << (m_SSPsr & 1) << ". (SMP=1)" << endl;
    }
	
    m_state = eACTIVE;
    stop_transfer();
    break;
  }
	  
}
//-----------------------------------------------------------

void SPI::startSPI()
{
    m_state = eIDLE;
    bits_transfered = 0;
}

SSP_MODULE::SSP_MODULE()
  : m_pirset(0),
    m_spi(0),
    m_i2c(0),
    m_sck(0),
    m_ss(0),
    m_sdo(0),
    m_sdi(0),
    m_i2c_tris(0),
    m_SckSource(0),
    m_SdoSource(0),
    m_SdiSource(0),
    m_SDI_Sink(0),
    m_SCL_Sink(0),
    m_SS_Sink(0),
    m_sink_set(false)
{
  sspbuf.setSSPMODULE(this);
  sspcon.setSSPMODULE(this);
  sspcon2.setSSPMODULE(this);
  sspstat.setSSPMODULE(this);
  sspadd.setSSPMODULE(this);

}
SSP_MODULE::~SSP_MODULE(){}

void SPI::newSSPBUF(unsigned int newTxByte)
{
  if (m_sspcon->isSSPEnabled()) {
    if (m_state == eIDLE) {
	m_SSPsr = newTxByte;
	start_transfer();
    } else {
      // Collision
      m_sspcon->setWCOL();
    }
  } 
}
void SPI::start_transfer()
{
  if (!m_sspcon || !m_sspstat)
    return;

  // load the shift register
  m_state = eACTIVE;
  bits_transfered = 0;
  unsigned int sspcon_val = m_sspcon->value.get();
  unsigned int sspstat_val = m_sspstat->value.get();

  if (verbose)
    cout << "SSP: SPI Starting transfer. byte=0x" << hex << m_SSPsr << endl;

  switch( sspcon_val & _SSPCON::SSPM_mask ) {
  case _SSPCON::SSPM_SPImaster4:
  case _SSPCON::SSPM_SPImaster16:
  case _SSPCON::SSPM_SPImaster64:
    // Setup callbacks for clocks
    set_halfclock_break();
    break;
  case _SSPCON::SSPM_SPImasterTMR2: 
	break;
  case _SSPCON::SSPM_SPIslaveSS:
    // The SS pin was pulled low
    if( sspstat_val & _SSPSTAT::CKE )
      m_sspmod->putStateSDO((m_SSPsr &(1<<7)) ? '1' : '0');
    break;
  case _SSPCON::SSPM_SPIslave:
    // I don't do any thing until first clock edge
    break;
  default:
    cout << "start_transfer: The selected SPI mode is unimplemented. mode=" << hex
	<<(sspcon_val & _SSPCON::SSPM_mask) << endl;
  }
  
}
void SPI::stop_transfer()
{
  if (!m_sspcon  || !m_sspstat || !m_sspbuf || !m_sspmod)
	return;

  if( m_state == eACTIVE ) {
    if( bits_transfered == 8 && !m_sspbuf->isFull() )
    {
        if (verbose)
            cout << "SPI: Stoping transfer. Normal finish. Setting sspif and BF\n";
	m_sspbuf->put_value(m_SSPsr & 0xff);
	m_sspbuf->setFullFlag(true);
        m_sspmod->set_sspif();
	m_sspstat->put_value(m_sspstat->value.get() | _SSPSTAT::BF);
    } else if( bits_transfered == 8 && m_sspbuf->isFull() ) {
      if (verbose)
          cout << "SPI: Stopping transfer. SSPBUF Overflow setting SSPOV." << endl;
        m_sspcon->setSSPOV();

    } else {
      cout << "SPI: Stopping transfer. Cancel finish." << endl;
      // The transfer was canceled in some way
    }
  } else {
    if (verbose)
      cout << "SSP: Stopping transfer. State != ACTIVE." << endl;
  }

  m_state = eIDLE;
  
}

I2C::I2C(SSP_MODULE *_ssp_mod, _SSPCON *_sspcon, _SSPSTAT *_sspstat, 
	_SSPBUF *_sspbuf, _SSPCON2 *_sspcon2, _SSPADD *_sspadd)
{
    m_sspmod = _ssp_mod;
    m_sspcon = _sspcon;
    m_sspstat = _sspstat;
    m_sspbuf = _sspbuf;
    m_sspcon2 = _sspcon2;
    m_sspadd = _sspadd;
    future_cycle = 0;
}

void I2C::set_idle()
{
    i2c_state = eIDLE;
}
bool I2C::isIdle()
{
    return(
	(m_sspstat->value.get() & _SSPSTAT::RW) == 0 &&
	(m_sspcon2->value.get() & 
	   (
	     _SSPCON2::ACKEN ||
	     _SSPCON2::RCEN ||
	     _SSPCON2::PEN ||
	     _SSPCON2::RSEN ||
	     _SSPCON2::SEN
	   )) == 0
	);
}
bool I2C::rx_byte()
{
    m_SSPsr = ( m_SSPsr << 1 ) |  (m_sspmod->get_SDI_State()?1:0);
    bits_transfered++;
    if (bits_transfered == 8)
    {
	m_sspcon2->put_value(m_sspcon2->value.get() & ~_SSPCON2::RCEN);
	if (verbose & 2)
	    cout << "CLK_RX_BYTE got byte=" << hex << m_SSPsr << endl;
	m_sspmod->SaveSSPsr(m_SSPsr & 0xff);
        m_sspmod->set_sspif();
	set_idle();
	return(true);
    }
    return(false);
}
void I2C::callback()
{


    if (verbose & 2)
        cout << "I2C::callback i2c_state " << i2c_state << " phase=" << phase <<endl;
    if (future_cycle != get_cycles().value)
    {
	cout << "I2C program error future_cycle=" << future_cycle << " now=" 
		<< get_cycles().value << " i2c_state=" << i2c_state << endl;
    }

    future_cycle = 0;
    switch(i2c_state)
    {
    case CLK_ACKEN:
	if (phase == 1)
	{
	    m_sspmod->setSCL(true);
	}
	else if (phase == 2)
	{
	    m_sspmod->setSCL(false);
       	    m_sspcon2->value.put( m_sspcon2->value.get() & ~(_SSPCON2::ACKEN ));
            m_sspmod->set_sspif();
	}
	else
	{
	    cout << "CLK_ACKEN unexpected phase " << phase << endl;
	}
	break;

    case CLK_START:
	if (phase == 0)
	{
	    phase++;
	    m_sspmod->setSDA(false);
	    setBRG();
	}
	else
	{
	    m_sspcon2->value.put(m_sspcon2->value.get() & 
		~(_SSPCON2::SEN | _SSPCON2::RSEN));
	    m_sspmod->setSCL(false);
	    m_sspmod->set_sspif();
	    set_idle();
	}
	break;

    case CLK_RSTART:
	if (phase == 0)
  	{
	    m_sspmod->setSCL(true);
	}
	break;

    case CLK_STOP:
	if (phase == 0)
	{
	    phase++;
	    if (m_sspmod->get_SCL_State())
	    {
		setBRG();
	    }
	    m_sspmod->setSCL(true);
	}
	else if (phase == 1)
	{
	    phase++;
	    setBRG();
	    m_sspmod->setSDA(true);
	}
	else
	{
	    if (m_sspstat->value.get() &  _SSPSTAT::P)
	    {
		if (verbose & 2)
		    cout << "I2C::callback stop finish\n";
	    	m_sspmod->set_sspif();
	    }
	    else
	    {
		if (verbose & 2)
		    cout << "I2C::callback stop fail\n";
	    	m_sspmod->set_bclif();
	    }
	    set_idle();
	    m_sspcon2->value.put(m_sspcon2->value.get() & ~_SSPCON2::PEN );
	}
	break;


    case CLK_TX_BYTE:
	if(m_sspmod->get_SCL_State()) 
	{
	    bool n_ack = m_sspmod->get_SDI_State();
	    bits_transfered++;
	    if (bits_transfered < 8)
	    {
	        m_SSPsr <<= 1;
	        m_sspmod->setSCL(false);
	        m_sspmod->setSDA((m_SSPsr & 0x80) == 0x80);
	    }
	    else if(bits_transfered == 8) 
	    {
	        m_sspmod->setSCL(false);
	        m_sspmod->setSDA(true);
	    	m_sspstat->put_value(m_sspstat->value.get() & ~_SSPSTAT::BF);
		if (verbose & 2)
		    cout << "I2C::callback CLK_TX_BYTE sent\n";
            }
	    else
	    {
		if (verbose & 2)
		{
		    cout << "I2C::callback CLK_TX_BYTE _ACK=" << n_ack <<
		        " clock=" << get_cycles().value << endl;
		}
		if (n_ack)
		    m_sspcon2->put_value(m_sspcon2->value.get() | _SSPCON2::ACKSTAT);
		else
		    m_sspcon2->put_value(m_sspcon2->value.get() & ~_SSPCON2::ACKSTAT);
		m_sspstat->put_value(m_sspstat->value.get() & ~_SSPSTAT::RW);
		m_sspmod->set_sspif();
		set_idle();
	        m_sspmod->setSCL(false);
	    }
	}
	else 
		m_sspmod->setSCL(true);
	break;

    case CLK_RX_BYTE:
	if(m_sspmod->get_SCL_State()) 
	{
	    rx_byte();
	    m_sspmod->setSCL(false);
	}
	else 
		m_sspmod->setSCL(true);
	break;


    default:
	cout << "I2C::callback unxpected i2c_state=" << dec << i2c_state << endl;
	break;
	
    }
}
void I2C::clock(bool clock_state)
{
  unsigned int sspcon_val = m_sspcon->value.get();
  unsigned int sspstat_val = m_sspstat->value.get();
    if (verbose & 2)
        cout << "I2C::clock  SCL=" << clock_state << " SDI=" << 
	    m_sspmod->get_SDI_State() << " i2c_state=" << i2c_state << 
	    " phase=" << phase << endl;
    if (clock_state)	// Do read on clock high transition
    {
	switch(i2c_state)
	{
	  case CLK_STOP:
	    if (phase == 1)
		setBRG();
	    break;

	  case CLK_ACKEN:
	    if (phase == 1)
	    {
		phase++;
		setBRG();
	    }
	    break;

	case CLK_RSTART:
	    if (phase == 0)
	    {
    		if (!m_sspmod->get_SDI_State())
    		{
		    if (verbose)
		        cout << "I2C::clock CLK_RSTART bus collision\n";
		    bus_collide();
	    	    m_sspmod->setSDA(true);
		}
		else
		{
		    clrBRG();
		    start_bit();
		}
	    }
	    else if (phase == 1)
	    {
		setBRG();
	    }
	    break;
	    

	  case RX_CMD:
	  case RX_CMD2:
	  case RX_DATA:
		if (bits_transfered < 8)
		{
	  	    m_SSPsr = (m_SSPsr << 1) | (m_sspmod->get_SDI_State()?1:0);
		    bits_transfered++;
		}
	    break;


	   case CLK_TX_BYTE:
	   case CLK_RX_BYTE:
	     setBRG();
	     break;

	   default:
	     break;
	}
    }
    else	// Do writes of clock low transition
    {
	switch(i2c_state)
	{
	case CLK_ACKEN:
	    clrBRG();
	    if (phase)
	    {
		m_sspmod->setSCL(false);
        	m_sspcon2->value.put(
			m_sspcon2->value.get() & ~(_SSPCON2::ACKEN ));
	    	m_sspmod->set_sspif();
	    	set_idle();
	    }
	    break;

	case CLK_START:
	    clrBRG();
	    if (phase == 0 )
	    {
		if (verbose)
		   cout << "I2C::clock CLK_START Bus collision\n";
		bus_collide();
	    }
	    else if (phase == 1)
	    {
        	m_sspcon2->value.put(m_sspcon2->value.get() & 
		    ~(_SSPCON2::SEN | _SSPCON2::RSEN));
	    }
	    break;

	case CLK_RSTART:
	    if (phase == 0)
        	m_sspmod->setSDA(true);
	    break;

	case RX_CMD:
	case RX_CMD2:
	    if (bits_transfered == 8)
	    {
    		if ( !( m_SSPsr == 0 && 
			(m_sspcon2->value.get() & _SSPCON2::GCEN)
		      )
		      &&
     		      (m_SSPsr & 0xfe) != m_sspadd->value.get() )
    		{
      		    cout << "READ_CMD address missmatch " << hex << m_SSPsr <<
			" != " << m_sspadd->value.get() << endl;
      		    set_idle();
		    return;
    		}
	    }
	    else if (bits_transfered == 9)
	    {
		if(end_ack())
		{
		    m_sspstat->put_value(sspstat_val & ~_SSPSTAT::DA);
		slave_command();
	        }
		return;
	    }
	    // Fall Through
	case RX_DATA:
	    if (bits_transfered == 8)
	    {
		if (verbose)
		    cout << "I2C::clock RX_DATA or CMD m_SSPsr=" << hex << (m_SSPsr & 0xff) << endl;
		if (m_sspmod->SaveSSPsr(m_SSPsr & 0xff) ) // ACK ?
		{
		    if (verbose)
	    	        cout << "I2C::clock RX_DATA or CMD  Send ACK\n";
	    	    m_sspmod->setSDA(false);
		}
		else
		{
		    if (verbose)
	    	        cout << "I2C::clock RX_DATA or CMD  Send NACK\n";
		    m_sspmod->setSDA(true);
		}
		bits_transfered++;
	    }
	    else if (bits_transfered == 9)
	    {
		end_ack();
		m_sspstat->put_value(sspstat_val | _SSPSTAT::DA);
	    }
	    break;


	case CLK_TX_BYTE:
	case CLK_RX_BYTE:
	    setBRG();
	    break;

	case TX_DATA:
	    bits_transfered++;
	    if (bits_transfered < 8)
	    {
	        m_SSPsr <<= 1;
	        m_sspmod->setSDA((m_SSPsr & 0x80) == 0x80);
	    }
	    else if(bits_transfered == 8) 
	    {
	        m_sspmod->setSDA(true);
	    	m_sspstat->put_value(sspstat_val & ~_SSPSTAT::BF);
		if (verbose)
		    cout << "I2C::clock TX_DATA  sent byte\n";
	    }
	    else if(bits_transfered == 9) 
	    {
	        m_sspmod->set_sspif();
	    	if (m_sspmod->get_SDI_State())	// NACK
	    	{
		    if (verbose)
		    	cout << "I2C::clock TX_DATA  got NACK\n";
		    m_sspstat->put_value(sspstat_val & _SSPSTAT::BF);
		    set_idle();
		    return;
	    	}
		m_sspstat->put_value(sspstat_val | _SSPSTAT::DA);
 	     	if (sspstat_val & _SSPSTAT::RW)
	    	{
		    sspcon_val &= ~ _SSPCON::CKP;
		    m_sspcon->put_value(sspcon_val);
		    if (verbose)
		        cout << "I2C::clock TX_DATA Strech clock sspcon=" << hex << sspcon_val << endl;
		    m_sspmod->setSCL(false);
	    	}
            }
	    break;

	default:
	    break;
	}
    }
}

void I2C::slave_command()
{
    unsigned int sspcon_val = m_sspcon->value.get();
    unsigned int sspstat_val = m_sspstat->value.get();

    if (verbose)
	cout << "I2C::slave_command m_SSPsr=" << hex << m_SSPsr << endl;
    if ( m_SSPsr == 0 && (m_sspcon2->value.get() & _SSPCON2::GCEN))
    {
	i2c_state = RX_DATA;
    }
    else
    {
	if (verbose)
	    cout << "I2c::slave_command i2c_state=" << i2c_state << " sspcon=" << sspcon_val << endl;
    	switch( sspcon_val & _SSPCON::SSPM_mask ) 
	{
      	case _SSPCON::SSPM_I2Cslave_10bitaddr_ints:
      	case _SSPCON::SSPM_I2Cslave_10bitaddr:
		if (i2c_state == RX_CMD && (m_SSPsr & 1))
		{
		    sspstat_val |= _SSPSTAT::RW;
		    i2c_state = TX_DATA;
	    	    m_sspmod->setSCL(false);  // clock low
	    	    sspcon_val &= ~ _SSPCON::CKP;
	    	    m_sspcon->put_value(sspcon_val);
		}
		else
		{
	       	    sspstat_val |= _SSPSTAT::UA;
		    i2c_state = (i2c_state == RX_CMD2) ? 
			RX_DATA : RX_CMD2;
		}
		break;

      	case _SSPCON::SSPM_I2Cslave_7bitaddr:
      	case _SSPCON::SSPM_I2Cslave_7bitaddr_ints:
		if (i2c_state == RX_CMD && (m_SSPsr & 1))
		{
		    sspstat_val |= _SSPSTAT::RW;
	            sspstat_val &= ~_SSPSTAT::BF;
	    	    i2c_state = TX_DATA;
		    sspcon_val &= ~ _SSPCON::CKP;
		    m_sspcon->put_value(sspcon_val);
		    m_sspmod->setSCL(false);  // clock low
		}
		else
		{
		    i2c_state = RX_DATA;
		}
		break;
	}
    	m_sspstat->put_value(sspstat_val);
    }
}
bool I2C::end_ack()
{

	m_sspmod->set_sspif();
	bits_transfered = 0;
 	if (m_sspmod->get_SDI_State())      // NACK
        {
	    if (verbose & 2)
	      cout << "I2C::end_ack NACK\n";
            set_idle();
	    return(false);
        }
	else
	{
	    m_sspmod->setSDA(true);
	    if (verbose & 2)
	      cout << "I2C::end_ack ACK\n";
	    return(true);
	}
}
void I2C::bus_collide()
{
   m_sspcon2->value.put(m_sspcon2->value.get() &
       ~ (_SSPCON2::SEN | _SSPCON2::RSEN | _SSPCON2::PEN |
	  _SSPCON2::RCEN | _SSPCON2::ACKEN));
   m_sspmod->set_bclif();
   set_idle();

}
void I2C::newSSPADD(unsigned int newTxByte)
{
    unsigned int sspstat_val = m_sspstat->value.get();

    if (sspstat_val & _SSPSTAT::UA)
    {
	m_sspstat->put_value(sspstat_val & ~_SSPSTAT::UA);
	m_sspmod->setSCL(true);		// turn off clock stretch
    }
}
void I2C::setBRG()
{
    if (future_cycle)
	cout << "ERROR I2C::setBRG called with future_cycle=" << future_cycle << endl;
      future_cycle = get_cycles().value + 
	  	((m_sspadd->value.get() &0x7f)/ 2) + 1;
      get_cycles().set_break(future_cycle, this);
}

void I2C::clrBRG()
{
	    if (future_cycle)
	    {
	    	get_cycles().clear_break(this);
		future_cycle = 0;
	    }
}
void I2C::newSSPBUF(unsigned int newTxByte)
{

    if (!m_sspstat || !m_sspcon)
	return;
    unsigned int sspstat_val = m_sspstat->value.get();
    unsigned int sspcon_val = m_sspcon->value.get();

    if (m_sspcon2 && (sspcon_val &  _SSPCON::SSPM_mask) ==  _SSPCON::SSPM_MSSPI2Cmaster)
    {
	if (isIdle())
	{
	   if (verbose)
		cout << "I2C::newSSPBUF send " << hex << newTxByte << endl;
	    m_sspmod->setSCL(false);
	    m_sspstat->put_value(sspstat_val | _SSPSTAT::BF | _SSPSTAT::RW);
	    m_SSPsr = newTxByte;
	    m_sspmod->setSDA((m_SSPsr & 0x80) == 0x80);
	    bits_transfered = 0;
	    i2c_state = CLK_TX_BYTE;
	    setBRG();
	}
	else
	{
	    cout << "I2C::newSSPBUF I2C not idle on write data=" << hex << 
		newTxByte << endl;
      	    // Collision
      	    m_sspcon->setWCOL();
	}
    }
    else
    {
	if (sspstat_val & _SSPSTAT::RW)
	{
      	    if (!(sspstat_val & _SSPSTAT::BF))
	    {    
		if (verbose)
		    cout << "I2C::newSSPBUF send " << hex << newTxByte << endl;
	        m_SSPsr = newTxByte;
	        m_sspstat->put_value(sspstat_val | _SSPSTAT::BF);
	        m_sspmod->setSDA((m_SSPsr & 0x80) == 0x80);
	        bits_transfered = 0;
    	    } 
	    else // Collision
	    {
	        cout << "I2C::newSSPBUF I2C not idle on write data=" << hex << 
	 	    newTxByte << endl;
      	        m_sspcon->setWCOL();
	    }
	} 
	else
	   cout << "I2C::newSSPBUF write SSPSTAT::RW not set\n";
    }
}
void I2C::sda(bool data_val)
{
    if (m_sspmod->get_SCL_State())	// Clock is high
    {
    	unsigned int stat_val = m_sspstat->value.get();
	unsigned int sspm = (m_sspcon->value.get() & _SSPCON::SSPM_mask);
	if (data_val)	// Data going high - STOP
	{
    	    stat_val = (stat_val & _SSPSTAT::BF) | _SSPSTAT::P;
	    if (! future_cycle)
	    	set_idle();

	    if (verbose)
		cout << "I2C::sda got STOP future_cycle=" << future_cycle <<  endl;
 	}
	else		// Data going low - START
	{
	    switch (i2c_state)
	    {
	    case CLK_STOP:
		break;

	    case CLK_START:
		if (phase == 0)
		{	
		    guint64 fc = get_cycles().value + 
			((m_sspadd->value.get() &0x7f)/ 2) + 1;

		    if (future_cycle)
		    {
			phase++;
			if (verbose)
			  cout << "I2C::sda BUS_CHECK fc=" << fc << " future_cycle=" << future_cycle << endl;
		    	get_cycles().reassign_break(future_cycle, fc, this);
		    	future_cycle = fc;
		    }
		    else
		    {
		    	get_cycles().set_break(fc, this);
		    	future_cycle = fc;
		    }
		}
		break;

	    default:
		i2c_state = RX_CMD;
		break;
	    }
    	    stat_val = (stat_val & _SSPSTAT::BF) | _SSPSTAT::S;
	    bits_transfered = 0;
	    m_SSPsr = 0;
	    if (verbose)
		cout << "I2C::sda got START ";
	}
	m_sspstat->put_value(stat_val);

	// interrupt ? 
	if (sspm == _SSPCON::SSPM_I2Cslave_7bitaddr_ints ||
	    sspm == _SSPCON::SSPM_I2Cslave_10bitaddr_ints)
	{
	    m_sspmod->set_sspif();
	}
    }
    else	// clock low
    {
	if (i2c_state == CLK_STOP)
	{
	    if (verbose)
	        cout << "I2C::sda CLK_STOP SDA low CLOCK low\n";
//	    setBRG();
	}
    }
}
/*
	master mode, begin reading a byte
*/
void I2C::master_rx()
{
    if (verbose)
        cout << "I2C::master_rx SCL=" << m_sspmod->get_SCL_State() << " SDI=" << m_sspmod->get_SDI_State() << endl;
    m_sspmod->setSCL(false);
    m_sspmod->setSDA(true);
    bits_transfered = 0;
    m_SSPsr = 0;
    i2c_state = CLK_RX_BYTE;
    setBRG();
}
/*
	master, begin start sequence
		SCL and SDA must be high, then force SDA low
*/
void I2C::start_bit()
{
    if (m_sspmod->get_SCL_State() && m_sspmod->get_SDI_State())
    {

	i2c_state = CLK_START;
	phase = 0;
	setBRG();

    }
    else
    {
	if (verbose & 2)
	    cout << "I2C::start_bit bus collision " <<
	        " SCL=" << m_sspmod->get_SCL_State() <<
	        " SDI=" << m_sspmod->get_SDI_State() << endl;
	bus_collide();
    }
}
/*
	Master mode, begin rstart sequence
		bring SDA and SCL high, then SDA low with SCL high (start)
*/ 
void I2C::rstart_bit()
{
    if (verbose)
        cout << "I2C::rstart_bit SCL=" << m_sspmod->get_SCL_State() << 
	    " SDI=" << m_sspmod->get_SDI_State() << endl;

    i2c_state = CLK_RSTART;
    phase = 0;
    m_sspmod->setSCL(false);

    if (!m_sspmod->get_SCL_State())
    {
	setBRG();
        m_sspmod->setSDA(true);
    }
    else
	bus_collide();

    
}
/*
	master, begin stop sequence
		drop SDA (mught cause start if SCL high)
		when SCL high, raise SDA (stop condition)
		
*/
void I2C::stop_bit()
{
    i2c_state = CLK_STOP;
    phase = 0;
    m_sspmod->setSDA(false);

    if (!m_sspmod->get_SDI_State())
    {
	setBRG();
    }
    else
	bus_collide();

}

/*
	master, begin ack sequence 
		clock SCL low, set SDA as per ACKDT,
		clock SCL high
*/
void I2C::ack_bit()
{
    if (verbose)
        cout << "I2C::ack_bit ACKDT="
	    << (m_sspcon2->value.get() & _SSPCON2::ACKDT) << endl;
    i2c_state = CLK_ACKEN;
    phase = 0;
    m_sspmod->setSCL(false);
    if (!m_sspmod->get_SCL_State())
    {
        phase++;
	setBRG();
        m_sspmod->setSDA((m_sspcon2->value.get() & _SSPCON2::ACKDT) ? true : false);
    }
    else
	bus_collide();

    
}
void SSP_MODULE::initialize(
		        PIR_SET *ps,
			PinModule *SckPin,
			PinModule *SsPin,
			PinModule *SdoPin,
			PinModule *SdiPin,
                 	PicTrisRegister *_i2ctris,
			SSP_TYPE _ssptype
		)
{
  m_pirset = ps;
  m_sck = SckPin;
  m_ss = SsPin;
  m_sdo = SdoPin;
  m_sdi = SdiPin;
  m_i2c_tris = _i2ctris;
  m_ssptype = _ssptype;
  m_SckSource = new PeripheralSignalSource(m_sck);
  m_SdoSource = new PeripheralSignalSource(m_sdo);
  m_SdiSource = new PeripheralSignalSource(m_sdi);
  if (! m_spi)
  {
    m_spi = new SPI(this, &sspcon, &sspstat, &sspbuf);
    m_i2c = new I2C(this, &sspcon, &sspstat, &sspbuf, &sspcon2, &sspadd);
    m_SDI_Sink = new SDI_SignalSink(this);
    m_SCL_Sink = new SCL_SignalSink(this);
    m_SS_Sink = new SS_SignalSink(this);
  }


}
void SSP_MODULE::ckpSPI(unsigned int value)
{
    if(m_spi && !m_spi->isIdle())
      cout << "SPI: You just changed CKP in the middle of a transfer." << endl;
	
    switch( value & _SSPCON::SSPM_mask ) {
    case _SSPCON::SSPM_SPImaster4:
    case _SSPCON::SSPM_SPImaster16:
    case _SSPCON::SSPM_SPImaster64:
      if (m_SckSource) m_SckSource->putState( (value & _SSPCON::CKP) ? '1' : '0' );
      break;
    case _SSPCON::SSPM_SPImasterTMR2:
      break;
    }
}

/*
	drive SCL by changing pin direction (with data low)
*/
void SSP_MODULE::setSCL(bool direction)
{
    if (!m_sck || !m_i2c_tris)
	return;

    unsigned int pin = m_sck->getPinNumber();
    unsigned int tris_val = m_i2c_tris->get();
    if (!direction)
	tris_val &= ~(1<<pin);
    else
	tris_val |= (1<<pin);

    m_i2c_tris->put_value(tris_val);
}
/*
	drive SDA by changing pin direction (with data low)
*/
void SSP_MODULE::setSDA(bool direction)
{
    unsigned int pin = m_sdi->getPinNumber();
    unsigned int tris_val = m_i2c_tris->get();
    if (!direction)
	tris_val &= ~(1<<pin);
    else
	tris_val |= (1<<pin);

    m_i2c_tris->put_value(tris_val);
}
/*
	deactivate SPI and I2C mode
*/
void SSP_MODULE::stopSSP(unsigned int old_value)
{
    if (sspcon.isSPIActive(old_value))
    {
        m_spi->stop_transfer();
        m_sck->setSource(0);
        m_sdo->setSource(0);

        if (verbose)
      	    cout << "SSP: SPI turned off" << endl;
    }
    else if (sspcon.isI2CActive(old_value))
    {
	m_i2c->set_idle();
        m_sck->setSource(0);
        m_sdi->setSource(0);
        if (verbose)
      	    cout << "SSP: I2C turned off" << endl;
    }
}
/*
	activate SPI module
*/
void SSP_MODULE::startSSP(unsigned int value)
{
    if (verbose)
      cout << "SSP: SPI turned on" << endl;
    sspbuf.setFullFlag(false);
    if (! m_sink_set)
    {
	if (m_sdi) m_sdi->addSink(m_SDI_Sink);
	if (m_sck) m_sck->addSink(m_SCL_Sink);
	if (m_ss) m_ss->addSink(m_SS_Sink);
	m_sink_set = true;
    }
    switch( value & _SSPCON::SSPM_mask ) {
    case _SSPCON::SSPM_SPImasterTMR2:
    case _SSPCON::SSPM_SPImaster4:
    case _SSPCON::SSPM_SPImaster16:
    case _SSPCON::SSPM_SPImaster64:
  	if (m_sck) m_sck->setSource(m_SckSource);
  	if (m_sdo) m_sdo->setSource(m_SdoSource);
        if (m_SckSource) m_SckSource->putState( (value & _SSPCON::CKP) ? '1' : '0' );
	if (m_SdoSource) m_SdoSource->putState('0'); // BUG, required to put SDO in know state
	break;

    case _SSPCON::SSPM_SPIslave:
    case _SSPCON::SSPM_SPIslaveSS:
  	if (m_sdo) m_sdo->setSource(m_SdoSource);
	if (m_SdoSource) m_SdoSource->putState('0'); // BUG, required to put SDO in know state
	break;

      case _SSPCON::SSPM_I2Cslave_7bitaddr:
      case _SSPCON::SSPM_I2Cslave_10bitaddr:
      case _SSPCON::SSPM_MSSPI2Cmaster:
      case _SSPCON::SSPM_I2Cfirmwaremaster:
      case _SSPCON::SSPM_I2Cslave_7bitaddr_ints:
      case _SSPCON::SSPM_I2Cslave_10bitaddr_ints:
	m_i2c->set_idle();
  	m_sck->setSource(m_SckSource);
  	m_sdi->setSource(m_SdiSource);
	m_sck->refreshPinOnUpdate(true);
	m_sdi->refreshPinOnUpdate(true);
	m_SdiSource->putState('0'); 
	m_SckSource->putState('0'); 
	m_sck->refreshPinOnUpdate(false);
	m_sdi->refreshPinOnUpdate(false);
	break;

    default:
	cout << "SSP: start, unexpected SSPM select bits SSPCON="
		<< hex << value << endl;;
	break;
    }
}
/*
	process mode change or clock edge due to write to SSPCON
*/
void SSP_MODULE::changeSSP(unsigned int new_value, unsigned int old_value)
{
    unsigned int diff = new_value ^ old_value;

    if (verbose)
	cout << "SSP_MODULE::changeSSP CKP new=" << hex << new_value << " old=" << old_value << endl;
    if (diff & _SSPCON::SSPM_mask)	// mode changed
    {
	stopSSP(old_value);
	startSSP(new_value);
    }
    else if (diff & _SSPCON::CKP)
    {
	if (sspcon.isSPIActive(new_value))
	    ckpSPI(new_value);
	else if (sspcon.isI2CActive(new_value) && new_value & _SSPCON::CKP)
		setSCL(true);
    }
}

//------------------------------------------------------------
// Called whenever the SDI/SDA input changes states.
// 
void SSP_MODULE::SDI_SinkState(char new3State)
{
  bool new_SDI_State = (new3State == '1' || new3State == 'W');
 
  if (new_SDI_State == m_SDI_State)
	return;

  m_SDI_State = new_SDI_State;

  if(sspcon.isI2CActive(sspcon.value.get()))
  {
      if(m_i2c) m_i2c->sda(m_SDI_State);
   }
}

// Called when the SCK/SDI input changes state
void SSP_MODULE::SCL_SinkState(char new3State)
{
  bool new_SCL_State = (new3State == '1' || new3State == 'W');
 
  if (new_SCL_State == m_SCL_State)
	return;

  m_SCL_State = new_SCL_State;

  if (!sspcon.isSSPEnabled() )
     return;

  switch( sspcon.value.get() & _SSPCON::SSPM_mask ) 
  {
      case _SSPCON::SSPM_SPIslaveSS:
      /*
     	SS high during transfer for BSSP, suspends transfers which
	continues when SS goes low.

	None BSSP interfaces handled when SS goes high  
      */
	if (m_SS_State)
	    return;	// suspend transfer 
			// Fall through
      case _SSPCON::SSPM_SPIslave:
	if (m_spi) m_spi->clock(m_SCL_State);
	break;

      case _SSPCON::SSPM_I2Cslave_7bitaddr:
      case _SSPCON::SSPM_I2Cslave_10bitaddr:
      case _SSPCON::SSPM_MSSPI2Cmaster:
      case _SSPCON::SSPM_I2Cfirmwaremaster:
      case _SSPCON::SSPM_I2Cslave_7bitaddr_ints:
      case _SSPCON::SSPM_I2Cslave_10bitaddr_ints:
	m_i2c->clock(m_SCL_State);
  }


}
/*
	on write to SSPBUF, pass on to either SPI or I2C if active
*/
void SSP_MODULE::newSSPBUF(unsigned int value)
{
  if (!m_spi)
  {
	cout << "Warning bug, SPI initialization error " << __FILE__ << ":" << __LINE__<<endl;
	return;
  }
  if (!m_i2c)
  {
	cout << "Warning bug, I2C initialization error " << __FILE__ << ":" << __LINE__<<endl;
	return;
  }
  if(sspcon.isSPIActive(sspcon.value.get()))
       m_spi->newSSPBUF(value);
  else if(sspcon.isI2CActive(sspcon.value.get()))
       m_i2c->newSSPBUF(value);
}

/*
	on write to SSPADD, pass onto I2C if active
*/
void SSP_MODULE::newSSPADD(unsigned int value)
{
  if(sspcon.isI2CActive(sspcon.value.get()))
       m_i2c->newSSPADD(value);
}
// clear BF flag

void SSP_MODULE::rdSSPBUF()
{
    sspstat.put_value(sspstat.value.get() & ~_SSPSTAT::BF);
}

void SSP_MODULE::SS_SinkState(char new3State)
{
  m_SS_State = (new3State == '1' || new3State == 'W');

  // If SS goes high in the middle of an SPI transfer while in slave_SS mode,
  // transfer is aborted unless BSSP which streches the clocking

  if (!sspcon.isSSPEnabled() || 
	! m_SS_State ||
	(sspcon.value.get() & _SSPCON::SSPM_mask) != _SSPCON::SSPM_SPIslaveSS ||
	! m_spi->isIdle() ||
	ssp_type() == SSP_TYPE_BSSP)
     return;

  m_spi->stop_transfer();
}

void SSP_MODULE::tmr2_clock()
{
  unsigned int sspcon_val = sspcon.value.get();
  if (! (sspcon_val & _SSPCON::SSPEN) || 
     ((sspcon_val & _SSPCON::SSPM_mask) != _SSPCON::SSPM_SPImasterTMR2) ||
     (m_spi && m_spi->isIdle()))
	return;

    Sck_toggle();
    if (m_spi) m_spi->clock( get_SCL_State() );
}
/*
	on write to SSPCON2 select master operation to initiate
*/
void SSP_MODULE::newSSPCON2(unsigned int value)
{
    if (!m_i2c)
	return;

    if(value & _SSPCON2::SEN)
	m_i2c->start_bit();
    else if(value & _SSPCON2::RSEN)
	m_i2c->rstart_bit();
    else if (value & _SSPCON2::PEN)
        m_i2c->stop_bit();
    else if (value & _SSPCON2::RCEN)
        m_i2c->master_rx();
    else if (value & _SSPCON2::ACKEN)
        m_i2c->ack_bit();


}
/*
	Process a received data byte
	    if BF == 0 and SSPOV == 0 return true otherwise false
	    if BF == 0 transfer data to SSPBUF and set BF
	    if BF == 1 set SSPOV
	    set SSPIF
*/
bool SSP_MODULE::SaveSSPsr(unsigned int value)
{
	bool ret = false;
	unsigned int stat_val = sspstat.value.get();
	unsigned int con_val = sspcon.value.get();

	if ((stat_val & _SSPSTAT::BF) == 0)
	{
	    if (verbose)
		cout << "SSP receive transfer " << hex << (value & 0xff) <<
			" to SSPBUF\n";
	    sspbuf.put_value(value);
	    sspstat.put_value(stat_val | _SSPSTAT::BF);
	    if ((con_val & _SSPCON::SSPOV) == 0)
		ret = true;
	}
	else
	{
	    sspcon.put_value(con_val | _SSPCON::SSPOV);
	    cout << "SSP receive overflow\n";
	}

	return(ret);
}
//-----------------------------------------------------------
//-------------------------------------------------------------------

/*
	register pointer to SSPMOD
*/
void _SSPCON2::setSSPMODULE(SSP_MODULE *sspmod)
{
  m_sspmod = sspmod;
}
/*
	write to SSPCON2 without processing data
*/
void  _SSPCON2::put_value(unsigned int new_value)
{

  trace.raw(write_trace.get() | value.get());
  value.put(new_value);

}
/*
    If a command is currently active, 
	lower 5 bits of register cannot be changed
    if no command is currently active,
	activate command and write data
*/
void _SSPCON2::put(unsigned int new_value)
{
  unsigned int cmd_active = value.get() & (ACKEN|RCEN|PEN|RSEN|SEN);
  if (verbose & 2)
      cout << "_SSPCON2::put " << hex << new_value << endl;
  if (cmd_active)
  {
	put_value((new_value & ~(ACKEN|RCEN|PEN|RSEN|SEN)) | cmd_active);
  }
  else
  {
      	switch (new_value & (ACKEN|RCEN|PEN|RSEN|SEN))
      	{
	case ACKEN:
	case RCEN:
	case PEN:
	case RSEN:
	case SEN:
      	    put_value(new_value);
      	    m_sspmod->newSSPCON2(new_value);
	    break;

	case 0:	// just write value
      	    put_value(new_value);
	    break;

	default:
	    cout << "SSPCON2 cannot select more than one function at a time\n";
	    break;
 	}
  }
	
}

_SSPCON2::_SSPCON2(void)
{
}
 


syntax highlighted by Code2HTML, v. 0.9.1