//! \brief Intel 8255 base emulation class //! //! \description Intel 8255 Programmable Peripheral Interface emulation class. //! The base class handles the functions and register I/O to //! emulate the 8255, while the subclass implements behavior //! of hardware attached to the 8255. //! //! All emulation is written to follow Intel's datasheet as //! closely as possible. //! //! Intel 8255A datasheet //! //! NOTE: Mode 2 emulation has NOT been tested yet! class Intel8255 { public: //! //! Port enumeration (A, B, and C) //! enum { //! Port A (input or output) PortA=0, //! Port B (input or output) PortB=1, //! Port C (input, output, or half input half output) PortC=2 }; public: //! Constructor Intel8255(); //! Destructor virtual ~Intel8255(); public: //! Reset state (as if activating reset signal) void reset(void); //! External acknowledgement of port A void ackPortA(void); //! External acknowledgement of port B void ackPortB(void); //! Strobed Input (latch to port A) virtual void strobePortA(void); //! Strobed Input (latch to port B) virtual void strobePortB(void); //! Called when CPU reads port A uint8_t readPortA(void); //! Called when CPU reads port B uint8_t readPortB(void); //! Called when CPU reads port C uint8_t readPortC(void); //! Called when CPU reads control port uint8_t readControl(void); //! Called when CPU reads from the chip uint8_t readByPort(const uint8_t p03); //! Called when CPU writes port A void writePortA(const uint8_t data,uint8_t mask=0xFFU); //! Called when CPU writes port B void writePortB(const uint8_t data,uint8_t mask=0xFFU); //! Called when CPU writes port C void writePortC(const uint8_t data,uint8_t mask=0xFFU); //! Called when CPU writes control port void writeControl(const uint8_t data); //! Called when CPU writes to the chip void writeByPort(const uint8_t p03,const uint8_t data); public: //! Called by 8255 emulation to latch from port A pins virtual uint8_t inPortA(void) const; //! Called by 8255 emulation to latch from port B pins virtual uint8_t inPortB(void) const; //! Called by 8255 emulation to latch from port C pins virtual uint8_t inPortC(void) const; public: //! Called by 8255 emulation when latching to port A pins virtual void outPortA(const uint8_t mask); //! Called by 8255 emulation when latching to port B pins virtual void outPortB(const uint8_t mask); //! Called by 8255 emulation when latching to port C pins virtual void outPortC(const uint8_t mask); public: //! Internal 8255 emulation code to update INTR A signal void updateINTR_A(void); //! Internal 8255 emulation code to update INTR B signal void updateINTR_B(void); public: //! Internal 8255 emulation code to check INTR A change and dispatch signal void checkINTR_A(void); //! Internal 8255 emulation code to check INTR B change and dispatch signal void checkINTR_B(void); public: //! Called by 8255 emulation when INTR A signal changes to dispatch signal virtual void sigINTR_A(void); //! Called by 8255 emulation when INTR B signal changes to dispatch signal virtual void sigINTR_B(void); public: //! \brief Retrieve the name of this chip (for debug/UI purposes) inline const char* getName(void) const { return nil_if_null(ppiName); } public: //! \brief Retrieve the name of a pin on the chip related to port A, B, or C (what it's connected to) (for debug/UI purposes) inline const char* pinName(const unsigned int port,const unsigned int i) const { return nil_if_null(pinNames[port][i]); } //! \brief Retrieve the name of a port (A, B, or C) (for debug/UI purposes) inline const char* portName(const unsigned int port) const { return nil_if_null(portNames[port]); } public: //! Port A write mask. Controls which bits are writeable uint8_t portAWriteMask = 0; //! Port B write mask. Controls which bits are writeable uint8_t portBWriteMask = 0; //! Port C write mask. Controls which bits are writeable uint8_t portCWriteMask = 0; public: //! PPI chip name (for debug/UI purposes) const char* ppiName; public: //! Pin names (for debug/UI purposes) const char* pinNames[3/*port*/][8/*bit*/] = {}; //! Port names (for debug/UI purposes) const char* portNames[3/*port*/] = {}; public: //! Port A output latch uint8_t latchOutPortA = 0; //! Port B output latch uint8_t latchOutPortB = 0; //! Port C output latch uint8_t latchOutPortC = 0; //! PPI mode byte uint8_t mode = 0; /* bit[7:7] = 1 mode set flag * bit[6:5] = mode select 00=mode 0 01=mode 1 1x=mode 2 * bit[4:4] = Port A 1=input 0=output * bit[3:3] = Port C upper 1=input 0=output * bit[2:2] = mode select 0=mode 0 1=mode 1 * bit[1:1] = Port B 1=input 0=output * bit[0:0] = Port C lower 1=input 0=output */ public: //! Input Buffer Full, port A contains information (port A, Mode 1) bool IBF_A = false; //! Input Buffer Full, port B contains information (port B, Mode 1) bool IBF_B = false; //! Output Buffer Full, port A contains information for the external device (port A, Mode 1) bool OBF_A = false; //! Output Buffer Full, port B contains information for the external device (port B, Mode 1) bool OBF_B = false; public: //! Interrupt Request A (to the microprocessor) bool INTR_A = false; //! Interrupt Request B (to the microprocessor) bool INTR_B = false; //! Previous Interrupt Request A state (for change detection) bool pINTR_A = false; //! Previous Interrupt Request B state (for change detection) bool pINTR_B = false; public: //! Interrupt 1 enable (mode 2) bool INTE_1 = false; //! Interrupt 2 enable (mode 2) bool INTE_2 = false; /* mode 2 */ //! Interrupt A enable bool INTE_A = false; //! Interrupt B enable bool INTE_B = false; protected: //! Return string "str", or "" (empty string) if str == NULL static inline const char *nil_if_null(const char *str) { return (str != NULL) ? str : ""; } };