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 Copyright (C) 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 |
|
/* |
117 |
|
* Constructor: Prepare emulation, open image file |
118 |
|
*/ |
119 |
|
|
120 |
< |
D64Drive::D64Drive(IEC *iec, const char *filepath) : Drive(iec), the_file(NULL), bam(ram + 0x700), bam_dirty(false) |
120 |
> |
ImageDrive::ImageDrive(IEC *iec, const char *filepath) : Drive(iec), the_file(NULL), bam(ram + 0x700), bam_dirty(false) |
121 |
|
{ |
122 |
+ |
desc.type = TYPE_D64; |
123 |
+ |
desc.header_size = 0; |
124 |
+ |
desc.num_tracks = 35; |
125 |
+ |
desc.id1 = desc.id2 = 0; |
126 |
+ |
desc.has_error_info = false; |
127 |
+ |
|
128 |
|
for (int i=0; i<18; i++) { |
129 |
|
ch[i].mode = CHMOD_FREE; |
130 |
|
ch[i].buf = NULL; |
143 |
|
* Destructor |
144 |
|
*/ |
145 |
|
|
146 |
< |
D64Drive::~D64Drive() |
146 |
> |
ImageDrive::~ImageDrive() |
147 |
|
{ |
148 |
|
close_image(); |
149 |
|
} |
153 |
|
* Close the image file |
154 |
|
*/ |
155 |
|
|
156 |
< |
void D64Drive::close_image(void) |
156 |
> |
void ImageDrive::close_image(void) |
157 |
|
{ |
158 |
|
if (the_file) { |
159 |
|
close_all_channels(); |
171 |
|
* Open the image file |
172 |
|
*/ |
173 |
|
|
174 |
< |
bool D64Drive::change_image(const char *path) |
174 |
> |
bool ImageDrive::change_image(const char *path) |
175 |
|
{ |
176 |
|
// Close old image file |
177 |
|
close_image(); |
205 |
|
* Open channel |
206 |
|
*/ |
207 |
|
|
208 |
< |
uint8 D64Drive::Open(int channel, const uint8 *name, int name_len) |
208 |
> |
uint8 ImageDrive::Open(int channel, const uint8 *name, int name_len) |
209 |
|
{ |
210 |
+ |
D(bug("ImageDrive::Open channel %d, file %s\n", channel, name)); |
211 |
+ |
|
212 |
|
set_error(ERR_OK); |
213 |
|
|
214 |
|
// Channel 15: execute file name as command |
239 |
|
* Open file |
240 |
|
*/ |
241 |
|
|
242 |
< |
uint8 D64Drive::open_file(int channel, const uint8 *name, int name_len) |
242 |
> |
uint8 ImageDrive::open_file(int channel, const uint8 *name, int name_len) |
243 |
|
{ |
244 |
|
uint8 plain_name[NAMEBUF_LENGTH]; |
245 |
|
int plain_name_len; |
250 |
|
if (plain_name_len > 16) |
251 |
|
plain_name_len = 16; |
252 |
|
|
253 |
+ |
D(bug(" plain name %s, type %d, mode %d\n", plain_name, type, mode)); |
254 |
+ |
|
255 |
|
// Channel 0 is READ, channel 1 is WRITE |
256 |
|
if (channel == 0 || channel == 1) { |
257 |
|
mode = channel ? FMODE_WRITE : FMODE_READ; |
284 |
|
if (find_first_file(plain_name, plain_name_len, dir_track, dir_sector, entry)) { |
285 |
|
|
286 |
|
// File exists |
287 |
+ |
D(bug(" file exists, dir track %d, sector %d, entry %d\n", dir_track, dir_sector, entry)); |
288 |
|
ch[channel].dir_track = dir_track; |
289 |
|
ch[channel].dir_sector = dir_sector; |
290 |
|
ch[channel].entry = entry; |
350 |
|
} else { |
351 |
|
|
352 |
|
// File doesn't exist |
353 |
+ |
D(bug(" file not found\n")); |
354 |
+ |
|
355 |
|
// Set file type to SEQ if not specified in file name |
356 |
|
if (type == FTYPE_DEL) |
357 |
|
type = FTYPE_SEQ; |
372 |
|
* Open channel for reading from file given track/sector of first block |
373 |
|
*/ |
374 |
|
|
375 |
< |
uint8 D64Drive::open_file_ts(int channel, int track, int sector) |
375 |
> |
uint8 ImageDrive::open_file_ts(int channel, int track, int sector) |
376 |
|
{ |
377 |
+ |
D(bug("open_file_ts track %d, sector %d\n", track, sector)); |
378 |
+ |
|
379 |
|
// Allocate buffer and set channel mode |
380 |
|
int buf = alloc_buffer(-1); |
381 |
|
if (buf == -1) { |
399 |
|
* Create file and open channel for writing to file |
400 |
|
*/ |
401 |
|
|
402 |
< |
uint8 D64Drive::create_file(int channel, const uint8 *name, int name_len, int type, bool overwrite) |
402 |
> |
uint8 ImageDrive::create_file(int channel, const uint8 *name, int name_len, int type, bool overwrite) |
403 |
|
{ |
404 |
+ |
D(bug("create_file %s, type %d\n", name, type)); |
405 |
+ |
|
406 |
|
// Allocate buffer |
407 |
|
int buf = alloc_buffer(-1); |
408 |
|
if (buf == -1) { |
429 |
|
return ST_OK; |
430 |
|
} |
431 |
|
ch[channel].num_blocks = 1; |
432 |
+ |
D(bug(" first data block on track %d, sector %d\n", ch[channel].track, ch[channel].sector)); |
433 |
|
|
434 |
|
// Write directory entry |
435 |
|
memset(de, 0, SIZEOF_DE); |
462 |
|
const char type_char_2[] = "EERSELQG"; |
463 |
|
const char type_char_3[] = "LQGRL???"; |
464 |
|
|
465 |
< |
uint8 D64Drive::open_directory(const uint8 *pattern, int pattern_len) |
465 |
> |
uint8 ImageDrive::open_directory(const uint8 *pattern, int pattern_len) |
466 |
|
{ |
467 |
|
// Special treatment for "$0" |
468 |
|
if (pattern[0] == '0' && pattern_len == 1) { |
617 |
|
* Open channel for direct buffer access |
618 |
|
*/ |
619 |
|
|
620 |
< |
uint8 D64Drive::open_direct(int channel, const uint8 *name) |
620 |
> |
uint8 ImageDrive::open_direct(int channel, const uint8 *name) |
621 |
|
{ |
622 |
|
int buf = -1; |
623 |
|
|
650 |
|
* Close channel |
651 |
|
*/ |
652 |
|
|
653 |
< |
uint8 D64Drive::Close(int channel) |
653 |
> |
uint8 ImageDrive::Close(int channel) |
654 |
|
{ |
655 |
+ |
D(bug("ImageDrive::Close channel %d\n", channel)); |
656 |
+ |
|
657 |
|
switch (ch[channel].mode) { |
658 |
|
case CHMOD_FREE: |
659 |
|
break; |
680 |
|
// Write last data block |
681 |
|
ch[channel].buf[0] = 0; |
682 |
|
ch[channel].buf[1] = ch[channel].buf_len - 1; |
683 |
+ |
D(bug(" writing last data block\n")); |
684 |
|
if (!write_sector(ch[channel].track, ch[channel].sector, ch[channel].buf)) |
685 |
|
goto free; |
686 |
|
|
698 |
|
de[DE_OVR_TRACK] = de[DE_OVR_SECTOR] = 0; |
699 |
|
} |
700 |
|
write_sector(ch[channel].dir_track, ch[channel].dir_sector, dir); |
701 |
+ |
D(bug(" directory entry updated\n")); |
702 |
|
} |
703 |
|
free: free_buffer(ch[channel].buf_num); |
704 |
|
ch[channel].buf = NULL; |
720 |
|
* Close all channels |
721 |
|
*/ |
722 |
|
|
723 |
< |
void D64Drive::close_all_channels() |
723 |
> |
void ImageDrive::close_all_channels() |
724 |
|
{ |
725 |
|
for (int i=0; i<15; i++) |
726 |
|
Close(i); |
735 |
|
* Read from channel |
736 |
|
*/ |
737 |
|
|
738 |
< |
uint8 D64Drive::Read(int channel, uint8 &byte) |
738 |
> |
uint8 ImageDrive::Read(int channel, uint8 &byte) |
739 |
|
{ |
740 |
+ |
// D(bug("ImageDrive::Read channel %d\n", channel)); |
741 |
+ |
|
742 |
|
switch (ch[channel].mode) { |
743 |
|
case CHMOD_FREE: |
744 |
|
if (current_error == ERR_OK) |
764 |
|
|
765 |
|
// Read next block if necessary |
766 |
|
if (ch[channel].buf_len == 0 && ch[channel].buf[0]) { |
767 |
+ |
D(bug(" reading next data block track %d, sector %d\n", ch[channel].buf[0], ch[channel].buf[1])); |
768 |
|
if (!read_sector(ch[channel].buf[0], ch[channel].buf[1], ch[channel].buf)) |
769 |
|
return ST_READ_TIMEOUT; |
770 |
|
ch[channel].buf_ptr = ch[channel].buf + 2; |
803 |
|
* Write byte to channel |
804 |
|
*/ |
805 |
|
|
806 |
< |
uint8 D64Drive::Write(int channel, uint8 byte, bool eoi) |
806 |
> |
uint8 ImageDrive::Write(int channel, uint8 byte, bool eoi) |
807 |
|
{ |
808 |
+ |
// D(bug("ImageDrive::Write channel %d, byte %02x, eoi %d\n", channel, byte, eoi)); |
809 |
+ |
|
810 |
|
switch (ch[channel].mode) { |
811 |
|
case CHMOD_FREE: |
812 |
|
if (current_error == ERR_OK) |
846 |
|
if (!alloc_next_block(track, sector, DATA_INTERLEAVE)) |
847 |
|
return ST_TIMEOUT; |
848 |
|
ch[channel].num_blocks++; |
849 |
+ |
D(bug("next data block on track %d, sector %d\n", track, sector)); |
850 |
|
|
851 |
|
// Write buffer with link to new block |
852 |
|
ch[channel].buf[0] = track; |
880 |
|
* Reset drive |
881 |
|
*/ |
882 |
|
|
883 |
< |
void D64Drive::Reset(void) |
883 |
> |
void ImageDrive::Reset(void) |
884 |
|
{ |
885 |
|
close_all_channels(); |
886 |
|
|
907 |
|
* <- Allocated buffer number or -1 |
908 |
|
*/ |
909 |
|
|
910 |
< |
int D64Drive::alloc_buffer(int want) |
910 |
> |
int ImageDrive::alloc_buffer(int want) |
911 |
|
{ |
912 |
|
if (want == -1) { |
913 |
|
for (want=3; want>=0; want--) |
933 |
|
* Free floppy buffer |
934 |
|
*/ |
935 |
|
|
936 |
< |
void D64Drive::free_buffer(int buf) |
936 |
> |
void ImageDrive::free_buffer(int buf) |
937 |
|
{ |
938 |
|
buf_free[buf] = true; |
939 |
|
} |
962 |
|
return *n == 0xa0 || c == 16; |
963 |
|
} |
964 |
|
|
965 |
< |
bool D64Drive::find_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry, bool cont) |
965 |
> |
bool ImageDrive::find_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry, bool cont) |
966 |
|
{ |
967 |
|
// Counter to prevent cyclic directories from resulting in an infinite loop |
968 |
|
int num_dir_blocks = 0; |
1000 |
|
return false; |
1001 |
|
} |
1002 |
|
|
1003 |
< |
bool D64Drive::find_first_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry) |
1003 |
> |
bool ImageDrive::find_first_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry) |
1004 |
|
{ |
1005 |
|
return find_file(pattern, pattern_len, dir_track, dir_sector, entry, false); |
1006 |
|
} |
1007 |
|
|
1008 |
< |
bool D64Drive::find_next_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry) |
1008 |
> |
bool ImageDrive::find_next_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry) |
1009 |
|
{ |
1010 |
|
return find_file(pattern, pattern_len, dir_track, dir_sector, entry, true); |
1011 |
|
} |
1017 |
|
* The track/sector and entry numbers are returned |
1018 |
|
*/ |
1019 |
|
|
1020 |
< |
bool D64Drive::alloc_dir_entry(int &track, int §or, int &entry) |
1020 |
> |
bool ImageDrive::alloc_dir_entry(int &track, int §or, int &entry) |
1021 |
|
{ |
1022 |
|
// First look for free entry in existing directory blocks |
1023 |
|
dir[DIR_NEXT_TRACK] = DIR_TRACK; |
1028 |
|
|
1029 |
|
uint8 *de = dir + DIR_ENTRIES; |
1030 |
|
for (entry=0; entry<8; entry++, de+=SIZEOF_DE) { |
1031 |
< |
if (de[DE_TYPE] == 0) |
1031 |
> |
if (de[DE_TYPE] == 0) { |
1032 |
> |
D(bug(" allocated entry %d in dir track %d, sector %d\n", entry, track, sector)); |
1033 |
|
return true; |
1034 |
+ |
} |
1035 |
|
} |
1036 |
|
} |
1037 |
|
|
1039 |
|
int last_track = track, last_sector = sector; |
1040 |
|
if (!alloc_next_block(track, sector, DIR_INTERLEAVE)) |
1041 |
|
return false; |
1042 |
+ |
D(bug(" new directory block track %d, sector %d\n", track, sector)); |
1043 |
|
|
1044 |
|
// Write link to new block to last block |
1045 |
|
dir[DIR_NEXT_TRACK] = track; |
1058 |
|
* Test if block is free in BAM (track/sector are not checked for validity) |
1059 |
|
*/ |
1060 |
|
|
1061 |
< |
bool D64Drive::is_block_free(int track, int sector) |
1061 |
> |
bool ImageDrive::is_block_free(int track, int sector) |
1062 |
|
{ |
1063 |
|
uint8 *p = bam + BAM_BITMAP + (track - 1) * 4; |
1064 |
|
int byte = sector / 8 + 1; |
1071 |
|
* Get number of free blocks on a track |
1072 |
|
*/ |
1073 |
|
|
1074 |
< |
int D64Drive::num_free_blocks(int track) |
1074 |
> |
int ImageDrive::num_free_blocks(int track) |
1075 |
|
{ |
1076 |
|
return bam[BAM_BITMAP + (track - 1) * 4]; |
1077 |
|
} |
1097 |
|
* Allocate block in BAM, returns error code |
1098 |
|
*/ |
1099 |
|
|
1100 |
< |
int D64Drive::alloc_block(int track, int sector) |
1100 |
> |
int ImageDrive::alloc_block(int track, int sector) |
1101 |
|
{ |
1102 |
|
if (track < 1 || track > 35 || sector < 0 || sector >= num_sectors[track]) |
1103 |
|
return ERR_ILLEGALTS; |
1110 |
|
if (p[byte] & (1 << bit)) { |
1111 |
|
|
1112 |
|
// Yes, allocate and decrement free block count |
1113 |
+ |
D(bug("allocating block at track %d, sector %d\n", track, sector)); |
1114 |
|
p[byte] &= ~(1 << bit); |
1115 |
|
p[0]--; |
1116 |
|
bam_dirty = true; |
1125 |
|
* Free block in BAM, returns error code |
1126 |
|
*/ |
1127 |
|
|
1128 |
< |
int D64Drive::free_block(int track, int sector) |
1128 |
> |
int ImageDrive::free_block(int track, int sector) |
1129 |
|
{ |
1130 |
|
if (track < 1 || track > 35 || sector < 0 || sector >= num_sectors[track]) |
1131 |
|
return ERR_ILLEGALTS; |
1138 |
|
if (!(p[byte] & (1 << bit))) { |
1139 |
|
|
1140 |
|
// Yes, free and increment free block count |
1141 |
+ |
D(bug("freeing block at track %d, sector %d\n", track, sector)); |
1142 |
|
p[byte] |= (1 << bit); |
1143 |
|
p[0]++; |
1144 |
|
bam_dirty = true; |
1151 |
|
* Allocate chain of data blocks in BAM |
1152 |
|
*/ |
1153 |
|
|
1154 |
< |
bool D64Drive::alloc_block_chain(int track, int sector) |
1154 |
> |
bool ImageDrive::alloc_block_chain(int track, int sector) |
1155 |
|
{ |
1156 |
|
uint8 buf[256]; |
1157 |
|
while (alloc_block(track, sector) == ERR_OK) { |
1168 |
|
* Free chain of data blocks in BAM |
1169 |
|
*/ |
1170 |
|
|
1171 |
< |
bool D64Drive::free_block_chain(int track, int sector) |
1171 |
> |
bool ImageDrive::free_block_chain(int track, int sector) |
1172 |
|
{ |
1173 |
|
uint8 buf[256]; |
1174 |
|
while (free_block(track, sector) == ERR_OK) { |
1188 |
|
* begin |
1189 |
|
*/ |
1190 |
|
|
1191 |
< |
bool D64Drive::alloc_next_block(int &track, int §or, int interleave) |
1191 |
> |
bool ImageDrive::alloc_next_block(int &track, int §or, int interleave) |
1192 |
|
{ |
1193 |
|
// Find track with free blocks |
1194 |
|
bool side_changed = false; |
1300 |
|
}; |
1301 |
|
|
1302 |
|
// Read sector, return error code |
1303 |
< |
int read_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) |
1303 |
> |
static int read_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) |
1304 |
|
{ |
1305 |
|
// Convert track/sector to byte offset in file |
1306 |
|
long offset = offset_from_ts(desc, track, sector); |
1320 |
|
} |
1321 |
|
|
1322 |
|
// Write sector, return error code |
1323 |
< |
int write_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) |
1323 |
> |
static int write_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) |
1324 |
|
{ |
1325 |
|
// Convert track/sector to byte offset in file |
1326 |
|
long offset = offset_from_ts(desc, track, sector); |
1338 |
|
} |
1339 |
|
|
1340 |
|
// Read sector and set error message, returns false on error |
1341 |
< |
bool D64Drive::read_sector(int track, int sector, uint8 *buffer) |
1341 |
> |
bool ImageDrive::read_sector(int track, int sector, uint8 *buffer) |
1342 |
|
{ |
1343 |
|
int error = ::read_sector(the_file, desc, track, sector, buffer); |
1344 |
|
if (error) |
1347 |
|
} |
1348 |
|
|
1349 |
|
// Write sector and set error message, returns false on error |
1350 |
< |
bool D64Drive::write_sector(int track, int sector, uint8 *buffer) |
1350 |
> |
bool ImageDrive::write_sector(int track, int sector, uint8 *buffer) |
1351 |
|
{ |
1352 |
|
int error = ::write_sector(the_file, desc, track, sector, buffer); |
1353 |
|
if (error) |
1356 |
|
} |
1357 |
|
|
1358 |
|
// Write error info back to image file |
1359 |
< |
void write_back_error_info(FILE *f, const image_file_desc &desc) |
1359 |
> |
static void write_back_error_info(FILE *f, const image_file_desc &desc) |
1360 |
|
{ |
1361 |
|
if (desc.type == TYPE_D64 && desc.has_error_info) { |
1362 |
|
int num_sectors = desc.num_tracks == 40 ? NUM_SECTORS_40 : NUM_SECTORS_35; |
1366 |
|
} |
1367 |
|
|
1368 |
|
// Format disk image |
1369 |
< |
bool format_image(FILE *f, image_file_desc &desc, bool lowlevel, uint8 id1, uint8 id2, const uint8 *disk_name, int disk_name_len) |
1369 |
> |
static bool format_image(FILE *f, image_file_desc &desc, bool lowlevel, uint8 id1, uint8 id2, const uint8 *disk_name, int disk_name_len) |
1370 |
|
{ |
1371 |
|
uint8 p[256]; |
1372 |
|
|
1430 |
|
*/ |
1431 |
|
|
1432 |
|
// BLOCK-READ:channel,0,track,sector |
1433 |
< |
void D64Drive::block_read_cmd(int channel, int track, int sector, bool user_cmd) |
1433 |
> |
void ImageDrive::block_read_cmd(int channel, int track, int sector, bool user_cmd) |
1434 |
|
{ |
1435 |
|
if (channel >= 16 || ch[channel].mode != CHMOD_DIRECT) { |
1436 |
|
set_error(ERR_NOCHANNEL); |
1448 |
|
} |
1449 |
|
|
1450 |
|
// BLOCK-WRITE:channel,0,track,sector |
1451 |
< |
void D64Drive::block_write_cmd(int channel, int track, int sector, bool user_cmd) |
1451 |
> |
void ImageDrive::block_write_cmd(int channel, int track, int sector, bool user_cmd) |
1452 |
|
{ |
1453 |
|
if (write_protected) { |
1454 |
|
set_error(ERR_WRITEPROTECT); |
1469 |
|
} |
1470 |
|
|
1471 |
|
// BLOCK-ALLOCATE:0,track,sector |
1472 |
< |
void D64Drive::block_allocate_cmd(int track, int sector) |
1472 |
> |
void ImageDrive::block_allocate_cmd(int track, int sector) |
1473 |
|
{ |
1474 |
|
int err = alloc_block(track, sector); |
1475 |
|
if (err) { |
1497 |
|
} |
1498 |
|
|
1499 |
|
// BLOCK-FREE:0,track,sector |
1500 |
< |
void D64Drive::block_free_cmd(int track, int sector) |
1500 |
> |
void ImageDrive::block_free_cmd(int track, int sector) |
1501 |
|
{ |
1502 |
|
int err = free_block(track, sector); |
1503 |
|
if (err) |
1505 |
|
} |
1506 |
|
|
1507 |
|
// BUFFER-POINTER:channel,pos |
1508 |
< |
void D64Drive::buffer_pointer_cmd(int channel, int pos) |
1508 |
> |
void ImageDrive::buffer_pointer_cmd(int channel, int pos) |
1509 |
|
{ |
1510 |
|
if (channel >= 16 || ch[channel].mode != CHMOD_DIRECT) { |
1511 |
|
set_error(ERR_NOCHANNEL); |
1516 |
|
} |
1517 |
|
|
1518 |
|
// M-R<adr low><adr high>[<number>] |
1519 |
< |
void D64Drive::mem_read_cmd(uint16 adr, uint8 len) |
1519 |
> |
void ImageDrive::mem_read_cmd(uint16 adr, uint8 len) |
1520 |
|
{ |
1521 |
|
error_len = len; |
1522 |
|
if (adr >= 0x300 && adr < 0x1000) { |
1533 |
|
} |
1534 |
|
|
1535 |
|
// M-W<adr low><adr high><number><data...> |
1536 |
< |
void D64Drive::mem_write_cmd(uint16 adr, uint8 len, uint8 *p) |
1536 |
> |
void ImageDrive::mem_write_cmd(uint16 adr, uint8 len, uint8 *p) |
1537 |
|
{ |
1538 |
|
while (len) { |
1539 |
|
if (adr >= 0x300 && adr < 0x1000) { |
1550 |
|
// COPY:new=file1,file2,... |
1551 |
|
// ^ ^ |
1552 |
|
// new_file old_files |
1553 |
< |
void D64Drive::copy_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_files, int old_files_len) |
1553 |
> |
void ImageDrive::copy_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_files, int old_files_len) |
1554 |
|
{ |
1555 |
|
// Check if destination file is already present |
1556 |
|
int dir_track, dir_sector, entry; |
1613 |
|
// RENAME:new=old |
1614 |
|
// ^ ^ |
1615 |
|
// new_file old_file |
1616 |
< |
void D64Drive::rename_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_file, int old_file_len) |
1616 |
> |
void ImageDrive::rename_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_file, int old_file_len) |
1617 |
|
{ |
1618 |
|
// Check if destination file is already present |
1619 |
|
int dir_track, dir_sector, entry; |
1644 |
|
// SCRATCH:file1,file2,... |
1645 |
|
// ^ |
1646 |
|
// files |
1647 |
< |
void D64Drive::scratch_cmd(const uint8 *files, int files_len) |
1647 |
> |
void ImageDrive::scratch_cmd(const uint8 *files, int files_len) |
1648 |
|
{ |
1649 |
|
// Check for write-protection |
1650 |
|
if (write_protected) { |
1692 |
|
} |
1693 |
|
|
1694 |
|
// INITIALIZE |
1695 |
< |
void D64Drive::initialize_cmd(void) |
1695 |
> |
void ImageDrive::initialize_cmd(void) |
1696 |
|
{ |
1697 |
|
// Close all channels and re-read BAM |
1698 |
|
close_all_channels(); |
1706 |
|
// NEW:name,id |
1707 |
|
// ^ ^ |
1708 |
|
// name comma (or NULL) |
1709 |
< |
void D64Drive::new_cmd(const uint8 *name, int name_len, const uint8 *comma) |
1709 |
> |
void ImageDrive::new_cmd(const uint8 *name, int name_len, const uint8 *comma) |
1710 |
|
{ |
1711 |
|
// Check for write-protection |
1712 |
|
if (write_protected) { |
1743 |
|
} |
1744 |
|
|
1745 |
|
// VALIDATE |
1746 |
< |
void D64Drive::validate_cmd(void) |
1746 |
> |
void ImageDrive::validate_cmd(void) |
1747 |
|
{ |
1748 |
|
// Backup of old BAM in case something goes amiss |
1749 |
|
uint8 old_bam[256]; |
1963 |
|
* Open disk image file, return file handle |
1964 |
|
*/ |
1965 |
|
|
1966 |
< |
FILE *open_image_file(const char *path, bool write_mode) |
1966 |
> |
static FILE *open_image_file(const char *path, bool write_mode) |
1967 |
|
{ |
1968 |
|
#if 0 |
1969 |
|
if (is_zipcode_file(path)) { |
2047 |
|
return true; |
2048 |
|
} |
2049 |
|
|
2050 |
< |
bool parse_image_file(FILE *f, image_file_desc &desc) |
2050 |
> |
static bool parse_image_file(FILE *f, image_file_desc &desc) |
2051 |
|
{ |
2052 |
|
// Read header |
2053 |
|
uint8 header[64]; |
2069 |
|
} |
2070 |
|
|
2071 |
|
|
2072 |
+ |
/* |
2073 |
+ |
* Read directory of disk image file into (empty) c64_dir_entry vector, |
2074 |
+ |
* returns false on error |
2075 |
+ |
*/ |
2076 |
+ |
|
2077 |
+ |
bool ReadImageDirectory(const char *path, vector<c64_dir_entry> &vec) |
2078 |
+ |
{ |
2079 |
+ |
bool result = false; |
2080 |
+ |
|
2081 |
+ |
// Open file |
2082 |
+ |
FILE *f = open_image_file(path, false); |
2083 |
+ |
if (f) { |
2084 |
+ |
int num_dir_blocks = 0; |
2085 |
+ |
|
2086 |
+ |
// Determine file type and fill in image_file_desc structure |
2087 |
+ |
image_file_desc desc; |
2088 |
+ |
if (!parse_image_file(f, desc)) |
2089 |
+ |
goto done; |
2090 |
+ |
|
2091 |
+ |
// Scan all directory blocks |
2092 |
+ |
uint8 dir[256]; |
2093 |
+ |
dir[DIR_NEXT_TRACK] = DIR_TRACK; |
2094 |
+ |
dir[DIR_NEXT_SECTOR] = 1; |
2095 |
+ |
|
2096 |
+ |
while (dir[DIR_NEXT_TRACK] && num_dir_blocks < num_sectors[DIR_TRACK]) { |
2097 |
+ |
if (read_sector(f, desc, dir[DIR_NEXT_TRACK], dir[DIR_NEXT_SECTOR], dir) != ERR_OK) |
2098 |
+ |
break; |
2099 |
+ |
num_dir_blocks++; |
2100 |
+ |
|
2101 |
+ |
// Scan all 8 entries of a block |
2102 |
+ |
uint8 *de = dir + DIR_ENTRIES; |
2103 |
+ |
for (int j=0; j<8; j++, de+=SIZEOF_DE) { |
2104 |
+ |
|
2105 |
+ |
// Skip empty entries |
2106 |
+ |
if (de[DE_TYPE] == 0) |
2107 |
+ |
continue; |
2108 |
+ |
|
2109 |
+ |
// Convert file name (strip everything after and including the first trailing space) |
2110 |
+ |
uint8 name_buf[17]; |
2111 |
+ |
memcpy(name_buf, de + DE_NAME, 16); |
2112 |
+ |
name_buf[16] = 0; |
2113 |
+ |
uint8 *p = (uint8 *)memchr(name_buf, 0xa0, 16); |
2114 |
+ |
if (p) |
2115 |
+ |
*p = 0; |
2116 |
+ |
|
2117 |
+ |
// Convert file type |
2118 |
+ |
int type = de[DE_TYPE] & 7; |
2119 |
+ |
if (type > 4) |
2120 |
+ |
type = FTYPE_UNKNOWN; |
2121 |
+ |
|
2122 |
+ |
// Read start address |
2123 |
+ |
uint8 sa_lo = 0, sa_hi = 0; |
2124 |
+ |
uint8 buf[256]; |
2125 |
+ |
if (read_sector(f, desc, de[DE_TRACK], de[DE_SECTOR], buf) == ERR_OK) { |
2126 |
+ |
sa_lo = buf[2]; |
2127 |
+ |
sa_hi = buf[3]; |
2128 |
+ |
} |
2129 |
+ |
|
2130 |
+ |
// Add entry |
2131 |
+ |
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)); |
2132 |
+ |
} |
2133 |
+ |
} |
2134 |
+ |
|
2135 |
+ |
result = true; |
2136 |
+ |
done: fclose(f); |
2137 |
+ |
} |
2138 |
+ |
return result; |
2139 |
+ |
} |
2140 |
+ |
|
2141 |
+ |
|
2142 |
|
/* |
2143 |
|
* Create new blank disk image file, returns false on error |
2144 |
|
*/ |