1 |
|
/* |
2 |
|
* 1541d64.cpp - 1541 emulation in disk image files (.d64/.x64/zipcode) |
3 |
|
* |
4 |
< |
* Frodo (C) 1994-1997,2002-2003 Christian Bauer |
4 |
> |
* Frodo (C) 1994-1997,2002-2005 Christian Bauer |
5 |
|
* zipcode decoding routines (C) 1993-1997 Marko Mäkelä, Paul David Doherty |
6 |
|
* |
7 |
|
* This program is free software; you can redistribute it and/or modify |
34 |
|
#include "C64.h" |
35 |
|
#include "main.h" |
36 |
|
|
37 |
+ |
#define DEBUG 0 |
38 |
+ |
#include "debug.h" |
39 |
+ |
|
40 |
|
|
41 |
|
// Channel modes (IRC users listen up :-) |
42 |
|
enum { |
109 |
|
|
110 |
|
// Prototypes |
111 |
|
static bool match(const uint8 *p, int p_len, const uint8 *n); |
112 |
+ |
static FILE *open_image_file(const char *path, bool write_mode); |
113 |
+ |
static bool parse_image_file(FILE *f, image_file_desc &desc); |
114 |
|
|
115 |
|
|
116 |
|
/* |
201 |
|
|
202 |
|
uint8 ImageDrive::Open(int channel, const uint8 *name, int name_len) |
203 |
|
{ |
204 |
+ |
D(bug("ImageDrive::Open channel %d, file %s\n", channel, name)); |
205 |
+ |
|
206 |
|
set_error(ERR_OK); |
207 |
|
|
208 |
|
// Channel 15: execute file name as command |
244 |
|
if (plain_name_len > 16) |
245 |
|
plain_name_len = 16; |
246 |
|
|
247 |
+ |
D(bug(" plain name %s, type %d, mode %d\n", plain_name, type, mode)); |
248 |
+ |
|
249 |
|
// Channel 0 is READ, channel 1 is WRITE |
250 |
|
if (channel == 0 || channel == 1) { |
251 |
|
mode = channel ? FMODE_WRITE : FMODE_READ; |
278 |
|
if (find_first_file(plain_name, plain_name_len, dir_track, dir_sector, entry)) { |
279 |
|
|
280 |
|
// File exists |
281 |
+ |
D(bug(" file exists, dir track %d, sector %d, entry %d\n", dir_track, dir_sector, entry)); |
282 |
|
ch[channel].dir_track = dir_track; |
283 |
|
ch[channel].dir_sector = dir_sector; |
284 |
|
ch[channel].entry = entry; |
344 |
|
} else { |
345 |
|
|
346 |
|
// File doesn't exist |
347 |
+ |
D(bug(" file not found\n")); |
348 |
+ |
|
349 |
|
// Set file type to SEQ if not specified in file name |
350 |
|
if (type == FTYPE_DEL) |
351 |
|
type = FTYPE_SEQ; |
368 |
|
|
369 |
|
uint8 ImageDrive::open_file_ts(int channel, int track, int sector) |
370 |
|
{ |
371 |
+ |
D(bug("open_file_ts track %d, sector %d\n", track, sector)); |
372 |
+ |
|
373 |
|
// Allocate buffer and set channel mode |
374 |
|
int buf = alloc_buffer(-1); |
375 |
|
if (buf == -1) { |
395 |
|
|
396 |
|
uint8 ImageDrive::create_file(int channel, const uint8 *name, int name_len, int type, bool overwrite) |
397 |
|
{ |
398 |
+ |
D(bug("create_file %s, type %d\n", name, type)); |
399 |
+ |
|
400 |
|
// Allocate buffer |
401 |
|
int buf = alloc_buffer(-1); |
402 |
|
if (buf == -1) { |
423 |
|
return ST_OK; |
424 |
|
} |
425 |
|
ch[channel].num_blocks = 1; |
426 |
+ |
D(bug(" first data block on track %d, sector %d\n", ch[channel].track, ch[channel].sector)); |
427 |
|
|
428 |
|
// Write directory entry |
429 |
|
memset(de, 0, SIZEOF_DE); |
646 |
|
|
647 |
|
uint8 ImageDrive::Close(int channel) |
648 |
|
{ |
649 |
+ |
D(bug("ImageDrive::Close channel %d\n", channel)); |
650 |
+ |
|
651 |
|
switch (ch[channel].mode) { |
652 |
|
case CHMOD_FREE: |
653 |
|
break; |
674 |
|
// Write last data block |
675 |
|
ch[channel].buf[0] = 0; |
676 |
|
ch[channel].buf[1] = ch[channel].buf_len - 1; |
677 |
+ |
D(bug(" writing last data block\n")); |
678 |
|
if (!write_sector(ch[channel].track, ch[channel].sector, ch[channel].buf)) |
679 |
|
goto free; |
680 |
|
|
692 |
|
de[DE_OVR_TRACK] = de[DE_OVR_SECTOR] = 0; |
693 |
|
} |
694 |
|
write_sector(ch[channel].dir_track, ch[channel].dir_sector, dir); |
695 |
+ |
D(bug(" directory entry updated\n")); |
696 |
|
} |
697 |
|
free: free_buffer(ch[channel].buf_num); |
698 |
|
ch[channel].buf = NULL; |
731 |
|
|
732 |
|
uint8 ImageDrive::Read(int channel, uint8 &byte) |
733 |
|
{ |
734 |
+ |
// D(bug("ImageDrive::Read channel %d\n", channel)); |
735 |
+ |
|
736 |
|
switch (ch[channel].mode) { |
737 |
|
case CHMOD_FREE: |
738 |
|
if (current_error == ERR_OK) |
758 |
|
|
759 |
|
// Read next block if necessary |
760 |
|
if (ch[channel].buf_len == 0 && ch[channel].buf[0]) { |
761 |
+ |
D(bug(" reading next data block track %d, sector %d\n", ch[channel].buf[0], ch[channel].buf[1])); |
762 |
|
if (!read_sector(ch[channel].buf[0], ch[channel].buf[1], ch[channel].buf)) |
763 |
|
return ST_READ_TIMEOUT; |
764 |
|
ch[channel].buf_ptr = ch[channel].buf + 2; |
799 |
|
|
800 |
|
uint8 ImageDrive::Write(int channel, uint8 byte, bool eoi) |
801 |
|
{ |
802 |
+ |
// D(bug("ImageDrive::Write channel %d, byte %02x, eoi %d\n", channel, byte, eoi)); |
803 |
+ |
|
804 |
|
switch (ch[channel].mode) { |
805 |
|
case CHMOD_FREE: |
806 |
|
if (current_error == ERR_OK) |
840 |
|
if (!alloc_next_block(track, sector, DATA_INTERLEAVE)) |
841 |
|
return ST_TIMEOUT; |
842 |
|
ch[channel].num_blocks++; |
843 |
+ |
D(bug("next data block on track %d, sector %d\n", track, sector)); |
844 |
|
|
845 |
|
// Write buffer with link to new block |
846 |
|
ch[channel].buf[0] = track; |
1022 |
|
|
1023 |
|
uint8 *de = dir + DIR_ENTRIES; |
1024 |
|
for (entry=0; entry<8; entry++, de+=SIZEOF_DE) { |
1025 |
< |
if (de[DE_TYPE] == 0) |
1025 |
> |
if (de[DE_TYPE] == 0) { |
1026 |
> |
D(bug(" allocated entry %d in dir track %d, sector %d\n", entry, track, sector)); |
1027 |
|
return true; |
1028 |
+ |
} |
1029 |
|
} |
1030 |
|
} |
1031 |
|
|
1033 |
|
int last_track = track, last_sector = sector; |
1034 |
|
if (!alloc_next_block(track, sector, DIR_INTERLEAVE)) |
1035 |
|
return false; |
1036 |
+ |
D(bug(" new directory block track %d, sector %d\n", track, sector)); |
1037 |
|
|
1038 |
|
// Write link to new block to last block |
1039 |
|
dir[DIR_NEXT_TRACK] = track; |
1104 |
|
if (p[byte] & (1 << bit)) { |
1105 |
|
|
1106 |
|
// Yes, allocate and decrement free block count |
1107 |
+ |
D(bug("allocating block at track %d, sector %d\n", track, sector)); |
1108 |
|
p[byte] &= ~(1 << bit); |
1109 |
|
p[0]--; |
1110 |
|
bam_dirty = true; |
1132 |
|
if (!(p[byte] & (1 << bit))) { |
1133 |
|
|
1134 |
|
// Yes, free and increment free block count |
1135 |
+ |
D(bug("freeing block at track %d, sector %d\n", track, sector)); |
1136 |
|
p[byte] |= (1 << bit); |
1137 |
|
p[0]++; |
1138 |
|
bam_dirty = true; |
1294 |
|
}; |
1295 |
|
|
1296 |
|
// Read sector, return error code |
1297 |
< |
int read_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) |
1297 |
> |
static int read_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) |
1298 |
|
{ |
1299 |
|
// Convert track/sector to byte offset in file |
1300 |
|
long offset = offset_from_ts(desc, track, sector); |
1314 |
|
} |
1315 |
|
|
1316 |
|
// Write sector, return error code |
1317 |
< |
int write_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) |
1317 |
> |
static int write_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) |
1318 |
|
{ |
1319 |
|
// Convert track/sector to byte offset in file |
1320 |
|
long offset = offset_from_ts(desc, track, sector); |
1350 |
|
} |
1351 |
|
|
1352 |
|
// Write error info back to image file |
1353 |
< |
void write_back_error_info(FILE *f, const image_file_desc &desc) |
1353 |
> |
static void write_back_error_info(FILE *f, const image_file_desc &desc) |
1354 |
|
{ |
1355 |
|
if (desc.type == TYPE_D64 && desc.has_error_info) { |
1356 |
|
int num_sectors = desc.num_tracks == 40 ? NUM_SECTORS_40 : NUM_SECTORS_35; |
1360 |
|
} |
1361 |
|
|
1362 |
|
// Format disk image |
1363 |
< |
bool format_image(FILE *f, image_file_desc &desc, bool lowlevel, uint8 id1, uint8 id2, const uint8 *disk_name, int disk_name_len) |
1363 |
> |
static bool format_image(FILE *f, image_file_desc &desc, bool lowlevel, uint8 id1, uint8 id2, const uint8 *disk_name, int disk_name_len) |
1364 |
|
{ |
1365 |
|
uint8 p[256]; |
1366 |
|
|
1957 |
|
* Open disk image file, return file handle |
1958 |
|
*/ |
1959 |
|
|
1960 |
< |
FILE *open_image_file(const char *path, bool write_mode) |
1960 |
> |
static FILE *open_image_file(const char *path, bool write_mode) |
1961 |
|
{ |
1962 |
|
#if 0 |
1963 |
|
if (is_zipcode_file(path)) { |
2041 |
|
return true; |
2042 |
|
} |
2043 |
|
|
2044 |
< |
bool parse_image_file(FILE *f, image_file_desc &desc) |
2044 |
> |
static bool parse_image_file(FILE *f, image_file_desc &desc) |
2045 |
|
{ |
2046 |
|
// Read header |
2047 |
|
uint8 header[64]; |
2063 |
|
} |
2064 |
|
|
2065 |
|
|
2066 |
+ |
/* |
2067 |
+ |
* Read directory of disk image file into (empty) c64_dir_entry vector, |
2068 |
+ |
* returns false on error |
2069 |
+ |
*/ |
2070 |
+ |
|
2071 |
+ |
bool ReadImageDirectory(const char *path, vector<c64_dir_entry> &vec) |
2072 |
+ |
{ |
2073 |
+ |
bool result = false; |
2074 |
+ |
|
2075 |
+ |
// Open file |
2076 |
+ |
FILE *f = open_image_file(path, false); |
2077 |
+ |
if (f) { |
2078 |
+ |
int num_dir_blocks = 0; |
2079 |
+ |
|
2080 |
+ |
// Determine file type and fill in image_file_desc structure |
2081 |
+ |
image_file_desc desc; |
2082 |
+ |
if (!parse_image_file(f, desc)) |
2083 |
+ |
goto done; |
2084 |
+ |
|
2085 |
+ |
// Scan all directory blocks |
2086 |
+ |
uint8 dir[256]; |
2087 |
+ |
dir[DIR_NEXT_TRACK] = DIR_TRACK; |
2088 |
+ |
dir[DIR_NEXT_SECTOR] = 1; |
2089 |
+ |
|
2090 |
+ |
while (dir[DIR_NEXT_TRACK] && num_dir_blocks < num_sectors[DIR_TRACK]) { |
2091 |
+ |
if (read_sector(f, desc, dir[DIR_NEXT_TRACK], dir[DIR_NEXT_SECTOR], dir) != ERR_OK) |
2092 |
+ |
break; |
2093 |
+ |
num_dir_blocks++; |
2094 |
+ |
|
2095 |
+ |
// Scan all 8 entries of a block |
2096 |
+ |
uint8 *de = dir + DIR_ENTRIES; |
2097 |
+ |
for (int j=0; j<8; j++, de+=SIZEOF_DE) { |
2098 |
+ |
|
2099 |
+ |
// Skip empty entries |
2100 |
+ |
if (de[DE_TYPE] == 0) |
2101 |
+ |
continue; |
2102 |
+ |
|
2103 |
+ |
// Convert file name (strip everything after and including the first trailing space) |
2104 |
+ |
uint8 name_buf[17]; |
2105 |
+ |
memcpy(name_buf, de + DE_NAME, 16); |
2106 |
+ |
name_buf[16] = 0; |
2107 |
+ |
uint8 *p = (uint8 *)memchr(name_buf, 0xa0, 16); |
2108 |
+ |
if (p) |
2109 |
+ |
*p = 0; |
2110 |
+ |
|
2111 |
+ |
// Convert file type |
2112 |
+ |
int type = de[DE_TYPE] & 7; |
2113 |
+ |
if (type > 4) |
2114 |
+ |
type = FTYPE_UNKNOWN; |
2115 |
+ |
|
2116 |
+ |
// Read start address |
2117 |
+ |
uint8 sa_lo = 0, sa_hi = 0; |
2118 |
+ |
uint8 buf[256]; |
2119 |
+ |
if (read_sector(f, desc, de[DE_TRACK], de[DE_SECTOR], buf) == ERR_OK) { |
2120 |
+ |
sa_lo = buf[2]; |
2121 |
+ |
sa_hi = buf[3]; |
2122 |
+ |
} |
2123 |
+ |
|
2124 |
+ |
// Add entry |
2125 |
+ |
vec.push_back(c64_dir_entry(name_buf, type, !(de[DE_TYPE] & 0x80), de[DE_TYPE] & 0x40, ((de[DE_NUM_BLOCKS_H] << 8) + de[DE_NUM_BLOCKS_L]) * 254, 0, sa_lo, sa_hi)); |
2126 |
+ |
} |
2127 |
+ |
} |
2128 |
+ |
|
2129 |
+ |
result = true; |
2130 |
+ |
done: fclose(f); |
2131 |
+ |
} |
2132 |
+ |
return result; |
2133 |
+ |
} |
2134 |
+ |
|
2135 |
+ |
|
2136 |
|
/* |
2137 |
|
* Create new blank disk image file, returns false on error |
2138 |
|
*/ |