forked from joncampbell123/dosbox-x
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinout.h
192 lines (162 loc) · 6.26 KB
/
inout.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/*
* Copyright (C) 2002-2021 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DOSBOX_INOUT_H
#define DOSBOX_INOUT_H
#include <stdio.h>
#include <stdint.h>
using io_port_t = uint16_t; // DOS only supports 16-bit port addresses
#define IO_MAX (64*1024+3)
#define IO_MB 0x1
#define IO_MW 0x2
#define IO_MD 0x4
#define IO_MA (IO_MB | IO_MW | IO_MD )
class IO_CalloutObject;
typedef Bitu IO_ReadHandler(Bitu port,Bitu iolen);
typedef void IO_WriteHandler(Bitu port,Bitu val,Bitu iolen);
typedef IO_ReadHandler* (IO_ReadCalloutHandler)(IO_CalloutObject &co,Bitu port,Bitu iolen);
typedef IO_WriteHandler* (IO_WriteCalloutHandler)(IO_CalloutObject &co,Bitu port,Bitu iolen);
extern IO_WriteHandler * io_writehandlers[3][IO_MAX];
extern IO_ReadHandler * io_readhandlers[3][IO_MAX];
void IO_RegisterReadHandler(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1);
void IO_RegisterWriteHandler(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1);
void IO_FreeReadHandler(Bitu port,Bitu mask,Bitu range=1);
void IO_FreeWriteHandler(Bitu port,Bitu mask,Bitu range=1);
void IO_InvalidateCachedHandler(Bitu port,Bitu range=1);
void IO_WriteB(Bitu port,uint8_t val);
void IO_WriteW(Bitu port,uint16_t val);
void IO_WriteD(Bitu port,uint32_t val);
uint8_t IO_ReadB(Bitu port);
uint16_t IO_ReadW(Bitu port);
uint32_t IO_ReadD(Bitu port);
static const Bitu IOMASK_ISA_10BIT = 0x3FFU; /* ISA 10-bit decode */
static const Bitu IOMASK_ISA_12BIT = 0xFFFU; /* ISA 12-bit decode */
static const Bitu IOMASK_FULL = 0xFFFFU; /* full 16-bit decode */
/* WARNING: Will only produce a correct result if 'x' is a nonzero power of two.
* For use with IOMASK_Combine.
*
* A device with 16 I/O ports would produce a range mask of:
*
* ~(16 - 1) = ~15 = ~0xF = 0xFFFFFFF0
*
* or
*
* ~(0x10 - 1) = ~0xF = 0xFFFFFFF0
*
*/
static inline constexpr Bitu IOMASK_Range(const Bitu x) {
return ~((Bitu)x - (Bitu)1U);
}
/* combine range mask with IOMASK value.
*
* Example: Sound Blaster 10-bit decode with 16 I/O ports:
*
* IOMASK_Combine(IOMASK_ISA_10BIT,IOMASK_Range(16));
*
*/
static inline constexpr Bitu IOMASK_Combine(const Bitu a,const Bitu b) {
return a & b;
}
/* Classes to manage the IO objects created by the various devices.
* The io objects will remove itself on destruction.*/
class IO_Base{
protected:
bool installed = false;
Bitu m_port, m_mask/*IO_MB, etc.*/, m_range/*number of ports*/;
public:
IO_Base() : m_port(0), m_mask(0), m_range(0) {};
};
/* NTS: To explain the Install() method, the caller not only provides the IOMASK_.. value, but ANDs
* the least significant bits to define the range of I/O ports to respond to. An ISA Sound Blaster
* for example would set portmask = (IOMASK_ISA_10BIT & (~0xF)) in order to respond to 220h-22Fh,
* 240h-24Fh, etc. At I/O callout time, the callout object is tested
* if (cpu_ioport & io_mask) == (m_port & io_mask)
*
* This does not prevent emulation of devices that start on non-aligned ports or strange port ranges,
* because the callout handler is free to decline the I/O request, leading the callout process to
* move on to the next device or mark the I/O port as empty. */
class IO_CalloutObject: private IO_Base {
public:
IO_CalloutObject() : IO_Base() {};
void InvalidateCachedHandlers(void);
void Install(Bitu port,Bitu portmask/*IOMASK_ISA_10BIT, etc.*/,IO_ReadCalloutHandler *r_handler,IO_WriteCalloutHandler *w_handler);
void Uninstall();
public:
uint16_t io_mask = 0xFFFF;
uint16_t range_mask = 0;
uint16_t alias_mask = 0xFFFF;
unsigned int getcounter = 0;
IO_ReadCalloutHandler *m_r_handler = NULL;
IO_WriteCalloutHandler *m_w_handler = NULL;
bool alloc = false;
public:
inline bool MatchPort(const uint16_t p) {
/* (p & io_mask) == (m_port & io_mask) but this also works.
* apparently modern x86 processors are faster at addition/subtraction than bitmasking.
* for this to work, m_port must be a multiple of the I/O range. For example, if the I/O
* range is 16 ports, then m_port must be a multiple of 16. */
return ((p - m_port) & io_mask) == 0;
}
inline bool isInstalled(void) {
return installed;
}
};
class IO_ReadHandleObject: private IO_Base {
public:
IO_ReadHandleObject() : IO_Base() {};
void Install(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1);
void Uninstall();
~IO_ReadHandleObject();
};
class IO_WriteHandleObject: private IO_Base{
public:
IO_WriteHandleObject() : IO_Base() {};
void Install(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1);
void Uninstall();
~IO_WriteHandleObject();
};
static INLINE void IO_Write(Bitu port,uint8_t val) {
IO_WriteB(port,val);
}
static INLINE uint8_t IO_Read(Bitu port){
return IO_ReadB(port);
}
enum IO_Type_t {
IO_TYPE_NONE=0,
IO_TYPE_MIN=1,
IO_TYPE_ISA=1,
IO_TYPE_PCI,
IO_TYPE_MB,
IO_TYPE_MAX
};
void IO_InitCallouts(void);
typedef uint32_t IO_Callout_t;
static inline constexpr uint32_t IO_Callout_t_comb(const enum IO_Type_t t,const uint32_t idx) {
return ((uint32_t)t << (uint32_t)28) + idx;
}
static inline constexpr enum IO_Type_t IO_Callout_t_type(const IO_Callout_t t) {
return (enum IO_Type_t)(t >> 28);
}
static inline constexpr uint32_t IO_Callout_t_index(const IO_Callout_t t) {
return t & (((uint32_t)1 << (uint32_t)28) - (uint32_t)1);
}
static const IO_Callout_t IO_Callout_t_none = (IO_Callout_t)0;
IO_Callout_t IO_AllocateCallout(IO_Type_t t);
void IO_FreeCallout(IO_Callout_t c);
IO_CalloutObject *IO_GetCallout(IO_Callout_t c);
void IO_PutCallout(IO_CalloutObject *obj);
#endif