Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
io_mapper.c
Go to the documentation of this file.
1 /* A work-in-progess MEGA65 (Commodore 65 clone origins) emulator
2  Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
3  I/O decoding part (used by memory_mapper.h and DMA mainly)
4  Copyright (C)2016-2022 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
5 
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
19 
20 #include "xemu/emutools.h"
21 #include "io_mapper.h"
22 #include "memory_mapper.h"
23 #include "xemu/f011_core.h"
24 #include "dma65.h"
25 #include "vic4.h"
26 #include "vic4_palette.h"
27 #include "sdcard.h"
28 #include "hypervisor.h"
29 #include "ethernet65.h"
30 #include "input_devices.h"
31 #include "matrix_mode.h"
32 #include "audio65.h"
33 #include "configdb.h"
34 #include "mega65.h"
35 
36 
37 int fpga_switches = 0; // State of FPGA board switches (bits 0 - 15), set switch 12 (hypervisor serial output)
38 Uint8 D6XX_registers[0x100]; // mega65 specific D6XX range, excluding the UART part (not used here!)
39 Uint8 D7XX[0x100]; // FIXME: hack for future M65 stuffs like ALU! FIXME: no snapshot on these!
40 struct Cia6526 cia1, cia2; // CIA emulation structures for the two CIAs
41 int cpu_mega65_opcodes = 0; // used by the CPU emu as well!
42 static int bigmult_valid_result = 0;
43 int port_d607 = 0xFF; // ugly hack to be able to read extra char row of C65 keyboard
44 
45 
46 static const Uint8 fpga_firmware_version[] = { 'X','e','m','u' };
47 static const Uint8 cpld_firmware_version[] = { 'N','o','w','!' };
48 
49 
50 #define RETURN_ON_IO_READ_NOT_IMPLEMENTED(func, fb) \
51  do { DEBUG("IO: NOT IMPLEMENTED read (emulator lacks feature), %s $%04X fallback to answer $%02X" NL, func, addr, fb); \
52  return fb; } while (0)
53 #define RETURN_ON_IO_WRITE_NOT_IMPLEMENTED(func) \
54  do { DEBUG("IO: NOT IMPLEMENTED write (emulator lacks feature), %s $%04X with data $%02X" NL, func, addr, data); \
55  return; } while(0)
56 
57 
58 static XEMU_INLINE void update_hw_multiplier ( void )
59 {
60  register const Uint32 input_a = xemu_u8p_to_u32le(D7XX + 0x70);
61  register const Uint32 input_b = xemu_u8p_to_u32le(D7XX + 0x74);
62  // Set flag to valid, so we don't relculate each time
63  // (this variable is used to avoid calling this function if no change was
64  // done on input_a and input_b)
65  bigmult_valid_result = 1;
66  // --- Do the product, multiplication ---
67  xemu_u64le_to_u8p(D7XX + 0x78, (Uint64)input_a * (Uint64)input_b);
68  // --- Do the quotient, divide ---
69  // ... but we really don't want to divide by zero, so let's test this
70  if (XEMU_LIKELY(input_b)) {
71  // input_b is non-zero, it's OK to divide
72  xemu_u64le_to_u8p(D7XX + 0x68, (Uint64)((Uint64)input_a << 32) / (Uint64)input_b);
73  } else {
74  // If we divide by zero, according to the VHDL,
75  // we set all bits to '1' in the result, that is $FF
76  // for all registers of div output. Probably it can be
77  // interpreted as some kind of "fixed point infinity"
78  // or just a measure of error with this special answer.
79  memset(D7XX + 0x68, 0xFF, 8);
80  }
81 }
82 
83 
84 
85 /* Internal decoder for I/O reads. Address *must* be within the 0-$3FFF (!!) range. The low 12 bits is the actual address inside the I/O area,
86  while the most significant nibble shows the I/O mode the operation is meant, according to the following table:
87  0 = C64 (VIC-II) I/O mode
88  1 = C65 (VIC-III) I/O mode
89  2 = *INVALID* should not happen, unless some maps the $FF-megabyte M65 specific area, then it should do nothing or so ...
90  3 = M65 (VIC-IV) I/O mode.
91  Even writing the "classic" I/O area at $D000 will ends up here. These addressed are stricly based on the VIC mode
92  according the table above, no $D000 addresses here at all!
93  FIXME: it seems I/O mode "2" may be not invalid, but some tricky stuff, C64 with extensions, or such. I have not so much idea yet :(
94  NOTE: vic_read_reg() and vic_write_reg() is kinda special! It uses offset'ed register addresses for different VIC mode registers ... */
95 
96 Uint8 io_read ( unsigned int addr )
97 {
98  // DEBUG("IO: read $%03X IO_mode is %d @ PC=$%04X" NL, addr & 0xFFF, addr >> 12, cpu65.pc);
99  switch (addr >> 8) {
100  /* ---------------------------------------------------- */
101  /* $D000-$D3FF: VIC-II, VIC-III+FDC+REC, VIC-IV+FDC+REC */
102  /* ---------------------------------------------------- */
103  case 0x00: // $D000-$D0FF ~ C64 I/O mode
104  case 0x01: // $D100-$D1FF ~ C64 I/O mode
105  case 0x02: // $D200-$D2FF ~ C64 I/O mode
106  case 0x03: // $D300-$D3FF ~ C64 I/O mode
107  return vic_read_reg((addr & 0x3F) | 0x100); // VIC-II read register
108  case 0x10: // $D000-$D0FF ~ C65 I/O mode
109  addr &= 0xFF;
110  if (XEMU_LIKELY(addr < 0x80))
111  return vic_read_reg(addr | 0x80); // VIC-III read register
112  if (XEMU_LIKELY(addr < 0xA0))
113  return fdc_read_reg(addr & 0xF);
114  RETURN_ON_IO_READ_NOT_IMPLEMENTED("RAM expansion controller", 0xFF);
115  case 0x30: // $D000-$D0FF ~ M65 I/O mode
116  addr &= 0xFF;
117  if (XEMU_LIKELY(addr < 0x80))
118  return vic_read_reg(addr); // VIC-IV read register
119  if (XEMU_LIKELY(addr < 0xA0))
120  return fdc_read_reg(addr & 0xF);
121  RETURN_ON_IO_READ_NOT_IMPLEMENTED("RAM expansion controller", 0xFF);
122  case 0x11: // $D100-$D1FF ~ C65 I/O mode
123  case 0x12: // $D200-$D2FF ~ C65 I/O mode
124  case 0x13: // $D300-$D3FF ~ C65 I/O mode
125  return 0xFF; // FIXME: AFAIK C65 does not allow to read palette register back, however M65 I/O mode does allow (?)
126  case 0x31: // $D100-$D1FF ~ M65 I/O mode
127  return vic4_read_palette_reg_red(addr); // function takes care using only 8 low bits of addr, no need to do here
128  case 0x32: // $D200-$D2FF ~ M65 I/O mode
130  case 0x33: // $D300-$D3FF ~ M65 I/O mode
132  /* ------------------------------------------------ */
133  /* $D400-$D7FF: SID, SID+UART+DMA, SID+UART+DMA+M65 */
134  /* ------------------------------------------------ */
135  case 0x04: // $D400-$D4FF ~ C64 I/O mode
136  case 0x05: // $D500-$D5FF ~ C64 I/O mode
137  case 0x06: // $D600-$D6FF ~ C64 I/O mode
138  case 0x07: // $D700-$D7FF ~ C64 I/O mode
139  case 0x14: // $D400-$D4FF ~ C65 I/O mode
140  case 0x15: // $D500-$D5FF ~ C65 I/O mode
141  case 0x34: // $D400-$D4FF ~ M65 I/O mode
142  case 0x35: // $D500-$D5FF ~ M65 I/O mode
143  switch (addr & 0x5F) {
144  case 0x19: return get_mouse_x_via_sid();
145  case 0x1A: return get_mouse_y_via_sid();
146  }
147  return 0xFF;
148  case 0x16: // $D600-$D6FF ~ C65 I/O mode
149  RETURN_ON_IO_READ_NOT_IMPLEMENTED("UART", 0xFF); // FIXME: UART is not yet supported!
150  case 0x36: // $D600-$D6FF ~ M65 I/O mode
151  addr &= 0xFF;
152  if (addr < 9)
153  RETURN_ON_IO_READ_NOT_IMPLEMENTED("UART", 0xFF); // FIXME: UART is not yet supported!
154  if (addr >= 0x80 && addr <= 0x93) // SDcard controller etc of MEGA65
155  return sdcard_read_register(addr - 0x80);
156  if ((addr & 0xF0) == 0xE0)
157  return eth65_read_reg(addr);
158  switch (addr) {
159  case 0x7C:
160  return 0; // emulate the "UART is ready" situation (used by some HICKUPs around from v0.11 or so)
161  case 0x7E: // upgraded hypervisor signal
162  if (D6XX_registers[0x7E] == 0x80) // 0x80 means for Xemu (not for a real M65!): ask the user!
164  "Not upgraded yet, it can do it|Already upgraded, I test hicked state",
165  "HICKUP asks hypervisor upgrade state. What do you want Xemu to answer?\n"
166  "(don't worry, it won't be asked again without RESET)"
167  ) ? 0xFF : 0;
168  return D6XX_registers[0x7E];
169  case 0x7F:
170  return in_hypervisor ? 'H' : 'U'; // FIXME: I am not sure about 'U' here (U for userspace, H for hypervisor mode)
171  case 0xF0:
172  return fpga_switches & 0xFF;
173  case 0xF1:
174  return (fpga_switches >> 8) & 0xFF;
175  case 0x10: // last keypress ASCII value
176  return hwa_kbd_get_last();
177  case 0x11: // modifier keys on kbd being used
178  return hwa_kbd_get_modifiers();
179  case 0x13: // $D613: direct access to the kbd matrix, read selected row (set by writing $D614), bit 0 = key pressed
180  return kbd_directscan_query(D6XX_registers[0x14]); // for further explanations please see this function in input_devices.c
181  case 0x29:
182  return configdb.mega65_model; // MEGA65 model
183  case 0x0F:
184  // D60F bit 5, real hardware (1), emulation (0), other bits are not emulated yet by Xemu, so I give simply zero
185  return 0;
186  case 0x1B:
187  // D61B amiga / 1531 mouse auto-detect. FIXME XXX what value we should return at this point? :-O
188  return 0xFF;
189  case 0x32: // D632-D635: FPGA firmware ID
190  case 0x33:
191  case 0x34:
192  case 0x35:
193  return fpga_firmware_version[addr - 0x32];
194  case 0x2C: // D62C-D62F: CPLD firmware ID
195  case 0x2D:
196  case 0x2E:
197  case 0x2F:
198  return cpld_firmware_version[addr - 0x2C];
199  default:
200  DEBUG("MEGA65: reading MEGA65 specific I/O @ $D6%02X result is $%02X" NL, addr, D6XX_registers[addr]);
201  return D6XX_registers[addr];
202  }
203  case 0x17: // $D700-$D7FF ~ C65 I/O mode
204  // FIXME: really a partial deconding like this? really on every 16 bytes?!
205  return dma_read_reg(addr & 0xF);
206  case 0x37: // $D700-$D7FF ~ M65 I/O mode
207  // FIXME: this is probably very bad! I guess DMA does not decode for every 16 addresses ... Proposed fix is here:
208  addr &= 0xFF;
209  if (addr < 15) // FIXME!!!! 0x0F was part of DMA reg array, but it seems now used by divisor busy stuff??
210  return dma_read_reg(addr & 0xF);
211  if (addr == 0x0F)
212  return 0; // FIXME: D70F bit 7 = 32/32 bits divisor busy flag, bit 6 = 32*32 mult busy flag. We're never busy, so the zero. But the OTHER bits??? Any purpose of those??
213  // ;) FIXME this is LAZY not to decode if we need to update bigmult at all ;-P
214  if (XEMU_UNLIKELY(!bigmult_valid_result))
215  update_hw_multiplier();
216  return D7XX[addr];
217  /* ----------------------- */
218  /* $D800-$DBFF: COLOUR RAM */
219  /* ----------------------- */
220  case 0x08: // $D800-$D8FF ~ C64 I/O mode
221  case 0x09: // $D900-$D9FF ~ C64 I/O mode
222  case 0x0A: // $DA00-$DAFF ~ C64 I/O mode
223  case 0x0B: // $DB00-$DBFF ~ C64 I/O mode
224  return colour_ram[addr - 0x0800] | 0xF0; // FIXME: is this true, that high nibble if faked to be '1' in C64 I/O mode, always?
225  case 0x18: // $D800-$D8FF ~ C65 I/O mode
226  case 0x19: // $D900-$D9FF ~ C65 I/O mode
227  case 0x1A: // $DA00-$DAFF ~ C65 I/O mode
228  case 0x1B: // $DB00-$DBFF ~ C65 I/O mode
229  return colour_ram[addr - 0x1800];
230  case 0x38: // $D800-$D8FF ~ M65 I/O mode
231  case 0x39: // $D900-$D9FF ~ M65 I/O mode
232  case 0x3A: // $DA00-$DAFF ~ M65 I/O mode
233  case 0x3B: // $DB00-$DBFF ~ M65 I/O mode
234  return colour_ram[addr - 0x3800];
235  /* --------------------------------------- */
236  /* $DC00-$DCFF: CIA#1, EXTENDED COLOUR RAM */
237  /* --------------------------------------- */
238  case 0x0C: // $DC00-$DCFF ~ C64 I/O mode
239  case 0x1C: // $DC00-$DCFF ~ C65 I/O mode
240  case 0x3C: // $DC00-$DCFF ~ M65 I/O mode
241  return (vic_registers[0x30] & 1) ? colour_ram[0x400 + (addr & 0xFF)] : cia_read(&cia1, addr & 0xF);
242  /* --------------------------------------- */
243  /* $DD00-$DDFF: CIA#2, EXTENDED COLOUR RAM */
244  /* --------------------------------------- */
245  case 0x0D: // $DD00-$DDFF ~ C64 I/O mode
246  case 0x1D: // $DD00-$DDFF ~ C65 I/O mode
247  case 0x3D: // $DD00-$DDFF ~ M65 I/O mode
248  return (vic_registers[0x30] & 1) ? colour_ram[0x500 + (addr & 0xFF)] : cia_read(&cia2, addr & 0xF);
249  /* ----------------------------------------------------- */
250  /* $DE00-$DFFF: IO exp, EXTENDED COLOUR RAM, disk buffer */
251  /* ----------------------------------------------------- */
252  case 0x0E: // $DE00-$DEFF ~ C64 I/O mode
253  case 0x0F: // $DF00-$DFFF ~ C64 I/O mode
254  case 0x1E: // $DE00-$DEFF ~ C65 I/O mode
255  case 0x1F: // $DF00-$DFFF ~ C65 I/O mode
256  case 0x3E: // $DE00-$DEFF ~ M65 I/O mode
257  case 0x3F: // $DF00-$DFFF ~ M65 I/O mode
258  // FIXME: is it really true for *ALL* I/O modes, that colour RAM expansion to 2K and
259  // disk buffer I/O mapping works in all of them??
260  if (vic_registers[0x30] & 1)
261  return colour_ram[0x600 + (addr & 0x1FF)];
263  return disk_buffer_io_mapped[addr & 0x1FF];
264  return 0xFF; // I/O exp is not supported
265  /* --------------------------------------------------------------- */
266  /* $2xxx I/O area is not supported: FIXME: what is that for real?! */
267  /* --------------------------------------------------------------- */
268  case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
269  case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F:
270  return 0xFF;
271  default:
272  FATAL("Xemu internal error: undecoded I/O area reading for address $(%X)%03X", addr >> 8, addr & 0xFFF);
273  }
274 }
275 
276 
277 
278 /* Please read comments at io_read() above, those apply here too.
279  In nutshell: this function *NEEDS* addresses 0-$3FFF based on the given I/O (VIC) mode! */
280 void io_write ( unsigned int addr, Uint8 data )
281 {
282  // DEBUG("IO: write $%03X with data $%02X IO_mode is %d @ PC=$%04X" NL, addr & 0xFFF, data, addr >> 12, cpu65.pc);
283  if (XEMU_UNLIKELY(cpu_rmw_old_data >= 0)) {
284  // RMW handling! FIXME: do this only in the needed I/O ports only, not here, globally!
285  // however, for that, we must check this at every devices where it can make any difference ...
286  Uint8 old_data = cpu_rmw_old_data;
287  cpu_rmw_old_data = -1; // set this back to minus _before_ doing self-call, or it would cause an infinite recursion-like madness ...
288  DEBUG("RMW: I/O internal addr %04X old data %02X new data %02X" NL, addr, old_data, data);
289  io_write(addr, old_data);
290  }
291  switch (addr >> 8) {
292  /* ---------------------------------------------------- */
293  /* $D000-$D3FF: VIC-II, VIC-III+FDC+REC, VIC-IV+FDC+REC */
294  /* ---------------------------------------------------- */
295  case 0x00: // $D000-$D0FF ~ C64 I/O mode
296  case 0x01: // $D100-$D1FF ~ C64 I/O mode
297  case 0x02: // $D200-$D2FF ~ C64 I/O mode
298  case 0x03: // $D300-$D3FF ~ C64 I/O mode
299  vic_write_reg((addr & 0x3F) | 0x100, data); // VIC-II write register
300  return;
301  case 0x10: // $D000-$D0FF ~ C65 I/O mode
302  addr &= 0xFF;
303  if (XEMU_LIKELY(addr < 0x80)) {
304  vic_write_reg(addr | 0x80, data); // VIC-III write register
305  return;
306  }
307  if (XEMU_LIKELY(addr < 0xA0)) {
308  fdc_write_reg(addr & 0xF, data);
309  return;
310  }
311  RETURN_ON_IO_WRITE_NOT_IMPLEMENTED("RAM expansion controller");
312  case 0x30: // $D000-$D0FF ~ M65 I/O mode
313  addr &= 0xFF;
314  if (XEMU_LIKELY(addr < 0x80)) {
315  vic_write_reg(addr, data); // VIC-IV write register
316  return;
317  }
318  if (XEMU_LIKELY(addr < 0xA0)) {
319  fdc_write_reg(addr & 0xF, data);
320  return;
321  }
322  RETURN_ON_IO_WRITE_NOT_IMPLEMENTED("RAM expansion controller");
323  case 0x11: // $D100-$D1FF ~ C65 I/O mode
324  vic3_write_palette_reg_red(addr, data); // function takes care using only 8 low bits of addr, no need to do here
325  return;
326  case 0x12: // $D200-$D2FF ~ C65 I/O mode
328  return;
329  case 0x13: // $D300-$D3FF ~ C65 I/O mode
331  return;
332  case 0x31: // $D100-$D1FF ~ M65 I/O mode
334  return;
335  case 0x32: // $D200-$D2FF ~ M65 I/O mode
337  return;
338  case 0x33: // $D300-$D3FF ~ M65 I/O mode
340  return;
341  /* ------------------------------------------------ */
342  /* $D400-$D7FF: SID, SID+UART+DMA, SID+UART+DMA+M65 */
343  /* ------------------------------------------------ */
344  case 0x04: // $D400-$D4FF ~ C64 I/O mode
345  case 0x05: // $D500-$D5FF ~ C64 I/O mode
346  case 0x06: // $D600-$D6FF ~ C64 I/O mode
347  case 0x07: // $D700-$D7FF ~ C64 I/O mode
348  case 0x14: // $D400-$D4FF ~ C65 I/O mode
349  case 0x15: // $D500-$D5FF ~ C65 I/O mode
350  case 0x34: // $D400-$D4FF ~ M65 I/O mode
351  case 0x35: // $D500-$D5FF ~ M65 I/O mode
352  //sid_write_reg(addr & 0x40 ? &sid[1] : &sid[0], addr & 31, data);
353  //DEBUGPRINT("SID #%d reg#%02X data=%02X" NL, (addr >> 5) & 3, addr & 0x1F, data);
354  //sid_write_reg(&sid[(addr >> 5) & 3], addr & 0x1F, data);
355  audio65_sid_write(addr, data); // We need full addr, audio65_sid_write will decide the SID instance from that!
356  return;
357  case 0x16: // $D600-$D6FF ~ C65 I/O mode
358  if ((addr & 0xFF) == 0x07) {
359  port_d607 = data;
360  return;
361  } else
362  RETURN_ON_IO_WRITE_NOT_IMPLEMENTED("UART"); // FIXME: UART is not yet supported!
363  case 0x36: // $D600-$D6FF ~ M65 I/O mode
364  addr &= 0xFF;
365  if (!in_hypervisor && addr >= 0x40 && addr <= 0x7F) {
366  // In user mode, writing to $D640-$D67F (in VIC4 iomode) causes to enter hypervisor mode with
367  // the trap number given by the offset in this range
369  return;
370  }
371  D6XX_registers[addr] = data; // I guess, the actual write won't happens if it was trapped, so I moved this to here after the previous "if"
372  if (addr < 9) {
373  if (addr == 7) {
374  port_d607 = data;
375  return;
376  } else
377  RETURN_ON_IO_WRITE_NOT_IMPLEMENTED("UART"); // FIXME: UART is not yet supported!
378  }
379  if (addr >= 0x80 && addr <= 0x93) { // SDcard controller etc of MEGA65
381  return;
382  }
383  if ((addr & 0xF0) == 0xE0) {
385  return;
386  }
387  switch (addr) {
388  case 0x10: // ASCII kbd last press value to zero whatever the written data would be
390  return;
391  case 0x11:
393  return;
394  case 0x15:
395  case 0x16:
396  case 0x17:
397  virtkey(addr - 0x15, data & 0x7F);
398  return;
399  case 0x72: // "$D672.6 HCPU:MATRIXEN Enable composited Matrix Mode, and disable UART access to serial monitor."
400  matrix_mode_toggle(data & 0x40);
401  return;
402  case 0x7C: // hypervisor serial monitor port
404  return;
405  case 0x7D:
406  DEBUG("MEGA65: features set as $%02X" NL, data);
407  if ((data & 2) != cpu_mega65_opcodes) {
408  DEBUG("MEGA65: enhanced opcodes have been turned %s." NL, data & 2 ? "ON" : "OFF");
409  cpu_mega65_opcodes = data & 2;
410  }
411  if ((data & 4) != rom_protect) {
412  DEBUG("MEGA65: ROM protection has been turned %s." NL, data & 4 ? "ON" : "OFF");
413  rom_protect = data & 4;
414  }
415  return;
416  case 0x7E:
417  D6XX_registers[0x7E] = 0xFF; // iomap.txt: "Hypervisor already-upgraded bit (sets permanently)"
418  DEBUG("MEGA65: Writing already-hicked register $%04X!" NL, addr);
419  hypervisor_debug_invalidate("$D67E was written, maybe new HICKUP will boot!");
420  return;
421  case 0x7F: // hypervisor leave
422  hypervisor_leave(); // 0x67F is also handled on enter's state, so it will be executed only in_hypervisor mode, which is what I want
423  return;
424  case 0xCF:
425  if (data == 0x42) {
426  if (ARE_YOU_SURE("FPGA reconfiguration request. System must be reset.\nIs it OK to do now?\nAnswering NO may crash your program requesting this task though,\nor can result in endless loop of trying.", ARE_YOU_SURE_DEFAULT_YES)) {
427  reset_mega65();
428  }
429  }
430  return;
431  default:
432  DEBUG("MEGA65: this I/O port is not emulated in Xemu yet: $D6%02X (tried to be written with $%02X)" NL, addr, data);
433  return;
434  }
435  return;
436  case 0x17: // $D700-$D7FF ~ C65 I/O mode
437  // FIXME: really a partial deconding like this? really on every 16 bytes?!
438  dma_write_reg(addr & 0xF, data);
439  return;
440  case 0x37: // $D700-$D7FF ~ M65 I/O mode
441  // FIXME: this is probably very bad! I guess DMA does not decode for every 16 addresses ... Proposed fix is here:
442  addr &= 0xFF;
443  if (addr < 16)
444  dma_write_reg(addr & 0xF, data);
445  //else if (XEMU_UNLIKELY((addr & 0xF0) == BIGMULT_ADDR))
446  else if (addr >= 0x68 && addr <= 0x7F)
447  bigmult_valid_result = 0;
448  D7XX[addr] = data;
449  return;
450  /* ----------------------- */
451  /* $D800-$DBFF: COLOUR RAM */
452  /* ----------------------- */
453  case 0x08: // $D800-$D8FF ~ C64 I/O mode
454  case 0x09: // $D900-$D9FF ~ C64 I/O mode
455  case 0x0A: // $DA00-$DAFF ~ C64 I/O mode
456  case 0x0B: // $DB00-$DBFF ~ C64 I/O mode
457  colour_ram[addr - 0x0800] = data & 0xF; // FIXME: is this true, that high nibble is masked, so switching to C65/M65 mode high nibble will be zero??
458  return;
459  case 0x18: // $D800-$D8FF ~ C65 I/O mode
460  case 0x19: // $D900-$D9FF ~ C65 I/O mode
461  case 0x1A: // $DA00-$DAFF ~ C65 I/O mode
462  case 0x1B: // $DB00-$DBFF ~ C65 I/O mode
463  colour_ram[addr - 0x1800] = data;
464  return;
465  case 0x38: // $D800-$D8FF ~ M65 I/O mode
466  case 0x39: // $D900-$D9FF ~ M65 I/O mode
467  case 0x3A: // $DA00-$DAFF ~ M65 I/O mode
468  case 0x3B: // $DB00-$DBFF ~ M65 I/O mode
469  colour_ram[addr - 0x3800] = data;
470  return;
471  /* --------------------------------------- */
472  /* $DC00-$DCFF: CIA#1, EXTENDED COLOUR RAM */
473  /* --------------------------------------- */
474  case 0x0C: // $DC00-$DCFF ~ C64 I/O mode
475  case 0x1C: // $DC00-$DCFF ~ C65 I/O mode
476  case 0x3C: // $DC00-$DCFF ~ M65 I/O mode
477  if (vic_registers[0x30] & 1)
478  colour_ram[0x400 + (addr & 0xFF)] = data;
479  else
480  cia_write(&cia1, addr & 0xF, data);
481  return;
482  /* --------------------------------------- */
483  /* $DD00-$DDFF: CIA#2, EXTENDED COLOUR RAM */
484  /* --------------------------------------- */
485  case 0x0D: // $DD00-$DDFF ~ C64 I/O mode
486  case 0x1D: // $DD00-$DDFF ~ C65 I/O mode
487  case 0x3D: // $DD00-$DDFF ~ M65 I/O mode
488  if (vic_registers[0x30] & 1)
489  colour_ram[0x500 + (addr & 0xFF)] = data;
490  else
491  cia_write(&cia2, addr & 0xF, data);
492  return;
493  /* ----------------------------------------------------- */
494  /* $DE00-$DFFF: IO exp, EXTENDED COLOUR RAM, disk buffer */
495  /* ----------------------------------------------------- */
496  case 0x0E: // $DE00-$DEFF ~ C64 I/O mode
497  case 0x0F: // $DF00-$DFFF ~ C64 I/O mode
498  case 0x1E: // $DE00-$DEFF ~ C65 I/O mode
499  case 0x1F: // $DF00-$DFFF ~ C65 I/O mode
500  case 0x3E: // $DE00-$DEFF ~ M65 I/O mode
501  case 0x3F: // $DF00-$DFFF ~ M65 I/O mode
502  // FIXME: is it really true for *ALL* I/O modes, that colour RAM expansion to 2K and
503  // disk buffer I/O mapping works in all of them??
504  if (vic_registers[0x30] & 1) {
505  colour_ram[0x600 + (addr & 0x1FF)] = data;
506  return;
507  }
509  disk_buffer_io_mapped[addr & 0x1FF] = data;
510  return;
511  }
512  return; // I/O exp is not supported
513  /* --------------------------------------------------------------- */
514  /* $2xxx I/O area is not supported: FIXME: what is that for real?! */
515  /* --------------------------------------------------------------- */
516  case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
517  case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F:
518  return;
519  default:
520  FATAL("Xemu internal error: undecoded I/O area writing for address $(%X)%03X and data $%02X", addr >> 8, addr & 0xFFF, data);
521  }
522 }
523 
524 
526  return io_read(addr | (vic_iomode << 12));
527 }
528 
529 void io_dma_writer ( int addr, Uint8 data ) {
530  io_write(addr | (vic_iomode << 12), data);
531 }
cpu_rmw_old_data
int cpu_rmw_old_data
Definition: memory_mapper.c:123
vic_read_reg
Uint8 vic_read_reg(int unsigned addr)
Definition: vic4.c:784
cia_read
Uint8 cia_read(struct Cia6526 *cia, int addr)
Definition: cia6526.c:121
vic4.h
cia2
struct Cia6526 cia1 cia2
Definition: io_mapper.c:40
configdb.h
io_dma_writer
void io_dma_writer(int addr, Uint8 data)
Definition: io_mapper.c:529
emutools.h
fdc_read_reg
Uint8 fdc_read_reg(int addr)
Definition: f011_core.c:472
f011_core.h
eth65_write_reg
void eth65_write_reg(int addr, Uint8 data)
Definition: ethernet65.c:419
ethernet65.h
port_d607
int port_d607
Definition: io_mapper.c:43
io_write
void io_write(unsigned int addr, Uint8 data)
Definition: io_mapper.c:280
vic4_write_palette_reg_green
void vic4_write_palette_reg_green(unsigned int num, Uint8 data)
Definition: vic4_palette.c:137
input_devices.h
sdcard_write_register
void sdcard_write_register(int reg, Uint8 data)
Definition: sdcard.c:973
vic3_write_palette_reg_blue
void vic3_write_palette_reg_blue(unsigned int num, Uint8 data)
Definition: vic4_palette.c:171
cpu_mega65_opcodes
int cpu_mega65_opcodes
Definition: io_mapper.c:41
hwa_kbd_disable_selector
void hwa_kbd_disable_selector(int state)
Definition: input_devices.c:86
vic3_write_palette_reg_green
void vic3_write_palette_reg_green(unsigned int num, Uint8 data)
Definition: vic4_palette.c:165
RETURN_ON_IO_READ_NOT_IMPLEMENTED
#define RETURN_ON_IO_READ_NOT_IMPLEMENTED(func, fb)
Definition: io_mapper.c:50
get_mouse_x_via_sid
Uint8 get_mouse_x_via_sid(void)
Definition: input_devices.c:384
colour_ram
Uint8 colour_ram[0x8000]
Definition: memory_mapper.c:65
io_mapper.h
addr
int addr
Definition: dma65.c:81
vic4_read_palette_reg_green
Uint8 vic4_read_palette_reg_green(unsigned int num)
Definition: vic4_palette.c:182
matrix_mode.h
rom_protect
int rom_protect
Definition: memory_mapper.c:144
XEMU_INLINE
#define XEMU_INLINE
Definition: emutools_basicdefs.h:126
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
mega65.h
Uint32
uint32_t Uint32
Definition: fat32.c:49
reset_mega65
void reset_mega65(void)
Definition: mega65.c:492
Uint8
uint8_t Uint8
Definition: fat32.c:51
SD_ST_MAPPED
#define SD_ST_MAPPED
Definition: sdcard.h:26
Cia6526
Definition: cia6526.h:37
io_dma_reader
Uint8 io_dma_reader(int addr)
Definition: io_mapper.c:525
get_mouse_y_via_sid
Uint8 get_mouse_y_via_sid(void)
Definition: input_devices.c:397
virtkey
void virtkey(Uint8 rno, Uint8 scancode)
Definition: input_devices.c:216
sd_status
Uint8 sd_status
Definition: sdcard.c:58
vic4_read_palette_reg_red
Uint8 vic4_read_palette_reg_red(unsigned int num)
Definition: vic4_palette.c:177
disk_buffer_io_mapped
Uint8 * disk_buffer_io_mapped
Definition: sdcard.c:80
hypervisor_leave
void hypervisor_leave(void)
Definition: hypervisor.c:313
kbd_directscan_query
Uint8 kbd_directscan_query(Uint8 row)
Definition: input_devices.c:181
hwa_kbd_get_last
Uint8 hwa_kbd_get_last(void)
Definition: input_devices.c:104
memory_mapper.h
matrix_mode_toggle
void matrix_mode_toggle(int status)
Definition: matrix_mode.c:518
XEMU_LIKELY
#define XEMU_LIKELY(__x__)
Definition: emutools_basicdefs.h:124
hypervisor_debug_invalidate
void hypervisor_debug_invalidate(const char *reason)
Definition: hypervisor.c:411
NL
#define NL
Definition: fat32.c:37
hypervisor.h
configdb
struct configdb_st configdb
Definition: configdb.c:34
fdc_write_reg
void fdc_write_reg(int addr, Uint8 data)
Definition: f011_core.c:277
dma_write_reg
void dma_write_reg(int addr, Uint8 data)
Definition: dma65.c:175
sdcard_read_register
Uint8 sdcard_read_register(int reg)
Definition: sdcard.c:1035
RETURN_ON_IO_WRITE_NOT_IMPLEMENTED
#define RETURN_ON_IO_WRITE_NOT_IMPLEMENTED(func)
Definition: io_mapper.c:53
ARE_YOU_SURE_DEFAULT_YES
#define ARE_YOU_SURE_DEFAULT_YES
Definition: emutools.h:125
vic_write_reg
void vic_write_reg(unsigned int addr, Uint8 data)
Definition: vic4.c:539
fpga_switches
int fpga_switches
Definition: io_mapper.c:37
hypervisor_serial_monitor_push_char
void hypervisor_serial_monitor_push_char(Uint8 chr)
Definition: hypervisor.c:381
dma_read_reg
Uint8 dma_read_reg(int addr)
Definition: dma65.c:502
D6XX_registers
Uint8 D6XX_registers[0x100]
Definition: io_mapper.c:38
vic4_write_palette_reg_blue
void vic4_write_palette_reg_blue(unsigned int num, Uint8 data)
Definition: vic4_palette.c:148
ARE_YOU_SURE
int ARE_YOU_SURE(const char *s, int flags)
Definition: emutools.c:1202
sdcard.h
vic_iomode
int vic_iomode
Definition: vic4.c:44
in_hypervisor
int in_hypervisor
Definition: hypervisor.c:40
vic4_write_palette_reg_red
void vic4_write_palette_reg_red(unsigned int num, Uint8 data)
Definition: vic4_palette.c:126
audio65_sid_write
void audio65_sid_write(const int addr, const Uint8 data)
Definition: audio65.c:98
configdb_st::mega65_model
int mega65_model
Definition: configdb.h:91
dma65.h
QUESTION_WINDOW
#define QUESTION_WINDOW(items, msg)
Definition: xep128.h:124
vic4_palette.h
hwa_kbd_move_next
void hwa_kbd_move_next(void)
Definition: input_devices.c:125
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
vic4_read_palette_reg_blue
Uint8 vic4_read_palette_reg_blue(unsigned int num)
Definition: vic4_palette.c:187
vic3_write_palette_reg_red
void vic3_write_palette_reg_red(unsigned int num, Uint8 data)
Definition: vic4_palette.c:159
FATAL
#define FATAL(...)
Definition: xep128.h:117
D7XX
Uint8 D7XX[0x100]
Definition: io_mapper.c:39
io_read
Uint8 io_read(unsigned int addr)
Definition: io_mapper.c:96
hypervisor_enter_via_write_trap
void hypervisor_enter_via_write_trap(int trapno)
Definition: hypervisor.c:95
vic_registers
Uint8 vic_registers[0x80]
Definition: vic4.c:43
hwa_kbd_get_modifiers
Uint8 hwa_kbd_get_modifiers(void)
Definition: input_devices.c:116
eth65_read_reg
Uint8 eth65_read_reg(int addr)
Definition: ethernet65.c:353
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
audio65.h
cia_write
void cia_write(struct Cia6526 *cia, int addr, Uint8 data)
Definition: cia6526.c:169