DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #ifndef DOSBOX_INOUT_H 00021 #define DOSBOX_INOUT_H 00022 00023 #include <stdio.h> 00024 #include <stdint.h> 00025 00026 #define IO_MAX (64*1024+3) 00027 00028 #define IO_MB 0x1 00029 #define IO_MW 0x2 00030 #define IO_MD 0x4 00031 #define IO_MA (IO_MB | IO_MW | IO_MD ) 00032 00033 class IO_CalloutObject; 00034 00035 typedef Bitu IO_ReadHandler(Bitu port,Bitu iolen); 00036 typedef void IO_WriteHandler(Bitu port,Bitu val,Bitu iolen); 00037 00038 typedef IO_ReadHandler* (IO_ReadCalloutHandler)(IO_CalloutObject &co,Bitu port,Bitu iolen); 00039 typedef IO_WriteHandler* (IO_WriteCalloutHandler)(IO_CalloutObject &co,Bitu port,Bitu iolen); 00040 00041 extern IO_WriteHandler * io_writehandlers[3][IO_MAX]; 00042 extern IO_ReadHandler * io_readhandlers[3][IO_MAX]; 00043 00044 void IO_RegisterReadHandler(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1); 00045 void IO_RegisterWriteHandler(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1); 00046 00047 void IO_FreeReadHandler(Bitu port,Bitu mask,Bitu range=1); 00048 void IO_FreeWriteHandler(Bitu port,Bitu mask,Bitu range=1); 00049 00050 void IO_InvalidateCachedHandler(Bitu port,Bitu range=1); 00051 00052 void IO_WriteB(Bitu port,Bit8u val); 00053 void IO_WriteW(Bitu port,Bit16u val); 00054 void IO_WriteD(Bitu port,Bit32u val); 00055 00056 Bit8u IO_ReadB(Bitu port); 00057 Bit16u IO_ReadW(Bitu port); 00058 Bit32u IO_ReadD(Bitu port); 00059 00060 static const Bitu IOMASK_ISA_10BIT = 0x3FFU; /* ISA 10-bit decode */ 00061 static const Bitu IOMASK_ISA_12BIT = 0xFFFU; /* ISA 12-bit decode */ 00062 static const Bitu IOMASK_FULL = 0xFFFFU; /* full 16-bit decode */ 00063 00064 /* WARNING: Will only produce a correct result if 'x' is a nonzero power of two. 00065 * For use with IOMASK_Combine. 00066 * 00067 * A device with 16 I/O ports would produce a range mask of: 00068 * 00069 * ~(16 - 1) = ~15 = ~0xF = 0xFFFFFFF0 00070 * 00071 * or 00072 * 00073 * ~(0x10 - 1) = ~0xF = 0xFFFFFFF0 00074 * 00075 */ 00076 static inline constexpr Bitu IOMASK_Range(const Bitu x) { 00077 return ~((Bitu)x - (Bitu)1U); 00078 } 00079 00080 /* combine range mask with IOMASK value. 00081 * 00082 * Example: Sound Blaster 10-bit decode with 16 I/O ports: 00083 * 00084 * IOMASK_Combine(IOMASK_ISA_10BIT,IOMASK_Range(16)); 00085 * 00086 */ 00087 static inline constexpr Bitu IOMASK_Combine(const Bitu a,const Bitu b) { 00088 return a & b; 00089 } 00090 00091 /* Classes to manage the IO objects created by the various devices. 00092 * The io objects will remove itself on destruction.*/ 00093 class IO_Base{ 00094 protected: 00095 bool installed; 00096 Bitu m_port, m_mask/*IO_MB, etc.*/, m_range/*number of ports*/; 00097 public: 00098 IO_Base() : installed(false), m_port(0), m_mask(0), m_range(0) {}; 00099 }; 00100 /* NTS: To explain the Install() method, the caller not only provides the IOMASK_.. value, but ANDs 00101 * the least significant bits to define the range of I/O ports to respond to. An ISA Sound Blaster 00102 * for example would set portmask = (IOMASK_ISA_10BIT & (~0xF)) in order to respond to 220h-22Fh, 00103 * 240h-24Fh, etc. At I/O callout time, the callout object is tested 00104 * if (cpu_ioport & io_mask) == (m_port & io_mask) 00105 * 00106 * This does not prevent emulation of devices that start on non-aligned ports or strange port ranges, 00107 * because the callout handler is free to decline the I/O request, leading the callout process to 00108 * move on to the next device or mark the I/O port as empty. */ 00109 class IO_CalloutObject: private IO_Base { 00110 public: 00111 IO_CalloutObject() : IO_Base(), io_mask(0xFFFFU), range_mask(0U), alias_mask(0xFFFFU), getcounter(0), m_r_handler(NULL), m_w_handler(NULL), alloc(false) {}; 00112 void InvalidateCachedHandlers(void); 00113 void Install(Bitu port,Bitu portmask/*IOMASK_ISA_10BIT, etc.*/,IO_ReadCalloutHandler *r_handler,IO_WriteCalloutHandler *w_handler); 00114 void Uninstall(); 00115 public: 00116 Bit16u io_mask; 00117 Bit16u range_mask; 00118 Bit16u alias_mask; 00119 unsigned int getcounter; 00120 IO_ReadCalloutHandler *m_r_handler; 00121 IO_WriteCalloutHandler *m_w_handler; 00122 bool alloc; 00123 public: 00124 inline bool MatchPort(const Bit16u p) { 00125 /* (p & io_mask) == (m_port & io_mask) but this also works. 00126 * apparently modern x86 processors are faster at addition/subtraction than bitmasking. 00127 * for this to work, m_port must be a multiple of the I/O range. For example, if the I/O 00128 * range is 16 ports, then m_port must be a multiple of 16. */ 00129 return ((p - m_port) & io_mask) == 0; 00130 } 00131 inline bool isInstalled(void) { 00132 return installed; 00133 } 00134 }; 00135 class IO_ReadHandleObject: private IO_Base { 00136 public: 00137 IO_ReadHandleObject() : IO_Base() {}; 00138 void Install(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1); 00139 void Uninstall(); 00140 ~IO_ReadHandleObject(); 00141 }; 00142 class IO_WriteHandleObject: private IO_Base{ 00143 public: 00144 IO_WriteHandleObject() : IO_Base() {}; 00145 void Install(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1); 00146 void Uninstall(); 00147 ~IO_WriteHandleObject(); 00148 }; 00149 00150 static INLINE void IO_Write(Bitu port,Bit8u val) { 00151 IO_WriteB(port,val); 00152 } 00153 static INLINE Bit8u IO_Read(Bitu port){ 00154 return IO_ReadB(port); 00155 } 00156 00157 enum IO_Type_t { 00158 IO_TYPE_NONE=0, 00159 IO_TYPE_MIN=1, 00160 IO_TYPE_ISA=1, 00161 IO_TYPE_PCI, 00162 IO_TYPE_MB, 00163 00164 IO_TYPE_MAX 00165 }; 00166 00167 void IO_InitCallouts(void); 00168 00169 typedef uint32_t IO_Callout_t; 00170 00171 static inline constexpr uint32_t IO_Callout_t_comb(const enum IO_Type_t t,const uint32_t idx) { 00172 return ((uint32_t)t << (uint32_t)28) + idx; 00173 } 00174 00175 static inline constexpr enum IO_Type_t IO_Callout_t_type(const IO_Callout_t t) { 00176 return (enum IO_Type_t)(t >> 28); 00177 } 00178 00179 static inline constexpr uint32_t IO_Callout_t_index(const IO_Callout_t t) { 00180 return t & (((uint32_t)1 << (uint32_t)28) - (uint32_t)1); 00181 } 00182 00183 static const IO_Callout_t IO_Callout_t_none = (IO_Callout_t)0; 00184 00185 IO_Callout_t IO_AllocateCallout(IO_Type_t t); 00186 void IO_FreeCallout(IO_Callout_t c); 00187 IO_CalloutObject *IO_GetCallout(IO_Callout_t c); 00188 void IO_PutCallout(IO_CalloutObject *obj); 00189 00190 #endif