OSDN Git Service

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