/* 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 __IOPORTS_H__ #define __IOPORTS_H__ #include "registers.h" #include "stimuli.h" class stimulus; class Stimulus_Node; class PinModule; ///**********************************************************************/ /// /// I/O ports /// /// An I/O port is collection of I/O pins. For a PIC processor, these /// are the PORTA, PORTB, etc, registers. gpsim models I/O ports in /// a similar way it models other registers; there's a base class from /// which all specific I/O ports are derived. However, I/O ports are /// special in that they're an interface between a processor's core /// and the outside world. The requirements vary wildly from one processor /// to the next; in fact they even vary dynamically within one processor. /// gpsim attempts to abstract this interface with a set of base classes /// that are responsible for routing signal state information. These /// base classes make no attempt to decipher this information, instead /// this job is left to the peripherals and stimuli connected to the /// I/O pins and ports. /// /// /// PinModule /// /// Here's a general description of gpsim I/O pin design: /// /// Data /// Select ======+ /// +-|-+ Outgoing /// Source1 ===>| M | data /// Source2 ===>| U |=============+ /// SourceN ===>| X | | /// +---+ | +-------+ /// Control +===>| IOPIN | /// Select ======+ | | /// +-|-+ I/O Pin | | /// Control1 ===>| M | Direction | |<======> Physical /// Control2 ===>| U |=================>| | Interface /// ControlN ===>| X | | | /// +---+ | | /// Sink Decode +===<| | /// Select ======+ | +-------+ /// +-|-+ Incoming | /// Sink1 <====| D | data | /// Sink2 <====| E |<============| /// SinkN <====| C | /// +---+ /// /// The PinModule models a Processor's I/O Pin. The schematic illustrates /// the abstract description of the PinModule. Its job is to merge together /// all of the Processor's peripherals that can control a processor's pin. /// For example, a UART peripheral may be shared with a general purpose I/O /// pin. The UART may have a transmit and receive pin and select whether it's /// in control of the I/O pins. The uart transmit pin and the port's I/O pin /// can both act as a source for the physical interface. The PinModule /// arbitrates between the two. Similarly, the UART receive pin can be multiplexed /// with a register pin. In this case, the PinModule will route signal /// changes to both devices. Finally, a peripheral like the '622's comparators /// may overide the output control. The PinModule again arbitrates. /// /// /// PortModule /// /// The PortModule is the base class for processor I/O ports. It's essentially /// a register that contains an array of PinModule's. /// /// Register PortModule /// |-> sfr_register | /// | | /// \------+--------/ /// | /// +--> PortRegister /// |--> PicPortRegister ///------------------------------------------------------------ /// /// SignalControl - A pure virtual class that defines the interface for /// a signal control. The I/O Pin Modules will query the source's state /// via SignalControl. The control is usually used to control the I/O pin /// direction (i.e. whether it's an input or output...), drive value, /// pullup state, etc. class SignalControl { public: virtual char getState()=0; }; ///------------------------------------------------------------ /// SinkRecipient /// Interface class that redirects a driven I/O pin change /// to the appropriate peripheral register that wants the /// change. class SinkRecipient { public: virtual void setState(const char)=0; }; ///------------------------------------------------------------ /// PeripheralSignalSource - A class to interface I/O pins with /// peripheral outputs. class PeripheralSignalSource : public SignalControl { public: PeripheralSignalSource(PinModule *_pin); /// getState - called by the PinModule to determine the source state virtual char getState(); /// putState - called by the peripheral to set a new state virtual void putState(const char new3State); /// toggle - called by the peripheral to toggle the current state. virtual void toggle(); private: PinModule *m_pin; char m_cState; }; ///------------------------------------------------------------ /// PortModule - Manages all of the I/O pins associated with a single /// port. The PortModule supplies the interface to the I/O pin's. It /// is designed to handle a group of I/O pins. However, the low level /// I/O pin processing is handled by PinModule objects contained within /// the PortModule. class PortModule { public: PortModule(unsigned int numIopins); virtual ~PortModule(); /// updatePort -- loop through update all I/O pins virtual void updatePort(); /// updatePin -- Update a single I/O pin virtual void updatePin(unsigned int iPinNumber); /// updateUI -- convey pin state info to a User Interface (e.g. the gui). virtual void updateUI(); /// addPinModule -- supply a pin module at a particular bit position. /// Most of the low level I/O pin related processing will be handled /// here. The PortModule per-pin helper methods below essentially /// call methods in the PinModule to do the dirty work. /// Each bit position can have only one PinModule. If multiple /// modules are added, only the first will be used and the others /// will be ignored. void addPinModule(PinModule *, unsigned int iPinNumber); /// addSource -- supply a pin with a source of data. There may SignalControl *addSource(SignalControl *, unsigned int iPinNumber); /// addControl -- supply a pin with a data direction control SignalControl *addControl(SignalControl *, unsigned int iPinNumber); /// addPullupControl -- supply a pin with a pullup control SignalControl *addPullupControl(SignalControl *, unsigned int iPinNumber); /// addSink -- supply a sink to receive info driven on to a pin SignalSink *addSink(SignalSink *, unsigned int iPinNumber); /// addPin -- supply an I/O pin. Note, this will create a default pin module /// if one is not already created. IOPIN *addPin(IOPIN *, unsigned int iPinNumber); /// getPin -- an I/O pin accessor. This returns the I/O pin at a particular /// bit position. IOPIN *getPin(unsigned int iPinNumber); /// operator[] -- PinModule accessor. This returns the pin module at /// a particular bit position. PinModule &operator [] (unsigned int pin_number); PinModule * getIOpins(unsigned int pin_number); protected: unsigned int mNumIopins; private: /// PinModule -- The array of PinModules that are handled by PortModule. PinModule **iopins; }; ///------------------------------------------------------------ /// PinModule - manages the interface to a physical I/O pin. Both /// simple and complex I/O pins are handled. An example of a simple /// I/O is one where there is a single data source, data sink and /// control, like say the GPIO pin on a small PIC. A complex pin /// is one that is multiplexed with peripherals. /// /// The parent class 'PinMonitor', allows the PinModule to be /// registered with the I/O pin. In other words, when the I/O pin /// changes state, the PinModule will be notified. class PinModule : public PinMonitor { public: PinModule(); PinModule(PortModule *, unsigned int _pinNumber, IOPIN *new_pin=0); virtual ~PinModule() {} /// updatePinModule -- The low level I/O pin state is resolved here /// by examined the direction and state of the I/O pin. void updatePinModule(); /// refreshPinOnUpdate - modal behavior. If set to true, then /// a pin's state will always be refreshed whenever the PinModule /// is updated. If false, then the pin is updated only if there /// is a detected state change. void refreshPinOnUpdate(bool bForcedUpdate); void setPin(IOPIN *); void setDefaultSource(SignalControl *); void setSource(SignalControl *); void setDefaultControl(SignalControl *); void setControl(SignalControl *); void setPullupControl(SignalControl *); void setDefaultPullupControl(SignalControl *); char getControlState(); char getSourceState(); char getPullupControlState(); unsigned int getPinNumber() { return m_pinNumber;} IOPIN &getPin() { return *m_pin;} /// virtual void setDrivenState(char); virtual void setDrivingState(char); virtual void set_nodeVoltage(double); virtual void putState(char); virtual void setDirection(); virtual void updateUI(); private: char m_cLastControlState; char m_cLastSinkState; char m_cLastSourceState; char m_cLastPullupControlState; SignalControl *m_defaultSource, *m_activeSource; SignalControl *m_defaultControl, *m_activeControl; SignalControl *m_defaultPullupControl, *m_activePullupControl; IOPIN *m_pin; PortModule *m_port; unsigned int m_pinNumber; bool m_bForcedUpdate; }; ///------------------------------------------------------------ class PortRegister : public sfr_register, public PortModule { public: PortRegister(unsigned int numIopins, unsigned int enableMask); virtual void put(unsigned int new_value); virtual void put_value(unsigned int new_value); virtual unsigned int get(); virtual unsigned int get_value(); virtual void putDrive(unsigned int new_drivingValue); virtual unsigned int getDriving(); virtual void setbit(unsigned int bit_number, char new_value); virtual void setEnableMask(unsigned int nEnableMask); unsigned int getEnableMask() { return mEnableMask; } virtual void updateUI(); protected: unsigned int mEnableMask; unsigned int drivingValue; RegisterValue rvDrivenValue; }; class PortSink : public SignalSink { public: PortSink(PortRegister *portReg, unsigned int iobit); virtual void setSinkState(char); private: PortRegister *m_PortRegister; unsigned int m_iobit; }; /// IOPORT - Base class for I/O ports - deprecated #if defined(OLD_IOPORT_DESIGN) class IOPORT : public sfr_register { public: IOPORT(unsigned int _num_iopins=8); ~IOPORT(); IOPIN *addPin(IOPIN *, unsigned int iPinNumber); IOPIN *getIO(unsigned int pin_number); virtual void put(unsigned int new_value); virtual void put_value(unsigned int new_value); // setbit() is called when a stimulus writes a value to one // of the I/O pins in this Port. virtual void setbit(unsigned int bit_number, bool new_value); virtual bool get_bit(unsigned int bit_number); virtual unsigned int get(void); virtual unsigned int get_value(void); virtual void trace_register_write(void); protected: /// The I/O pins associated with this I/O port. /// This could be anything (or nothing.) IOPIN **pins; unsigned int valid_iopins, // A mask that for those ports that don't have all 8 io bits. stimulus_mask, // A mask indicating which io bits have a stimulus. internal_latch, // num_iopins; // Number of I/O pins attached to this port // Deprecated functions of the IOPORT class /// Stimuli void attach_stimulus(stimulus *new_stim, unsigned int bit_position); virtual int update_stimuli(void); void attach_iopin(IOPIN * new_pin, unsigned int bit_position); void attach_node(Stimulus_Node *new_node, unsigned int bit_position); virtual double get_bit_voltage(unsigned int bit_number); virtual void change_pin_direction(unsigned int bit_number, bool new_direction); }; #endif // OLD_IOPORT_DESIGN #endif // __IOPORTS_H__