DOSBox-X
|
00001 00002 #include "dos_inc.h" 00003 #include "setup.h" 00004 #include "8255.h" 00005 00006 Intel8255::Intel8255() { 00007 ppiName = NULL; 00008 pINTR_A = pINTR_B = 0; 00009 for (unsigned int c=0;c < 3;c++) { 00010 portNames[c] = NULL; 00011 for (unsigned int i=0;i < 8;i++) 00012 pinNames[c][i] = NULL; 00013 } 00014 } 00015 00016 Intel8255::~Intel8255() { 00017 } 00018 00019 void Intel8255::reset(void) { 00020 IBF_A = IBF_B = 0; 00021 OBF_A = OBF_B = 0; 00022 INTE_A = INTE_B = 0; 00023 INTE_1 = INTE_2 = 0; 00024 INTR_A = INTR_B = 0; 00025 writeControl(0x9B); /* default: port A input, port B input, port C input mode 0 mode 0 */ 00026 latchOutPortA = 0; 00027 latchOutPortB = 0; 00028 latchOutPortC = 0; 00029 } 00030 00031 uint8_t Intel8255::readPortA(void) { 00032 IBF_A = true; 00033 00034 latchOutPortA = 00035 (latchOutPortA & portAWriteMask ) + 00036 ( inPortA() & (~portAWriteMask)); 00037 00038 updateINTR_A(); 00039 IBF_A = false; 00040 checkINTR_A(); 00041 return latchOutPortA; 00042 } 00043 00044 uint8_t Intel8255::readPortB(void) { 00045 IBF_B = true; 00046 00047 latchOutPortB = 00048 (latchOutPortB & portBWriteMask ) + 00049 ( inPortB() & (~portBWriteMask)); 00050 00051 updateINTR_B(); 00052 IBF_B = false; 00053 checkINTR_B(); 00054 return latchOutPortB; 00055 } 00056 00057 uint8_t Intel8255::readPortC(void) { 00058 latchOutPortC = 00059 (latchOutPortC & portCWriteMask ) + 00060 ( inPortC() & (~portCWriteMask)); 00061 return latchOutPortC; 00062 } 00063 00064 uint8_t Intel8255::readControl(void) { 00065 return mode; /* illegal, but probably reads mode byte */ 00066 } 00067 00068 void Intel8255::writePortA(const uint8_t data,uint8_t mask) { 00069 mask &= portAWriteMask; 00070 latchOutPortA = (latchOutPortA & (~mask)) + (data & mask); 00071 if (mask) { 00072 OBF_A = true; 00073 updateINTR_A(); 00074 outPortA(mask); 00075 checkINTR_A(); 00076 } 00077 } 00078 00079 void Intel8255::writePortB(const uint8_t data,uint8_t mask) { 00080 mask &= portBWriteMask; 00081 latchOutPortB = (latchOutPortB & (~mask)) + (data & mask); 00082 if (mask) { 00083 OBF_B = true; 00084 updateINTR_B(); 00085 outPortB(mask); 00086 checkINTR_B(); 00087 } 00088 } 00089 00090 void Intel8255::writePortC(const uint8_t data,uint8_t mask) { 00091 mask &= portCWriteMask; 00092 latchOutPortC = (latchOutPortC & (~mask)) + (data & mask); 00093 if (mask) outPortC(mask); 00094 } 00095 00096 void Intel8255::writeControl(const uint8_t data) { 00097 if (data & 0x80) { 00098 /* bit[7:7] = 1 mode set flag 00099 * bit[6:5] = mode select 00=mode 0 01=mode 1 1x=mode 2 00100 * bit[4:4] = Port A 1=input 0=output 00101 * bit[3:3] = Port C upper 1=input 0=output 00102 * bit[2:2] = mode select 0=mode 0 1=mode 1 00103 * bit[1:1] = Port B 1=input 0=output 00104 * bit[0:0] = Port C lower 1=input 0=output */ 00105 /* mode byte */ 00106 mode = data; 00107 00108 /* update write masks */ 00109 portAWriteMask = (mode & 0x10) ? 0x00 : 0xFF; /* bit 4 */ 00110 portBWriteMask = (mode & 0x02) ? 0x00 : 0xFF; /* bit 1 */ 00111 portCWriteMask = ((mode & 0x01) ? 0x00 : 0x0F) +/* bit 0 */ 00112 ((mode & 0x08) ? 0x00 : 0xF0); /* bit 3 */ 00113 00114 /* modes take additional bits from port C */ 00115 if (mode & 0x04) { /* port B mode 1 */ 00116 /* port C meanings: 00117 * 00118 * output: 00119 * bit[2:2] = Acknowledge, from device (IN) 00120 * bit[1:1] = Output buffer full aka CPU has written data to this port (OUT) 00121 * bit[0:0] = Interrupt request B (OUT) 00122 * 00123 * input: 00124 * bit[2:2] = Strobe input (loads data into the latch) (IN) 00125 * bit[1:1] = Input buffer full (OUT) 00126 * bit[0:0] = Interrupt request B (OUT) */ 00127 portCWriteMask &= ~0x07; 00128 } 00129 if (mode & 0x40) { /* port A mode 2 */ 00130 /* port C meanings: 00131 * 00132 * bit[7:7] = Output buffer full aka CPU has written data to this port (OUT) 00133 * bit[6:6] = Acknowledge, from device. This latches the output. Else output is high impedance (IN) 00134 * bit[5:5] = Input buffer full (OUT) 00135 * bit[4:4] = Strobe input (loads data into the latch) (IN) 00136 * bit[3:3] = Interrupt request A (OUT) */ 00137 portCWriteMask &= ~0xF8; 00138 } 00139 else if (mode & 0x20) { /* port A mode 1 */ 00140 /* port C meanings: 00141 * 00142 * output: 00143 * bit[7:7] = Output buffer full aka CPU has written data to this port (OUT) 00144 * bit[6:6] = Acknowledge, from device (IN) 00145 * bit[3:3] = Interrupt request A (OUT) 00146 * 00147 * input: 00148 * bit[5:5] = Input buffer full (OUT) 00149 * bit[4:4] = Strobe input (loads data input the latch) (IN) 00150 * bit[3:3] = Interrupt request A (OUT) */ 00151 portCWriteMask &= ~((mode & 0x10) ? 0x38 : 0xC8); 00152 } 00153 00154 /* according to PC-98 hardware it seems changing a port to input makes the latch forget it's contents */ 00155 latchOutPortA &= ~portAWriteMask; 00156 latchOutPortB &= ~portBWriteMask; 00157 latchOutPortC &= ~portCWriteMask; 00158 00159 /* update */ 00160 outPortA(portAWriteMask); 00161 outPortB(portBWriteMask); 00162 outPortC(portCWriteMask); 00163 00164 updateINTR_A(); 00165 updateINTR_B(); 00166 checkINTR_A(); 00167 checkINTR_B(); 00168 } 00169 else { 00170 /* bit[7:7] = 0 bit set/reset 00171 * bit[6:4] = X don't care 00172 * bit[3:1] = bit bit select 00173 * bit[0:0] = set/reset 1=set 0=reset */ 00174 /* single bit set/reset port C */ 00175 const uint8_t bit = ((unsigned int)data >> 1U) & 7U; 00176 00177 if (mode & 0x40) { /* Port A mode 2 */ 00178 if (bit == 4) { 00179 INTE_2 = !!(data & 1); 00180 updateINTR_A(); 00181 checkINTR_A(); 00182 } 00183 else if (bit == 6) { 00184 INTE_1 = !!(data & 1); 00185 updateINTR_A(); 00186 checkINTR_A(); 00187 } 00188 } 00189 else if (mode & 0x20) { /* Port A mode 1 */ 00190 if (bit == ((mode & 0x10) ? /*input*/ 4 : /*output*/6)) { 00191 INTE_A = !!(data & 1); 00192 updateINTR_A(); 00193 checkINTR_A(); 00194 } 00195 } 00196 00197 if (mode & 0x04) { /* Port B mode 1 */ 00198 if (bit == 2) { 00199 INTE_B = !!(data & 1); 00200 updateINTR_B(); 00201 checkINTR_B(); 00202 } 00203 } 00204 00205 writePortC(/*data*/(data & 1U) << bit,/*mask*/1U << bit); 00206 } 00207 } 00208 00209 uint8_t Intel8255::inPortA(void) const { 00210 return 0x00U; /* override this */ 00211 } 00212 00213 uint8_t Intel8255::inPortB(void) const { 00214 return 0x00U; /* override this */ 00215 } 00216 00217 uint8_t Intel8255::inPortC(void) const { 00218 return 0x00U; /* override this */ 00219 } 00220 00221 void Intel8255::outPortA(const uint8_t mask) { 00222 (void)mask;//UNUSED 00223 /* override this */ 00224 } 00225 00226 void Intel8255::outPortB(const uint8_t mask) { 00227 (void)mask;//UNUSED 00228 /* override this */ 00229 } 00230 00231 void Intel8255::outPortC(const uint8_t mask) { 00232 (void)mask;//UNUSED 00233 /* override this */ 00234 } 00235 00236 void Intel8255::updateINTR_A(void) { 00237 if (mode & 0x40) { /* mode 2 */ 00238 INTR_A = (INTE_1 && (!OBF_A)) ^ (INTE_2 && IBF_A); /* OBF goes low when CPU writes, goes high when cleared */ 00239 } 00240 else if (mode & 0x20) { /* mode 1 */ 00241 if (mode & 0x10) /* input */ 00242 INTR_A = INTE_A && IBF_A; 00243 else /* output */ 00244 INTR_A = INTE_A && (!OBF_A); /* OBF goes low when CPU writes, goes high when cleared */ 00245 } 00246 else { 00247 INTR_A = false; 00248 } 00249 } 00250 00251 void Intel8255::updateINTR_B(void) { 00252 if (mode & 0x04) { /* mode 1 */ 00253 if (mode & 0x02) /* input */ 00254 INTR_B = INTE_B && IBF_B; 00255 else /* output */ 00256 INTR_B = INTE_B && (!OBF_B); /* OBF goes low when CPU writes, goes high when cleared */ 00257 } 00258 else { 00259 INTR_B = false; 00260 } 00261 } 00262 00263 void Intel8255::checkINTR_A(void) { 00264 if (pINTR_A != INTR_A) { 00265 pINTR_A = INTR_A; 00266 sigINTR_A(); 00267 } 00268 } 00269 00270 void Intel8255::checkINTR_B(void) { 00271 if (pINTR_B != INTR_B) { 00272 pINTR_B = INTR_B; 00273 sigINTR_B(); 00274 } 00275 } 00276 00277 void Intel8255::sigINTR_A(void) { 00278 /* override this */ 00279 } 00280 00281 void Intel8255::sigINTR_B(void) { 00282 /* override this */ 00283 } 00284 00285 void Intel8255::strobePortA(void) { 00286 readPortA(); /* override this */ 00287 } 00288 00289 void Intel8255::strobePortB(void) { 00290 readPortB(); /* override this */ 00291 } 00292 00293 void Intel8255::ackPortA(void) { 00294 OBF_A = false; 00295 updateINTR_A(); 00296 checkINTR_A(); 00297 } 00298 00299 void Intel8255::ackPortB(void) { 00300 OBF_B = false; 00301 updateINTR_B(); 00302 checkINTR_B(); 00303 } 00304 00305 uint8_t Intel8255::readByPort(uint8_t p03) { 00306 switch (p03) { 00307 case 0: return readPortA(); 00308 case 1: return readPortB(); 00309 case 2: return readPortC(); 00310 case 3: return readControl(); 00311 } 00312 00313 return 0; 00314 } 00315 00316 void Intel8255::writeByPort(uint8_t p03,uint8_t data) { 00317 switch (p03) { 00318 case 0: writePortA(data); break; 00319 case 1: writePortB(data); break; 00320 case 2: writePortC(data); break; 00321 case 3: writeControl(data); break; 00322 } 00323 } 00324