mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-07 18:36:09 +08:00
177 lines
7.4 KiB
C++
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 : "";
|
|
}
|
|
};
|