2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
12 //#define IO_ADDR_MASK (addr_max - 1)
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"));
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));
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;
42 void IO::write_io8(uint32_t addr, uint32_t data)
44 write_port8(addr, data, false);
47 uint32_t IO::read_io8(uint32_t addr)
49 return read_port8(addr, false);
52 void IO::write_io16(uint32_t addr, uint32_t data)
54 write_port16(addr, data, false);
57 uint32_t IO::read_io16(uint32_t addr)
59 return read_port16(addr, false);
62 void IO::write_io32(uint32_t addr, uint32_t data)
64 write_port32(addr, data, false);
67 uint32_t IO::read_io32(uint32_t addr)
69 return read_port32(addr, false);
72 void IO::write_io8w(uint32_t addr, uint32_t data, int* wait)
74 *wait = wr_table[addr & IO_ADDR_MASK].wait;
75 write_port8(addr, data, false);
78 uint32_t IO::read_io8w(uint32_t addr, int* wait)
80 *wait = rd_table[addr & IO_ADDR_MASK].wait;
81 return read_port8(addr, false);
84 void IO::write_io16w(uint32_t addr, uint32_t data, int* wait)
86 *wait = wr_table[addr & IO_ADDR_MASK].wait;
87 write_port16(addr, data, false);
90 uint32_t IO::read_io16w(uint32_t addr, int* wait)
92 *wait = rd_table[addr & IO_ADDR_MASK].wait;
93 return read_port16(addr, false);
96 void IO::write_io32w(uint32_t addr, uint32_t data, int* wait)
98 *wait = wr_table[addr & IO_ADDR_MASK].wait;
99 write_port32(addr, data, false);
102 uint32_t IO::read_io32w(uint32_t addr, int* wait)
104 *wait = rd_table[addr & IO_ADDR_MASK].wait;
105 return read_port32(addr, false);
108 void IO::write_dma_io8(uint32_t addr, uint32_t data)
110 write_port8(addr, data, true);
113 uint32_t IO::read_dma_io8(uint32_t addr)
115 return read_port8(addr, true);
118 void IO::write_dma_io16(uint32_t addr, uint32_t data)
120 write_port16(addr, data, true);
123 uint32_t IO::read_dma_io16(uint32_t addr)
125 return read_port16(addr, true);
128 void IO::write_dma_io32(uint32_t addr, uint32_t data)
130 write_port32(addr, data, true);
133 uint32_t IO::read_dma_io32(uint32_t addr)
135 return read_port32(addr, true);
138 void IO::write_port8(uint32_t addr, uint32_t data, bool is_dma)
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
144 if(!wr_table[laddr].dev->this_device_id && !wr_table[laddr].is_flipflop) {
145 this->out_debug_log(_T("UNKNOWN:\t"));
148 this->out_debug_log(_T("CPU=%d\t"), cpu_index);
150 this->out_debug_log(_T("%06x\tOUT8\t%04x,%02x\n"), get_cpu_pc(cpu_index), addr, data & 0xff);
153 if(wr_table[laddr].is_flipflop) {
154 rd_table[laddr].value = data & 0xff;
156 wr_table[laddr].dev->write_dma_io8(addr2, data & 0xff);
158 wr_table[laddr].dev->write_io8(addr2, data & 0xff);
162 uint32_t IO::read_port8(uint32_t addr, bool is_dma)
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
169 if(!rd_table[laddr].dev->this_device_id && !rd_table[laddr].value_registered) {
170 this->out_debug_log(_T("UNKNOWN:\t"));
173 this->out_debug_log(_T("CPU=%d\t"), cpu_index);
175 this->out_debug_log(_T("%06x\tIN8\t%04x = %02x\n"), get_cpu_pc(cpu_index), addr, val & 0xff);
181 void IO::write_port16(uint32_t addr, uint32_t data, bool is_dma)
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
187 if(!wr_table[laddr].dev->this_device_id && !wr_table[laddr].is_flipflop) {
188 this->out_debug_log(_T("UNKNOWN:\t"));
191 this->out_debug_log(_T("CPU=%d\t"), cpu_index);
193 this->out_debug_log(_T("%06x\tOUT16\t%04x,%04x\n"), get_cpu_pc(cpu_index), addr, data & 0xffff);
196 if(wr_table[laddr].is_flipflop) {
197 rd_table[laddr].value = data & 0xffff;
199 wr_table[laddr].dev->write_dma_io16(addr2, data & 0xffff);
201 wr_table[laddr].dev->write_io16(addr2, data & 0xffff);
205 uint32_t IO::read_port16(uint32_t addr, bool is_dma)
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
212 if(!rd_table[laddr].dev->this_device_id && !rd_table[laddr].value_registered) {
213 this->out_debug_log(_T("UNKNOWN:\t"));
216 this->out_debug_log(_T("CPU=%d\t"), cpu_index);
218 this->out_debug_log(_T("%06x\tIN16\t%04x = %04x\n"), get_cpu_pc(cpu_index), addr, val & 0xffff);
224 void IO::write_port32(uint32_t addr, uint32_t data, bool is_dma)
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
230 if(!wr_table[laddr].dev->this_device_id && !wr_table[laddr].is_flipflop) {
231 this->out_debug_log(_T("UNKNOWN:\t"));
234 this->out_debug_log(_T("CPU=%d\t"), cpu_index);
236 this->out_debug_log(_T("%06x\tOUT32\t%04x,%08x\n"), get_cpu_pc(cpu_index), addr, data);
239 if(wr_table[laddr].is_flipflop) {
240 rd_table[laddr].value = data;
242 wr_table[laddr].dev->write_dma_io32(addr2, data);
244 wr_table[laddr].dev->write_io32(addr2, data);
248 uint32_t IO::read_port32(uint32_t addr, bool is_dma)
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
255 if(!rd_table[laddr].dev->this_device_id && !rd_table[laddr].value_registered) {
256 this->out_debug_log(_T("UNKNOWN:\t"));
259 this->out_debug_log(_T("CPU=%d\t"), cpu_index);
261 this->out_debug_log(_T("%06x\tIN32\t%04x = %08x\n"), get_cpu_pc(cpu_index), laddr | haddr, val);
269 void IO::set_iomap_single_r(uint32_t addr, DEVICE* device)
271 IO::initialize(); // subclass may overload initialize()
273 rd_table[addr & IO_ADDR_MASK].dev = device;
274 rd_table[addr & IO_ADDR_MASK].addr = addr & IO_ADDR_MASK;
277 void IO::set_iomap_single_w(uint32_t addr, DEVICE* device)
281 wr_table[addr & IO_ADDR_MASK].dev = device;
282 wr_table[addr & IO_ADDR_MASK].addr = addr & IO_ADDR_MASK;
285 void IO::set_iomap_single_rw(uint32_t addr, DEVICE* device)
287 set_iomap_single_r(addr, device);
288 set_iomap_single_w(addr, device);
291 void IO::set_iomap_alias_r(uint32_t addr, DEVICE* device, uint32_t alias)
295 rd_table[addr & IO_ADDR_MASK].dev = device;
296 rd_table[addr & IO_ADDR_MASK].addr = alias & IO_ADDR_MASK;
299 void IO::set_iomap_alias_w(uint32_t addr, DEVICE* device, uint32_t alias)
303 wr_table[addr & IO_ADDR_MASK].dev = device;
304 wr_table[addr & IO_ADDR_MASK].addr = alias & IO_ADDR_MASK;
307 void IO::set_iomap_alias_rw(uint32_t addr, DEVICE* device, uint32_t alias)
309 set_iomap_alias_r(addr, device, alias);
310 set_iomap_alias_w(addr, device, alias);
313 void IO::set_iomap_range_r(uint32_t s, uint32_t e, DEVICE* device)
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;
323 void IO::set_iomap_range_w(uint32_t s, uint32_t e, DEVICE* device)
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;
333 void IO::set_iomap_range_rw(uint32_t s, uint32_t e, DEVICE* device)
335 set_iomap_range_r(s, e, device);
336 set_iomap_range_w(s, e, device);
339 void IO::set_iovalue_single_r(uint32_t addr, uint32_t value)
343 rd_table[addr & IO_ADDR_MASK].value = value;
344 rd_table[addr & IO_ADDR_MASK].value_registered = true;
347 void IO::set_iovalue_range_r(uint32_t s, uint32_t e, uint32_t value)
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;
357 void IO::set_flipflop_single_rw(uint32_t addr, uint32_t value)
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;
366 void IO::set_flipflop_range_rw(uint32_t s, uint32_t e, uint32_t value)
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;
377 void IO::set_iowait_single_r(uint32_t addr, int wait)
381 rd_table[addr & IO_ADDR_MASK].wait = wait;
384 void IO::set_iowait_single_w(uint32_t addr, int wait)
388 wr_table[addr & IO_ADDR_MASK].wait = wait;
391 void IO::set_iowait_single_rw(uint32_t addr, int wait)
393 set_iowait_single_r(addr, wait);
394 set_iowait_single_w(addr, wait);
397 void IO::set_iowait_range_r(uint32_t s, uint32_t e, int wait)
401 for(uint32_t i = s; i <= e; i++) {
402 rd_table[i & IO_ADDR_MASK].wait = wait;
406 void IO::set_iowait_range_w(uint32_t s, uint32_t e, int wait)
410 for(uint32_t i = s; i <= e; i++) {
411 wr_table[i & IO_ADDR_MASK].wait = wait;
415 void IO::set_iowait_range_rw(uint32_t s, uint32_t e, int wait)
417 set_iowait_range_r(s, e, wait);
418 set_iowait_range_w(s, e, wait);
421 #define STATE_VERSION 1
423 bool IO::process_state(FILEIO* state_fio, bool loading)
425 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
429 if(!state_fio->StateCheckInt32(this_device_id)) {
432 for(int i = 0; i < addr_max; i++) {
433 state_fio->StateValue(rd_table[i].value);