Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
commodore_65.c
Go to the documentation of this file.
1 /* Test-case for simple, work-in-progress Commodore 65 emulator.
2 
3  Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
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 "xemu/emutools_files.h"
22 #include "commodore_65.h"
23 #include "xemu/cpu65.h"
24 #include "xemu/cia6526.h"
25 #include "xemu/f011_core.h"
26 #include "xemu/d81access.h"
27 #include "dma65.h"
28 #include "xemu/emutools_hid.h"
29 #include "vic3.h"
30 #include "xemu/sid.h"
31 #include "xemu/cbmhostfs.h"
32 #include "xemu/c64_kbd_mapping.h"
33 #include "xemu/emutools_config.h"
34 #include "c65_snapshot.h"
35 #include "xemu/emutools_gui.h"
36 #include "ui.h"
37 #include "inject.h"
38 #include "configdb.h"
39 
40 
41 static SDL_AudioDeviceID audio = 0;
42 
43 Uint8 memory[0x100000]; // 65CE02 MAP'able address space
44 struct Cia6526 cia1, cia2; // CIA emulation structures for the two CIAs
45 struct SidEmulation sids[2]; // the two SIDs
46 static int nmi_level; // please read the comment at nmi_set() below
47 static int mouse_x = 0;
48 static int mouse_y = 0;
49 static int shift_status = 0;
50 
51 char current_rom_filepath[PATH_MAX];
52 
53 Uint8 disk_cache[512]; // internal memory of the F011 disk controller
54 
55 
56 // We re-map I/O requests to a high address space does not exist for real. cpu_read() and cpu_write() should handle this as an IO space request
57 // It must be high enough not to collide with the 1Mbyte address space + almost-64K "overflow" area and mapping should not cause to alter lower 12 bits of the addresses,
58 // (that is, the constant should have three '0' hex digits at its end)
59 // though the exact value does not matter too much over the mentioned requirements above.
60 #define IO_REMAP_VIRTUAL 0x110000
61 // Other re-mapping addresses
62 // Re-mapping for VIC3 reg $30
63 #define ROM_C000_REMAP 0x20000
64 #define ROM_8000_REMAP 0x30000
65 #define ROM_A000_REMAP 0x30000
66 #define ROM_E000_REMAP 0x30000
67 // Re-mapping for "CPU-port" related stuffs
68 #define ROM_C64_CHR_REMAP 0x20000
69 #define ROM_C64_KERNAL_REMAP 0x20000
70 #define ROM_C64_BASIC_REMAP 0x20000
71 
72 static int addr_trans_rd[16]; // address translating offsets for READ operation (it can be added to the CPU address simply, selected by the high 4 bits of the CPU address)
73 static int addr_trans_wr[16]; // address translating offsets for WRITE operation (it can be added to the CPU address simply, selected by the high 4 bits of the CPU address)
74 static int map_mask; // MAP mask, should be filled at the MAP opcode, *before* calling apply_memory_config() then
75 static int map_offset_low; // MAP low offset, should be filled at the MAP opcode, *before* calling apply_memory_config() then
76 static int map_offset_high; // MAP high offset, should be filled at the MAP opcode, *before* calling apply_memory_config() then
77 
78 char emulator_speed_title[] = "???MHz";
79 
80 
81 
82 /* You *MUST* call this every time, when *any* of these events applies:
83  * MAP 4510 opcode is issued, map_offset_low, map_offset_high, map_mask are modified
84  * "CPU port" data or DDR register has been written, witn cpu_port[0 or 1] modified
85  * VIC3 register $30 is written, with vic3_registers[0x30] modified
86  The reason of this madness: do the ugly work here, as memory configuration change is
87  less frequent than memory usage (read/write). Thus do more work here, but simplier
88  work when doing actual memory read/writes, with a simple addition and shift, or such.
89  The tables are 4K in steps, 4510 would require only 8K steps, but there are other
90  reasons (ie, I/O area is only 4K long, mapping is not done by the CPU).
91  More advanced technique can be used not to handle *everything* here, but it's better
92  for the initial steps, to have all address translating logic at once.
93 */
94 void apply_memory_config ( void )
95 {
96  // FIXME: what happens if VIC-3 reg $30 mapped ROM is tried to be written? Ignored, or RAM is used to write to, as with the CPU port mapping?
97  // About the produced signals on the "CPU port"
98  int cp = (memory[1] | (~memory[0]));
99  // Simple ones, only CPU MAP may apply not other factors
100  // Also, these are the "lower" blocks, needs the offset for the "lower" area in case of CPU MAP'ed state
101  addr_trans_wr[0] = addr_trans_rd[0] = addr_trans_wr[1] = addr_trans_rd[1] = (map_mask & 1) ? map_offset_low : 0; // $0XXX + $1XXX, MAP block 0 [mask 1]
102  addr_trans_wr[2] = addr_trans_rd[2] = addr_trans_wr[3] = addr_trans_rd[3] = (map_mask & 2) ? map_offset_low : 0; // $2XXX + $3XXX, MAP block 1 [mask 2]
103  addr_trans_wr[4] = addr_trans_rd[4] = addr_trans_wr[5] = addr_trans_rd[5] = (map_mask & 4) ? map_offset_low : 0; // $4XXX + $5XXX, MAP block 2 [mask 4]
104  addr_trans_wr[6] = addr_trans_rd[6] = addr_trans_wr[7] = addr_trans_rd[7] = (map_mask & 8) ? map_offset_low : 0; // $6XXX + $7XXX, MAP block 3 [mask 8]
105  // From this point, we must use the "high" area offset if it's CPU MAP'ed
106  // $8XXX and $9XXX, MAP block 4 [mask 16]
107  if (vic3_registers[0x30] & 8)
108  addr_trans_wr[8] = addr_trans_rd[8] = addr_trans_wr[9] = addr_trans_rd[9] = ROM_8000_REMAP;
109  else if (map_mask & 16)
110  addr_trans_wr[8] = addr_trans_rd[8] = addr_trans_wr[9] = addr_trans_rd[9] = map_offset_high;
111  else
112  addr_trans_wr[8] = addr_trans_rd[8] = addr_trans_wr[9] = addr_trans_rd[9] = 0;
113  // $AXXX and $BXXX, MAP block 5 [mask 32]
114  if (vic3_registers[0x30] & 16)
115  addr_trans_wr[0xA] = addr_trans_rd[0xA] = addr_trans_wr[0xB] = addr_trans_rd[0xB] = ROM_A000_REMAP;
116  else if ((map_mask & 32))
117  addr_trans_wr[0xA] = addr_trans_rd[0xA] = addr_trans_wr[0xB] = addr_trans_rd[0xB] = map_offset_high;
118  else {
119  addr_trans_wr[0xA] = addr_trans_wr[0xB] = 0;
120  addr_trans_rd[0xA] = addr_trans_rd[0xB] = ((cp & 3) == 3) ? ROM_C64_BASIC_REMAP : 0;
121  }
122  // $CXXX, MAP block 6 [mask 64]
123  // Warning: all VIC3 reg $30 related ROM maps are for 8K size, *except* of '@C000' (interface ROM) which is only 4K! Also this is in another ROM bank than the others
124  if (vic3_registers[0x30] & 32)
125  addr_trans_wr[0xC] = addr_trans_rd[0xC] = ROM_C000_REMAP;
126  else
127  addr_trans_wr[0xC] = addr_trans_rd[0xC] = (map_mask & 64) ? map_offset_high : 0;
128  // $DXXX, *still* MAP block 6 [mask 64]
129  if (map_mask & 64)
130  addr_trans_wr[0xD] = addr_trans_rd[0xD] = map_offset_high;
131  else {
132  if ((cp & 7) > 4) {
133  addr_trans_wr[0xD] = addr_trans_rd[0xD] = IO_REMAP_VIRTUAL;
134  } else {
135  addr_trans_wr[0xD] = 0;
136  addr_trans_rd[0xD] = (cp & 3) ? ROM_C64_CHR_REMAP : 0;
137  }
138  }
139  // $EXXX and $FXXX, MAP block 7 [mask 128]
140  if (vic3_registers[0x30] & 128)
141  addr_trans_wr[0xE] = addr_trans_rd[0xE] = addr_trans_wr[0xF] = addr_trans_rd[0xF] = ROM_E000_REMAP;
142  else if (map_mask & 128)
143  addr_trans_wr[0xE] = addr_trans_rd[0xE] = addr_trans_wr[0xF] = addr_trans_rd[0xF] = map_offset_high;
144  else {
145  addr_trans_wr[0xE] = addr_trans_wr[0xF] = 0;
146  addr_trans_rd[0xE] = addr_trans_rd[0xF] = ((cp & 3) > 1) ? ROM_C64_KERNAL_REMAP : 0;
147  }
148 }
149 
150 
151 
152 static void cia1_setint_cb ( int level )
153 {
154  DEBUG("%s: IRQ level changed to %d" NL, cia1.name, level);
155  if (level)
156  cpu65.irqLevel |= 1;
157  else
158  cpu65.irqLevel &= ~1;
159 }
160 
161 
162 static inline void nmi_set ( int level, int mask )
163 {
164  // NMI is a low active _EDGE_ triggered 65xx input ... In my emulator though, the signal
165  // is "high active", and also we must form the "edge" ourselves from "level". NMI level is
166  // set as a 2bit number, on bit 0, CIA2, on bit 1, keyboard RESTORE key. Thus having zero
167  // value for level means (in the emu!) that not RESTORE key is pressed neither CIA2 has active
168  // IRQ output, non-zero value means some activation. Well, if I am not confused enough here,
169  // this should mean that nmi_level zero->non-zero transit should produce the edge (which should
170  // be the falling edge in the real hardware anyway ... but the rising here. heh, I should follow
171  // the signal level of the hardware in my emulator, honestly ...)
172  int nmi_new_level;
173  if (level)
174  nmi_new_level = nmi_level | mask;
175  else
176  nmi_new_level = nmi_level & (~mask);
177  if ((!nmi_level) && nmi_new_level) {
178  DEBUG("NMI edge is emulated towards the CPU (%d->%d)" NL, nmi_level, nmi_new_level);
179  cpu65.nmiEdge = 1; // the "NMI edge" trigger is deleted by the CPU emulator itself (it's not a level trigger)
180  }
181  nmi_level = nmi_new_level;
182 }
183 
184 
185 
186 static void cia2_setint_cb ( int level )
187 {
188  nmi_set(level, 1);
189 }
190 
191 
192 
193 void clear_emu_events ( void )
194 {
195  hid_reset_events(1);
196 }
197 
198 
199 static Uint8 port_d607 = 0xFF;
200 
201 
202 static Uint8 cia1_in_b ( void )
203 {
204 #ifdef FAKE_TYPING_SUPPORT
205  if (XEMU_UNLIKELY(c64_fake_typing_enabled) && (((cia1.PRA | (~cia1.DDRA)) & 0xFF) != 0xFF) && (((cia1.PRB | (~cia1.DDRB)) & 0xFF) == 0xFF))
206  c64_handle_fake_typing_internals(cia1.PRA | (~cia1.DDRA));
207 #endif
208  return c64_keyboard_read_on_CIA1_B(
209  cia1.PRA | (~cia1.DDRA),
210  cia1.PRB | (~cia1.DDRB),
211  joystick_emu == 1 ? c64_get_joy_state() : 0xFF, port_d607 & 2
212  );
213 }
214 
215 
216 static Uint8 cia1_in_a ( void )
217 {
218  return c64_keyboard_read_on_CIA1_A(
219  cia1.PRB | (~cia1.DDRB),
220  cia1.PRA | (~cia1.DDRA),
221  joystick_emu == 2 ? c64_get_joy_state() : 0xFF
222  );
223 }
224 
225 
226 static void cia2_out_a ( Uint8 data )
227 {
228  vic3_select_bank((~(data | (~cia2.DDRA))) & 3);
229  //vic2_16k_bank = ((~(data | (~cia2.DDRA))) & 3) << 14;
230  //DEBUG("VIC2: 16K BANK is set to $%04X (CIA mask=$%02X)" NL, vic2_16k_bank, cia2.DDRA);
231 }
232 
233 
234 static Uint8 cia2_in_a ( void )
235 {
236  // CIA for real seems to always read their input pins on reading the data
237  // register, even if it's output. However VIC bank for example should be
238  // readable back this way. Trying to implement here something at least
239  // resembling a real situation, also taking account the DATA and CLK lines
240  // of the IEC bus has input and output too with inverter gates. Though note,
241  // IEC bus otherwise is not emulated by Xemu yet.
242  return (cia2.PRA & 0x3F) | ((~cia2.PRA << 2) & 0xC0);
243 }
244 
245 
246 static Uint8 cia2_in_b ( void )
247 {
248  // Some kind of ad-hoc stuff, allow to read back data out register if the
249  // port bit is output, otherwise (input) give bit '1', by virtually
250  // emulation a pull-up as its kind. It seems to be needed, as some C65 ROMs
251  // actually has check for some user port lines and doing "interesting"
252  // things (mostly crashing ...) when something sensed as grounded.
253  // It was a kind of hw debug feature for early C65 ROMs.
254  return cia2.PRB | ~cia2.DDRB;
255 }
256 
257 
258 static void audio_callback(void *userdata, Uint8 *stream, int len)
259 {
260  DEBUG("AUDIO: audio callback, wants %d samples" NL, len);
261  // We use the trick, to render boths SIDs with step of 2, with a byte offset
262  // to get a stereo stream, wanted by SDL.
263  sid_render(&sids[1], ((short *)(stream)) + 0, len >> 1, 2); // SID @ left
264  sid_render(&sids[0], ((short *)(stream)) + 1, len >> 1, 2); // SID @ right
265 }
266 
267 
268 #ifdef XEMU_SNAPSHOT_SUPPORT
269 static void c65_snapshot_saver_on_exit_callback ( void )
270 {
271  if (!configdb.snapsave)
272  return;
273  if (xemusnap_save(configdb.snapsave))
274  ERROR_WINDOW("Could not save snapshot \"%s\": %s", configdb.snapsave, xemusnap_error_buffer);
275  else
276  INFO_WINDOW("Snapshot has been saved to \"%s\".", configdb.snapsave);
277 }
278 #endif
279 
280 
281 // define the callback, d81access call this, we can dispatch the change in FDC config to the F011 core emulation this way, automatically
282 void d81access_cb_chgmode ( const int which, const int mode ) {
283  int have_disk = ((mode & 0xFF) != D81ACCESS_EMPTY);
284  int can_write = (!(mode & D81ACCESS_RO));
285  if (which < 2)
286  DEBUGPRINT("C65FDC: configuring F011 FDC (#%d) with have_disk=%d, can_write=%d" NL, which, have_disk, can_write);
287  fdc_set_disk(which, have_disk, can_write);
288 }
289 // Here we implement F011 core's callbacks using d81access (and yes, F011 uses 512 bytes long sectors for real)
290 int fdc_cb_rd_sec ( const int which, Uint8 *buffer, const Uint8 side, const Uint8 track, const Uint8 sector )
291 {
292  const int ret = d81access_read_sect(which, buffer, side, track, sector, 512);
293  DEBUG("SDCARD: D81: reading sector at d81_pos=(%d,%d,%d), return value=%d" NL, side, track, sector, ret);
294  return ret;
295 }
296 int fdc_cb_wr_sec ( const int which, Uint8 *buffer, const Uint8 side, const Uint8 track, const Uint8 sector )
297 {
298  const int ret = d81access_write_sect(which, buffer, side, track, sector, 512);
299  DEBUG("SDCARD: D81: writing sector at d81_pos=(%d,%d,%d), return value=%d" NL, side, track, sector, ret);
300  return ret;
301 }
302 
303 
304 int c65_load_rom ( const char *fn, unsigned int dma_rev )
305 {
306  if (xemu_load_file(fn, memory + 0x20000, 0x20000, 0x20000, strcmp(fn, DEFAULT_ROM_FILE) ? "Cannot load specified C65 ROM" : "Cannot load the default C65 ROM") != 0x20000)
307  return -1;
309  dma_init_set_rev(dma_rev, memory + 0x20000 + 0x16);
310  return 0;
311 }
312 
313 
314 
315 static void c65_init ( int sid_cycles_per_sec, int sound_mix_freq )
316 {
317  //const char *p;
318  SDL_AudioSpec audio_want, audio_got;
319  hid_init(
320  c64_key_map,
322  SDL_ENABLE // joy HID events enabled
323  );
324 #ifdef HID_KBD_MAP_CFG_SUPPORT
325  hid_keymap_from_config_file(configdb.keymap);
326 #endif
327  joystick_emu = 2; // use port-2 by default
328  nmi_level = 0;
329  // *** host-FS
330  if (configdb.hostfsdir)
332  else
333  hostfs_init(sdl_pref_dir, "hostfs");
334  // *** Init memory space
335  memset(memory, 0xFF, sizeof memory);
336  // *** Initialize VIC3
337  vic3_init();
338  // *** Memory configuration
339  memory[0] = memory[1] = 0xFF; // the "CPU I/O port" on 6510/C64, implemented by VIC3 for real in C65!
340  map_mask = 0; // as all 8K blocks are unmapped, we don't need to worry about the low/high offset to set here
341  apply_memory_config(); // VIC3 $30 reg is already filled, so it's OK to call this now
342  // *** CIAs
343  cia_init(&cia1, "CIA-1",
344  NULL, // callback: OUTA
345  NULL, // callback: OUTB
346  NULL, // callback: OUTSR
347  cia1_in_a, // callback: INA ~ joy#2
348  cia1_in_b, // callback: INB ~ keyboard
349  NULL, // callback: INSR
350  cia1_setint_cb // callback: SETINT
351  );
352  cia_init(&cia2, "CIA-2",
353  cia2_out_a, // callback: OUTA ~ eg VIC-II bank
354  NULL, // callback: OUTB
355  NULL, // callback: OUTSR
356  cia2_in_a, // callback: INA
357  cia2_in_b, // callback: INB
358  NULL, // callback: INSR
359  cia2_setint_cb // callback: SETINT ~ that would be NMI in our case
360  );
361  // *** Initialize DMA
363  // *** Load ROM image
364  if (c65_load_rom(configdb.rom, configdb.dmarev)) // ... but this overrides the DMA revision!
365  XEMUEXIT(1);
366  // Initialize FDC
368  // Initialize D81 access abstraction for FDC
369  d81access_init();
370  atexit(d81access_close_all);
373  // SIDs, plus SDL audio
374  sid_init(&sids[0], sid_cycles_per_sec, sound_mix_freq);
375  sid_init(&sids[1], sid_cycles_per_sec, sound_mix_freq);
376  SDL_memset(&audio_want, 0, sizeof(audio_want));
377  audio_want.freq = sound_mix_freq;
378  audio_want.format = AUDIO_S16SYS; // used format by SID emulation (ie: signed short)
379  audio_want.channels = 2; // that is: stereo, for the two SIDs
380  audio_want.samples = 1024; // Sample size suggested (?) for the callback to render once
381  audio_want.callback = audio_callback; // Audio render callback function, called periodically by SDL on demand
382  audio_want.userdata = NULL; // Not used, "userdata" parameter passed to the callback by SDL
383  audio = SDL_OpenAudioDevice(NULL, 0, &audio_want, &audio_got, 0);
384  if (audio) {
385  int i;
386  for (i = 0; i < SDL_GetNumAudioDevices(0); i++)
387  DEBUG("AUDIO: audio device is #%d: %s" NL, i, SDL_GetAudioDeviceName(i, 0));
388  // Sanity check that we really got the same audio specification we wanted
389  if (audio_want.freq != audio_got.freq || audio_want.format != audio_got.format || audio_want.channels != audio_got.channels) {
390  SDL_CloseAudioDevice(audio); // forget audio, if it's not our expected format :(
391  audio = 0;
392  ERROR_WINDOW("Audio parameter mismatches.");
393  }
394  DEBUG("AUDIO: initialized (#%d), %d Hz, %d channels, %d buffer sample size." NL, audio, audio_got.freq, audio_got.channels, audio_got.samples);
395  } else
396  ERROR_WINDOW("Cannot open audio device!");
397  // *** RESET CPU, also fetches the RESET vector into PC
398  cpu65_reset();
399  DEBUG("INIT: end of initialization!" NL);
400  // *** Snapshot init and loading etc should be the LAST!!!! (at least the load must be last to have initiated machine state, xemusnap_init() can be called earlier too)
401 #ifdef XEMU_SNAPSHOT_SUPPORT
402  xemusnap_init(c65_snapshot_definition);
403  if (configdb.snapload) {
404  if (xemusnap_load(configdb.snapload))
405  FATAL("Couldn't load snapshot \"%s\": %s", configdb.snapload, xemusnap_error_buffer);
406  }
407  atexit(c65_snapshot_saver_on_exit_callback);
408 #endif
409 }
410 
411 
412 
413 
414 
415 
416 
417 // *** Implements the MAP opcode of 4510, called by the 65CE02 emulator
419 {
420  cpu65.cpu_inhibit_interrupts = 1; // disable interrupts to the next "EOM" (ie: NOP) opcode
421  DEBUG("CPU: MAP opcode, input A=$%02X X=$%02X Y=$%02X Z=$%02X" NL, cpu65.a, cpu65.x, cpu65.y, cpu65.z);
422  map_offset_low = (cpu65.a << 8) | ((cpu65.x & 15) << 16); // offset of lower half (blocks 0-3)
423  map_offset_high = (cpu65.y << 8) | ((cpu65.z & 15) << 16); // offset of higher half (blocks 4-7)
424  map_mask = (cpu65.z & 0xF0) | (cpu65.x >> 4); // "is mapped" mask for blocks (1 bit for each)
425  DEBUG("MEM: applying new memory configuration because of MAP CPU opcode" NL);
426  DEBUG("LOW -OFFSET = $%X" NL, map_offset_low);
427  DEBUG("HIGH-OFFSET = $%X" NL, map_offset_high);
428  DEBUG("MASK = $%02X" NL, map_mask);
430 }
431 
432 
433 // *** Implements the EOM opcode of 4510, called by the 65CE02 emulator
435 {
436  if (cpu65.cpu_inhibit_interrupts) {
437  cpu65.cpu_inhibit_interrupts = 0;
438  DEBUG("CPU: EOM, interrupts were disabled because of MAP till the EOM" NL);
439  } else
440  DEBUG("CPU: NOP in not treated as EOM (no MAP before)" NL);
441 }
442 
443 
444 static inline Uint8 read_some_sid_register ( int addr )
445 {
446  // currently we don't support reading SID registers at all (1351 mouse emulation may need POT-X and POT-Y in the future though, TODO)
447  switch (addr & 0x1F) {
448  case 0x19:
449  if (!is_mouse_grab())
450  return 0xFF;
451  mouse_x = (mouse_x + hid_read_mouse_rel_x(-31, 31)) & 63;
452  return mouse_x << 1;
453  case 0x1A:
454  if (!is_mouse_grab())
455  return 0xFF;
456  mouse_y = (mouse_y - hid_read_mouse_rel_y(-31, 31)) & 63;
457  return mouse_y << 1;
458  default:
459  return 0xFF;
460  }
461 }
462 
463 
464 static inline void write_some_sid_register ( int addr, Uint8 data )
465 {
466  int instance = (addr >> 6) & 1; // Selects left/right SID based on address
467  DEBUG("SID%d: writing register $%04X ($%04X) with data $%02X @ PC=$%04X" NL, ((addr >> 6) & 1) + 1, addr & 0x1F, addr + 0xD000, data, cpu65.pc);
468  sid_write_reg(&sids[instance], addr & 0x1F, data);
469 }
470 
471 
473 {
474  addr &= 0xFFF; // Internally, we use I/O addresses $0000-$0FFF only!
475  switch ((addr >> 8) | vic_new_mode) { // "addr >> 8" is from 0...F, vic_new_mode can be $10 or 0, that is $00-$1F for all cases
476  /* --- I/O read in old VIC I/O mode --- */
477  case 0x00: // $D000-$D0FF
478  case 0x01: // $D100-$D1FF, C65 VIC-III palette, red components (in old VIC mode, cannot be accessed)
479  case 0x02: // $D200-$D2FF, C65 VIC-III palette, green components (in old VIC mode, cannot be accessed)
480  case 0x03: // $D300-$D3FF, C65 VIC-III palette, blue components (in old VIC mode, cannot be accessed)
481  // In old VIC-II mode, according to c65manual.txt and C64 "standard", VIC-II registers can be seen at every 64 bytes in I/O range $D000-$D3FF
482  return vic3_read_reg(addr & 0x3F);
483  case 0x04: // $D400-$D4FF, SID stuffs
484  case 0x05: // $D500-$D5FF
485  case 0x06: // $D600-$D6FF, would be C65 UART, in old I/O mode: SID images still
486  case 0x07: // $D700-$D7FF, would be C65 DMA, in old I/O mode; SID images still
487  return read_some_sid_register(addr);
488  case 0x08: // $D800-$D8FF, colour SRAM
489  case 0x09: // $D900-$D9FF, colour SRAM
490  case 0x0A: // $DA00-$DAFF, colour SRAM
491  case 0x0B: // $DB00-$DBFF, colour SRAM
492  return memory[0x1F000 + addr]; // 0x1F800 would be the colour RAM on C65, but since the offset in I/O address range is already $800, we use 0x1F000
493  case 0x0C: // $DC00-$DCFF, CIA-1 or colour SRAM second half
494  // TODO: check if "extended colour SRAM" would work at all in old I/O mode this way!!!!
495  return vic3_registers[0x30] & 1 ? memory[0x1F000 + addr] : cia_read(&cia1, addr & 0xF);
496  case 0x0D: // $DD00-$DDFF, CIA-2 or colour SRAM second half
497  return vic3_registers[0x30] & 1 ? memory[0x1F000 + addr] : cia_read(&cia2, addr & 0xF);
498  case 0x0E: // $DE00-$DEFF, I/O-1 or colour SRAM second half on C65
499  case 0x0F: // $DF00-$DFFF, I/O-2 or colour SRAM second half on C65
500  return vic3_registers[0x30] & 1 ? memory[0x1F000 + addr] : 0xFF; // I/O exp area is not emulated by Xemu, gives $FF on reads
501  /* --- I/O read in new VIC I/O mode --- */
502  case 0x10: // $D000-$D0FF
503  if (XEMU_LIKELY(addr < 0x80))
504  return vic3_read_reg(addr);
505  if (addr < 0xA0)
506  return fdc_read_reg(addr & 0xF);
507  if (addr == 0xFE)
508  return hostfs_read_reg0();
509  if (addr == 0xFF)
510  return hostfs_read_reg1();
511  return 0xFF; // RAM expansion controller (not emulated by Xemu)
512  case 0x11: // $D100-$D1FF, C65 VIC-III palette, red components
513  case 0x12: // $D200-$D2FF, C65 VIC-III palette, green components
514  case 0x13: // $D300-$D3FF, C65 VIC-III palette, blue components
515  return 0xFF; // palette registers are write-only on C65????
516  case 0x14: // $D400-$D4FF, SID stuffs
517  case 0x15: // $D500-$D5FF
518  return read_some_sid_register(addr);
519  case 0x16: // $D600-$D6FF, C65 UART
520  //DEBUGPRINT("READ D%03X" NL, addr);
521  return 0xFF; // not emulated by Xemu, yet, TODO
522  case 0x17: // $D700-$D7FF, C65 DMA
523  return dma_read_reg(addr & 15);
524  case 0x18: // $D800-$D8FF, colour SRAM
525  case 0x19: // $D900-$D9FF, colour SRAM
526  case 0x1A: // $DA00-$DAFF, colour SRAM
527  case 0x1B: // $DB00-$DBFF, colour SRAM
528  return memory[0x1F000 + addr]; // 0x1F800 would be the colour RAM on C65, but since the offset in I/O address range is already $800, we use 0x1F000
529  case 0x1C:
530  return vic3_registers[0x30] & 1 ? memory[0x1F000 + addr] : cia_read(&cia1, addr & 0xF);
531  case 0x1D:
532  return vic3_registers[0x30] & 1 ? memory[0x1F000 + addr] : cia_read(&cia2, addr & 0xF);
533  case 0x1E: // $DE00-$DEFF, I/O-1 or colour SRAM second half on C65
534  case 0x1F: // $DF00-$DFFF, I/O-2 or colour SRAM second half on C65
535  return vic3_registers[0x30] & 1 ? memory[0x1F000 + addr] : 0xFF; // I/O exp area is not emulated by Xemu, gives $FF on reads
536  default:
537  FATAL("Invalid switch case in io_read(%d)!! CASE=%X, vic_new_mode=%d", addr, (addr >> 8) | vic_new_mode, vic_new_mode);
538  break;
539  }
540  return 0xFF; // just make gcc happy ...
541 }
542 
543 
544 
545 
546 void io_write ( int addr, Uint8 data )
547 {
548  addr &= 0xFFF; // Internally, we use I/O addresses $0000-$0FFF only!
549  switch ((addr >> 8) | vic_new_mode) { // "addr >> 8" is from 0...F, vic_new_mode can be $10 or 0, that is $00-$1F for all cases
550  /* --- I/O write in old VIC I/O mode --- */
551  case 0x00: // $D000-$D0FF
552  case 0x01: // $D100-$D1FF, C65 VIC-III palette, red components (in old VIC mode, cannot be accessed)
553  case 0x02: // $D200-$D2FF, C65 VIC-III palette, green components (in old VIC mode, cannot be accessed)
554  case 0x03: // $D300-$D3FF, C65 VIC-III palette, blue components (in old VIC mode, cannot be accessed)
555  // In old VIC-II mode, according to c65manual.txt and C64 "standard", VIC-II registers can be seen at every 64 bytes in I/O range $D000-$D3FF
556  vic3_write_reg(addr & 0x3F, data);
557  return;
558  case 0x04: // $D400-$D4FF, SID stuffs
559  case 0x05: // $D500-$D5FF
560  case 0x06: // $D600-$D6FF, would be C65 UART, in old I/O mode: SID images still
561  case 0x07: // $D700-$D7FF, would be C65 DMA, in old I/O mode; SID images still
562  write_some_sid_register(addr, data);
563  return;
564  case 0x08: // $D800-$D8FF, colour SRAM
565  case 0x09: // $D900-$D9FF, colour SRAM
566  case 0x0A: // $DA00-$DAFF, colour SRAM
567  case 0x0B: // $DB00-$DBFF, colour SRAM
568  memory[0x1F000 + addr] = data; // 0x1F800 would be the colour RAM on C65, but since the offset in I/O address range is already $800, we use 0x1F000
569  return;
570  case 0x0C: // $DC00-$DCFF, CIA-1 or colour SRAM second half
571  // TODO: check if "extended colour SRAM" would work at all in old I/O mode this way!!!!
572  if (vic3_registers[0x30] & 1)
573  memory[0x1F000 + addr] = data;
574  else
575  cia_write(&cia1, addr & 0xF, data);
576  return;
577  case 0x0D: // $DD00-$DDFF, CIA-2 or colour SRAM second half
578  if (vic3_registers[0x30] & 1)
579  memory[0x1F000 + addr] = data;
580  else
581  cia_write(&cia2, addr & 0xF, data);
582  return;
583  case 0x0E: // $DE00-$DEFF, I/O-1 or colour SRAM second half on C65
584  case 0x0F: // $DF00-$DFFF, I/O-2 or colour SRAM second half on C65
585  if (vic3_registers[0x30] & 1)
586  memory[0x1F000 + addr] = data;
587  return;
588  /* --- I/O write in new VIC I/O mode --- */
589  case 0x10: // $D000-$D0FF
590  if (XEMU_LIKELY(addr < 0x80)) {
592  return;
593  }
594  if (addr < 0xA0) {
595  fdc_write_reg(addr & 0xF, data);
596  return;
597  }
598  if (addr == 0xFE) {
600  return;
601  }
602  if (addr == 0xFF) {
604  return;
605  }
606  return; // Note: RAM expansion controller (not emulated by Xemu)
607  case 0x11: // $D100-$D1FF, C65 VIC-III palette, red components
608  case 0x12: // $D200-$D2FF, C65 VIC-III palette, green components
609  case 0x13: // $D300-$D3FF, C65 VIC-III palette, blue components
610  vic3_write_palette_reg(addr - 0x100, data);
611  return;
612  case 0x14: // $D400-$D4FF, SID stuffs
613  case 0x15: // $D500-$D5FF
614  write_some_sid_register(addr, data);
615  return;
616  case 0x16: // $D600-$D6FF, C65 UART
617  if (addr == 0x607) {
618  port_d607 = data;
619  }
620  //DEBUGPRINT("WRITE D%03X with data %02X" NL, addr, data);
621  return; // not emulated by Xemu, yet, TODO
622  case 0x17: // $D700-$D7FF, C65 DMA
623  dma_write_reg(addr & 15, data);
624  return;
625  case 0x18: // $D800-$D8FF, colour SRAM
626  case 0x19: // $D900-$D9FF, colour SRAM
627  case 0x1A: // $DA00-$DAFF, colour SRAM
628  case 0x1B: // $DB00-$DBFF, colour SRAM
629  memory[0x1F000 + addr] = data; // 0x1F800 would be the colour RAM on C65, but since the offset in I/O address range is already $800, we use 0x1F000
630  return ;
631  case 0x1C:
632  if (vic3_registers[0x30] & 1)
633  memory[0x1F000 + addr] = data;
634  else
635  cia_write(&cia1, addr & 0xF, data);
636  return;
637  case 0x1D:
638  if (vic3_registers[0x30] & 1)
639  memory[0x1F000 + addr] = data;
640  else
641  cia_write(&cia2, addr & 0xF, data);
642  return;
643  case 0x1E: // $DE00-$DEFF, I/O-1 or colour SRAM second half on C65
644  case 0x1F: // $DF00-$DFFF, I/O-2 or colour SRAM second half on C65
645  if (vic3_registers[0x30] & 1)
646  memory[0x1F000 + addr] = data;
647  return;
648  default:
649  FATAL("Invalid switch case in io_write(%d)!! CASE=%X, vic_new_mode=%d", addr, (addr >> 8) | vic_new_mode, vic_new_mode);
650  return;
651  }
652 }
653 
654 
655 
657 {
658  addr &= 0xFFFFF;
659  if (XEMU_UNLIKELY(addr < 2)) { // "CPU port" at memory addr 0/1
660  if ((memory[addr] & 7) != (data & 7)) {
661  memory[addr] = data;
662  DEBUG("MEM: applying new memory configuration because of CPU port writing" NL);
664  } else
665  memory[addr] = data;
666  } else if (
667  (XEMU_LIKELY(addr < 0x20000))
668 #if defined(ALLOW_256K_RAMEXP) && defined(ALLOW_512K_RAMEXP)
669  || (addr >= 0x40000)
670 #else
671 # ifdef ALLOW_256K_RAMEXP
672  || (addr >= 0x40000 && addr < 0x80000)
673 # endif
674 # ifdef ALLOW_512K_RAMEXP
675  || (addr >= 0x80000)
676 # endif
677 #endif
678  )
679  memory[addr] = data;
680 }
681 
682 
684 {
685  if (XEMU_LIKELY(addr <= 0xFFFFF))
687  else
688  DEBUG("DMA-C65-BACKEND: writing memory above 1Mbyte (addr=$%X,data=%02X) PC=%04X" NL, addr, data, cpu65.pc);
689 }
690 
691 
693 {
694  return memory[addr & 0xFFFFF];
695 }
696 
697 
699 {
700  if (XEMU_LIKELY(addr <= 0xFFFFF))
701  return memory[addr & 0xFFFFF];
702  else {
703  DEBUG("DMA-C65-BACKEND: reading memory above 1Mbyte (addr=$%X) PC=%04X" NL, addr, cpu65.pc);
704  return 0xFF;
705  }
706 }
707 
708 
709 
710 // This function is called by the 65CE02 emulator in case of reading a byte (regardless of data or code)
712 {
713  register int phys_addr = addr_trans_rd[addr >> 12] + addr; // translating address with the READ table created by apply_memory_config()
714  if (XEMU_LIKELY(phys_addr < 0x10FF00))
715  return memory[phys_addr & 0xFFFFF]; // light optimization, do not call read_phys_mem for this single stuff :)
716  else
717  return io_read(phys_addr);
718 }
719 
720 
721 
722 // This function is called by the 65CE02 emulator in case of writing a byte
724 {
725  register int phys_addr = addr_trans_wr[addr >> 12] + addr; // translating address with the WRITE table created by apply_memory_config()
726  if (XEMU_LIKELY(phys_addr < 0x10FF00))
727  write_phys_mem(phys_addr, data);
728  else
729  io_write(phys_addr, data);
730 }
731 
732 
733 
734 // Called in case of an RMW (read-modify-write) opcode write access.
735 // Original NMOS 6502 would write the old_data first, then new_data.
736 // It has no inpact in case of normal RAM, but it *does* with an I/O register in some cases!
737 // CMOS line of 65xx (probably 65CE02 as well?) seems not write twice, but read twice.
738 // However this leads to incompatibilities, as some software used the RMW behavour by intent.
739 // Thus Mega65 fixed the problem to "restore" the old way of RMW behaviour.
740 // I also follow this path here, even if it's *NOT* what 65CE02 would do actually!
741 void cpu65_write_rmw_callback ( Uint16 addr, Uint8 old_data, Uint8 new_data )
742 {
743  int phys_addr = addr_trans_wr[addr >> 12] + addr; // translating address with the WRITE table created by apply_memory_config()
744  if (XEMU_LIKELY(phys_addr < 0x10FF00))
745  write_phys_mem(phys_addr, new_data); // "normal" memory, just write once, no need to emulate the behaviour
746  else {
747  DEBUG("CPU: RMW opcode is used on I/O area for $%04X" NL, addr);
748  io_write(phys_addr, old_data); // first write back the old data ...
749  io_write(phys_addr, new_data); // ... then the new
750  }
751 }
752 
753 
754 int dump_memory ( const char *fn )
755 {
756  if (fn && *fn) {
757  DEBUGPRINT("MEM: Dumping memory into file: %s" NL, fn);
758  return xemu_save_file(fn, memory, 0x20000, "Cannot dump memory into file");
759  } else {
760  return 0;
761  }
762 }
763 
764 
765 static void shutdown_callback ( void )
766 {
767  int a;
768  for (a = 0; a < 0x40; a++)
769  DEBUG("VIC-3 register $%02X is %02X" NL, a, vic3_registers[a]);
770  cia_dump_state (&cia1);
771  cia_dump_state (&cia2);
772 #if !defined(XEMU_ARCH_HTML)
774 #endif
775  DEBUGPRINT("Scanline render info = \"%s\"" NL, scanline_render_debug_info);
776  DEBUGPRINT("VIC3: D011=$%02X D018=$%02X D030=$%02X D031=$%02X" NL,
778  );
779  DEBUG("Execution has been stopped at PC=$%04X [$%05X]" NL, cpu65.pc, addr_trans_rd[cpu65.pc >> 12] + cpu65.pc);
780 }
781 
782 
783 int c65_reset_asked ( void )
784 {
785  if (ARE_YOU_SURE("Are you sure to HARD RESET your Commodore-65?", i_am_sure_override | ARE_YOU_SURE_DEFAULT_YES)) {
786  c65_reset();
787  return 1;
788  } else
789  return 0;
790 }
791 
792 void c65_reset ( void )
793 {
794  memory[0] = memory[1] = 0xFF;
795  map_mask = 0;
796  vic3_registers[0x30] = 0;
798  cpu65_reset();
799  dma_reset();
800  nmi_level = 0;
801  DEBUG("RESET!" NL);
802 }
803 
804 
805 
806 // Called by emutools_hid!!! to handle special private keys assigned to this emulator
807 int emu_callback_key ( int pos, SDL_Scancode key, int pressed, int handled )
808 {
809  if (pressed) {
810  if (key == SDL_SCANCODE_F10) { // reset
811  c65_reset_asked();
812  } else if (key == SDL_SCANCODE_KP_ENTER) {
814  } else if (key == SDL_SCANCODE_LSHIFT) {
815  shift_status |= 1;
816  } else if (key == SDL_SCANCODE_RSHIFT) {
817  shift_status |= 2;
818  }
819  if (shift_status == 3 && set_mouse_grab(SDL_FALSE, 0)) {
820  DEBUGPRINT("UI: mouse grab cancelled" NL);
821  }
822  } else {
823  if (key == SDL_SCANCODE_LSHIFT) {
824  shift_status &= 2;
825  } else if (key == SDL_SCANCODE_RSHIFT) {
826  shift_status &= 1;
827  } else if (pos == -2 && key == 0) { // special case pos = -2, key = 0, handled = mouse button (which?) and release event!
828  if (handled == SDL_BUTTON_LEFT && set_mouse_grab(SDL_TRUE, 0)) {
829  OSD(-1, -1, "Mouse grab activated. Press\nboth SHIFTs together to cancel.");
830  DEBUGPRINT("UI: mouse grab activated" NL);
831  }
832  if (handled == SDL_BUTTON_RIGHT) {
833  ui_enter();
834  }
835  }
836  }
837  return 0;
838 }
839 
840 
841 #ifdef XEMU_FILES_SCREENSHOT_SUPPORT
843 static inline void do_pending_screenshot ( void )
844 {
846  return;
848  if (!xemu_screenshot_png(
849  NULL, NULL,
850  1,
851  2,
852  NULL, // allow function to figure it out ;)
853  SCREEN_WIDTH,
856  )) {
857  const char *p = strrchr(xemu_screenshot_full_path, DIRSEP_CHR);
858  if (p)
859  OSD(-1, -1, "%s", p + 1);
860  }
861 }
862 #endif
863 
864 
865 static void update_emulator ( void )
866 {
867 #ifdef XEMU_FILES_SCREENSHOT_SUPPORT
868  // DO call this _RIGHT BEFORE_ xemu_update_screen() otherwise the texture
869  // does not exist anymore OR not the full frame is rendered yet for screenshot!
870  do_pending_screenshot();
871 #endif
875  nmi_set(IS_RESTORE_PRESSED(), 2); // Custom handling of the restore key ...
876  xemu_timekeeping_delay(40000);
877  // Ugly CIA trick to maintain realtime TOD in CIAs :)
878  const struct tm *t = xemu_get_localtime();
879  const Uint8 sec10ths = xemu_get_microseconds() / 100000;
880  cia_ugly_tod_updater(&cia1, t, sec10ths, 0);
881  cia_ugly_tod_updater(&cia2, t, sec10ths, 0);
882 }
883 
884 
885 static int cycles;
886 
887 
888 static void emulation_loop ( void )
889 {
891  for (;;) {
893 #ifdef CPU_STEP_MULTI_OPS
895 #endif
896  ); // FIXME: this is maybe not correct, that DMA's speed depends on the fast/slow clock as well?
897  if (cycles >= cpu_cycles_per_scanline) {
898  int exit_loop = 0;
899  cia_tick(&cia1, 64);
900  cia_tick(&cia2, 64);
901  cycles -= cpu_cycles_per_scanline;
905  if (frameskip) {
906  frameskip = 0;
908  } else {
909  frameskip = 1;
910  update_emulator();
911  //vic3_open_frame_access();
912  exit_loop = 1;
913  }
914  sids[0].sFrameCount++;
915  sids[1].sFrameCount++;
916  }
918  if (exit_loop)
919  return;
920  }
921  }
922 }
923 
924 
925 
926 int main ( int argc, char **argv )
927 {
928  //int cycles;
929  xemu_pre_init(APP_ORG, TARGET_NAME, "The Unusable Commodore 65 emulator from LGB");
931  if (xemucfg_parse_all(argc, argv))
932  return 1;
933  /* Initiailize SDL - note, it must be before loading ROMs, as it depends on path info from SDL! */
935  if (xemu_post_init(
936  TARGET_DESC APP_DESC_APPEND, // window title
937  1, // resizable window
938  SCREEN_WIDTH, SCREEN_HEIGHT, // texture sizes
939  SCREEN_WIDTH, SCREEN_HEIGHT * 2,// logical size (used with keeping aspect ratio by the SDL render stuffs)
940  SCREEN_WIDTH, SCREEN_HEIGHT * 2,// window size
941  SCREEN_FORMAT, // pixel format
942  0, // we have *NO* pre-defined colours as with more simple machines (too many we need). we want to do this ourselves!
943  NULL, // -- "" --
944  NULL, // -- "" --
945  configdb.sdlrenderquality, // render scaling quality
946  USE_LOCKED_TEXTURE, // 1 = locked texture access
947  shutdown_callback // registered shutdown function
948  ))
949  return 1;
950  // Initialize C65 ...
951  c65_init(
952  SID_CYCLES_PER_SEC, // SID cycles per sec
953  AUDIO_SAMPLE_FREQ // sound mix freq
954  );
957  if (configdb.prg)
959 #ifdef FAKE_TYPING_SUPPORT
960  if (configdb.go64) {
961  if (configdb.autoload)
962  c64_register_fake_typing(fake_typing_for_load64);
963  else
964  c64_register_fake_typing(fake_typing_for_go64);
965  } else if (configdb.autoload)
966  c64_register_fake_typing(fake_typing_for_load65);
967 #endif
968  cycles = 0;
969  if (audio)
970  SDL_PauseAudioDevice(audio, 0);
972  if (!configdb.syscon)
973  sysconsole_close(NULL);
975  XEMU_MAIN_LOOP(emulation_loop, 25, 1);
976  return 0;
977 }
978 
979 /* --- SNAPSHOT RELATED --- */
980 
981 #ifdef XEMU_SNAPSHOT_SUPPORT
982 
983 #include <string.h>
984 
985 #define SNAPSHOT_C65_BLOCK_VERSION 0
986 #define SNAPSHOT_C65_BLOCK_SIZE 0x100
987 
988 
989 int c65emu_snapshot_load_state ( const struct xemu_snapshot_definition_st *def, struct xemu_snapshot_block_st *block )
990 {
991  Uint8 buffer[SNAPSHOT_C65_BLOCK_SIZE];
992  int a;
993  if (block->block_version != SNAPSHOT_C65_BLOCK_VERSION || block->sub_counter || block->sub_size != sizeof buffer)
994  RETURN_XSNAPERR_USER("Bad C65 block syntax");
995  a = xemusnap_read_file(buffer, sizeof buffer);
996  if (a) return a;
997  /* loading state ... */
998  map_mask = (int)P_AS_BE32(buffer + 0);
999  map_offset_low = (int)P_AS_BE32(buffer + 4);
1000  map_offset_high = (int)P_AS_BE32(buffer + 8);
1001  cpu65.cpu_inhibit_interrupts = (int)P_AS_BE32(buffer + 12);
1002  return 0;
1003 }
1004 
1005 
1006 int c65emu_snapshot_save_state ( const struct xemu_snapshot_definition_st *def )
1007 {
1008  Uint8 buffer[SNAPSHOT_C65_BLOCK_SIZE];
1009  int a = xemusnap_write_block_header(def->idstr, SNAPSHOT_C65_BLOCK_VERSION);
1010  if (a) return a;
1011  memset(buffer, 0xFF, sizeof buffer);
1012  /* saving state ... */
1013  U32_AS_BE(buffer + 0, map_mask);
1014  U32_AS_BE(buffer + 4, map_offset_low);
1015  U32_AS_BE(buffer + 8, map_offset_high);
1016  U32_AS_BE(buffer + 12, cpu65.cpu_inhibit_interrupts);
1017  return xemusnap_write_sub_block(buffer, sizeof buffer);
1018 }
1019 
1020 
1021 int c65emu_snapshot_loading_finalize ( const struct xemu_snapshot_definition_st *def, struct xemu_snapshot_block_st *block )
1022 {
1024  DEBUGPRINT("SNAP: loaded (finalize-callback!)." NL);
1025  return 0;
1026 }
1027 #endif
sid_render
void sid_render(struct SidEmulation *sidemu, short *buffer, unsigned long len, int step)
Definition: sid.c:256
xemu_pre_init
void xemu_pre_init(const char *app_organization, const char *app_name, const char *slogan)
Definition: emutools.c:651
d81access_close_all
void d81access_close_all(void)
Definition: d81access.c:100
dma_reset
void dma_reset(void)
Definition: dma65.c:488
inject_ready_check_do
void inject_ready_check_do(void)
Definition: inject.c:234
USE_LOCKED_TEXTURE
#define USE_LOCKED_TEXTURE
Definition: commodore_65.h:26
cia6526.h
TARGET_DESC
#define TARGET_DESC
Definition: xemu-target.h:2
ROM_C64_BASIC_REMAP
#define ROM_C64_BASIC_REMAP
Definition: commodore_65.c:70
dma_init_set_rev
void dma_init_set_rev(unsigned int revision, Uint8 *rom_ver_signature)
Definition: dma65.c:439
cia_ugly_tod_updater
void cia_ugly_tod_updater(struct Cia6526 *cia, const struct tm *t, Uint8 sec10, int hour_offset)
Definition: cia6526.c:270
cia_read
Uint8 cia_read(struct Cia6526 *cia, int addr)
Definition: cia6526.c:121
hostfs_read_reg1
Uint8 hostfs_read_reg1(void)
Definition: cbmhostfs.c:669
D81ACCESS_AUTOCLOSE
#define D81ACCESS_AUTOCLOSE
Definition: d81access.h:38
xemu_timekeeping_delay
void xemu_timekeeping_delay(int td_em)
Definition: emutools.c:405
emutools.h
sysconsole_close
void sysconsole_close(const char *waitmsg)
Definition: emutools.c:1393
fdc_read_reg
Uint8 fdc_read_reg(int addr)
Definition: f011_core.c:472
fdc_set_disk
void fdc_set_disk(int which, int in_have_disk, int in_have_write)
Definition: f011_core.c:177
configdb_st::prg
char * prg
Definition: configdb.h:33
XEMU_MAIN_LOOP
#define XEMU_MAIN_LOOP(func, p1, p2)
Definition: emutools.h:58
ui.h
d81access_read_sect
int d81access_read_sect(const int which, Uint8 *buffer, const Uint8 side, const Uint8 track, const Uint8 sector, const int sector_size)
Definition: d81access.c:539
f011_core.h
d81access_write_sect
int d81access_write_sect(const int which, Uint8 *buffer, const Uint8 side, const Uint8 track, const Uint8 sector, const int sector_size)
Definition: d81access.c:572
read_phys_mem
Uint8 read_phys_mem(int addr)
Definition: commodore_65.c:692
fdc_cb_wr_sec
int fdc_cb_wr_sec(const int which, Uint8 *buffer, const Uint8 side, const Uint8 track, const Uint8 sector)
Definition: commodore_65.c:296
Cia6526::DDRB
Uint8 DDRB
Definition: cia6526.h:46
vic3.h
xemu_get_localtime
struct tm * xemu_get_localtime(void)
Definition: emutools.c:187
cpu_cycles_per_scanline
int cpu_cycles_per_scanline
Definition: vic3.c:64
disk_cache
Uint8 disk_cache[512]
Definition: commodore_65.c:53
current_rom_filepath
char current_rom_filepath[PATH_MAX]
Definition: commodore_65.c:51
SCREEN_WIDTH
#define SCREEN_WIDTH
Definition: vic3.h:29
have_disk
int have_disk
Definition: f011_core.c:67
c64_key_map
const struct KeyMappingDefault c64_key_map[]
Definition: c64_kbd_mapping.c:33
hid_read_mouse_rel_x
int hid_read_mouse_rel_x(int min, int max)
Definition: emutools_hid.c:485
vic3_init
void vic3_init(void)
Definition: vic3.c:926
register_screenshot_request
int register_screenshot_request
Definition: enterprise128.c:54
xemu_update_screen
void xemu_update_screen(void)
Definition: emutools.c:1184
c65_reset
void c65_reset(void)
Definition: commodore_65.c:792
i_am_sure_override
int i_am_sure_override
Definition: emutools.c:74
ROM_A000_REMAP
#define ROM_A000_REMAP
Definition: commodore_65.c:65
hostfs_init
void hostfs_init(const char *basedir, const char *subdir)
Definition: cbmhostfs.c:183
joystick_emu
int joystick_emu
Definition: c64_kbd_mapping.c:137
configdb_st::gui
char * gui
Definition: configdb.h:32
configdb_st::go64
int go64
Definition: configdb.h:34
configdb_st::rom
char * rom
Definition: configdb.h:32
is_mouse_grab
SDL_bool is_mouse_grab(void)
Definition: emutools.c:145
hid_read_mouse_rel_y
int hid_read_mouse_rel_y(int min, int max)
Definition: emutools_hid.c:497
c65_reset_asked
int c65_reset_asked(void)
Definition: commodore_65.c:783
d81access_init
void d81access_init(void)
Definition: d81access.c:56
INFO_WINDOW
#define INFO_WINDOW(...)
Definition: xep128.h:114
addr
int addr
Definition: dma65.c:81
IO_REMAP_VIRTUAL
#define IO_REMAP_VIRTUAL
Definition: commodore_65.c:60
emu_callback_key
int emu_callback_key(int pos, SDL_Scancode key, int pressed, int handled)
Definition: commodore_65.c:807
fn
const char * fn
Definition: roms.c:42
set_mouse_grab
int set_mouse_grab(SDL_bool state, int force_allow)
Definition: emutools.c:131
configdb_st::disk8
char * disk8
Definition: configdb.h:30
configdb_st::snapsave
char * snapsave
Definition: configdb.h:33
hid_handle_all_sdl_events
void hid_handle_all_sdl_events(void)
Definition: emutools_hid.c:613
dma_status
Uint8 dma_status
Definition: dma65.c:51
cpu65_write_callback
void cpu65_write_callback(Uint16 addr, Uint8 data)
Definition: commodore_65.c:723
io_write
void io_write(int addr, Uint8 data)
Definition: commodore_65.c:546
xemucfg_parse_all
int xemucfg_parse_all(int argc, char **argv)
write_phys_mem_for_dma
void write_phys_mem_for_dma(int addr, Uint8 data)
Definition: commodore_65.c:683
emutools_gui.h
configdb_st::keymap
char * keymap
Definition: configdb.h:32
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
osd_init_with_defaults
int osd_init_with_defaults(void)
Definition: osd.c:131
ROM_C64_CHR_REMAP
#define ROM_C64_CHR_REMAP
Definition: commodore_65.c:68
hid_init
void hid_init(const struct KeyMappingDefault *key_map_in, Uint8 virtual_shift_pos_in, int joy_enable)
Definition: emutools_hid.c:300
cia_tick
void cia_tick(struct Cia6526 *cia, int ticks)
Definition: cia6526.c:281
hid_reset_events
void hid_reset_events(int burn)
Definition: emutools_hid.c:170
cia2
struct Cia6526 cia1 cia2
Definition: commodore_65.c:44
d81access_attach_fsobj
int d81access_attach_fsobj(int which, const char *fn, int mode)
Definition: d81access.c:173
Uint8
uint8_t Uint8
Definition: fat32.c:51
Cia6526::DDRA
Uint8 DDRA
Definition: cia6526.h:46
inject_ready_check_status
int inject_ready_check_status
Definition: inject.c:31
xemu_set_full_screen
void xemu_set_full_screen(int setting)
Definition: emutools.c:311
configdb_st::d81ro
int d81ro
Definition: configdb.h:34
Cia6526
Definition: cia6526.h:37
c64_toggle_joy_emu
void c64_toggle_joy_emu(void)
Definition: c64_kbd_mapping.c:140
configdb_st::sdlrenderquality
int sdlrenderquality
Definition: configdb.h:35
configdb_define_emulator_options
void configdb_define_emulator_options(void)
Definition: configdb.c:36
xemugui_init
int xemugui_init(const char *name)
Definition: emutools_gui.c:82
read_phys_mem_for_dma
Uint8 read_phys_mem_for_dma(int addr)
Definition: commodore_65.c:698
block
Uint32 block
Definition: fat32.c:156
cpu65_do_nop_callback
void cpu65_do_nop_callback(void)
Definition: commodore_65.c:434
TARGET_NAME
#define TARGET_NAME
Definition: xemu-target.h:1
emutools_files.h
cbmhostfs.h
APP_ORG
#define APP_ORG
Definition: emutools.h:50
Cia6526::PRA
Uint8 PRA
Definition: cia6526.h:46
vic3_write_palette_reg
void vic3_write_palette_reg(int num, Uint8 data)
Definition: vic3.c:906
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
xemu_save_file
int xemu_save_file(const char *filename_in, void *data, int size, const char *cry)
Definition: emutools_files.c:622
cpu65_write_rmw_callback
void cpu65_write_rmw_callback(Uint16 addr, Uint8 old_data, Uint8 new_data)
Definition: commodore_65.c:741
D81ACCESS_RO
#define D81ACCESS_RO
Definition: d81access.h:37
VIRTUAL_SHIFT_POS
#define VIRTUAL_SHIFT_POS
Definition: commodore_lcd.c:84
vic3_registers
Uint8 vic3_registers[0x80]
Definition: vic3.c:61
configdb.h
xemu_get_microseconds
unsigned int xemu_get_microseconds(void)
Definition: emutools.c:205
dump_memory
int dump_memory(const char *fn)
Definition: commodore_65.c:754
Cia6526::PRB
Uint8 PRB
Definition: cia6526.h:46
c64_get_joy_state
Uint8 c64_get_joy_state(void)
Definition: c64_kbd_mapping.c:151
ERROR_WINDOW
#define ERROR_WINDOW(...)
Definition: xep128.h:116
d81access_cb_chgmode
void d81access_cb_chgmode(const int which, const int mode)
Definition: commodore_65.c:282
XEMU_LIKELY
#define XEMU_LIKELY(__x__)
Definition: emutools_basicdefs.h:124
configdb_st::hostfsdir
char * hostfsdir
Definition: configdb.h:32
mode
int mode
Definition: vera.c:61
main
int main(int argc, char **argv)
Definition: commodore_65.c:926
vic_new_mode
int vic_new_mode
Definition: vic3.c:62
instance
int instance
Definition: primo.c:89
D81ACCESS_PRG
#define D81ACCESS_PRG
Definition: d81access.h:34
configdb_st::autoload
int autoload
Definition: configdb.h:34
hostfs_write_reg1
void hostfs_write_reg1(Uint8 data)
Definition: cbmhostfs.c:720
D81ACCESS_EMPTY
#define D81ACCESS_EMPTY
Definition: d81access.h:32
NL
#define NL
Definition: fat32.c:37
vic3_render_scanline
int vic3_render_scanline(void)
Definition: vic3.c:571
emutools_config.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
commodore_65.h
fdc_cb_rd_sec
int fdc_cb_rd_sec(const int which, Uint8 *buffer, const Uint8 side, const Uint8 track, const Uint8 sector)
Definition: commodore_65.c:290
ROM_C64_KERNAL_REMAP
#define ROM_C64_KERNAL_REMAP
Definition: commodore_65.c:69
xemu_post_init
int xemu_post_init(const char *window_title, int is_resizable, int texture_x_size, int texture_y_size, int logical_x_size, int logical_y_size, int win_x_size, int win_y_size, Uint32 pixel_format, int n_colours, const Uint8 *colours, Uint32 *store_palette, int render_scale_quality, int locked_texture_update, void(*shutdown_callback)(void))
Definition: emutools.c:908
memory
Uint8 memory[0x100000]
Definition: commodore_65.c:43
xemu_load_file
int xemu_load_file(const char *filename, void *store_to, int min_size, int max_size, const char *cry)
Definition: emutools_files.c:674
SID_CYCLES_PER_SEC
#define SID_CYCLES_PER_SEC
Definition: commodore_65.h:32
dma_write_reg
void dma_write_reg(int addr, Uint8 data)
Definition: dma65.c:175
write_phys_mem
void write_phys_mem(int addr, Uint8 data)
Definition: commodore_65.c:656
emulator_speed_title
char emulator_speed_title[]
Definition: commodore_65.c:78
D81ACCESS_FAKE64
#define D81ACCESS_FAKE64
Definition: d81access.h:39
sid_write_reg
void sid_write_reg(struct SidEmulation *sidemu, int reg, unsigned char val)
Definition: sid.c:513
cpu65.h
cpu65_read_callback
Uint8 cpu65_read_callback(Uint16 addr)
Definition: commodore_65.c:711
XEMUEXIT
#define XEMUEXIT(n)
Definition: emutools_basicdefs.h:246
CPU_STEP_MULTI_OPS
#define CPU_STEP_MULTI_OPS
Definition: xemu-target.h:6
cia_init
void cia_init(struct Cia6526 *cia, const char *name, void(*outa)(Uint8 data), void(*outb)(Uint8 data), void(*outsr)(Uint8 data), Uint8(*ina)(void), Uint8(*inb)(void), Uint8(*insr)(void), void(*setint)(int level))
Definition: cia6526.c:98
ARE_YOU_SURE_DEFAULT_YES
#define ARE_YOU_SURE_DEFAULT_YES
Definition: emutools.h:125
xemu_timekeeping_start
void xemu_timekeeping_start(void)
Definition: emutools.c:1122
apply_memory_config
void apply_memory_config(void)
Definition: commodore_65.c:94
dma_update_multi_steps
int dma_update_multi_steps(int do_for_cycles)
Definition: dma65.c:405
fdc_init
void fdc_init(Uint8 *cache_set)
Definition: f011_core.c:110
vic3_read_reg
Uint8 vic3_read_reg(int addr)
Definition: vic3.c:854
configdb_st::syscon
int syscon
Definition: configdb.h:34
cia_dump_state
void cia_dump_state(struct Cia6526 *cia)
Definition: cia6526.c:323
vic3_select_bank
void vic3_select_bank(int bank)
Definition: vic3.c:720
hostfs_flush_all
void hostfs_flush_all(void)
Definition: cbmhostfs.c:270
io_read
Uint8 io_read(int addr)
Definition: commodore_65.c:472
sid.h
dma_read_reg
Uint8 dma_read_reg(int addr)
Definition: dma65.c:502
clear_emu_events
void clear_emu_events(void)
Definition: commodore_65.c:193
hostfs_write_reg0
void hostfs_write_reg0(Uint8 data)
Definition: cbmhostfs.c:625
cpu65_reset
void cpu65_reset(void)
Definition: cpu65.c:353
hostfs_read_reg0
Uint8 hostfs_read_reg0(void)
Definition: cbmhostfs.c:617
ARE_YOU_SURE
int ARE_YOU_SURE(const char *s, int flags)
Definition: emutools.c:1202
configdb_st::fullscreen
int fullscreen
Definition: configdb.h:34
SCREEN_HEIGHT
#define SCREEN_HEIGHT
Definition: vic3.h:30
SCREEN_FORMAT
#define SCREEN_FORMAT
Definition: commodore_65.h:25
inject.h
OSD
#define OSD(...)
Definition: xep128.h:100
ROM_8000_REMAP
#define ROM_8000_REMAP
Definition: commodore_65.c:64
xemu_load_filepath
char xemu_load_filepath[PATH_MAX]
Definition: emutools_files.c:35
inject_register_prg
int inject_register_prg(const char *prg_fn, int prg_mode)
Definition: inject.c:140
dma_init
void dma_init(unsigned int revision)
Definition: dma65.c:465
c65_snapshot.h
mask
int mask
Definition: dma65.c:83
vic3_open_frame_access
void vic3_open_frame_access(void)
Definition: vic3.c:104
sid_init
void sid_init(struct SidEmulation *sidemu, unsigned long cyclesPerSec, unsigned long mixfrq)
Definition: sid.c:649
AUDIO_SAMPLE_FREQ
#define AUDIO_SAMPLE_FREQ
Definition: commodore_65.h:33
stream
Uint8 * stream
Definition: inject.c:36
APP_DESC_APPEND
#define APP_DESC_APPEND
Definition: emutools.h:52
Uint16
uint16_t Uint16
Definition: fat32.c:50
xemugui_iteration
int xemugui_iteration(void)
Definition: emutools_gui.c:120
cpu65_do_aug_callback
void cpu65_do_aug_callback(void)
Definition: commodore_65.c:418
emutools_hid.h
configdb_st::snapload
char * snapload
Definition: configdb.h:33
c65_load_rom
int c65_load_rom(const char *fn, unsigned int dma_rev)
Definition: commodore_65.c:304
configdb_st::disk9
char * disk9
Definition: configdb.h:31
sids
struct SidEmulation sids[2]
Definition: commodore_65.c:45
configdb_st::dmarev
int dmarev
Definition: configdb.h:35
ALLOW_512K_RAMEXP
#define ALLOW_512K_RAMEXP
Definition: commodore_65.h:40
ROM_C000_REMAP
#define ROM_C000_REMAP
Definition: commodore_65.c:63
configdb_st::prgmode
int prgmode
Definition: configdb.h:35
D81ACCESS_DIR
#define D81ACCESS_DIR
Definition: d81access.h:35
D81ACCESS_IMG
#define D81ACCESS_IMG
Definition: d81access.h:33
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
scanline_render_debug_info
char scanline_render_debug_info[320]
Definition: vic3.c:99
DEFAULT_ROM_FILE
#define DEFAULT_ROM_FILE
Definition: commodore_65.h:35
cpu65_step
int cpu65_step(void)
Definition: cpu65.c:796
dma65.h
sdl_pref_dir
char * sdl_pref_dir
Definition: emutools.c:97
FATAL
#define FATAL(...)
Definition: xep128.h:117
IS_RESTORE_PRESSED
#define IS_RESTORE_PRESSED()
Definition: c64_kbd_mapping.h:33
ui_enter
void ui_enter(void)
Definition: ui.c:326
vic3_write_reg
void vic3_write_reg(int addr, Uint8 data)
Definition: vic3.c:745
configdb_st::dumpmem
char * dumpmem
Definition: configdb.h:32
window_title_info_addon
char * window_title_info_addon
Definition: emutools.c:91
SidEmulation::sFrameCount
int sFrameCount
Definition: sid.h:79
ROM_E000_REMAP
#define ROM_E000_REMAP
Definition: commodore_65.c:66
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
c64_kbd_mapping.h
SidEmulation
Definition: sid.h:78
frameskip
int frameskip
Definition: vic3.c:75
vic3_check_raster_interrupt
void vic3_check_raster_interrupt(void)
Definition: vic3.c:138
d81access.h
cia_write
void cia_write(struct Cia6526 *cia, int addr, Uint8 data)
Definition: cia6526.c:169
DIRSEP_CHR
#define DIRSEP_CHR
Definition: emutools_basicdefs.h:142