DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
include/inout.h
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