Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
sdcard.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)2016-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 #include "xemu/emutools.h"
20 #include "xemu/emutools_files.h"
21 #include "sdcard.h"
22 #include "xemu/f011_core.h"
23 #include "xemu/d81access.h"
24 #include "mega65.h"
25 #include "xemu/cpu65.h"
26 #include "io_mapper.h"
27 #include "sdcontent.h"
28 #include "memcontent.h"
29 #include "hypervisor.h"
30 #include "vic4.h"
31 
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <limits.h>
37 
38 #define COMPRESSED_SD
39 #define USE_KEEP_BUSY
40 
41 #ifdef USE_KEEP_BUSY
42 # define KEEP_BUSY(n) keep_busy=n
43 #else
44 # define KEEP_BUSY(n)
45 #endif
46 
47 #define SD_ST_SDHC 0x10
48 
49 // FIXME: invent same sane value here (the perfect solution would be to use sdcontent/mfat subsystem to query the boundaries of the FAT partitions)
50 #define MIN_MOUNT_SECTOR_NO 10
51 
52 #define SD_BUFFER_POS 0x0E00
53 #define FD_BUFFER_POS 0x0C00
54 
55 
56 static Uint8 sd_regs[0x30];
57 static int sdfd; // SD-card controller emulation, UNIX file descriptor of the open image file
58 Uint8 sd_status; // SD-status byte
59 static int sdhc_mode = 1;
60 static Uint32 sdcard_size_in_blocks; // SD card size in term of number of 512 byte blocks
61 static int sd_fill_mode = 0;
62 static Uint8 sd_fill_value = 0;
63 static int default_d81_is_from_sd;
64 #ifdef COMPRESSED_SD
65 static int sd_compressed = 0;
66 static off_t sd_bdata_start;
67 static int compressed_block;
68 #endif
69 static int sd_is_read_only;
70 #ifdef USE_KEEP_BUSY
71 static int keep_busy = 0;
72 #endif
73 // 4K buffer space: Actually the SD buffer _IS_ inside this, also the F011 buffer should be (FIXME: that is not implemented yet right now!!)
75 static Uint8 sd_fill_buffer[512]; // Only used by the sd fill mode write command
77 // FIXME/TODO: unfortunately it seems I/O mapping of SD-buffer is buggy even on
78 // real MEGA65 and the new code to have mapping allowing FD _and_ SD buffer mount
79 // causes problems. So let's revert back to a fixed "SD-only" solution for now.
81 
82 static const char *default_d81_basename[2] = { "mega65.d81", "mega65_9.d81" };
83 static const char *default_d81_disk_label[2] = { "XEMU EXTERNAL", "XEMU EXTERNAL 9" };
84 const char xemu_external_d81_signature[] = "\xFF\xFE<{[(XemuExternalDiskMagic)]}>";
85 
86 // Disk image mount information for the two units
87 static struct {
88  char *current_name;
89  int internal; // is internal mount? FIXME: in this source it's a hard to understand 3-stated logic being 0,1 or -1 ... let's fix this!
91  Uint32 at_sector; // valid only if "internal", internal mount sector number
92  Uint32 at_sector_initial; // internal mount sector number during only the first (reset/poweron) trap
93  int monitoring_initial; // if true, at_sector_initial is monitored and changed, if false, not anymore
94 } mount_info[2];
95 
96 #ifdef VIRTUAL_DISK_IMAGE_SUPPORT
97 
98 #define VIRTUAL_DISK_BLOCKS_PER_CHUNK 2048
99 // Simulate a 4Gbyte card for virtual disk (the number is: number of blocks). Does not matter since only the actual written blocks stored in memory from it
100 #define VIRTUAL_DISK_SIZE_IN_BLOCKS 8388608U
101 
102 #define RANGE_MAP_SIZE 256
103 
104 struct virtdisk_chunk_st {
105  struct virtdisk_chunk_st *next; // pointer to the next chunk, or NULL, if it was the last (in that case vdisk.tail should point to this chunk)
106  int used_blocks; // number of used blocks in this chunk (up to vidsk.blocks_per_chunk)
107  Uint32 block_no_min; // optimization: lowest numbered block inside _this_ chunk of blocks
108  Uint32 block_no_max; // optimization: highest numbered block inside _this_ chunk of blocks
109  Uint8 *base; // base pointer of the data area on this chunk, 512 bytes per block then
110  Uint32 list[]; // block number list for this chunk (see: used_blocks) [C99/C11 flexible array members syntax]
111 };
112 struct virtdisk_st {
113  struct virtdisk_chunk_st *head, *tail; // pointers to the head and tail of the linked list of chunks, or NULL for both, if there is nothing yet
114  int blocks_per_chunk; // number of blocks handled by a chunk
115  int allocation_size; // pre-calculated to have number of bytes allocated for a chunk, including the data area + struct itself
116  int base_offset; // pre-calculated to have the offset to the data area inside a chunk
117  int all_chunks; // number of all currently allocated chunks
118  int all_blocks; // number of all currently USED blocks within all chunks
119  Uint8 range_map[RANGE_MAP_SIZE]; // optimization: store here if a given range is stored in memory, eliminating the need to search all chunks over, if not
120  Uint32 range_map_divisor; // optimization: for the above, to form range number from block number
121  int mode; // what mode is used, 0=no virtual disk
122 };
123 
124 static struct virtdisk_st vdisk = { .head = NULL };
125 
126 static void virtdisk_destroy ( void )
127 {
128  if (vdisk.head) {
129  struct virtdisk_chunk_st *v = vdisk.head;
130  int ranges = 0;
131  for (unsigned int a = 0; a < RANGE_MAP_SIZE; a++)
132  for (Uint8 m = 0x80; m; m >>= 1)
133  if ((vdisk.range_map[a] & m))
134  ranges++;
135  DEBUGPRINT("SDCARD: VDISK: destroying %d chunks (active data: %d blocks, %dKbytes, %d%%, ranges: %d/%d) of storage." NL,
136  vdisk.all_chunks, vdisk.all_blocks, vdisk.all_blocks >> 1,
137  100 * vdisk.all_blocks / (vdisk.all_chunks * vdisk.blocks_per_chunk),
138  ranges, RANGE_MAP_SIZE * 8
139  );
140  while (v) {
141  struct virtdisk_chunk_st *next = v->next;
142  free(v);
143  v = next;
144  }
145  }
146  vdisk.head = NULL;
147  vdisk.tail = NULL;
148  vdisk.all_chunks = 0;
149  vdisk.all_blocks = 0;
150  memset(vdisk.range_map, 0, RANGE_MAP_SIZE);
151 }
152 
153 
154 static void virtdisk_init ( int blocks_per_chunk, Uint32 total_number_of_blocks )
155 {
156  virtdisk_destroy();
157  vdisk.blocks_per_chunk = blocks_per_chunk;
158  vdisk.base_offset = sizeof(struct virtdisk_chunk_st) + (sizeof(Uint32) * blocks_per_chunk);
159  vdisk.allocation_size = (blocks_per_chunk << 9) + vdisk.base_offset;
160  vdisk.range_map_divisor = (total_number_of_blocks / (RANGE_MAP_SIZE * 8)) + 1;
161  DEBUGPRINT("SDCARD: VDISK: %d blocks (%dKbytes) per chunk, range-divisor is %u" NL, blocks_per_chunk, blocks_per_chunk >> 1, vdisk.range_map_divisor);
162 }
163 
164 
165 // Note: you must take care to call this function with "block" not outside of the desired capacity or some logic (range_map) will cause crash.
166 // That's not a problem, as this function is intended to use as storage backend, thus boundary checking should be done BEFORE you call this!
167 static Uint8 *virtdisk_search_block ( Uint32 block, int do_allocate )
168 {
169  struct virtdisk_chunk_st *v;
170  Uint32 range_index = block / vdisk.range_map_divisor;
171  Uint8 range_mask = 1U << (range_index & 7U);
172  range_index >>= 3U;
173  if (XEMU_LIKELY(vdisk.head && (vdisk.range_map[range_index] & range_mask))) {
174  v = vdisk.head;
175  do {
176  if (block >= v->block_no_min && block <= v->block_no_max)
177  for (unsigned int a = 0; a < v->used_blocks; a++)
178  if (v->list[a] == block)
179  return v->base + (a << 9);
180  v = v->next;
181  } while (v);
182  }
183  // if we can't found the block, and do_allocate is false, we return with zero
184  // otherwise we continue to allocate a block
185  if (!do_allocate)
186  return NULL;
187  //DEBUGPRINT("RANGE-INDEX=%d RANGE-MASK=%d" NL, range_index, range_mask);
188  // We're instructed to allocate block if cannot be found already elsewhere
189  // This condition checks if we have room in "tail" or there is any chunk already at all (tail is not NULL)
190  if (vdisk.tail && (vdisk.tail->used_blocks < vdisk.blocks_per_chunk)) {
191  v = vdisk.tail;
192  // OK, we had room in the tail, so put the block there
193  vdisk.all_blocks++;
194  if (block < v->block_no_min)
195  v->block_no_min = block;
196  if (block > v->block_no_max)
197  v->block_no_max = block;
198  vdisk.range_map[range_index] |= range_mask;
199  v->list[v->used_blocks] = block;
200  return v->base + ((v->used_blocks++) << 9);
201  }
202  // we don't have room in the tail, or not any chunk yet AT ALL!
203  // Let's allocate a new chunk, and use the first block from it!
204  v = xemu_malloc(vdisk.allocation_size); // xemu_malloc() is safe, it malloc()s space or abort the whole program if it cannot ...
205  v->next = NULL;
206  v->base = (Uint8*)v + vdisk.base_offset;
207  vdisk.all_chunks++;
208  if (vdisk.tail)
209  vdisk.tail->next = v;
210  vdisk.tail = v;
211  if (!vdisk.head)
212  vdisk.head = v;
213  v->list[0] = block;
214  v->used_blocks = 1;
215  v->block_no_min = block;
216  v->block_no_max = block;
217  vdisk.range_map[range_index] |= range_mask;
218  vdisk.all_blocks++;
219  return v->base; // no need to add block offset in storage, always the first block is served in a new chunk!
220 }
221 
222 
223 static inline void virtdisk_write_block ( Uint32 block, Uint8 *buffer )
224 {
225  // Check if the block is all zero. If yes, we can omit write if the block is not cached
226  Uint8 *vbuf = virtdisk_search_block(block, has_block_nonzero_byte(buffer));
227  if (vbuf)
228  memcpy(vbuf, buffer, 512);
229  // TODO: Like with the next function, this whole strategy needs to be changed when mixed operation is used!!!!!
230 }
231 
232 
233 static inline void virtdisk_read_block ( Uint32 block, Uint8 *buffer )
234 {
235  Uint8 *vbuf = virtdisk_search_block(block, 0);
236  if (vbuf)
237  memcpy(buffer, vbuf, 512);
238  else
239  memset(buffer, 0, 512); // if not found, we fake an "all zero" answer (TODO: later in mixed operation, image+vdisk, this must be modified!)
240 }
241 #endif
242 
243 
244 // define the callback, d81access call this, we can dispatch the change in FDC config to the F011 core emulation this way, automatically.
245 // So basically these stuff binds F011 emulation and d81access so the F011 emulation used the d81access framework.
246 void d81access_cb_chgmode ( const int which, const int mode ) {
247  const int have_disk = ((mode & 0xFF) != D81ACCESS_EMPTY);
248  const int can_write = (!(mode & D81ACCESS_RO));
249  if (which < 2)
250  DEBUGPRINT("SDCARD: configuring F011 FDC (#%d) with have_disk=%d, can_write=%d" NL, which, have_disk, can_write);
251  fdc_set_disk(which, have_disk, can_write);
252 }
253 // Here we implement F011 core's callbacks using d81access (and yes, F011 uses 512 bytes long sectors for real)
254 int fdc_cb_rd_sec ( const int which, Uint8 *buffer, const Uint8 side, const Uint8 track, const Uint8 sector )
255 {
256  const int ret = d81access_read_sect(which, buffer, side, track, sector, 512);
257  DEBUG("SDCARD: D81: reading sector at d81_pos=(%d,%d,%d), return value=%d" NL, side, track, sector, ret);
258  return ret;
259 }
260 int fdc_cb_wr_sec ( const int which, Uint8 *buffer, const Uint8 side, const Uint8 track, const Uint8 sector )
261 {
262  const int ret = d81access_write_sect(which, buffer, side, track, sector , 512);
263  DEBUG("SDCARD: D81: writing sector at d81_pos=(%d,%d,%d), return value=%d" NL, side, track, sector, ret);
264  return ret;
265 }
266 
267 
268 static void sdcard_shutdown ( void )
269 {
271  if (sdfd >= 0) {
272  close(sdfd);
273  sdfd = -1;
274  }
275 #ifdef VIRTUAL_DISK_IMAGE_SUPPORT
276  virtdisk_destroy();
277 #endif
278 }
279 
280 
281 #ifdef COMPRESSED_SD
282 static int detect_compressed_image ( int fd )
283 {
284  static const char compressed_marker[] = "XemuBlockCompressedImage000";
285  Uint8 buf[512];
286  if (lseek(sdfd, 0, SEEK_SET) == OFF_T_ERROR || xemu_safe_read(fd, buf, 512) != 512)
287  return -1;
288  if (memcmp(buf, compressed_marker, sizeof compressed_marker)) {
289  DEBUGPRINT("SDCARD: image is not compressed" NL);
290  return 0;
291  }
292  if (((buf[0x1C] << 16) | (buf[0x1D] << 8) | buf[0x1E]) != 3) {
293  ERROR_WINDOW("Invalid/unknown compressed image format");
294  return -1;
295  }
296  sdcard_size_in_blocks = (buf[0x1F] << 16) | (buf[0x20] << 8) | buf[0x21];
297  DEBUGPRINT("SDCARD: compressed image with %u blocks" NL, sdcard_size_in_blocks);
298  sd_bdata_start = 3 * sdcard_size_in_blocks + 0x22;
299  sd_is_read_only = O_RDONLY;
300  return 1;
301 }
302 #endif
303 
304 
306 {
307  return sdcard_size_in_blocks;
308 }
309 
310 
311 static XEMU_INLINE void set_disk_buffer_cpu_view ( void )
312 {
313  disk_buffer_cpu_view = disk_buffers + ((sd_regs[9] & 0x80) ? SD_BUFFER_POS : FD_BUFFER_POS);
314 }
315 
316 
317 static void show_card_init_done ( void )
318 {
319  DEBUGPRINT("SDCARD: card init done, size=%u Mbytes (%s), virtsd_mode=%s, default_D81_from_sd=%d" NL,
320  sdcard_size_in_blocks >> 11,
321  sd_is_read_only ? "R/O" : "R/W",
322  vdisk.mode ? "IN-MEMORY-VIRTUAL" : "image-file",
323  default_d81_is_from_sd
324  );
325 }
326 
327 
328 int sdcard_init ( const char *fn, const int virtsd_flag, const int default_d81_is_from_sd_in )
329 {
330  default_d81_is_from_sd = default_d81_is_from_sd_in;
331  memset(sd_regs, 0, sizeof sd_regs); // reset all registers
332  memcpy(D6XX_registers + 0x80, sd_regs, sizeof sd_regs); // be sure, this is in sync with the D6XX register backend (used by io_mapper which also calls us ...)
333  set_disk_buffer_cpu_view(); // make sure to initialize disk_buffer_cpu_view based on current sd_regs[9] otherwise disk_buffer_cpu_view may points to NULL when referenced!
334  for (int a = 0; a < 2; a++) {
335  mount_info[a].current_name = xemu_strdup("<INIT>");
336  mount_info[a].internal = -1;
337  mount_info[a].force_external_name = NULL;
338  mount_info[a].at_sector = 0;
339  mount_info[a].at_sector_initial = 0;
340  mount_info[a].monitoring_initial = 0;
341  }
342  int just_created_image_file = 0; // will signal to format image automatically for the user (if set, by default it's clear, here)
343  char fnbuf[PATH_MAX + 1];
344 #ifdef VIRTUAL_DISK_IMAGE_SUPPORT
345  if (virtsd_flag) {
346  virtdisk_init(VIRTUAL_DISK_BLOCKS_PER_CHUNK, VIRTUAL_DISK_SIZE_IN_BLOCKS);
347  vdisk.mode = 1;
348  } else
349 #else
350  vdisk.mode = 0;
351 #endif
352  d81access_init();
353  atexit(sdcard_shutdown);
354  fdc_init(disk_buffers + FD_BUFFER_POS); // initialize F011 emulation
355  KEEP_BUSY(0);
356  sd_status = 0;
357  memset(sd_fill_buffer, sd_fill_value, 512);
358 #ifdef VIRTUAL_DISK_IMAGE_SUPPORT
359  if (vdisk.mode) {
360  sdfd = -1;
361  sd_is_read_only = 0;
362  sdcard_size_in_blocks = VIRTUAL_DISK_SIZE_IN_BLOCKS;
363 #ifdef COMPRESSED_SD
364  sd_compressed = 0;
365 #endif
366  show_card_init_done();
367 #ifdef SD_CONTENT_SUPPORT
368  sdcontent_handle(sdcard_size_in_blocks, fn, SDCONTENT_FORCE_FDISK);
369 #endif
370  return 0;
371  }
372 #endif
373 retry:
374  sd_is_read_only = O_RDONLY;
375  sdfd = xemu_open_file(fn, O_RDWR, &sd_is_read_only, fnbuf);
376  sd_is_read_only = (sd_is_read_only != XEMU_OPEN_FILE_FIRST_MODE_USED);
377  if (sdfd < 0) {
378  int r = errno;
379  ERROR_WINDOW("Cannot open SD-card image %s, SD-card access won't work! ERROR: %s", fnbuf, strerror(r));
380  DEBUG("SDCARD: cannot open image %s" NL, fn);
381  if (r == ENOENT && !strcmp(fn, SDCARD_NAME)) {
382  r = QUESTION_WINDOW(
383  "No|Yes"
384  ,
385  "Default SDCARD image does not exist. Would you like me to create one for you?\n"
386  "Note: it will be a 4Gbytes long file, since this is the minimal size for an SDHC card,\n"
387  "what MEGA65 needs. Do not worry, it's a 'sparse' file on most modern OSes which does\n"
388  "not takes as much disk space as its displayed size suggests.\n"
389  "This is unavoidable to emulate something uses an SDHC-card."
390  );
391  if (r) {
392  r = xemu_create_large_empty_file(fnbuf, 4294967296UL, 1);
393  if (r) {
394  ERROR_WINDOW("Couldn't create SD-card image file (hint: do you have enough space?)\nError message was: %s", strerror(r));
395  } else {
396  just_created_image_file = 1; // signal the rest of the code, that we have a brand new image file, which can be safely auto-formatted even w/o asking the user
397  goto retry;
398  }
399  }
400  }
401  } else {
402  if (sd_is_read_only)
403  INFO_WINDOW("SDCARD: image file %s could be open only in R/O mode!", fnbuf);
404  else
405  DEBUG("SDCARD: image file re-opened in RD/WR mode, good" NL);
406  // Check size!
407  DEBUG("SDCARD: cool, SD-card image %s (as %s) is open" NL, fn, fnbuf);
408  off_t size_in_bytes = xemu_safe_file_size_by_fd(sdfd);
409  if (size_in_bytes == OFF_T_ERROR) {
410  ERROR_WINDOW("Cannot query the size of the SD-card image %s, SD-card access won't work! ERROR: %s", fn, strerror(errno));
411  close(sdfd);
412  sdfd = -1;
413  return sdfd;
414  }
415 #ifdef COMPRESSED_SD
416  sd_compressed = detect_compressed_image(sdfd);
417  if (sd_compressed < 0) {
418  ERROR_WINDOW("Error while trying to detect compressed SD-image");
419  sdcard_size_in_blocks = 0; // just cheating to trigger error handling later
420  }
421 #endif
422  sdcard_size_in_blocks = size_in_bytes >> 9;
423  DEBUG("SDCARD: detected size in Mbytes: %d" NL, (int)(size_in_bytes >> 20));
424  if (size_in_bytes < 67108864UL) {
425  ERROR_WINDOW("SD-card image is too small! Min required size is 64Mbytes!");
426  close(sdfd);
427  sdfd = -1;
428  return sdfd;
429  }
430  if (size_in_bytes & (off_t)511) {
431  ERROR_WINDOW("SD-card image size is not multiple of 512 bytes!!");
432  close(sdfd);
433  sdfd = -1;
434  return sdfd;
435  }
436  if (size_in_bytes > 34359738368UL) {
437  ERROR_WINDOW("SD-card image is too large! Max allowed size is 32Gbytes!");
438  close(sdfd);
439  sdfd = -1;
440  return sdfd;
441  }
442  }
443  if (sdfd >= 0) {
444  show_card_init_done();
445  //sdcontent_handle(sdcard_size_in_blocks, NULL, SDCONTENT_ASK_FDISK | SDCONTENT_ASK_FILES);
446  if (just_created_image_file) {
447  just_created_image_file = 0;
448  // Just created SD-card image file by Xemu itself! So it's nice if we format it for the user at this point!
449  if (!sdcontent_handle(sdcard_size_in_blocks, NULL, SDCONTENT_FORCE_FDISK)) {
450  INFO_WINDOW("Your just created SD-card image file has\nbeen auto-fdisk/format'ed by Xemu. Great :).");
451  sdcontent_write_rom_stub();
452  }
453  }
454  }
455  if (!virtsd_flag && sdfd >= 0) {
456  static const char msg[] = " on the SD-card image.\nPlease use UI menu: Disks -> SD-card -> Update files ...\nUI can be accessed with right mouse click into the emulator window.";
457  int r = sdcontent_check_xemu_signature();
458  if (r < 0) {
459  ERROR_WINDOW("Warning! Cannot read SD-card to get Xemu signature!");
460  } else if (r == 0) {
461  INFO_WINDOW("Cannot find Xemu's signature%s", msg);
462  } else if (r < MEMCONTENT_VERSION_ID) {
463  INFO_WINDOW("Xemu's singature is too old%s to upgrade", msg);
464  } else if (r > MEMCONTENT_VERSION_ID) {
465  INFO_WINDOW("Xemu's signature is too new%s to DOWNgrade", msg);
466  }
467  // TODO: check MEGA65.D81 on the disk, and get its starting sector (!) number. So we can know if mount of MEGA65.D81 is
468  // requested later by sector number given in D81 "mount" registers. We can use this information to
469  // give a D81 as an external mount instead then, to please users not to have the default D81 "inside"
470  // the SD-card image rather than in their native file system.
471  }
472  return sdfd;
473 }
474 
475 
476 static XEMU_INLINE Uint32 U8A_TO_U32 ( Uint8 *a )
477 {
478  return ((Uint32)a[0]) | ((Uint32)a[1] << 8) | ((Uint32)a[2] << 16) | ((Uint32)a[3] << 24);
479 }
480 
481 
482 static int host_seek ( Uint32 block )
483 {
484  if (sdfd < 0)
485  FATAL("host_seek is called with invalid sdfd!"); // FIXME: this check can go away, once we're sure it does not apply!
486  off_t offset;
487 #ifdef COMPRESSED_SD
488  if (sd_compressed) {
489  offset = block * 3 + 0x22;
490  if (lseek(sdfd, offset, SEEK_SET) != offset)
491  FATAL("SDCARD: SEEK: compressed image host-OS seek failure: %s", strerror(errno));
492  Uint8 buf[3];
493  if (xemu_safe_read(sdfd, buf, 3) != 3)
494  FATAL("SDCARD: SEEK: compressed image host-OK pre-read failure: %s", strerror(errno));
495  compressed_block = (buf[0] & 0x80);
496  buf[0] &= 0x7F;
497  offset = ((off_t)((buf[0] << 16) | (buf[1] << 8) | buf[2]) << 9) + sd_bdata_start;
498  //DEBUGPRINT("SD-COMP: got address: %d" NL, (int)offset);
499  } else {
500  offset = (off_t)block << 9;
501  }
502 #else
503  offset = (off_t)block << 9;
504 #endif
505  if (lseek(sdfd, offset, SEEK_SET) != offset)
506  FATAL("SDCARD: SEEK: image seek host-OS failure: %s", strerror(errno));
507  return 0;
508 }
509 
510 
511 // static int status_read_counter = 0;
512 
513 // This tries to emulate the behaviour, that at least another one status query
514 // is needed to BUSY flag to go away instead of with no time. DUNNO if it is needed at all.
515 static Uint8 sdcard_read_status ( void )
516 {
517  Uint8 ret = sd_status;
518  DEBUG("SDCARD: reading SD status $D680 result is $%02X PC=$%04X" NL, ret, cpu65.pc);
519 // if (status_read_counter > 20) {
520 // sd_status &= ~(SD_ST_BUSY1 | SD_ST_BUSY0);
521 // status_read_counter = 0;
522 // DEBUGPRINT(">>> SDCARD resetting status read counter <<<" NL);
523 // }
524 // status_read_counter++;
525  // Suggested by @Jimbo on MEGA65/Xemu Discord: a workaround to report busy status
526  // if external SD bus is used, always when reading status. It seems to be needed now
527  // with newer hyppo, otherwise it misinterprets the SDHC detection method on the external bus!
528  if (ret & SD_ST_EXT_BUS)
529  ret |= SD_ST_BUSY1 | SD_ST_BUSY0;
530 #ifdef USE_KEEP_BUSY
531  if (!keep_busy)
533 #endif
534  //ret |= 0x10; // FIXME? according to Paul, the old "SDHC" flag stuck to one always from now
535  return ret;
536 }
537 
538 
539 // TODO: later we need to deal with buffer selection, whatever
540 static XEMU_INLINE Uint8 *get_buffer_memory ( int is_write )
541 {
542  // Currently the only buffer available in Xemu is the SD buffer, UNLESS it's a write operation and "fill mode" is used
543  // (sd_fill_buffer is just filled with a single byte value)
544  return (is_write && sd_fill_mode) ? sd_fill_buffer : (disk_buffers + SD_BUFFER_POS);
545 }
546 
547 
549 {
550  if (block >= sdcard_size_in_blocks) {
551  DEBUGPRINT("SDCARD: SEEK: invalid block was requested to READ: block=%u (max_block=%u) @ PC=$%04X" NL, block, sdcard_size_in_blocks, cpu65.pc);
552  return -1;
553  }
554 #ifdef VIRTUAL_DISK_IMAGE_SUPPORT
555  if (vdisk.mode) {
556  virtdisk_read_block(block, buffer);
557  return 0;
558  }
559 #endif
560  if (host_seek(block))
561  return -1;
562  if (xemu_safe_read(sdfd, buffer, 512) == 512)
563  return 0;
564  else
565  return -1;
566 }
567 
568 
570 {
571  if (block >= sdcard_size_in_blocks) {
572  DEBUGPRINT("SDCARD: SEEK: invalid block was requested to WRITE: block=%u (max_block=%u) @ PC=$%04X" NL, block, sdcard_size_in_blocks, cpu65.pc);
573  return -1;
574  }
575  if (sd_is_read_only) // on compressed SD image, it's also set btw
576  return -1; // read-only SD-card
577 #ifdef VIRTUAL_DISK_IMAGE_SUPPORT
578  if (vdisk.mode) {
579  virtdisk_write_block(block, buffer);
580  return 0;
581  }
582 #endif
583  if (host_seek(block))
584  return -1;
585  if (xemu_safe_write(sdfd, buffer, 512) == 512)
586  return 0;
587  else
588  return -1;
589 }
590 
591 
592 /* Lots of TODO's here:
593  * + study M65's quite complex error handling behaviour to really match ...
594  * + with external D81 mounting: have a "fake D81" on the card, and redirect accesses to that, if someone if insane enough to try to access D81 at the SD-level too ...
595  * + In general: SD emulation is "too fast" done in zero emulated CPU time, which can affect the emulation badly if an I/O-rich task is running on Xemu/M65
596  * */
597 static void sdcard_block_io ( Uint32 block, int is_write )
598 {
599  static int protect_important_blocks = 1;
600  DEBUG("SDCARD: %s block #%u @ PC=$%04X" NL,
601  is_write ? "writing" : "reading",
602  block, cpu65.pc
603  );
604  if (XEMU_UNLIKELY(is_write && (block == 0 || block == XEMU_INFO_SDCARD_BLOCK_NO) && sdfd >= 0 && protect_important_blocks)) {
605  if (protect_important_blocks == 2) {
606  goto error;
607  } else {
608  char msg[128];
609  sprintf(msg, "Program tries to overwrite SD sector #%d!\nUnless you fdisk/format your card, it's not something you want.", block);
610  switch (QUESTION_WINDOW("Reject this|Reject all|Allow this|Allow all", msg)) {
611  case 0:
612  goto error;
613  case 1:
614  protect_important_blocks = 2;
615  goto error;
616  case 2:
617  break;
618  case 3:
619  protect_important_blocks = 0;
620  break;
621  }
622  }
623  }
625  DEBUGPRINT("SDCARD: bus #1 is empty" NL);
626  // FIXME: what kind of error we should create here?????
628  KEEP_BUSY(1);
629  return;
630  }
631  Uint8 *buffer = get_buffer_memory(is_write);
632  int ret = is_write ? sdcard_write_block(block, buffer) : sdcard_read_block(block, buffer);
633  if (ret || !sdhc_mode) {
634  error:
635  sd_status |= SD_ST_ERROR | SD_ST_FSM_ERROR; // | SD_ST_BUSY1 | SD_ST_BUSY0;
637  //KEEP_BUSY(1);
638  return;
639  }
641 #if 0
642  off_t offset = sd_sector;
643  offset <<= 9; // make byte offset from sector (always SDHC card!)
644  int ret = host__seek(offset);
645  if (XEMU_UNLIKELY(!ret && is_write && sd_is_read_only)) {
646  ret = 1; // write protected SD image?
647  }
648  if (XEMU_LIKELY(!ret)) {
649  Uint8 *wp = get_buffer_memory(is_write);
650  if (
651 #ifdef COMPRESSED_SD
652  (is_write && compressed_block) ||
653 #endif
654  (is_write ? xemu_safe_write(sdfd, wp, 512) : xemu_safe_read(sdfd, wp, 512)) != 512
655  )
656  ret = -1;
657  }
658  if (XEMU_UNLIKELY(ret < 0)) {
659  sd_status |= SD_ST_ERROR | SD_ST_FSM_ERROR; // | SD_ST_BUSY1 | SD_ST_BUSY0;
661  //KEEP_BUSY(1);
662  return;
663  }
665 #endif
666 }
667 
668 
669 static void sdcard_command ( Uint8 cmd )
670 {
671  static Uint32 multi_io_block;
672  static Uint8 sd_last_ok_cmd;
673  DEBUG("SDCARD: writing command register $D680 with $%02X PC=$%04X" NL, cmd, cpu65.pc);
674  sd_status &= ~(SD_ST_BUSY1 | SD_ST_BUSY0); // ugly hack :-@
675  KEEP_BUSY(0);
676 // status_read_counter = 0;
677  switch (cmd) {
678  case 0x00: // RESET SD-card
679  case 0x10: // RESET SD-card with flags specified [FIXME: I don't know what the difference is ...]
680  sd_status = SD_ST_RESET | (sd_status & SD_ST_EXT_BUS); // clear all other flags, but not the bus selection, FIXME: bus selection should not be touched?
681  memset(sd_regs + 1, 0, 4); // clear SD-sector 4 byte register. FIXME: what should we zero/reset other than this, still?
682  sdhc_mode = 1;
683  break;
684  case 0x01: // END RESET
685  case 0x11: // ... [FIXME: again, I don't know what the difference is ...]
687  break;
688  case 0x57: // write sector gate
689  break; // FIXME: implement this!!!
690  case 0x02: // read block
691  sdcard_block_io(U8A_TO_U32(sd_regs + 1), 0);
692  break;
693  case 0x03: // write block
694  sdcard_block_io(U8A_TO_U32(sd_regs + 1), 1);
695  break;
696  case 0x53: // FLASH read! (not an SD-card command!)
697  memset(disk_buffers + SD_BUFFER_POS, 0xFF, 0x200); // Not so much a real read khmm ...
698  break;
699  case 0x04: // multi sector write - first sector
700  if (sd_last_ok_cmd != 0x04) {
701  multi_io_block = U8A_TO_U32(sd_regs + 1);
702  sdcard_block_io(multi_io_block, 1);
703  } else {
704  DEBUGPRINT("SDCARD: bad multi-command sequence command $%02X after command $%02X" NL, cmd, sd_last_ok_cmd);
706  }
707  break;
708  case 0x05: // multi sector write - not the first, neither the last sector
709  if (sd_last_ok_cmd == 0x04 || sd_last_ok_cmd == 0x05 || sd_last_ok_cmd == 0x57) {
710  multi_io_block++;
711  sdcard_block_io(multi_io_block, 1);
712  } else {
713  DEBUGPRINT("SDCARD: bad multi-command sequence command $%02X after command $%02X" NL, cmd, sd_last_ok_cmd);
715  }
716  break;
717  case 0x06: // multi sector write - last sector
718  if (sd_last_ok_cmd == 0x04 || sd_last_ok_cmd == 0x05 || sd_last_ok_cmd == 0x57) {
719  multi_io_block++;
720  sdcard_block_io(multi_io_block, 1);
721  } else {
722  DEBUGPRINT("SDCARD: bad multi-command sequence command $%02X after command $%02X" NL, cmd, sd_last_ok_cmd);
724  }
725  break;
726  case 0x0C: // request flush of the SD-card [currently does nothing in Xemu ...]
727  break;
728  case 0x40: // SDHC mode OFF - Not supported on newer M65s!
729  sd_status &= ~SD_ST_SDHC;
730  sdhc_mode = 0;
731  break;
732  case 0x41: // SDHC mode ON - Not supported on newer M65s!
734  sdhc_mode = 1;
735  break;
736  case 0x44: // sd_clear_error <= '0' FIXME: what is this?
737  break;
738  case 0x45: // sd_clear_error <= '1' FIXME: what is this?
739  break;
740  case 0x81: // map SD-buffer
743  break;
744  case 0x82: // unmap SD-buffer
746  break;
747  case 0x83: // SD write fill mode set
748  sd_fill_mode = 1;
749  break;
750  case 0x84: // SD write fill mode clear
751  sd_fill_mode = 0;
752  break;
753  case 0xC0: // select internal SD-card bus
755  break;
756  case 0xC1: // select external SD-card bus
758  break;
759  default:
761  DEBUGPRINT("SDCARD: warning, unimplemented SD-card controller command $%02X" NL, cmd);
762  break;
763  }
765  sd_last_ok_cmd = 0xFF;
766  } else {
767  sd_last_ok_cmd = cmd;
768  }
769 }
770 
771 
772 // These are called from hdos.c as part of the beginning/end of the machine
773 // initialization (ie, trap reset). The purpose here currently is activating
774 // and deactivating mount monitoring so we can override later the default
775 // on-sdcard D81 image mount with external one, knowing the mount-sector-number.
776 
777 
779 {
780  for (int unit = 0; unit < 2; unit++) {
781  mount_info[unit].at_sector_initial = 0;
782  mount_info[unit].monitoring_initial = 1;
783  }
784  memset(sd_regs + 0x0C, 0, 4);
785  memset(sd_regs + 0x10, 0, 4);
786  sd_regs[0xB] &= 255 - (8 + 1); // set D81 (internal) mounted to zero for the two units
787 }
788 
789 
791 {
792  for (int unit = 0; unit < 2; unit++) {
793  mount_info[unit].monitoring_initial = 0; // stop monitoring initial D81 mounts, end of "machine-start" state
794  if (!unit && !mount_info[unit].at_sector_initial)
795  DEBUGPRINT("SDCARD: D81-DEFAULT: WARNING: could not determine default on-sd D81 mount sector info during the RESET TRAP for unit #%d!" NL, unit);
796  }
797 }
798 
799 
800 static int do_default_d81_mount_hack ( const int unit )
801 {
802  static char *default_d81_path[2] = { NULL, NULL };
803  if (!default_d81_path[unit]) {
804  // Prepare to determine the full path of the default external d81 image, if we haven't got it yet
805  const char *hdosroot;
806  (void)hypervisor_hdos_virtualization_status(-1, &hdosroot);
807  const int len = strlen(hdosroot) + strlen(default_d81_basename[unit]) + 1;
808  default_d81_path[unit] = xemu_malloc(len);
809  snprintf(default_d81_path[unit], len, "%s%s", hdosroot, default_d81_basename[unit]);
810  }
811  DEBUGPRINT("SDCARD: D81-DEFAULT: trying to mount external D81 instead of internal default one as %s on unit #%d" NL, default_d81_path[unit], unit);
812  // we want to create the default image file if does not exist (note the "0" for d81access_create_image_file, ie do not overwrite exisiting image)
813  // d81access_create_image_file() returns with 0 if image was created, -2 if image existed before, and -1 for other errors
814  if (d81access_create_image_file(default_d81_path[unit], default_d81_disk_label[unit], 0, NULL) == -1)
815  return -1;
816  // ... so, the file existed before case allows to reach this point, since then retval is -2 (and not -1 as a generic error)
817  return sdcard_force_external_mount(unit, default_d81_path[unit], "Cannot mount default external D81");
818 }
819 
820 
821 int sdcard_default_d81_mount ( const int unit )
822 {
823  if (default_d81_is_from_sd) {
824  ERROR_WINDOW("This function is not available when\n\"default D81 mount from SD\" option is inactive!");
825  return -1;
826  }
827  return do_default_d81_mount_hack(unit);
828 }
829 
830 
831 // Return values:
832 // * -1: error
833 // * 0: no image was mounted internally (not enabled etc)
834 // * 1: image has been mounted
835 static int internal_mount ( const int unit )
836 {
837  int ro_flag = 0;
839  if (!unit) {
840  // must be 'image enabled' and 'disk present' bit set for "unit 0"
841  if ((sd_regs[0xB] & 0x03) != 0x03 || mount_info[0].force_external_name)
842  return 0;
843  if (/*(sd_regs[0xB] & 0x04) ||*/ sd_is_read_only) // it seems checking the register as well causes RO mount for some reason, let's ignore for now!
844  ro_flag = D81ACCESS_RO;
845  at_sector = U8A_TO_U32(sd_regs + 0x0C);
846  } else {
847  // must be 'image enabled' and 'disk present' bit set for "unit 1"
848  if ((sd_regs[0xB] & 0x18) != 0x18 || mount_info[1].force_external_name)
849  return 0;
850  if (/*(sd_regs[0xB] & 0x20) ||*/ sd_is_read_only) // see above at the similar line for drive-0
851  ro_flag = D81ACCESS_RO;
852  at_sector = U8A_TO_U32(sd_regs + 0x10);
853  }
854  // FIXME: actual upper limit should take account the image size to mount which can be different now than D81_SIZE like in case of D65 image (not now, but in the future?)
855  // FIXME: also a better algorithm to find limits, see the comment at defining MIN_MOUNT_SECTOR_NO near the beginning in this file
856  if (at_sector < MIN_MOUNT_SECTOR_NO || ((at_sector + (D81_SIZE >> 9)) >= sdcard_size_in_blocks)) {
857  DEBUGPRINT("SDCARD: D81: internal mount #%d **INVALID** SD sector (mount refused!), too %s $%X" NL, unit, at_sector < MIN_MOUNT_SECTOR_NO ? "low" : "high", at_sector);
858  d81access_close(unit);
859  mount_info[unit].current_name[0] = '\0';
860  mount_info[unit].internal = -1;
861  return -1;
862  }
863  mount_info[unit].at_sector = at_sector;
864  // FIXME: remove this? This logic has to be moved to the register write time, as this code is not executed maybe, if other external (CLI etc) mount overrides stuff anyway
865  /*if (XEMU_UNLIKELY(mount_info[unit].monitoring_initial && !mount_info[unit].at_sector_initial))
866  mount_info[unit].at_sector_initial = at_sector;*/
867  if (at_sector == mount_info[unit].at_sector_initial && !default_d81_is_from_sd) {
868  // it seems the first ever mounted D81 wanted to be mounted now, so let's override that with external mount at this point
869  if (!do_default_d81_mount_hack(unit))
870  return 1; // if succeeded, stop processing further! (note the return value needs of this functions!)
871  }
872  // FIXME/TODO: no support yet to take account D64,D71,D65 mount from SD-card! However it's not so common I guess from SD-card in case of emulator, but more from external FS in that case
873  DEBUGPRINT("SDCARD: D81: internal mount #%d from SD sector $%X (%s)" NL, unit, at_sector, ro_flag ? "R/O" : "R/W");
874  d81access_attach_fd(unit, sdfd, (off_t)at_sector << 9, D81ACCESS_IMG | ro_flag);
875  char fn[32];
876  sprintf(fn, "<SD@$%X:%s>", at_sector, ro_flag ? "RO" : "RW");
877  xemu_restrdup(&mount_info[unit].current_name, fn);
878  mount_info[unit].internal = 1;
879  return 1;
880 }
881 
882 
883 static int some_mount ( const int unit )
884 {
885  const char *extfn = mount_info[unit].force_external_name;
886  if (extfn) { // force external mount
887  if (strcmp(mount_info[unit].current_name, extfn)) {
888  DEBUGPRINT("SDCARD: D81: external mount #%d change from \"%s\" to \"%s\"" NL, unit, mount_info[unit].current_name, extfn);
890  DEBUGPRINT("SDCARD: D81: external mount #%d failed at \"%s\", closing unit." NL, unit, extfn);
891  d81access_close(unit);
892  mount_info[unit].current_name[0] = '\0';
893  return -1;
894  } else {
895  xemu_restrdup(&mount_info[unit].current_name, extfn);
896  }
897  } else {
898  DEBUGPRINT("SDCARD: D81: external mount #%d but no change, \"%s\" = \"%s\"" NL, unit, mount_info[unit].current_name, extfn);
899  }
900  mount_info[unit].internal = 0;
901  // at this point, let's update sd_regs register to reflect that we use external mount ...
902  sd_regs[0xB] |= !unit ? 1 : 8;
903  return 0;
904  }
905  // fall back to try internal mount
906  if (internal_mount(unit) == 0) {
907  DEBUGPRINT("SDCARD: D81: internal mount #%d has no condition to mount anything." NL, unit);
908  d81access_close(unit); // unmount, if internal_mount() finds no internal mount situation
909  mount_info[unit].current_name[0] = '\0';
910  mount_info[unit].internal = -1;
911  } /* else
912  DEBUGPRINT("SDCARD: D81: internal mount #%d failed?" NL, unit); */ // FIXME: remove/rethink this part! internal_mount() can return with non-zero, zero or negative as answer!!
913  return 0;
914 }
915 
916 
917 const char *sdcard_get_mount_info ( const int unit, int *is_internal )
918 {
919  if (is_internal)
920  *is_internal = mount_info[unit & 1].internal;
921  return mount_info[unit & 1].current_name;
922 }
923 
924 
925 int sdcard_force_external_mount ( const int unit, const char *filename, const char *cry )
926 {
927  DEBUGPRINT("SDCARD: D81: %s(%d, \"%s\", \"%s\");" NL, __func__, unit, filename, cry);
928  if (filename && *filename) {
929  xemu_restrdup(&mount_info[unit].force_external_name, filename);
930  } else if (mount_info[unit].force_external_name) {
931  free(mount_info[unit].force_external_name);
932  mount_info[unit].force_external_name = NULL;
933  }
934  if (some_mount(unit)) {
935  // error. close access - if ANY
936  d81access_close(unit);
937  mount_info[unit].current_name[0] = '\0';
938  if (mount_info[unit].force_external_name) {
939  if (cry) {
940  ERROR_WINDOW("%s\nCould not mount requested file as unit #%d:\n%s", cry, unit, filename);
941  }
942  free(mount_info[unit].force_external_name);
943  mount_info[unit].force_external_name = NULL;
944  }
945  return -1;
946  }
947  return 0;
948 }
949 
950 
951 int sdcard_force_external_mount_with_image_creation ( const int unit, const char *filename, const int do_overwrite, const char *cry )
952 {
953  if (d81access_create_image_file(filename, NULL, do_overwrite, "Cannot create D81"))
954  return -1;
955  return sdcard_force_external_mount(unit, filename, cry);
956 }
957 
958 
959 int sdcard_unmount ( const int unit )
960 {
961  d81access_close(unit);
962  mount_info[unit].internal = 0; // FIXME ???
963  xemu_restrdup(&mount_info[unit].current_name, "<EMPTY>");
964  if (mount_info[unit].force_external_name) {
965  // We must null this out, otherwise next (even internal) mount will pick it up and use it again as this external mount!
966  free(mount_info[unit].force_external_name);
967  mount_info[unit].force_external_name = NULL;
968  }
969  return 0;
970 }
971 
972 
974 {
975  const Uint8 prev_data = sd_regs[reg];
976  sd_regs[reg] = data;
977  // Note: don't update D6XX backend as it's already done in the I/O decoder
978  switch (reg) {
979  case 0x00: // command/status register
980  sdcard_command(data);
981  break;
982  case 0x01: // sector address
983  case 0x02: // sector address
984  case 0x03: // sector address
985  case 0x04: // sector address
986  DEBUG("SDCARD: writing sector number register $%04X with $%02X PC=$%04X" NL, reg + 0xD680, data, cpu65.pc);
987  break;
988  case 0x06: // write-only register: byte value for SD-fill mode on SD write command
989  sd_fill_value = data;
990  if (sd_fill_value != sd_fill_buffer[0])
991  memset(sd_fill_buffer, sd_fill_value, 512);
992  break;
993  case 0x09:
994  set_disk_buffer_cpu_view(); // update disk_buffer_cpu_view pointer according to sd_regs[9] just written
995  break;
996  case 0x0B:
997  // FIXME: note, this logic is probably not precise. There is true "mount event" but if D81 image access
998  // allowed, any write to D81 addr registers cause to immediately "move the mounting window" without the need
999  // to write this reg at all again. At least AFAIK. Should be checked!!
1000  DEBUGPRINT("SDCARD: writing FDC configuration register $%04X with $%02X (old_data=$%02X) PC=$%04X" NL, reg + 0xD680, data, prev_data, cpu65.pc);
1001  if (XEMU_UNLIKELY(mount_info[0].monitoring_initial && !mount_info[0].at_sector_initial && (data & 1)))
1002  mount_info[0].at_sector_initial = U8A_TO_U32(sd_regs + 0x0C);
1003  if (XEMU_UNLIKELY(mount_info[1].monitoring_initial && !mount_info[1].at_sector_initial && (data & 8)))
1004  mount_info[1].at_sector_initial = U8A_TO_U32(sd_regs + 0x10);
1005  if ((data ^ prev_data) & 0x07) // FIXME: ignores bit 6 "superfloppy"
1006  some_mount(0);
1007  if ((data ^ prev_data) & 0x38) // FIXME: ignores bit 7 "superfloppy"
1008  some_mount(1);
1009  break;
1010  case 0x0C: // first D81 disk image starting sector registers
1011  case 0x0D:
1012  case 0x0E:
1013  case 0x0F:
1014  if (data != prev_data) {
1015  DEBUGPRINT("SDCARD: writing D81 #0 sector register $%04X with $%02X PC=$%04X" NL, reg + 0xD680, data, cpu65.pc);
1016  internal_mount(0);
1017  }
1018  break;
1019  case 0x10: // second D81 disk image starting sector registers
1020  case 0x11:
1021  case 0x12:
1022  case 0x13:
1023  if (data != prev_data) {
1024  DEBUGPRINT("SDCARD: writing D81 #1 sector register $%04X with $%02X PC=$%04X" NL, reg + 0xD680, data, cpu65.pc);
1025  internal_mount(1);
1026  }
1027  break;
1028  default:
1029  DEBUGPRINT("SDCARD: unimplemented register: $%02X tried to be written with data $%02X" NL, reg, data);
1030  break;
1031  }
1032 }
1033 
1034 
1036 {
1037  Uint8 data = sd_regs[reg]; // default answer
1038  switch (reg) {
1039  case 0:
1040  return sdcard_read_status();
1041  case 1:
1042  case 2:
1043  case 3:
1044  case 4:
1045  break; // allow to read back SD sector address
1046  case 6:
1047  break;
1048  case 8:
1049  return fdc_get_buffer_disk_address() & 0xFF;
1050  case 9:
1051  return
1052  (fdc_get_buffer_disk_address() >> 8) | // $D689.0 - High bit of F011 buffer pointer (disk side) (read only)
1053  ((fdc_get_status_a(-1) & (64 + 32)) == (64 + 32) ? 2 : 0) | // $D689.1 - Sector read from SD/F011/FDC, but not yet read by CPU (i.e., EQ and DRQ)
1054  (sd_regs[0x9] & 0x80); // $D689.7 - Memory mapped sector buffer select: 1=SD-Card, 0=F011/FDC
1055  break;
1056  case 0xA:
1057  // FIXME: ethernet I/O mode should be a disctict I/O mode??
1058  // bits 2 and 3 is always zero in Xemu (no drive virtualization for drive 0 and 1)
1059  return
1060  (vic_registers[0x30] & 1) | // $D68A.0 SD:CDC00 (read only) Set if colour RAM at $DC00
1061  (vic_iomode == VIC4_IOMODE ? 2 : 0) // $D68A.1 SD:VICIII (read only) Set if VIC-IV or ethernet IO bank visible
1062  ;
1063  break;
1064  case 0xB:
1065  break;
1066  case 0xC:
1067  case 0xD:
1068  case 0xE:
1069  case 0xF:
1070  break;
1071  case 0x10:
1072  case 0x11:
1073  case 0x12:
1074  case 0x13:
1075  break;
1076  default:
1077  DEBUGPRINT("SDCARD: unimplemented register: $%02X tried to be read, defaulting to the back storage with data $%02X" NL, reg, data);
1078  break;
1079  }
1080  return data;
1081 }
1082 
1083 
1084 /* --- SNAPSHOT RELATED --- */
1085 
1086 
1087 #ifdef XEMU_SNAPSHOT_SUPPORT
1088 
1089 #include <string.h>
1090 
1091 #define SNAPSHOT_SDCARD_BLOCK_VERSION 0
1092 #define SNAPSHOT_SDCARD_BLOCK_SIZE (0x100 + sizeof(disk_buffers))
1093 
1094 int sdcard_snapshot_load_state ( const struct xemu_snapshot_definition_st *def, struct xemu_snapshot_block_st *block )
1095 {
1096  Uint8 buffer[SNAPSHOT_SDCARD_BLOCK_SIZE];
1097  int a;
1098  if (block->block_version != SNAPSHOT_SDCARD_BLOCK_VERSION || block->sub_counter || block->sub_size != sizeof buffer)
1099  RETURN_XSNAPERR_USER("Bad SD-Card block syntax");
1100  a = xemusnap_read_file(buffer, sizeof buffer);
1101  if (a) return a;
1102  /* loading state ... */
1103  memcpy(sd_sector_registers, buffer, 4);
1104  memcpy(sd_d81_img1_start, buffer + 4, 4);
1105  fd_mounted = (int)P_AS_BE32(buffer + 8);
1106  sd_is_read_only = (int)P_AS_BE32(buffer + 16);
1107  //d81_is_read_only = (int)P_AS_BE32(buffer + 20);
1108  //use_d81 = (int)P_AS_BE32(buffer + 24);
1109  sd_status = buffer[0xFF];
1110  memcpy(disk_buffers, buffer + 0x100, sizeof disk_buffers);
1111  return 0;
1112 }
1113 
1114 
1115 int sdcard_snapshot_save_state ( const struct xemu_snapshot_definition_st *def )
1116 {
1117  Uint8 buffer[SNAPSHOT_SDCARD_BLOCK_SIZE];
1118  int a = xemusnap_write_block_header(def->idstr, SNAPSHOT_SDCARD_BLOCK_VERSION);
1119  if (a) return a;
1120  memset(buffer, 0xFF, sizeof buffer);
1121  /* saving state ... */
1122  memcpy(buffer, sd_sector_registers, 4);
1123  memcpy(buffer + 4,sd_d81_img1_start, 4);
1124  U32_AS_BE(buffer + 8, fd_mounted);
1125  U32_AS_BE(buffer + 16, sd_is_read_only);
1126  //U32_AS_BE(buffer + 20, d81_is_read_only);
1127  //U32_AS_BE(buffer + 24, use_d81);
1128  buffer[0xFF] = sd_status;
1129  memcpy(buffer + 0x100, disk_buffers, sizeof disk_buffers);
1130  return xemusnap_write_sub_block(buffer, sizeof buffer);
1131 }
1132 
1133 #endif
sdcard_get_mount_info
const char * sdcard_get_mount_info(const int unit, int *is_internal)
Definition: sdcard.c:917
d81access_close_all
void d81access_close_all(void)
Definition: d81access.c:100
SD_BUFFER_POS
#define SD_BUFFER_POS
Definition: sdcard.c:52
d81access_cb_chgmode
void d81access_cb_chgmode(const int which, const int mode)
Definition: sdcard.c:246
vic4.h
SDCARD_NAME
#define SDCARD_NAME
Definition: mega65.h:27
D81ACCESS_AUTOCLOSE
#define D81ACCESS_AUTOCLOSE
Definition: d81access.h:38
MIN_MOUNT_SECTOR_NO
#define MIN_MOUNT_SECTOR_NO
Definition: sdcard.c:50
emutools.h
D81ACCESS_D71
#define D81ACCESS_D71
Definition: d81access.h:41
fdc_set_disk
void fdc_set_disk(int which, int in_have_disk, int in_have_write)
Definition: f011_core.c:177
fdc_get_buffer_disk_address
int fdc_get_buffer_disk_address(void)
Definition: f011_core.c:137
disk_buffer_cpu_view
Uint8 * disk_buffer_cpu_view
Definition: sdcard.c:76
sdcard_force_external_mount
int sdcard_force_external_mount(const int unit, const char *filename, const char *cry)
Definition: sdcard.c:925
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
xemu_open_file
int xemu_open_file(const char *filename, int mode, int *mode2, char *filepath_back)
Definition: emutools_files.c:469
OFF_T_ERROR
#define OFF_T_ERROR
Definition: fat32.c:42
KEEP_BUSY
#define KEEP_BUSY(n)
Definition: sdcard.c:42
have_disk
int have_disk
Definition: f011_core.c:67
sdcard_write_register
void sdcard_write_register(int reg, Uint8 data)
Definition: sdcard.c:973
sdcard_notify_system_start_begin
void sdcard_notify_system_start_begin(void)
Definition: sdcard.c:778
disk_buffers
Uint8 disk_buffers[0x1000]
Definition: sdcard.c:74
SD_ST_SDHC
#define SD_ST_SDHC
Definition: sdcard.c:47
monitoring_initial
int monitoring_initial
Definition: sdcard.c:93
d81access_init
void d81access_init(void)
Definition: d81access.c:56
INFO_WINDOW
#define INFO_WINDOW(...)
Definition: xep128.h:114
io_mapper.h
fn
const char * fn
Definition: roms.c:42
XEMU_INLINE
#define XEMU_INLINE
Definition: emutools_basicdefs.h:126
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
mega65.h
Uint32
uint32_t Uint32
Definition: fat32.c:49
SD_ST_BUSY0
#define SD_ST_BUSY0
Definition: sdcard.h:29
fdc_cb_wr_sec
int fdc_cb_wr_sec(const int which, Uint8 *buffer, const Uint8 side, const Uint8 track, const Uint8 sector)
Definition: sdcard.c:260
sdcontent.h
hypervisor_hdos_virtualization_status
int hypervisor_hdos_virtualization_status(const int set, const char **root_ptr)
Definition: hdos.c:829
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
SD_ST_EXT_BUS
#define SD_ST_EXT_BUS
Definition: sdcard.h:22
SD_ST_MAPPED
#define SD_ST_MAPPED
Definition: sdcard.h:26
D81_SIZE
#define D81_SIZE
Definition: d81access.h:22
sdcard_unmount
int sdcard_unmount(const int unit)
Definition: sdcard.c:959
sdcard_get_size
Uint32 sdcard_get_size(void)
Definition: sdcard.c:305
SD_ST_FSM_ERROR
#define SD_ST_FSM_ERROR
Definition: sdcard.h:24
block
Uint32 block
Definition: fat32.c:156
at_sector_initial
Uint32 at_sector_initial
Definition: sdcard.c:92
xemu_safe_file_size_by_fd
off_t xemu_safe_file_size_by_fd(int fd)
Definition: emutools_files.c:583
sd_status
Uint8 sd_status
Definition: sdcard.c:58
emutools_files.h
xemu_malloc
void * xemu_malloc(size_t size)
Definition: emutools.c:226
next
Uint8 next
Definition: input_devices.c:77
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
sdcard_write_block
int sdcard_write_block(Uint32 block, Uint8 *buffer)
Definition: sdcard.c:569
disk_buffer_io_mapped
Uint8 * disk_buffer_io_mapped
Definition: sdcard.c:80
D81ACCESS_D64
#define D81ACCESS_D64
Definition: d81access.h:40
d81access_close
void d81access_close(int which)
Definition: d81access.c:78
D81ACCESS_RO
#define D81ACCESS_RO
Definition: d81access.h:37
fdc_cb_rd_sec
int fdc_cb_rd_sec(const int which, Uint8 *buffer, const Uint8 side, const Uint8 track, const Uint8 sector)
Definition: sdcard.c:254
ERROR_WINDOW
#define ERROR_WINDOW(...)
Definition: xep128.h:116
d81access_attach_fd
void d81access_attach_fd(int which, int fd, off_t offset, int mode)
Definition: d81access.c:145
VIC4_IOMODE
#define VIC4_IOMODE
Definition: vic4.h:26
sdcard_init
int sdcard_init(const char *fn, const int virtsd_flag, const int default_d81_is_from_sd_in)
Definition: sdcard.c:328
d81access_create_image_file
int d81access_create_image_file(const char *fn, const char *diskname, const int do_overwrite, const char *cry)
Definition: d81access.c:701
XEMU_LIKELY
#define XEMU_LIKELY(__x__)
Definition: emutools_basicdefs.h:124
mode
int mode
Definition: vera.c:61
sdcard_force_external_mount_with_image_creation
int sdcard_force_external_mount_with_image_creation(const int unit, const char *filename, const int do_overwrite, const char *cry)
Definition: sdcard.c:951
D81ACCESS_PRG
#define D81ACCESS_PRG
Definition: d81access.h:34
force_external_name
char * force_external_name
Definition: sdcard.c:90
D81ACCESS_EMPTY
#define D81ACCESS_EMPTY
Definition: d81access.h:32
NL
#define NL
Definition: fat32.c:37
hypervisor.h
compress_sd_image.r
def r
Definition: compress_sd_image.py:76
base
int base
Definition: dma65.c:82
cpu65.h
sdcard_read_register
Uint8 sdcard_read_register(int reg)
Definition: sdcard.c:1035
FD_BUFFER_POS
#define FD_BUFFER_POS
Definition: sdcard.c:53
xemu_safe_read
ssize_t xemu_safe_read(int fd, void *buffer, size_t length)
Definition: emutools_files.c:543
sdcard_notify_system_start_end
void sdcard_notify_system_start_end(void)
Definition: sdcard.c:790
fdc_init
void fdc_init(Uint8 *cache_set)
Definition: f011_core.c:110
D6XX_registers
Uint8 D6XX_registers[0x100]
Definition: io_mapper.c:38
sdcard.h
xemu_strdup
char * xemu_strdup(const char *s)
Definition: emutools.c:278
vic_iomode
int vic_iomode
Definition: vic4.c:44
memcontent.h
COMPRESSED_SD
#define COMPRESSED_SD
Definition: sdcard.c:38
D81ACCESS_DIR
#define D81ACCESS_DIR
Definition: d81access.h:35
fdc_get_status_a
int fdc_get_status_a(const int which)
Definition: f011_core.c:149
QUESTION_WINDOW
#define QUESTION_WINDOW(items, msg)
Definition: xep128.h:124
SD_ST_BUSY1
#define SD_ST_BUSY1
Definition: sdcard.h:28
D81ACCESS_IMG
#define D81ACCESS_IMG
Definition: d81access.h:33
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
xemu_create_large_empty_file
int xemu_create_large_empty_file(const char *os_path, Uint64 size, int is_sparse)
Definition: emutools_files.c:727
sdcard_read_block
int sdcard_read_block(Uint32 block, Uint8 *buffer)
Definition: sdcard.c:548
MEMCONTENT_VERSION_ID
#define MEMCONTENT_VERSION_ID
Definition: memcontent.h:15
xemu_safe_write
ssize_t xemu_safe_write(int fd, const void *buffer, size_t length)
Definition: emutools_files.c:563
xemu_external_d81_signature
const char xemu_external_d81_signature[]
Definition: sdcard.c:84
current_name
char * current_name
Definition: sdcard.c:88
FATAL
#define FATAL(...)
Definition: xep128.h:117
at_sector
Uint32 at_sector
Definition: sdcard.c:91
XEMU_OPEN_FILE_FIRST_MODE_USED
#define XEMU_OPEN_FILE_FIRST_MODE_USED
Definition: emutools_files.h:45
vic_registers
Uint8 vic_registers[0x80]
Definition: vic4.c:43
SD_ST_RESET
#define SD_ST_RESET
Definition: sdcard.h:27
xemu_restrdup
void xemu_restrdup(char **ptr, const char *str)
Definition: emutools.c:286
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
SD_ST_ERROR
#define SD_ST_ERROR
Definition: sdcard.h:23
d81access.h
sdcard_default_d81_mount
int sdcard_default_d81_mount(const int unit)
Definition: sdcard.c:821
buf
Uint8 buf[512]
Definition: fat32.c:155