dosbox-x/include/8255.h
2021-08-22 15:47:10 +09:00

177 lines
7.4 KiB
C++

//! \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.
//!
//! <a target="_blank" href="http://hackipedia.org/browse/Hardware/By%20company/Intel/8255,%20Programmable%20Peripheral%20Interface/8255A,%208255A-5%20Programmable%20Peripheral%20Interface%20(1991-08).pdf">Intel 8255A datasheet</a>
//!
//! 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 : "";
}
};