OSDN Git Service

[GENERAL] Merge upstream 2018-03-01.
[csp-qt/common_source_project-fm7.git] / source / src / vm / io.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2008.12.29 -
6
7         [ i/o bus ]
8 */
9
10 #include "io.h"
11
12 #define IO_ADDR_MASK (addr_max - 1)
13
14 void IO::initialize()
15 {
16         // allocate tables here to support multiple instances with different address range
17         if(wr_table == NULL) {
18                 wr_table = (wr_bank_t *)calloc(addr_max, sizeof(wr_bank_t));
19                 rd_table = (rd_bank_t *)calloc(addr_max, sizeof(rd_bank_t));
20                 
21                 // vm->dummy must be generated first !
22                 for(int i = 0; i < addr_max; i++) {
23                         wr_table[i].dev = rd_table[i].dev = vm->dummy;
24                         wr_table[i].addr = rd_table[i].addr = i;
25                 }
26         }
27 }
28
29 void IO::release()
30 {
31         free(wr_table);
32         free(rd_table);
33 }
34
35 void IO::write_io8(uint32_t addr, uint32_t data)
36 {
37         write_port8(addr, data, false);
38 }
39
40 uint32_t IO::read_io8(uint32_t addr)
41 {
42         return read_port8(addr, false);
43 }
44
45 void IO::write_io16(uint32_t addr, uint32_t data)
46 {
47         write_port16(addr, data, false);
48 }
49
50 uint32_t IO::read_io16(uint32_t addr)
51 {
52         return read_port16(addr, false);
53 }
54
55 void IO::write_io32(uint32_t addr, uint32_t data)
56 {
57         write_port32(addr, data, false);
58 }
59
60 uint32_t IO::read_io32(uint32_t addr)
61 {
62         return read_port32(addr, false);
63 }
64
65 void IO::write_io8w(uint32_t addr, uint32_t data, int* wait)
66 {
67         *wait = wr_table[addr & IO_ADDR_MASK].wait;
68         write_port8(addr, data, false);
69 }
70
71 uint32_t IO::read_io8w(uint32_t addr, int* wait)
72 {
73         *wait = rd_table[addr & IO_ADDR_MASK].wait;
74         return read_port8(addr, false);
75 }
76
77 void IO::write_io16w(uint32_t addr, uint32_t data, int* wait)
78 {
79         *wait = wr_table[addr & IO_ADDR_MASK].wait;
80         write_port16(addr, data, false);
81 }
82
83 uint32_t IO::read_io16w(uint32_t addr, int* wait)
84 {
85         *wait = rd_table[addr & IO_ADDR_MASK].wait;
86         return read_port16(addr, false);
87 }
88
89 void IO::write_io32w(uint32_t addr, uint32_t data, int* wait)
90 {
91         *wait = wr_table[addr & IO_ADDR_MASK].wait;
92         write_port32(addr, data, false);
93 }
94
95 uint32_t IO::read_io32w(uint32_t addr, int* wait)
96 {
97         *wait = rd_table[addr & IO_ADDR_MASK].wait;
98         return read_port32(addr, false);
99 }
100
101 void IO::write_dma_io8(uint32_t addr, uint32_t data)
102 {
103         write_port8(addr, data, true);
104 }
105
106 uint32_t IO::read_dma_io8(uint32_t addr)
107 {
108         return read_port8(addr, true);
109 }
110
111 void IO::write_dma_io16(uint32_t addr, uint32_t data)
112 {
113         write_port16(addr, data, true);
114 }
115
116 uint32_t IO::read_dma_io16(uint32_t addr)
117 {
118         return read_port16(addr, true);
119 }
120
121 void IO::write_dma_io32(uint32_t addr, uint32_t data)
122 {
123         write_port32(addr, data, true);
124 }
125
126 uint32_t IO::read_dma_io32(uint32_t addr)
127 {
128         return read_port32(addr, true);
129 }
130
131 void IO::write_port8(uint32_t addr, uint32_t data, bool is_dma)
132 {
133         uint32_t laddr = addr & IO_ADDR_MASK, haddr = addr & ~IO_ADDR_MASK;
134         uint32_t addr2 = haddr | wr_table[laddr].addr;
135 #ifdef _IO_DEBUG_LOG
136         if(!wr_table[laddr].dev->this_device_id && !wr_table[laddr].is_flipflop) {
137                 this->out_debug_log(_T("UNKNOWN:\t"));
138         }
139         this->out_debug_log(_T("%06x\tOUT8\t%04x,%02x\n"), get_cpu_pc(cpu_index), addr, data);
140 #endif
141         if(wr_table[laddr].is_flipflop) {
142                 rd_table[laddr].value = data & 0xff;
143         } else if(is_dma) {
144                 wr_table[laddr].dev->write_dma_io8(addr2, data & 0xff);
145         } else {
146                 wr_table[laddr].dev->write_io8(addr2, data & 0xff);
147         }
148 }
149
150 uint32_t IO::read_port8(uint32_t addr, bool is_dma)
151 {
152         uint32_t laddr = addr & IO_ADDR_MASK, haddr = addr & ~IO_ADDR_MASK;
153         uint32_t addr2 = haddr | rd_table[laddr].addr;
154         uint32_t val = rd_table[laddr].value_registered ? rd_table[laddr].value : is_dma ? rd_table[laddr].dev->read_dma_io8(addr2) : rd_table[laddr].dev->read_io8(addr2);
155 #ifdef _IO_DEBUG_LOG
156         if(!rd_table[laddr].dev->this_device_id && !rd_table[laddr].value_registered) {
157                 this->out_debug_log(_T("UNKNOWN:\t"));
158         }
159         this->out_debug_log(_T("%06x\tIN8\t%04x = %02x\n"), get_cpu_pc(cpu_index), addr, val);
160 #endif
161         return val & 0xff;
162 }
163
164 void IO::write_port16(uint32_t addr, uint32_t data, bool is_dma)
165 {
166         uint32_t laddr = addr & IO_ADDR_MASK, haddr = addr & ~IO_ADDR_MASK;
167         uint32_t addr2 = haddr | wr_table[laddr].addr;
168 #ifdef _IO_DEBUG_LOG
169         if(!wr_table[laddr].dev->this_device_id && !wr_table[laddr].is_flipflop) {
170                 this->out_debug_log(_T("UNKNOWN:\t"));
171         }
172         this->out_debug_log(_T("%06x\tOUT16\t%04x,%04x\n"), get_cpu_pc(cpu_index), addr, data);
173 #endif
174         if(wr_table[laddr].is_flipflop) {
175                 rd_table[laddr].value = data & 0xffff;
176         } else if(is_dma) {
177                 wr_table[laddr].dev->write_dma_io16(addr2, data & 0xffff);
178         } else {
179                 wr_table[laddr].dev->write_io16(addr2, data & 0xffff);
180         }
181 }
182
183 uint32_t IO::read_port16(uint32_t addr, bool is_dma)
184 {
185         uint32_t laddr = addr & IO_ADDR_MASK, haddr = addr & ~IO_ADDR_MASK;
186         uint32_t addr2 = haddr | rd_table[laddr].addr;
187         uint32_t val = rd_table[laddr].value_registered ? rd_table[laddr].value : is_dma ? rd_table[laddr].dev->read_dma_io16(addr2) : rd_table[laddr].dev->read_io16(addr2);
188 #ifdef _IO_DEBUG_LOG
189         if(!rd_table[laddr].dev->this_device_id && !rd_table[laddr].value_registered) {
190                 this->out_debug_log(_T("UNKNOWN:\t"));
191         }
192         this->out_debug_log(_T("%06x\tIN16\t%04x = %04x\n"), get_cpu_pc(cpu_index), addr, val);
193 #endif
194         return val & 0xffff;
195 }
196
197 void IO::write_port32(uint32_t addr, uint32_t data, bool is_dma)
198 {
199         uint32_t laddr = addr & IO_ADDR_MASK, haddr = addr & ~IO_ADDR_MASK;
200         uint32_t addr2 = haddr | wr_table[laddr].addr;
201 #ifdef _IO_DEBUG_LOG
202         if(!wr_table[laddr].dev->this_device_id && !wr_table[laddr].is_flipflop) {
203                 this->out_debug_log(_T("UNKNOWN:\t"));
204         }
205         this->out_debug_log(_T("%06x\tOUT32\t%04x,%08x\n"), get_cpu_pc(cpu_index), addr, data);
206 #endif
207         if(wr_table[laddr].is_flipflop) {
208                 rd_table[laddr].value = data;
209         } else if(is_dma) {
210                 wr_table[laddr].dev->write_dma_io32(addr2, data);
211         } else {
212                 wr_table[laddr].dev->write_io32(addr2, data);
213         }
214 }
215
216 uint32_t IO::read_port32(uint32_t addr, bool is_dma)
217 {
218         uint32_t laddr = addr & IO_ADDR_MASK, haddr = addr & ~IO_ADDR_MASK;
219         uint32_t addr2 = haddr | rd_table[laddr].addr;
220         uint32_t val = rd_table[laddr].value_registered ? rd_table[laddr].value : is_dma ? rd_table[laddr].dev->read_dma_io32(addr2) : rd_table[laddr].dev->read_io32(addr2);
221 #ifdef _IO_DEBUG_LOG
222         if(!rd_table[laddr].dev->this_device_id && !rd_table[laddr].value_registered) {
223                 this->out_debug_log(_T("UNKNOWN:\t"));
224         }
225         this->out_debug_log(_T("%06x\tIN32\t%04x = %08x\n"), get_cpu_pc(cpu_index), laddr | haddr, val);
226 #endif
227         return val;
228 }
229
230 // register
231
232 void IO::set_iomap_single_r(uint32_t addr, DEVICE* device)
233 {
234         IO::initialize(); // subclass may overload initialize()
235         
236         rd_table[addr & IO_ADDR_MASK].dev = device;
237         rd_table[addr & IO_ADDR_MASK].addr = addr & IO_ADDR_MASK;
238 }
239
240 void IO::set_iomap_single_w(uint32_t addr, DEVICE* device)
241 {
242         IO::initialize();
243         
244         wr_table[addr & IO_ADDR_MASK].dev = device;
245         wr_table[addr & IO_ADDR_MASK].addr = addr & IO_ADDR_MASK;
246 }
247
248 void IO::set_iomap_single_rw(uint32_t addr, DEVICE* device)
249 {
250         set_iomap_single_r(addr, device);
251         set_iomap_single_w(addr, device);
252 }
253
254 void IO::set_iomap_alias_r(uint32_t addr, DEVICE* device, uint32_t alias)
255 {
256         IO::initialize();
257         
258         rd_table[addr & IO_ADDR_MASK].dev = device;
259         rd_table[addr & IO_ADDR_MASK].addr = alias & IO_ADDR_MASK;
260 }
261
262 void IO::set_iomap_alias_w(uint32_t addr, DEVICE* device, uint32_t alias)
263 {
264         IO::initialize();
265         
266         wr_table[addr & IO_ADDR_MASK].dev = device;
267         wr_table[addr & IO_ADDR_MASK].addr = alias & IO_ADDR_MASK;
268 }
269
270 void IO::set_iomap_alias_rw(uint32_t addr, DEVICE* device, uint32_t alias)
271 {
272         set_iomap_alias_r(addr, device, alias);
273         set_iomap_alias_w(addr, device, alias);
274 }
275
276 void IO::set_iomap_range_r(uint32_t s, uint32_t e, DEVICE* device)
277 {
278         IO::initialize();
279         
280         for(uint32_t i = s; i <= e; i++) {
281                 rd_table[i & IO_ADDR_MASK].dev = device;
282                 rd_table[i & IO_ADDR_MASK].addr = i & IO_ADDR_MASK;
283         }
284 }
285
286 void IO::set_iomap_range_w(uint32_t s, uint32_t e, DEVICE* device)
287 {
288         IO::initialize();
289         
290         for(uint32_t i = s; i <= e; i++) {
291                 wr_table[i & IO_ADDR_MASK].dev = device;
292                 wr_table[i & IO_ADDR_MASK].addr = i & IO_ADDR_MASK;
293         }
294 }
295
296 void IO::set_iomap_range_rw(uint32_t s, uint32_t e, DEVICE* device)
297 {
298         set_iomap_range_r(s, e, device);
299         set_iomap_range_w(s, e, device);
300 }
301
302 void IO::set_iovalue_single_r(uint32_t addr, uint32_t value)
303 {
304         IO::initialize();
305         
306         rd_table[addr & IO_ADDR_MASK].value = value;
307         rd_table[addr & IO_ADDR_MASK].value_registered = true;
308 }
309
310 void IO::set_iovalue_range_r(uint32_t s, uint32_t e, uint32_t value)
311 {
312         IO::initialize();
313         
314         for(uint32_t i = s; i <= e; i++) {
315                 rd_table[i & IO_ADDR_MASK].value = value;
316                 rd_table[i & IO_ADDR_MASK].value_registered = true;
317         }
318 }
319
320 void IO::set_flipflop_single_rw(uint32_t addr, uint32_t value)
321 {
322         IO::initialize();
323         
324         wr_table[addr & IO_ADDR_MASK].is_flipflop = true;
325         rd_table[addr & IO_ADDR_MASK].value = value;
326         rd_table[addr & IO_ADDR_MASK].value_registered = true;
327 }
328
329 void IO::set_flipflop_range_rw(uint32_t s, uint32_t e, uint32_t value)
330 {
331         IO::initialize();
332         
333         for(uint32_t i = s; i <= e; i++) {
334                 wr_table[i & IO_ADDR_MASK].is_flipflop = true;
335                 rd_table[i & IO_ADDR_MASK].value = value;
336                 rd_table[i & IO_ADDR_MASK].value_registered = true;
337         }
338 }
339
340 void IO::set_iowait_single_r(uint32_t addr, int wait)
341 {
342         IO::initialize();
343         
344         rd_table[addr & IO_ADDR_MASK].wait = wait;
345 }
346
347 void IO::set_iowait_single_w(uint32_t addr, int wait)
348 {
349         IO::initialize();
350         
351         wr_table[addr & IO_ADDR_MASK].wait = wait;
352 }
353
354 void IO::set_iowait_single_rw(uint32_t addr, int wait)
355 {
356         set_iowait_single_r(addr, wait);
357         set_iowait_single_w(addr, wait);
358 }
359
360 void IO::set_iowait_range_r(uint32_t s, uint32_t e, int wait)
361 {
362         IO::initialize();
363         
364         for(uint32_t i = s; i <= e; i++) {
365                 rd_table[i & IO_ADDR_MASK].wait = wait;
366         }
367 }
368
369 void IO::set_iowait_range_w(uint32_t s, uint32_t e, int wait)
370 {
371         IO::initialize();
372         
373         for(uint32_t i = s; i <= e; i++) {
374                 wr_table[i & IO_ADDR_MASK].wait = wait;
375         }
376 }
377
378 void IO::set_iowait_range_rw(uint32_t s, uint32_t e, int wait)
379 {
380         set_iowait_range_r(s, e, wait);
381         set_iowait_range_w(s, e, wait);
382 }
383
384 #define STATE_VERSION   1
385
386 void IO::save_state(FILEIO* state_fio)
387 {
388         state_fio->FputUint32(STATE_VERSION);
389         state_fio->FputInt32(this_device_id);
390         
391         for(int i = 0; i < addr_max; i++) {
392                 state_fio->FputUint32(rd_table[i].value);
393         }
394 }
395
396 bool IO::load_state(FILEIO* state_fio)
397 {
398         if(state_fio->FgetUint32() != STATE_VERSION) {
399                 return false;
400         }
401         if(state_fio->FgetInt32() != this_device_id) {
402                 return false;
403         }
404         for(int i = 0; i < addr_max; i++) {
405                 rd_table[i].value = state_fio->FgetUint32();
406         }
407         return true;
408 }
409