OSDN Git Service

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