/*
Copyright (C) 1998,1999 T. 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>
class InvalidRegister; // Forward reference
#ifndef __SSP_H__
#define __SSP_H__
#include "pic-processor.h"
#include "14bit-registers.h"
#include "ioports.h"
#include "pir.h"
class PinModule;
class PIR1;
class PIR_SET;
class _14bit_processor;
class PicTrisRegister;
class _SSPBUF;
class _SSPSTAT;
class SDI_SignalSink;
class SCL_SignalSink;
class SS_SignalSink;
enum SSP_TYPE {
SSP_TYPE_BSSP = 1,
SSP_TYPE_SSP,
SSP_TYPE_MSSP
};
class SSP_MODULE;
class _SSPCON : public sfr_register, public TriggerObject
{
public:
enum {
SSPM_SPImaster4 = 0x0, // SPI master mode, clock = FOSC/4
SSPM_SPImaster16 = 0x1, // SPI master mode, clock = FOSC/16
SSPM_SPImaster64 = 0x2, // SPI master mode, clock = FOSC/64
SSPM_SPImasterTMR2 = 0x3, // SPI master mode, clock = TMR2/2
SSPM_SPIslaveSS = 0x4, // SPI slave mode, clock = SCK, /SS controlled
SSPM_SPIslave = 0x5, // SPI slave mode, clock = SCK, not /SS controlled
SSPM_I2Cslave_7bitaddr = 0x6,
SSPM_I2Cslave_10bitaddr = 0x7,
SSPM_MSSPI2Cmaster = 0x8,
SSPM_I2Cfirmwaremaster = 0xb,
SSPM_I2Cslave_7bitaddr_ints = 0xe,
SSPM_I2Cslave_10bitaddr_ints = 0xf,
/* None of the documentation I have seen show these, but Scott? thought
they were the good name RRR
SSPM_I2Cfirmwaremultimaster_7bitaddr_ints = 0xe,
SSPM_I2Cfirmwaremaster_10bitaddr_ints = 0xf,
*/
};
_SSPCON();
// Register bit definitions
enum {
SSPM0 = 1<<0,
SSPM1 = 1<<1,
SSPM2 = 1<<2,
SSPM3 = 1<<3,
CKP = 1<<4,
SSPEN = 1<<5,
SSPOV = 1<<6,
WCOL = 1<<7
};
static const unsigned int SSPM_mask = (SSPM0|SSPM1|SSPM2|SSPM3);
virtual void put(unsigned int);
virtual void put_value(unsigned int);
bool isSSPEnabled() { return (value.get() & SSPEN) == SSPEN; }
bool isI2CActive(unsigned int);
bool isI2CSlave(unsigned int);
bool isI2CMaster(unsigned int);
bool isSPIActive(unsigned int);
bool isSPIMaster() {
return isSSPEnabled() && ((value.get() & SSPM_mask) <= SSPM_SPImasterTMR2);
}
void setWCOL();
void setSSPOV() { put_value(value.get() | SSPOV);}
void setSSPMODULE(SSP_MODULE *);
private:
SSP_MODULE *m_sspmod;
};
class _SSPCON2 : public sfr_register
{
public:
enum {
SEN = 1<<0, // Start or Stretch enable
RSEN = 1<<1, // Repeated Start
PEN = 1<<2, // Stop condition enable
RCEN = 1<<3, // Receive enable bit
ACKEN = 1<<4, // Acknowledge Sequence enable bit
ACKDT = 1<<5, // Acknowledge Data bit
ACKSTAT = 1<<6, // Acknowledge status bit
GCEN = 1<<7 // General call enable
};
void put(unsigned int new_value);
void put_value(unsigned int new_value);
_SSPCON2(void);
void setSSPMODULE(SSP_MODULE *);
private:
SSP_MODULE *m_sspmod;
};
class _SSPSTAT : public sfr_register
{
public:
// Register bit definitions
enum {
BF = 1<<0, // Buffer Full
UA = 1<<1, // Update Address
RW = 1<<2, // Read/Write info
S = 1<<3, // Start bit (I2C mode)
P = 1<<4, // Stop bit (I2C mode)
DA = 1<<5, // Data/Address bit (I2C mode)
// below are SSP and MSSP only. This class will force them to
// always be 0 if ssptype == SSP_TYPE_BSSP. This will give the
// corrent behavior.
CKE = 1<<6, // SPI clock edge select
SMP = 1<<7 // SPI data input sample phase
};
void setSSPMODULE(SSP_MODULE *);
virtual void put(unsigned int new_value);
virtual void put_value(unsigned int new_value);
private:
SSP_MODULE *m_sspmod;
};
class _SSPBUF : public sfr_register
{
public:
SSP_TYPE ssptype;
_SSPBUF();
virtual void put(unsigned int new_value);
virtual void put_value(unsigned int new_value);
virtual unsigned int get();
virtual unsigned int get_value();
void setSSPMODULE(SSP_MODULE *);
bool isFull() { return m_bIsFull; }
void setFullFlag(bool bNewFull) { m_bIsFull = bNewFull; }
private:
SSP_MODULE *m_sspmod;
bool m_bIsFull;
};
class _SSPADD : public sfr_register
{
public:
void setSSPMODULE(SSP_MODULE *);
virtual void put(unsigned int new_value);
virtual void put_value(unsigned int new_value);
private:
SSP_MODULE *m_sspmod;
};
class SPI: public TriggerObject
{
public:
SSP_MODULE *m_sspmod;
_SSPBUF *m_sspbuf;
_SSPCON *m_sspcon;
_SSPSTAT *m_sspstat;
SPI(SSP_MODULE *, _SSPCON *, _SSPSTAT *, _SSPBUF *);
bool isIdle() { return m_state==eIDLE;}
virtual void clock(bool);
virtual void start_transfer();
virtual void stop_transfer();
void set_halfclock_break();
virtual void callback();
void newSSPBUF(unsigned int);
virtual void startSPI();
private:
unsigned int m_SSPsr; // internal Shift Register
enum SSPStateMachine {
eIDLE,
eACTIVE,
eWAITING_FOR_LAST_SMP
} m_state;
int bits_transfered;
};
class I2C: public TriggerObject
{
public:
SSP_MODULE *m_sspmod;
_SSPBUF *m_sspbuf;
_SSPCON *m_sspcon;
_SSPSTAT *m_sspstat;
_SSPCON2 *m_sspcon2;
_SSPADD *m_sspadd;
I2C(SSP_MODULE *, _SSPCON *, _SSPSTAT *, _SSPBUF *, _SSPCON2 *, _SSPADD *);
virtual void clock(bool);
virtual void sda(bool);
virtual void callback();
virtual void set_idle();
virtual void newSSPBUF(unsigned int value);
virtual void newSSPADD(unsigned int value);
virtual void start_bit();
virtual void rstart_bit();
virtual void stop_bit();
virtual void master_rx();
virtual void ack_bit();
virtual bool isIdle();
virtual void setBRG();
virtual void clrBRG();
virtual bool rx_byte();
virtual void bus_collide();
virtual void slave_command();
virtual bool end_ack();
private:
unsigned int m_SSPsr; // internal Shift Register
enum I2CStateMachine {
eIDLE,
RX_CMD,
RX_CMD2,
RX_DATA,
TX_DATA,
CLK_TX_BYTE,
CLK_RX_BYTE,
CLK_ACKEN,
CLK_RSTART,
CLK_STOP,
CLK_START
} i2c_state;
int bits_transfered;
int phase;
guint64 future_cycle;
};
class SSP_MODULE
{
public:
_SSPBUF sspbuf;
_SSPCON sspcon;
_SSPSTAT sspstat;
_SSPCON2 sspcon2; // MSSP
// set to NULL for BSSP (It doesn't have this register)
_SSPADD sspadd;
SSP_MODULE();
virtual ~SSP_MODULE();
void initialize(PIR_SET *ps,
PinModule *_SckPin,
PinModule *_SdiPin,
PinModule *_SdoPin,
PinModule *_SsPin,
PicTrisRegister *_i2ctris,
SSP_TYPE ssptype = SSP_TYPE_BSSP);
virtual void SDI_SinkState(char);
virtual void SS_SinkState(char);
virtual void SCL_SinkState(char);
virtual bool get_SDI_State() { return m_SDI_State;}
virtual bool get_SCL_State() { return m_SCL_State;}
virtual bool get_SS_State() { return m_SS_State;}
virtual void Sck_toggle() { m_SckSource->toggle();}
virtual void putStateSDO(char _state) {m_SdoSource->putState(_state);}
virtual void putStateSCK(char _state) {m_SckSource->putState(_state);}
virtual void set_sspif() { m_pirset->set_sspif();}
virtual void set_bclif() { m_pirset->set_bclif();}
virtual void startSSP(unsigned int value);
virtual void stopSSP(unsigned int value);
virtual void changeSSP(unsigned int new_value, unsigned int old_value);
virtual void ckpSPI(unsigned int value);
virtual void newSSPBUF(unsigned int value);
virtual void newSSPADD(unsigned int value);
virtual void newSSPCON2(unsigned int value);
virtual void rdSSPBUF();
virtual void tmr2_clock();
virtual SSP_TYPE ssp_type() { return m_ssptype; }
virtual void setSCL(bool);
virtual void setSDA(bool);
virtual bool SaveSSPsr(unsigned int value);
private:
PIR_SET *m_pirset;
SPI *m_spi;
I2C *m_i2c;
PinModule *m_sck;
PinModule *m_ss;
PinModule *m_sdo;
PinModule *m_sdi;
PicTrisRegister *m_i2c_tris;
SSP_TYPE m_ssptype;
bool m_SDI_State;
bool m_SCL_State;
bool m_SS_State;
PeripheralSignalSource *m_SckSource;
PeripheralSignalSource *m_SdoSource;
PeripheralSignalSource *m_SdiSource;
SDI_SignalSink *m_SDI_Sink;
SCL_SignalSink *m_SCL_Sink;
SS_SignalSink *m_SS_Sink;
bool m_sink_set;
};
#endif // __SSP_H__
syntax highlighted by Code2HTML, v. 0.9.1