Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
memory_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  Copyright (C)2017-2022 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18 
19 
20 // This source tries to present a bit complex but seems to be optimized solution
21 // for memory+I/O decoding on M65.
22 // Currently there is *NO* emulation of different speed (ie wait-states) of given
23 // memory blocks, and that would slow down the emulation as well to always check
24 // that information as well.
25 
26 
27 #include "xemu/emutools.h"
28 #include "memory_mapper.h"
29 #include "mega65.h"
30 #include "io_mapper.h"
31 #include "xemu/cpu65.h"
32 #include "hypervisor.h"
33 #include "vic4.h"
34 #include "dma65.h"
35 #include "ethernet65.h"
36 #include "audio65.h"
37 #include "sdcard.h"
38 #include <string.h>
39 
40 #define ALLOW_CPU_CUSTOM_FUNCTIONS_INCLUDE
41 #include "cpu_custom_functions.h"
42 
43 //#define DEBUGMEM DEBUG
44 
45 
46 // 512K is the max "main" RAM. Currently only 384K is used by M65
47 Uint8 main_ram[512 << 10];
48 
49 // Ugly hack for more RAM!
50 #define chip_ram (main_ram + 0)
51 #define fast_ram (main_ram + 0x20000)
52 #define extra_ram (main_ram + 0x40000)
53 
54 
55 // 128K of "chip-RAM". VIC-IV in M65 can see this, though the last 2K is also covered by the first 2K of the colour RAM.
56 // that area from chip-RAM cannot be modified by the CPU/DMA/etc though since the colour RAM is there. We emulate anyway
57 // 128K of chip-RAM so we don't need to check memory access limit all the time in VIC-IV emulation. But it's still true,
58 // that the last 2K of chip-RAM is a "static" content and not so much useful.
59 //Uint8 chip_ram[0x20000];
60 // 128K of "fast-RAM". In English, this is C65 ROM, but on M65 you can actually write this area too, and you can use it
61 // as normal RAM. However VIC-IV cannot see this.
62 //Uint8 fast_ram[0x20000];
63 // 32K of colour RAM. VIC-IV can see this as for colour information only. The first 2K can be seen at the last 2K of
64 // the chip-RAM. Also, the first 1 or 2K can be seen in the C64-style I/O area too, at $D800
65 Uint8 colour_ram[0x8000];
66 // Write-Only memory (WOM) for character fetch when it would be the ROM (on C64 eg)
67 Uint8 char_wom[0x2000];
68 // 16K of hypervisor RAM, can be only seen in hypervisor mode.
70 // 64 bytes of NVRAM
72 // 8 bytes of UUID
74 // RTC registers
76 
78 
79 
81  int start, end; // starting and ending physical address of a memory region
84 };
85 
86 
87 // table of readers/writers for 256 byte CPU pages are "public" (not static) as will be used
88 // from inlined function in the CPU emulator core level for better performance.
89 // The second 256 entries are for unmapped all-RAM cache.
90 // The extra elements over 0x200 used for ROM and I/O mapping, DMA access decoding, and 32 bit opcodes.
91 
92 #define MEM_SLOT_C64_8KROM_A000 0x200
93 #define MEM_SLOT_C64_4KROM_D000 0x220
94 #define MEM_SLOT_OLD_4K_IO_D000 0x230
95 #define MEM_SLOT_C64_8KROM_E000 0x240
96 #define MEM_SLOT_C65_8KROM_8000 0x260
97 #define MEM_SLOT_C65_8KROM_A000 0x280
98 #define MEM_SLOT_C65_8KROM_E000 0x2A0
99 #define MEM_SLOT_C65_4KROM_C000 0x2C0
100 #define MEM_SLOT_DMA_RD_SRC 0x2D0
101 #define MEM_SLOT_DMA_WR_SRC 0x2D1
102 #define MEM_SLOT_DMA_RD_DST 0x2D2
103 #define MEM_SLOT_DMA_WR_DST 0x2D3
104 #define MEM_SLOT_DMA_RD_LST 0x2D4
105 #define MEM_SLOT_CPU_32BIT 0x2D5
106 #define MEM_SLOT_DEBUG_RESOLVER 0x2D6
107 #define MEM_SLOTS 0x2D7
108 
109 #define VIC3_ROM_MASK_8000 0x08
110 #define VIC3_ROM_MASK_A000 0x10
111 #define VIC3_ROM_MASK_C000 0x20
112 #define VIC3_ROM_MASK_E000 0x80
113 
114 #define MAP_MARKER_DUMMY_OFFSET 0x2000
115 
116 static int mem_page_phys[MEM_SLOTS] MAXALIGNED;
121 static const struct m65_memory_map_st *mem_page_refp[MEM_SLOTS];
122 
124 
125 static int applied_memcfg[9]; // not 8, since one slot is actually halved because of CXXX/DXXX handled differently
126 static int memcfg_cpu_io_port_policy_A000_to_BFFF;
127 static int memcfg_cpu_io_port_policy_D000_to_DFFF;
128 static int memcfg_cpu_io_port_policy_E000_to_FFFF;
129 
130 static const int memcfg_cpu_io_port_policies_A000_to_BFFF[8] = {
131  0x1A0, 0x1A0, 0x1A0, MEM_SLOT_C64_8KROM_A000, 0x1A0, 0x1A0, 0x1A0, MEM_SLOT_C64_8KROM_A000
132 };
133 static const int memcfg_cpu_io_port_policies_D000_to_DFFF[8] = {
135 };
136 static const int memcfg_cpu_io_port_policies_E000_to_FFFF[8] = {
138 };
139 
140 static Uint8 memcfg_vic3_rom_mapping_last, memcfg_cpu_io_port_last;
141 static Uint8 cpu_io_port[2];
143 static int map_marker_low, map_marker_high;
146 
147 
148 #define DEFINE_READER(name) static Uint8 name ( MEMORY_HANDLERS_ADDR_TYPE )
149 #define DEFINE_WRITER(name) static void name ( MEMORY_HANDLERS_ADDR_TYPE, Uint8 data )
150 
151 DEFINE_READER(zero_physical_page_reader) {
153 }
154 DEFINE_WRITER(zero_physical_page_writer)
155 {
158  else
160 }
161 DEFINE_READER(opl3_reader) {
162  return 0xFF;
163 }
164 DEFINE_WRITER(opl3_writer) {
166 }
167 DEFINE_READER(chip_ram_from_page1_reader) {
168  return chip_ram[GET_READER_OFFSET() + 0x100];
169 }
170 DEFINE_WRITER(chip_ram_from_page1_writer) {
171  chip_ram[GET_WRITER_OFFSET() + 0x100] = data;
172 }
173 DEFINE_READER(fast_ram_reader) {
174  return fast_ram[GET_READER_OFFSET()];
175 }
176 DEFINE_WRITER(fast_ram_writer) {
177  if (XEMU_LIKELY(!rom_protect))
179 }
180 DEFINE_READER(extra_ram_reader) {
181  return extra_ram[GET_READER_OFFSET()];
182 }
183 DEFINE_WRITER(extra_ram_writer) {
185 }
186 DEFINE_READER(colour_ram_reader) {
187  return colour_ram[GET_READER_OFFSET()];
188 }
189 DEFINE_WRITER(colour_ram_writer) {
191  // we also need the update the "real" RAM
192  //main_ram[GET_WRITER_OFFSET() & 2047] = data;
193 }
194 DEFINE_READER(dummy_reader) {
195  return 0xFF;
196 }
197 DEFINE_WRITER(dummy_writer) {
198 }
199 DEFINE_READER(hypervisor_ram_reader) {
201 }
202 DEFINE_WRITER(hypervisor_ram_writer) {
205 }
206 DEFINE_WRITER(char_wom_writer) { // Note: there is NO read for this, as it's write-only memory!
208 }
209 DEFINE_READER(slow_ram_reader) {
210  return slow_ram[GET_READER_OFFSET()];
211 }
212 DEFINE_WRITER(slow_ram_writer) {
214 }
215 DEFINE_READER(invalid_mem_reader) {
216  char msg[128];
217  sprintf(msg, "Unhandled memory read operation for linear address $%X (PC=$%04X)", GET_READER_OFFSET(), cpu65.pc);
218  if (skip_unhandled_mem <= 1)
219  skip_unhandled_mem = QUESTION_WINDOW("EXIT|Ignore now|Ignore all|Silent ignore all", msg);
220  switch (skip_unhandled_mem) {
221  case 0:
222  XEMUEXIT(1);
223  break;
224  case 1:
225  case 2:
226  DEBUGPRINT("WARNING: %s" NL, msg);
227  break;
228  default:
229  DEBUG("WARNING: %s" NL, msg);
230  break;
231  }
232  return 0xFF;
233 }
234 DEFINE_WRITER(invalid_mem_writer) {
235  char msg[128];
236  sprintf(msg, "Unhandled memory write operation for linear address $%X data = $%02X (PC=$%04X)", GET_WRITER_OFFSET(), data, cpu65.pc);
237  if (skip_unhandled_mem <= 1)
238  skip_unhandled_mem = QUESTION_WINDOW("EXIT|Ignore now|Ignore all|Silent ignore all", msg);
239  switch (skip_unhandled_mem) {
240  case 0:
241  FATAL("Exit on request after illegal memory access");
242  break;
243  case 1:
244  case 2:
245  DEBUGPRINT("WARNING: %s" NL, msg);
246  break;
247  default:
248  DEBUG("WARNING: %s" NL, msg);
249  break;
250  }
251 }
252 DEFINE_READER(fatal_mem_reader) {
253  FATAL("Unhandled physical memory mapping on read map. Xemu software bug?");
254 }
255 DEFINE_WRITER(fatal_mem_writer) {
256  FATAL("Unhandled physical memory mapping on write map. Xemu software bug?");
257 }
258 DEFINE_READER(unreferenced_mem_reader) {
259  FATAL("Unreferenced physical memory mapping on read map. Xemu software bug?");
260 }
261 DEFINE_WRITER(unreferenced_mem_writer) {
262  FATAL("Unreferenced physical memory mapping on write map. Xemu software bug?");
263 }
264 DEFINE_READER(m65_io_reader) {
265  return io_read(GET_READER_OFFSET());
266 }
267 DEFINE_WRITER(m65_io_writer) {
269 }
270 DEFINE_READER(legacy_io_reader) {
271  return io_read(GET_READER_OFFSET() | (vic_iomode << 12));
272 }
273 DEFINE_WRITER(legacy_io_writer) {
275 }
276 DEFINE_READER(eth_buffer_reader) {
278 }
279 DEFINE_WRITER(eth_buffer_writer) {
281 }
282 DEFINE_READER(disk_buffers_reader) {
283  const unsigned int offs = GET_READER_OFFSET();
284  if (in_hypervisor)
285  return disk_buffers[offs];
286  else
287  return disk_buffer_cpu_view[offs & 0x1FF];
288 }
289 DEFINE_WRITER(disk_buffers_writer) {
290  const unsigned int offs = GET_WRITER_OFFSET();
291  if (in_hypervisor)
292  disk_buffers[offs] = data;
293  else
294  disk_buffer_cpu_view[offs & 0x1FF] = data;
295 }
296 DEFINE_READER(i2c_io_reader) {
297  int addr = GET_READER_OFFSET();
298  Uint8 data = 0x00; // initial value, if nothing match (unknown I2C to Xemu?)
299  switch (addr) {
300  case 0x100: // 8 bytes of UUID (64 bit value)
301  case 0x101:
302  case 0x102:
303  case 0x103:
304  case 0x104:
305  case 0x105:
306  case 0x106:
307  case 0x107:
308  data = mega65_uuid[addr & 7];
309  break;
310  case 0x110: // RTC: seconds BCD
311  case 0x111: // RTC: minutes BCD
312  case 0x112: // RTC: hours BCD
313  case 0x113: // RTC: day of month BCD
314  case 0x114: // RTC: month BCD
315  case 0x115: // RTC: year BCD
316  data = rtc_regs[addr - 0x110];
317  break;
318  default:
319  if (addr > 0x140 && addr <= 0x17F)
320  data = nvram[addr - 0x140];
321  break;
322  }
323  return data;
324 }
325 DEFINE_WRITER(i2c_io_writer) {
326  int addr = GET_WRITER_OFFSET();
327  switch (addr) {
328  default:
329  if (addr > 0x140 && addr <= 0x17F)
330  nvram[addr - 0x140] = data;
331  break;
332  }
333 }
334 
335 // Memory layout table for MEGA65
336 // Please note, that for optimization considerations, it should be organized in a way
337 // to have most common entries first, for faster hit in most cases.
338 static const struct m65_memory_map_st m65_memory_map[] = {
339  // 126K chip-RAM (last 2K is not availbale because it's colour RAM), with physical zero page excluded (this is because it needs the CPU port handled with different handler!)
340  { 0x100, 0x1F7FF, chip_ram_from_page1_reader, chip_ram_from_page1_writer },
341  // the "physical" zero page because of CPU port ...
342  { 0, 0xFF, zero_physical_page_reader, zero_physical_page_writer },
343  // 128K of fast-RAM, normally ROM for C65, but can be RAM too!
344  { 0x20000, 0x3FFFF, fast_ram_reader, fast_ram_writer },
345  { 0x40000, 0x5FFFF, extra_ram_reader, extra_ram_writer },
346  // the last 2K of the first 128K, being the first 2K of the colour RAM (quite nice sentence in my opinion)
347  { 0x1F800, 0x1FFFF, colour_ram_reader, colour_ram_writer },
348  // As I/O can be handled quite uniformely, and needs other decoding later anyway, we handle the WHOLE I/O area for all modes in once!
349  // This is 16K space, though one 4K is invalid for I/O modes ($FFD2000-$FFD2FFF), the sequence: C64,C65,INVALID,M65 of 4Ks
350  { 0xFFD0000, 0xFFD3FFF, m65_io_reader, m65_io_writer },
351  // full colour RAM
352  { 0xFF80000, 0xFF87FFF, colour_ram_reader, colour_ram_writer }, // full colour RAM (32K)
353  { 0xFFF8000, 0xFFFBFFF, hypervisor_ram_reader, hypervisor_ram_writer }, // 16KB HYPPO hickup/hypervisor ROM
354  { 0xFF7E000, 0xFF7FFFF, dummy_reader, char_wom_writer }, // Character "WriteOnlyMemory"
355  { 0xFFDE800, 0xFFDEFFF, eth_buffer_reader, eth_buffer_writer }, // ethernet RX/TX buffer, NOTE: the same address, reading is always the RX_read, writing is always TX_write
356  { 0xFFD6000, 0xFFD6FFF, disk_buffers_reader, disk_buffers_writer }, // disk buffer for SD (can be mapped to I/O space too), F011, and some "3.5K scratch space" [??]
357  { 0xFFD7000, 0xFFD7FFF, i2c_io_reader, i2c_io_writer }, // I2C devices
358  { 0x8000000, 0x8000000 + SLOW_RAM_SIZE - 1, slow_ram_reader, slow_ram_writer }, // "slow RAM" also called "hyper RAM" (not to be confused with hypervisor RAM!)
359  { 0x8000000 + SLOW_RAM_SIZE, 0xFDFFFFF, dummy_reader, dummy_writer }, // ununsed big part of the "slow RAM" or so ...
360  { 0x4000000, 0x7FFFFFF, dummy_reader, dummy_writer }, // slow RAM memory area, not exactly known what it's for, let's define as "dummy"
361  { 0xFE00000, 0xFE000FF, opl3_reader, opl3_writer },
362  { 0x60000, 0xFFFFF, dummy_reader, dummy_writer }, // upper "unused" area of C65 (!) memory map. It seems C65 ROMs want it (Expansion RAM?) so we define as unused.
363  // the last entry *MUST* include the all possible addressing space to "catch" undecoded memory area accesses!!
364  { 0, 0xFFFFFFF, invalid_mem_reader, invalid_mem_writer },
365  // even after the last entry :-) to filter out programming bugs, catch all possible even not valid M65 physical address space acceses ...
366  { INT_MIN, INT_MAX, fatal_mem_reader, fatal_mem_writer }
367 };
368 // a mapping item which NEVER matches (ie, starting address of region is higher then ending ...)
369 static const struct m65_memory_map_st impossible_mapping = {
370  0x10000001, 0x10000000, unreferenced_mem_reader, unreferenced_mem_writer
371 };
372 
373 
374 
375 
376 
377 
378 
379 
380 static void phys_addr_decoder ( int phys, int slot, int hint_slot )
381 {
382  const struct m65_memory_map_st *p;
383  phys &= 0xFFFFF00; // we map only at 256 bytes boundaries!!!! It also helps to wrap around 28 bit M65 addresses TODO/FIXME: is this correct behaviour?
384  if (mem_page_phys[slot] == phys) // kind of "mapping cache" for the given cache slot
385  return; // skip, if the slot already contains info on the current physical address
386  mem_page_phys[slot] = phys;
387  // tricky part: if hint_slot is non-negative, it's used for "contiunity" information related to this slot,
388  // ie check, if the current map request can be fit into the region already mapped by hint_slot, then no
389  // need for the search loop. hint_slot can be any slot, but logically it's sane to be used when the given
390  // hint_slot is "likely" to have some contiunity with the slot given by "slot" otherwise it's just makes
391  // thing worse. If not used, hint_slot should be negative to skip this feature. hint_slot can be even same
392  // as "slot" if you need a "moving" mapping in a "caching" slot, ie DMA-aux access functions, etc.
393  if (hint_slot >= 0 && mem_page_refp[hint_slot]->end < 0xFFFFFFF) { // FIXME there was a serious bug here, taking invalid mem slot for anything after hinting that
394  p = mem_page_refp[hint_slot];
395  if (phys >= p->start && phys <= p->end) {
396 #ifdef DEBUGMEM
397  DEBUGMEM("MEM: PHYS-MAP: slot#$%03X: slot hint TAKEN :)" NL, slot);
398 #endif
399  goto found;
400  }
401  }
402  // Scan the memory map, as not found "cached" result on the same slot, or by the hinting slot
403  for (p = m65_memory_map; phys < p->start || phys > p->end; p++)
404  ;
405 found:
406  mem_page_rd_o[slot] = mem_page_wr_o[slot] = phys - p->start;
407  mem_page_rd_f[slot] = p->rd_f;
408  mem_page_wr_f[slot] = p->wr_f;
409  //if (p->rd_f == invalid_mem_reader)
410  // FATAL("Invalid memory region is tried to be mapped to slot $%X for phys addr $%X" NL, slot, phys);
411  mem_page_refp[slot] = p;
412 #ifdef DEBUGMEM
413  DEBUGMEM("MEM: PHYS-MAP: slot#$%03X: phys = $%X mapped (area: $%X-$%X, rd_o=%X, wr_o=%X) [hint slot was: %03X]" NL,
414  slot,
415  phys,
416  p->start, p->end,
417  mem_page_rd_o[slot], mem_page_wr_o[slot],
418  hint_slot
419  );
420 #endif
421 }
422 
423 
424 static void XEMU_INLINE phys_addr_decoder_array ( int megabyte_offset, int offset, int slot, int slots, int hint_slot )
425 {
426  for (;;) {
427  // we try to use the "hint_slot" feature, which tries to optimize table building with exploiting the
428  // fact, that "likely" the next page table entry suits into the same physical decoding "entry" just
429  // with different offset (so we don't need to re-walk the memory configuration table)
430  phys_addr_decoder(megabyte_offset | (offset & 0xFFFFF), slot, hint_slot);
431  if (!--slots)
432  return;
433  hint_slot = slot++;
434  offset += 0x100;
435  }
436 }
437 
438 
439 #define MEM_TABLE_COPY(to,from,pages) do { \
440  memcpy(mem_page_rd_o + (to), mem_page_rd_o + (from), sizeof(int) * (pages)); \
441  memcpy(mem_page_wr_o + (to), mem_page_wr_o + (from), sizeof(int) * (pages)); \
442  memcpy(mem_page_rd_f + (to), mem_page_rd_f + (from), sizeof(mem_page_rd_f_type) * (pages)); \
443  memcpy(mem_page_wr_f + (to), mem_page_wr_f + (from), sizeof(mem_page_wr_f_type) * (pages)); \
444  memcpy(mem_page_refp + (to), mem_page_refp + (from), sizeof(const struct m65_memory_map_st*) * (pages)); \
445  memcpy(mem_page_phys + (to), mem_page_phys + (from), sizeof(int) * (pages)); \
446 } while (0)
447 
448 
449 
450 // Not a performance critical function, since it's only needed at emulator init time
451 static void init_helper_custom_memtab_policy (
452  int rd_o, // custom read-offset to set, apply value -1 for not to change
453  mem_page_rd_f_type rd_f, // custom read-function to set, apply NULL for not to change
454  int wr_o,
456  int slot, // starting slot
457  int slots // number of slots
458 ) {
459  while (slots--) {
460  if (rd_o >= 0) {
461  mem_page_rd_o[slot] = rd_o;
462  rd_o += 0x100;
463  }
464  if (rd_f)
465  mem_page_rd_f[slot] = rd_f;
466  if (wr_o >= 0) {
467  mem_page_wr_o[slot] = wr_o;
468  wr_o += 0x100;
469  }
470  if (wr_f)
471  mem_page_wr_f[slot] = wr_f;
472  mem_page_phys[slot] = 1; // invalidate phys info, to avoid cache-missbehaviour in decoder
473  mem_page_refp[slot] = &impossible_mapping; // invalidate this too
474  slot++;
475  }
476 }
477 
478 
479 void memory_init ( void )
480 {
481  int a;
482  memset(D6XX_registers, 0, sizeof D6XX_registers);
483  memset(D7XX, 0xFF, sizeof D7XX);
484  rom_protect = 0;
485  in_hypervisor = 0;
486  for (a = 0; a < MEM_SLOTS; a++) {
487  // First of ALL! Initialize mem_page_phys for an impossible value! or otherwise bad crashes would happen ...
488  mem_page_phys[a] = 1; // this is cool enough, since phys addr for this func, can be only 256 byte aligned, so it won't find these ever as cached!
489  phys_addr_decoder((a & 0xFF) << 8, a, -1); // at least we have well defined defaults :) with 'real' and 'virtual' slots as well ...
490  }
491  // Generate "templates" for VIC-III ROM mapping entry points
492  // FIXME: the theory, that VIC-III ROM mapping is not like C64, ie writing a mapped in ROM, would write the ROM, not something "under" as with C64
493  // static void XEMU_INLINE phys_addr_decoder_array ( int megabyte_offset, int offset, int slot, int slots, int hint_slot )
494  phys_addr_decoder_array(0, 0x38000, MEM_SLOT_C65_8KROM_8000, 32, -1); // 8K(32 pages) C65 VIC-III ROM mapping ($8000) from $38000
495  phys_addr_decoder_array(0, 0x3A000, MEM_SLOT_C65_8KROM_A000, 32, -1); // 8K(32 pages) C65 VIC-III ROM mapping ($A000) from $3A000
496  phys_addr_decoder_array(0, 0x2C000, MEM_SLOT_C65_4KROM_C000, 16, -1); // 4K(16 pages) C65 VIC-III ROM mapping ($C000) from $2C000
497  phys_addr_decoder_array(0, 0x3E000, MEM_SLOT_C65_8KROM_E000, 32, -1); // 8K(32 pages) C65 VIC-III ROM mapping ($E000) from $3E000
498  phys_addr_decoder_array(0, 0x2A000, MEM_SLOT_C64_8KROM_A000, 32, -1); // 8K(32 pages) C64 CPU I/O ROM mapping ($A000) from $2A000 [C64 BASIC]
499  phys_addr_decoder_array(0, 0x2D000, MEM_SLOT_C64_4KROM_D000, 16, -1); // 4K(16 pages) C64 CPU I/O ROM mapping ($D000) from $2D000 [C64 CHARGEN]
500  phys_addr_decoder_array(0, 0x2E000, MEM_SLOT_C64_8KROM_E000, 32, -1); // 8K(32 pages) C64 CPU I/O ROM mapping ($E000) from $2E000 [C64 KERNAL]
501  // C64 ROM mappings by CPU I/O port should be "tuned" for the "write through RAM" policy though ...
502  // we re-use some write-specific info for pre-initialized unmapped RAM for write access here
503  init_helper_custom_memtab_policy(-1, NULL, mem_page_wr_o[0xA0], mem_page_wr_f[0xA0], MEM_SLOT_C64_8KROM_A000, 32); // for C64 BASIC ROM
504  init_helper_custom_memtab_policy(-1, NULL, mem_page_wr_o[0xD0], mem_page_wr_f[0xD0], MEM_SLOT_C64_4KROM_D000, 16); // for C64 CHARGEN ROM
505  init_helper_custom_memtab_policy(-1, NULL, mem_page_wr_o[0xE0], mem_page_wr_f[0xE0], MEM_SLOT_C64_8KROM_E000, 32); // for C64 KERNAL ROM
506  // The C64/C65-style I/O area is handled in this way: as it is I/O mode dependent unlike M65 high-megabyte areas,
507  // we maps I/O (any mode) and "customize it" with an offset to transfer into the right mode (or such).
508  phys_addr_decoder_array(0xFF << 20, 0xD0000, MEM_SLOT_OLD_4K_IO_D000, 16, -1);
509  init_helper_custom_memtab_policy(-1, legacy_io_reader, -1, legacy_io_writer, MEM_SLOT_OLD_4K_IO_D000, 16);
510  // Initialize some memory related "caching" stuffs and state etc ...
511  cpu_rmw_old_data = -1;
512  memcfg_vic3_rom_mapping_last = 0xFF;
513  memcfg_cpu_io_port_last = 0xFF;
514  cpu_io_port[0] = 0;
515  cpu_io_port[1] = 0;
516  map_mask = 0;
517  map_offset_low = 0;
518  map_offset_high = 0;
519  map_megabyte_low = 0;
520  map_megabyte_high = 0;
521  map_marker_low = MAP_MARKER_DUMMY_OFFSET;
522  map_marker_high = MAP_MARKER_DUMMY_OFFSET;
523  //skip_unhandled_mem = 0;
524  for (a = 0; a < 9; a++)
525  applied_memcfg[a] = MAP_MARKER_DUMMY_OFFSET - 1;
526  // Setting up the default memory configuration for M65 at least!
527  // Note, the exact order is IMPORTANT as being the first use of memory subsystem, actually these will initialize some things ...
531  // Initiailize memory content with something ...
532  memset(main_ram, 0x00, sizeof main_ram);
533  memset(colour_ram, 0x00, sizeof colour_ram);
534  memset(slow_ram, 0xFF, sizeof slow_ram);
535  DEBUG("MEM: End of memory initiailization" NL);
536 }
537 
538 
539 
540 
541 
542 static void apply_memory_config_0000_to_7FFF ( void ) {
543  int hint_slot = -1;
544  // 0000 - 1FFF
545  if (map_mask & 0x01) {
546  if (applied_memcfg[0] != map_marker_low) {
547  phys_addr_decoder_array(map_megabyte_low, map_offset_low, 0x00, 0x20, -1);
548  applied_memcfg[0] = map_marker_low;
549  }
550  hint_slot = 0x1F;
551  } else {
552  if (applied_memcfg[0]) {
553  MEM_TABLE_COPY(0x00, 0x100, 0x20);
554  applied_memcfg[0] = 0;
555  }
556  }
557  // 2000 - 3FFF
558  if (map_mask & 0x02) {
559  if (applied_memcfg[1] != map_marker_low) {
560  phys_addr_decoder_array(map_megabyte_low, map_offset_low + 0x2000, 0x20, 0x20, hint_slot);
561  applied_memcfg[1] = map_marker_low;
562  }
563  hint_slot = 0x3F;
564  } else {
565  if (applied_memcfg[1]) {
566  MEM_TABLE_COPY(0x20, 0x120, 0x20);
567  applied_memcfg[1] = 0;
568  }
569  }
570  // 4000 - 5FFF
571  if (map_mask & 0x04) {
572  if (applied_memcfg[2] != map_marker_low) {
573  phys_addr_decoder_array(map_megabyte_low, map_offset_low + 0x4000, 0x40, 0x20, hint_slot);
574  applied_memcfg[2] = map_marker_low;
575  }
576  hint_slot = 0x5F;
577  } else {
578  if (applied_memcfg[2]) {
579  MEM_TABLE_COPY(0x40, 0x140, 0x20);
580  applied_memcfg[2] = 0;
581  }
582  }
583  // 6000 - 7FFF
584  if (map_mask & 0x08) {
585  if (applied_memcfg[3] != map_marker_low) {
586  phys_addr_decoder_array(map_megabyte_low, map_offset_low + 0x6000, 0x60, 0x20, hint_slot);
587  applied_memcfg[3] = map_marker_low;
588  }
589  } else {
590  if (applied_memcfg[3]) {
591  MEM_TABLE_COPY(0x60, 0x160, 0x20);
592  applied_memcfg[3] = 0;
593  }
594  }
595 }
596 static void apply_memory_config_8000_to_9FFF ( void ) {
597  if (memcfg_vic3_rom_mapping_last & VIC3_ROM_MASK_8000) {
598  if (applied_memcfg[4] >= 0) {
600  applied_memcfg[4] = -1;
601  }
602  } else if (map_mask & 0x10) {
603  if (applied_memcfg[4] != map_marker_high) {
604  phys_addr_decoder_array(map_megabyte_high, map_offset_high + 0x8000, 0x80, 0x20, -1);
605  applied_memcfg[4] = map_marker_high;
606  }
607  } else {
608  if (applied_memcfg[4]) {
609  MEM_TABLE_COPY(0x80, 0x180, 0x20);
610  applied_memcfg[4] = 0;
611  }
612  }
613 }
614 static void apply_memory_config_A000_to_BFFF ( void ) {
615  if (memcfg_vic3_rom_mapping_last & VIC3_ROM_MASK_A000) {
616  if (applied_memcfg[5] >= 0) {
618  applied_memcfg[5] = -1;
619  }
620  } else if (map_mask & 0x20) {
621  if (applied_memcfg[5] != map_marker_high) {
622  phys_addr_decoder_array(map_megabyte_high, map_offset_high + 0xA000, 0xA0, 0x20, -1);
623  applied_memcfg[5] = map_marker_high;
624  }
625  } else {
626  if (applied_memcfg[5] != memcfg_cpu_io_port_policy_A000_to_BFFF) {
627  MEM_TABLE_COPY(0xA0, memcfg_cpu_io_port_policy_A000_to_BFFF, 0x20);
628  applied_memcfg[5] = memcfg_cpu_io_port_policy_A000_to_BFFF;
629  }
630  }
631 }
632 static void apply_memory_config_C000_to_CFFF ( void ) {
633  // Special range, just 4K in length!
634  if (memcfg_vic3_rom_mapping_last & VIC3_ROM_MASK_C000) {
635  if (applied_memcfg[6] >= 0) {
637  applied_memcfg[6] = -1;
638  }
639  } else if (map_mask & 0x40) {
640  if (applied_memcfg[6] != map_marker_high) {
641  phys_addr_decoder_array(map_megabyte_high, map_offset_high + 0xC000, 0xC0, 0x10, -1);
642  applied_memcfg[6] = map_marker_high;
643  }
644  } else {
645  if (applied_memcfg[6]) {
646  MEM_TABLE_COPY(0xC0, 0x1C0, 0x10);
647  applied_memcfg[6] = 0;
648  }
649  }
650 }
651 static void apply_memory_config_D000_to_DFFF ( void ) {
652  // Special range, just 4K in length!
653  if (map_mask & 0x40) {
654  if (applied_memcfg[7] != map_marker_high) {
655  phys_addr_decoder_array(map_megabyte_high, map_offset_high + 0xD000, 0xD0, 0x10, -1);
656  applied_memcfg[7] = map_marker_high;
657  }
658  } else {
659  if (applied_memcfg[7] != memcfg_cpu_io_port_policy_D000_to_DFFF) {
660  MEM_TABLE_COPY(0xD0, memcfg_cpu_io_port_policy_D000_to_DFFF, 0x10);
661  applied_memcfg[7] = memcfg_cpu_io_port_policy_D000_to_DFFF;
662  }
663  }
664 }
665 static void apply_memory_config_E000_to_FFFF ( void ) {
666  if (memcfg_vic3_rom_mapping_last & VIC3_ROM_MASK_E000) {
667  if (applied_memcfg[8] >= 0) {
669  applied_memcfg[8] = -1;
670  }
671  } else if (map_mask & 0x80) {
672  if (applied_memcfg[8] != map_marker_high) {
673  phys_addr_decoder_array(map_megabyte_high, map_offset_high + 0xE000, 0xE0, 0x20, -1);
674  applied_memcfg[8] = map_marker_high;
675  }
676  } else {
677  if (applied_memcfg[8] != memcfg_cpu_io_port_policy_E000_to_FFFF) {
678  MEM_TABLE_COPY(0xE0, memcfg_cpu_io_port_policy_E000_to_FFFF, 0x20);
679  applied_memcfg[8] = memcfg_cpu_io_port_policy_E000_to_FFFF;
680  }
681  }
682 }
683 
684 
685 
686 
687 
688 // must be called when VIC-III register $D030 is written, with the written value exactly
690 {
691  // D030 regiser of VIC-III is:
692  // 7 6 5 4 3 2 1 0
693  // | ROM | CROM | ROM | ROM | ROM | PAL | EXT | CRAM |
694  // | @E000 | @9000 | @C000 | @A000 | @8000 | | SYNC | @DC00 |
695  if (in_hypervisor)
696  value = 0; // in hypervisor, VIC-III ROM banking should *not* work (newer M65 change)
697  else
698  value &= VIC3_ROM_MASK_8000 | VIC3_ROM_MASK_A000 | VIC3_ROM_MASK_C000 | VIC3_ROM_MASK_E000; // only keep bits we're interested in
699  if (value != memcfg_vic3_rom_mapping_last) { // only do, if there was a change
700  Uint8 change = memcfg_vic3_rom_mapping_last ^ value; // change mask, bits have 1 only if there was a change
701  DEBUG("MEM: VIC-III ROM mapping change $%02X -> %02X" NL, memcfg_vic3_rom_mapping_last, value);
702  memcfg_vic3_rom_mapping_last = value; // don't forget to store the current state for next check!
703  // now check bits changed in ROM mapping
704  if (change & VIC3_ROM_MASK_8000)
705  apply_memory_config_8000_to_9FFF();
706  if (change & VIC3_ROM_MASK_A000)
707  apply_memory_config_A000_to_BFFF();
708  if (change & VIC3_ROM_MASK_C000)
709  apply_memory_config_C000_to_CFFF();
710  if (change & VIC3_ROM_MASK_E000)
711  apply_memory_config_E000_to_FFFF();
712  }
713 }
714 
715 
716 static void apply_cpu_io_port_config ( void )
717 {
718  Uint8 desired = (cpu_io_port[1] | (~cpu_io_port[0])) & 7;
719  if (desired != memcfg_cpu_io_port_last) {
720  DEBUG("MEM: CPUIOPORT: port composite value (new one) is %d" NL, desired);
721  memcfg_cpu_io_port_last = desired;
722  memcfg_cpu_io_port_policy_A000_to_BFFF = memcfg_cpu_io_port_policies_A000_to_BFFF[desired];
723  memcfg_cpu_io_port_policy_D000_to_DFFF = memcfg_cpu_io_port_policies_D000_to_DFFF[desired];
724  memcfg_cpu_io_port_policy_E000_to_FFFF = memcfg_cpu_io_port_policies_E000_to_FFFF[desired];
725  // check only regions to apply, where CPU I/O port can change anything
726  apply_memory_config_A000_to_BFFF();
727  apply_memory_config_D000_to_DFFF();
728  apply_memory_config_E000_to_FFFF();
729  DEBUG("MEM: CPUIOPORT: new config had been applied" NL);
730  }
731 }
732 
733 
734 
735 // must be called on CPU I/O port write, addr=0/1 for DDR/DATA
736 // do not call with other addr than 0/1!
738 {
739  if (XEMU_UNLIKELY((addr == 0) && ((value & 0xFE) == 64))) { // M65-specific speed control stuff!
740  value &= 1;
741  if (value != ((D6XX_registers[0x7D] >> 4) & 1)) {
742  if (value)
743  D6XX_registers[0x7D] |= 16;
744  else
745  D6XX_registers[0x7D] &= ~16;
747  }
748  } else {
749  cpu_io_port[addr] = value;
750  apply_cpu_io_port_config();
751  }
752 }
753 
754 
756 {
757  cpu_io_port[0] = p0;
758  cpu_io_port[1] = p1;
759  apply_cpu_io_port_config();
760 }
761 
762 
764 {
765  return cpu_io_port[addr];
766 }
767 
768 
769 
770 
771 
772 // Call this after MAP opcode, map_* variables must be pre-initialized
773 // Can be also used to set custom mapping (hypervisor enter/leave, maybe snapshot loading)
774 void memory_set_do_map ( void )
775 {
776  // map_marker_low and map_maker_high are just articial markers, not so much to do with real offset, used to
777  // detect already done operations. It must be unique for each possible mappings, that is the only rule.
778  // to leave room for other values we use both of megabyte info and offset info, but moved from the zero
779  // reference (WARNING: mapped from zero and unmapped are different states!) to have place for other markers too.
782  // We need to check every possible memory regions for the effect caused by MAPping ...
783  apply_memory_config_0000_to_7FFF();
784  apply_memory_config_8000_to_9FFF();
785  apply_memory_config_A000_to_BFFF();
786  apply_memory_config_C000_to_CFFF();
787  apply_memory_config_D000_to_DFFF();
788  apply_memory_config_E000_to_FFFF();
789  DEBUG("MEM: memory_set_do_map() applied" NL);
790 }
791 
792 
793 // This implements the MAP opcode, ie "AUG" in case of 65CE02, which was re-defined to "MAP" in C65's CPU
794 // M65's extension to select "MB" (ie: megabyte slice, which wraps within!) is supported as well
796 {
797  /* 7 6 5 4 3 2 1 0 BIT
798  +-------+-------+-------+-------+-------+-------+-------+-------+
799  | LOWER | LOWER | LOWER | LOWER | LOWER | LOWER | LOWER | LOWER | A
800  | OFF15 | OFF14 | OFF13 | OFF12 | OFF11 | OFF10 | OFF9 | OFF8 |
801  +-------+-------+-------+-------+-------+-------+-------+-------+
802  | MAP | MAP | MAP | MAP | LOWER | LOWER | LOWER | LOWER | X
803  | BLK3 | BLK2 | BLK1 | BLK0 | OFF19 | OFF18 | OFF17 | OFF16 |
804  +-------+-------+-------+-------+-------+-------+-------+-------+
805  | UPPER | UPPER | UPPER | UPPER | UPPER | UPPER | UPPER | UPPER | Y
806  | OFF15 | OFF14 | OFF13 | OFF12 | OFF11 | OFF10 | OFF9 | OFF8 |
807  +-------+-------+-------+-------+-------+-------+-------+-------+
808  | MAP | MAP | MAP | MAP | UPPER | UPPER | UPPER | UPPER | Z
809  | BLK7 | BLK6 | BLK5 | BLK4 | OFF19 | OFF18 | OFF17 | OFF16 |
810  +-------+-------+-------+-------+-------+-------+-------+-------+
811  -- C65GS extension: Set the MegaByte register for low and high mobies
812  -- so that we can address all 256MB of RAM.
813  if reg_x = x"0f" then
814  reg_mb_low <= reg_a;
815  end if;
816  if reg_z = x"0f" then
817  reg_mb_high <= reg_y;
818  end if; */
819  cpu65.cpu_inhibit_interrupts = 1; // disable interrupts till the next "EOM" (ie: NOP) opcode
820  DEBUG("CPU: MAP opcode, input A=$%02X X=$%02X Y=$%02X Z=$%02X" NL, cpu65.a, cpu65.x, cpu65.y, cpu65.z);
821  map_offset_low = (cpu65.a << 8) | ((cpu65.x & 15) << 16); // offset of lower half (blocks 0-3)
822  map_offset_high = (cpu65.y << 8) | ((cpu65.z & 15) << 16); // offset of higher half (blocks 4-7)
823  map_mask = (cpu65.z & 0xF0) | ( cpu65.x >> 4); // "is mapped" mask for blocks (1 bit for each)
824  // M65 specific "MB" (megabyte) selector "mode":
825  if (cpu65.x == 0x0F)
826  map_megabyte_low = (int)cpu65.a << 20;
827  if (cpu65.z == 0x0F)
828  map_megabyte_high = (int)cpu65.y << 20;
829  DEBUG("MEM: applying new memory configuration because of MAP CPU opcode" NL);
830  DEBUG("LOW -OFFSET = $%03X, MB = $%02X" NL, map_offset_low , map_megabyte_low >> 20);
831  DEBUG("HIGH-OFFSET = $%03X, MB = $%02X" NL, map_offset_high, map_megabyte_high >> 20);
832  DEBUG("MASK = $%02X" NL, map_mask);
834 }
835 
836 
837 
838 // *** Implements the EOM opcode of 4510, called by the 65CE02 emulator
840 {
841  if (cpu65.cpu_inhibit_interrupts) {
842  cpu65.cpu_inhibit_interrupts = 0;
843  DEBUG("CPU: EOM, interrupts were disabled because of MAP till the EOM" NL);
844  } else
845  DEBUG("CPU: NOP not treated as EOM (no MAP before)" NL);
846 }
847 
848 
849 /* For 32 (28 ...) bit linear addressing we use a dedicated mapper slot. Please read
850  command above, similar situation as with the DMA. However we need to fetch the
851  base (+Z) from base page, so it can be a bit less efficient if different 32 bit
852  pointers used all the time in 4510GS code. */
853 
854 
855 static XEMU_INLINE int cpu_get_flat_addressing_mode_address ( int index )
856 {
857  register int addr = cpu65_read_callback(cpu65.pc++); // fetch base page address
858  // FIXME: really, BP/ZP is wrapped around in case of linear addressing and eg BP addr of $FF got?????? (I think IT SHOULD BE!)
859  // FIXME: migrate to cpu_read_paged(), but we need CPU emu core to utilize BP rather than BP << 8, and
860  // similar older hacks ...
861  return (
862  cpu65_read_callback(cpu65.bphi | addr ) |
863  (cpu65_read_callback(cpu65.bphi | ((addr + 1) & 0xFF)) << 8) |
864  (cpu65_read_callback(cpu65.bphi | ((addr + 2) & 0xFF)) << 16) |
865  (cpu65_read_callback(cpu65.bphi | ((addr + 3) & 0xFF)) << 24)
866  ) + index; // I don't handle the overflow of 28 bit addr.space situation, as addr will be anyway "trimmed" later in phys_addr_decoder() issued by the user of this func
867 }
868 
870 {
871  register int addr = cpu_get_flat_addressing_mode_address(cpu65.z);
872  phys_addr_decoder(addr, MEM_SLOT_CPU_32BIT, MEM_SLOT_CPU_32BIT);
874 }
875 
877 {
878  register int addr = cpu_get_flat_addressing_mode_address(cpu65.z);
879  phys_addr_decoder(addr, MEM_SLOT_CPU_32BIT, MEM_SLOT_CPU_32BIT);
881 }
882 
883 
884 // FIXME: very ugly and very slow and maybe very buggy implementation! Should be done in a sane way in the next memory decoder version being developmented ...
886 {
887  for (int shift = 0, ret = 0, addr = cpu_get_flat_addressing_mode_address(index) ;; ) {
888  phys_addr_decoder(addr, MEM_SLOT_CPU_32BIT, MEM_SLOT_CPU_32BIT);
890  if (shift == 24)
891  return ret;
892  addr++;
893  shift += 8;
894  }
895 }
896 
897 // FIXME: very ugly and very slow and maybe very buggy implementation! Should be done in a sane way in the next memory decoder version being developmented ...
899 {
900  for (int a = 0, addr = cpu_get_flat_addressing_mode_address(index) ;; ) {
901  phys_addr_decoder(addr, MEM_SLOT_CPU_32BIT, MEM_SLOT_CPU_32BIT);
903  if (a == 3)
904  break;
905  addr++;
906  data >>= 8;
907  a++;
908  }
909 }
910 
911 
912 /* DMA related call-backs. We use a dedicated memory mapper "slot" for each DMA functions.
913  Source can be _written_ too (in case of SWAP operation for example). There are dedicated
914  slots for each functionality, so we don't need to re-map physical address again and again,
915  and we can take advantage of using the "cache" provided by phys_addr_decoder() which can
916  be especially efficient in case of linear operations, what DMA usually does.
917  Performance analysis (can be applied to other memory operations somewhat too, even CPU):
918  * if the next access for the given DMA func is in the same 256 page, phys_addr_decoder will return after just a comparsion operation
919  * if not, the "hint_slot" (3rd paramater) is used, if at least the same physical region (ie also fast-ram, etc) is used, again it's faster than full scan
920  * if even the previous statment is not true, phys_addr_decoder will scan the phyisical M65 memory layout to find the region, only */
921 
922 
924 {
925  phys_addr_decoder(addr, MEM_SLOT_DMA_RD_SRC, MEM_SLOT_DMA_RD_SRC);
927 }
928 
930 {
931  phys_addr_decoder(addr, MEM_SLOT_DMA_WR_SRC, MEM_SLOT_DMA_WR_SRC);
933 }
934 
936 {
937  phys_addr_decoder(addr, MEM_SLOT_DMA_RD_DST, MEM_SLOT_DMA_RD_DST);
939 }
940 
942 {
943  phys_addr_decoder(addr, MEM_SLOT_DMA_WR_DST, MEM_SLOT_DMA_WR_DST);
945 }
946 
948 {
949  phys_addr_decoder(addr, MEM_SLOT_DMA_RD_LST, MEM_SLOT_DMA_RD_LST);
951 }
952 
953 /* Debugger (ie: [uart]monitor) for reading/writing physical address */
955 {
958 }
959 
961 {
964 }
965 
967 {
968  int slot = cpu_addr >> 8;
969  return mem_page_rd_o[slot] + mem_page_refp[slot]->start + (int)(cpu_addr & 0xFF);
970 }
971 
972 /* the same as above but for CPU addresses */
974 {
975  return CALL_MEMORY_READER(addr >> 8, addr);
976 }
977 
979 {
981 }
MEM_SLOT_DMA_RD_LST
#define MEM_SLOT_DMA_RD_LST
Definition: memory_mapper.c:104
mem_page_wr_f_type
void(* mem_page_wr_f_type)(MEMORY_HANDLERS_ADDR_TYPE, Uint8 data)
Definition: cpu_custom_functions.h:65
m65_memory_map_st::end
int end
Definition: memory_mapper.c:81
memory_dma_source_mreader
Uint8 memory_dma_source_mreader(int addr)
Definition: memory_mapper.c:923
memory_cpurd2linear_xlat
int memory_cpurd2linear_xlat(Uint16 cpu_addr)
Definition: memory_mapper.c:966
index
int index
Definition: vera.c:66
memory_init
void memory_init(void)
Definition: memory_mapper.c:479
chip_ram
#define chip_ram
Definition: memory_mapper.c:50
vic4.h
MEM_SLOT_C65_8KROM_8000
#define MEM_SLOT_C65_8KROM_8000
Definition: memory_mapper.c:96
map_megabyte_high
int map_megabyte_high
Definition: memory_mapper.c:142
machine_set_speed
void machine_set_speed(int verbose)
Definition: mega65.c:101
emutools.h
char_wom
Uint8 char_wom[0x2000]
Definition: memory_mapper.c:67
DEFINE_WRITER
#define DEFINE_WRITER(name)
Definition: memory_mapper.c:149
disk_buffer_cpu_view
Uint8 * disk_buffer_cpu_view
Definition: sdcard.c:76
ethernet65.h
VIC3_ROM_MASK_C000
#define VIC3_ROM_MASK_C000
Definition: memory_mapper.c:111
memory_dma_target_mwriter
void memory_dma_target_mwriter(int addr, Uint8 data)
Definition: memory_mapper.c:941
DEFINE_READER
#define DEFINE_READER(name)
Definition: memory_mapper.c:148
disk_buffers
Uint8 disk_buffers[0x1000]
Definition: sdcard.c:74
memory_set_vic3_rom_mapping
void memory_set_vic3_rom_mapping(Uint8 value)
Definition: memory_mapper.c:689
GET_OFFSET_BYTE_ONLY
#define GET_OFFSET_BYTE_ONLY()
Definition: cpu_custom_functions.h:46
hypervisor_ram
Uint8 hypervisor_ram[0x4000]
Definition: memory_mapper.c:69
memory_dma_source_mwriter
void memory_dma_source_mwriter(int addr, Uint8 data)
Definition: memory_mapper.c:929
cpu65_do_nop_callback
void cpu65_do_nop_callback(void)
Definition: memory_mapper.c:839
cpu_rmw_old_data
int cpu_rmw_old_data
Definition: memory_mapper.c:123
cpu_custom_functions.h
map_offset_high
int map_offset_high
Definition: memory_mapper.c:142
cpu65_read_linear_long_opcode_callback
Uint32 cpu65_read_linear_long_opcode_callback(const Uint8 index)
Definition: memory_mapper.c:885
colour_ram
Uint8 colour_ram[0x8000]
Definition: memory_mapper.c:65
io_mapper.h
addr
int addr
Definition: dma65.c:81
VIC3_ROM_MASK_E000
#define VIC3_ROM_MASK_E000
Definition: memory_mapper.c:112
io_write
void io_write(int addr, Uint8 data)
Definition: commodore_65.c:546
memory_debug_read_phys_addr
Uint8 memory_debug_read_phys_addr(int addr)
Definition: memory_mapper.c:954
mem_page_rd_f_type
Uint8(* mem_page_rd_f_type)(MEMORY_HANDLERS_ADDR_TYPE)
Definition: cpu_custom_functions.h:64
SLOW_RAM_SIZE
#define SLOW_RAM_SIZE
Definition: memory_mapper.h:44
rom_protect
int rom_protect
Definition: memory_mapper.c:144
extra_ram
#define extra_ram
Definition: memory_mapper.c:52
XEMU_INLINE
#define XEMU_INLINE
Definition: emutools_basicdefs.h:126
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
mega65.h
skip_unhandled_mem
int skip_unhandled_mem
Definition: memory_mapper.c:145
CALL_MEMORY_READER
#define CALL_MEMORY_READER(slot, addr)
Definition: cpu_custom_functions.h:38
Uint32
uint32_t Uint32
Definition: fat32.c:49
mem_page_rd_o
int mem_page_rd_o[]
Definition: memory_mapper.c:117
MEM_SLOT_OLD_4K_IO_D000
#define MEM_SLOT_OLD_4K_IO_D000
Definition: memory_mapper.c:94
eth65_write_tx_buffer
void eth65_write_tx_buffer(int offset, Uint8 data)
Definition: ethernet65.c:514
VIC3_ROM_MASK_A000
#define VIC3_ROM_MASK_A000
Definition: memory_mapper.c:110
MEM_SLOT_CPU_32BIT
#define MEM_SLOT_CPU_32BIT
Definition: memory_mapper.c:105
Uint8
uint8_t Uint8
Definition: fat32.c:51
audio65_opl3_write
void audio65_opl3_write(Uint8 reg, Uint8 data)
Definition: audio65.c:109
MEM_SLOT_C64_8KROM_E000
#define MEM_SLOT_C64_8KROM_E000
Definition: memory_mapper.c:95
memory_set_cpu_io_port
void memory_set_cpu_io_port(int addr, Uint8 value)
Definition: memory_mapper.c:737
MEM_SLOT_DMA_WR_DST
#define MEM_SLOT_DMA_WR_DST
Definition: memory_mapper.c:103
CALL_MEMORY_WRITER
#define CALL_MEMORY_WRITER(slot, addr, data)
Definition: cpu_custom_functions.h:39
GET_WRITER_OFFSET
#define GET_WRITER_OFFSET()
Definition: cpu_custom_functions.h:45
main_ram
Uint8 main_ram[512<< 10]
Definition: memory_mapper.c:47
memory_dma_list_reader
Uint8 memory_dma_list_reader(int addr)
Definition: memory_mapper.c:947
VIC3_ROM_MASK_8000
#define VIC3_ROM_MASK_8000
Definition: memory_mapper.c:109
cpu65_do_aug_callback
void cpu65_do_aug_callback(void)
Definition: memory_mapper.c:795
map_offset_low
int map_offset_low
Definition: memory_mapper.c:142
memory_get_cpu_io_port
Uint8 memory_get_cpu_io_port(int addr)
Definition: memory_mapper.c:763
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
MEM_SLOT_DMA_WR_SRC
#define MEM_SLOT_DMA_WR_SRC
Definition: memory_mapper.c:101
MAXALIGNED
#define MAXALIGNED
Definition: emutools_basicdefs.h:188
map_mask
int map_mask
Definition: memory_mapper.c:142
MEM_SLOT_C65_8KROM_E000
#define MEM_SLOT_C65_8KROM_E000
Definition: memory_mapper.c:98
MEM_SLOT_DEBUG_RESOLVER
#define MEM_SLOT_DEBUG_RESOLVER
Definition: memory_mapper.c:106
memory_mapper.h
XEMU_LIKELY
#define XEMU_LIKELY(__x__)
Definition: emutools_basicdefs.h:124
memory_set_do_map
void memory_set_do_map(void)
Definition: memory_mapper.c:774
mega65_uuid
Uint8 mega65_uuid[8]
Definition: memory_mapper.c:73
map_megabyte_low
int map_megabyte_low
Definition: memory_mapper.c:142
rtc_regs
Uint8 rtc_regs[6]
Definition: memory_mapper.c:75
NL
#define NL
Definition: fat32.c:37
memory_dma_target_mreader
Uint8 memory_dma_target_mreader(int addr)
Definition: memory_mapper.c:935
hypervisor.h
slow_ram
Uint8 slow_ram[SLOW_RAM_SIZE]
Definition: memory_mapper.c:77
mem_page_wr_f
mem_page_wr_f_type mem_page_wr_f[]
Definition: memory_mapper.c:120
MEM_TABLE_COPY
#define MEM_TABLE_COPY(to, from, pages)
Definition: memory_mapper.c:439
cpu65.h
cpu65_read_callback
Uint8 cpu65_read_callback(Uint16 addr)
Definition: commodore_65.c:711
memory_debug_write_cpu_addr
void memory_debug_write_cpu_addr(Uint16 addr, Uint8 data)
Definition: memory_mapper.c:978
XEMUEXIT
#define XEMUEXIT(n)
Definition: emutools_basicdefs.h:246
cpu65_read_linear_opcode_callback
Uint8 cpu65_read_linear_opcode_callback(void)
Definition: memory_mapper.c:869
MEM_SLOT_C65_4KROM_C000
#define MEM_SLOT_C65_4KROM_C000
Definition: memory_mapper.c:99
MEM_SLOT_DMA_RD_DST
#define MEM_SLOT_DMA_RD_DST
Definition: memory_mapper.c:102
io_read
Uint8 io_read(int addr)
Definition: commodore_65.c:472
mem_page_wr_o
int mem_page_wr_o[]
Definition: memory_mapper.c:118
D6XX_registers
Uint8 D6XX_registers[0x100]
Definition: io_mapper.c:38
fast_ram
#define fast_ram
Definition: memory_mapper.c:51
eth65_read_rx_buffer
Uint8 eth65_read_rx_buffer(int offset)
Definition: ethernet65.c:508
memory_debug_read_cpu_addr
Uint8 memory_debug_read_cpu_addr(Uint16 addr)
Definition: memory_mapper.c:973
sdcard.h
m65_memory_map_st::wr_f
mem_page_wr_f_type wr_f
Definition: memory_mapper.c:83
vic_iomode
int vic_iomode
Definition: vic4.c:44
memory_debug_write_phys_addr
void memory_debug_write_phys_addr(int addr, Uint8 data)
Definition: memory_mapper.c:960
in_hypervisor
int in_hypervisor
Definition: hypervisor.c:40
mem_page_rd_f
mem_page_rd_f_type mem_page_rd_f[]
Definition: memory_mapper.c:119
value
int value
Definition: dma65.c:90
Uint16
uint16_t Uint16
Definition: fat32.c:50
found
char found[8+3+1]
Definition: cpmfs.c:36
dma65.h
m65_memory_map_st::rd_f
mem_page_rd_f_type rd_f
Definition: memory_mapper.c:82
cpu65_write_linear_long_opcode_callback
void cpu65_write_linear_long_opcode_callback(const Uint8 index, Uint32 data)
Definition: memory_mapper.c:898
QUESTION_WINDOW
#define QUESTION_WINDOW(items, msg)
Definition: xep128.h:124
nvram
Uint8 nvram[64]
Definition: memory_mapper.c:71
MEM_SLOT_C65_8KROM_A000
#define MEM_SLOT_C65_8KROM_A000
Definition: memory_mapper.c:97
MEM_SLOT_C64_8KROM_A000
#define MEM_SLOT_C64_8KROM_A000
Definition: memory_mapper.c:92
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
MEM_SLOTS
#define MEM_SLOTS
Definition: memory_mapper.c:107
m65_memory_map_st
Definition: memory_mapper.c:80
MEM_SLOT_DMA_RD_SRC
#define MEM_SLOT_DMA_RD_SRC
Definition: memory_mapper.c:100
FATAL
#define FATAL(...)
Definition: xep128.h:117
D7XX
Uint8 D7XX[0x100]
Definition: io_mapper.c:39
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
audio65.h
m65_memory_map_st::start
int start
Definition: memory_mapper.c:81
GET_READER_OFFSET
#define GET_READER_OFFSET()
Definition: cpu_custom_functions.h:44
MAP_MARKER_DUMMY_OFFSET
#define MAP_MARKER_DUMMY_OFFSET
Definition: memory_mapper.c:114
cpu65_write_linear_opcode_callback
void cpu65_write_linear_opcode_callback(Uint8 data)
Definition: memory_mapper.c:876
memory_set_cpu_io_port_ddr_and_data
void memory_set_cpu_io_port_ddr_and_data(Uint8 p0, Uint8 p1)
Definition: memory_mapper.c:755
MEM_SLOT_C64_4KROM_D000
#define MEM_SLOT_C64_4KROM_D000
Definition: memory_mapper.c:93