1 /*
2 * sio.c - Serial I/O emulation
3 *
4 * Copyright (C) 1995-1998 David Firth
5 * Copyright (C) 1998-2010 Atari800 development team (see DOC/CREDITS)
6 *
7 * This file is part of the Atari800 emulator project which emulates
8 * the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
9 *
10 * Atari800 is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * Atari800 is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with Atari800; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #define _POSIX_C_SOURCE 200112L /* for snprintf */
26
27 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32
33 #include "afile.h"
34 #include "antic.h" /* ANTIC_ypos */
35 #include "atari.h"
36 #include "binload.h"
37 #include "cassette.h"
38 #include "compfile.h"
39 #include "cpu.h"
40 #include "esc.h"
41 #include "log.h"
42 #include "memory.h"
43 #include "platform.h"
44 #include "pokey.h"
45 #include "pokeysnd.h"
46 #include "sio.h"
47 #include "util.h"
48 #ifndef BASIC
49 #include "statesav.h"
50 #endif
51
52 #undef DEBUG_PRO
53 #undef DEBUG_VAPI
54
55 /* If ATR image is in double density (256 bytes per sector),
56 then the boot sectors (sectors 1-3) can be:
57 - logical (as seen by Atari) - 128 bytes in each sector
58 - physical (as stored on the disk) - 256 bytes in each sector.
59 Only the first half of sector is used for storing data, the rest is zero.
60 - SIO2PC (the type used by the SIO2PC program) - 3 * 128 bytes for data
61 of boot sectors, then 3 * 128 unused bytes (zero)
62 The XFD images in double density have either logical or physical
63 boot sectors. */
64 #define BOOT_SECTORS_LOGICAL 0
65 #define BOOT_SECTORS_PHYSICAL 1
66 #define BOOT_SECTORS_SIO2PC 2
67 static int boot_sectors_type[SIO_MAX_DRIVES];
68
69 static int image_type[SIO_MAX_DRIVES];
70 #define IMAGE_TYPE_XFD 0
71 #define IMAGE_TYPE_ATR 1
72 #define IMAGE_TYPE_PRO 2
73 #define IMAGE_TYPE_VAPI 3
74 static FILE *disk[SIO_MAX_DRIVES] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
75 static int sectorcount[SIO_MAX_DRIVES];
76 static int sectorsize[SIO_MAX_DRIVES];
77 /* these two are used by the 1450XLD parallel disk device */
78 int SIO_format_sectorcount[SIO_MAX_DRIVES];
79 int SIO_format_sectorsize[SIO_MAX_DRIVES];
80 static int io_success[SIO_MAX_DRIVES];
81 /* stores dup sector counter for PRO images */
82 typedef struct tagpro_additional_info_t {
83 int max_sector;
84 unsigned char *count;
85 } pro_additional_info_t;
86
87 #define MAX_VAPI_PHANTOM_SEC 40
88 #define VAPI_BYTES_PER_TRACK 26042.0
89 #define VAPI_CYCLES_PER_ROT 372706
90 #define VAPI_CYCLES_PER_TRACK_STEP 35780 /*70937*/
91 #define VAPI_CYCLES_HEAD_SETTLE 70134
92 #define VAPI_CYCLES_TRACK_READ_DELTA 1426
93 #define VAPI_CYCLES_CMD_ACK_TRANS 3188
94 #define VAPI_CYCLES_SECTOR_READ 29014
95 #define VAPI_CYCLES_MISSING_SECTOR (2*VAPI_CYCLES_PER_ROT + 14453)
96 #define VAPI_CYCLES_BAD_SECTOR_NUM 1521
97
98 /* stores dup sector information for VAPI images */
99 typedef struct tagvapi_sec_info_t {
100 int sec_count;
101 unsigned int sec_offset[MAX_VAPI_PHANTOM_SEC];
102 unsigned char sec_status[MAX_VAPI_PHANTOM_SEC];
103 unsigned int sec_rot_pos[MAX_VAPI_PHANTOM_SEC];
104 } vapi_sec_info_t;
105
106 typedef struct tagvapi_additional_info_t {
107 vapi_sec_info_t *sectors;
108 int sec_stat_buff[4];
109 int vapi_delay_time;
110 } vapi_additional_info_t;
111
112 /* VAPI Format Header */
113 typedef struct tagvapi_file_header_t {
114 unsigned char signature[4];
115 unsigned char majorver;
116 unsigned char minorver;
117 unsigned char reserved1[22];
118 unsigned char startdata[4];
119 unsigned char reserved[16];
120 } vapi_file_header_t;
121
122 typedef struct tagvapi_track_header_t {
123 unsigned char next[4];
124 unsigned char type[2];
125 unsigned char reserved1[2];
126 unsigned char tracknum;
127 unsigned char reserved2;
128 unsigned char sectorcnt[2];
129 unsigned char reserved3[8];
130 unsigned char startdata[4];
131 unsigned char reserved4[8];
132 } vapi_track_header_t;
133
134 typedef struct tagvapi_sector_list_header_t {
135 unsigned char sizelist[4];
136 unsigned char type;
137 unsigned char reserved[3];
138 } vapi_sector_list_header_t;
139
140 typedef struct tagvapi_sector_header_t {
141 unsigned char sectornum;
142 unsigned char sectorstatus;
143 unsigned char sectorpos[2];
144 unsigned char startdata[4];
145 } vapi_sector_header_t;
146
147 #define VAPI_32(x) (x[0] + (x[1] << 8) + (x[2] << 16) + (x[3] << 24))
148 #define VAPI_16(x) (x[0] + (x[1] << 8))
149
150 /* Additional Info for all copy protected disk types */
151 static void *additional_info[SIO_MAX_DRIVES];
152
153 SIO_UnitStatus SIO_drive_status[SIO_MAX_DRIVES];
154 char SIO_filename[SIO_MAX_DRIVES][FILENAME_MAX];
155
156 Util_tmpbufdef(static, sio_tmpbuf[SIO_MAX_DRIVES])
157
158 int SIO_last_op;
159 int SIO_last_op_time = 0;
160 int SIO_last_drive;
161 int SIO_last_sector;
162 char SIO_status[256];
163
164 /* Serial I/O emulation support */
165 #define SIO_NoFrame (0x00)
166 #define SIO_CommandFrame (0x01)
167 #define SIO_StatusRead (0x02)
168 #define SIO_ReadFrame (0x03)
169 #define SIO_WriteFrame (0x04)
170 #define SIO_FinalStatus (0x05)
171 #define SIO_FormatFrame (0x06)
172 #define SIO_CasReadWrite (0x60)
173 static UBYTE CommandFrame[6];
174 static int CommandIndex = 0;
175 static UBYTE DataBuffer[256 + 3];
176 static int DataIndex = 0;
177 static int TransferStatus = SIO_NoFrame;
178 static int ExpectedBytes = 0;
179
180 int ignore_header_writeprotect = FALSE;
181
SIO_Initialise(int * argc,char * argv[])182 int SIO_Initialise(int *argc, char *argv[])
183 {
184 int i;
185 for (i = 0; i < SIO_MAX_DRIVES; i++) {
186 strcpy(SIO_filename[i], "Off");
187 SIO_drive_status[i] = SIO_OFF;
188 SIO_format_sectorsize[i] = 128;
189 SIO_format_sectorcount[i] = 720;
190 }
191 TransferStatus = SIO_NoFrame;
192
193 return TRUE;
194 }
195
196 /* umount disks so temporary files are deleted */
SIO_Exit(void)197 void SIO_Exit(void)
198 {
199 int i;
200 for (i = 1; i <= SIO_MAX_DRIVES; i++)
201 SIO_Dismount(i);
202 }
203
SIO_Mount(int diskno,const char * filename,int b_open_readonly)204 int SIO_Mount(int diskno, const char *filename, int b_open_readonly)
205 {
206 FILE *f = NULL;
207 SIO_UnitStatus status = SIO_READ_WRITE;
208 struct AFILE_ATR_Header header;
209
210 /* avoid overruns in SIO_filename[] */
211 if (strlen(filename) >= FILENAME_MAX)
212 return FALSE;
213
214 /* release previous disk */
215 SIO_Dismount(diskno);
216
217 /* open file */
218 if (!b_open_readonly)
219 f = Util_fopen(filename, "rb+", sio_tmpbuf[diskno - 1]);
220 if (f == NULL) {
221 f = Util_fopen(filename, "rb", sio_tmpbuf[diskno - 1]);
222 if (f == NULL)
223 return FALSE;
224 status = SIO_READ_ONLY;
225 }
226
227 /* read header */
228 if (fread(&header, 1, sizeof(struct AFILE_ATR_Header), f) != sizeof(struct AFILE_ATR_Header)) {
229 fclose(f);
230 return FALSE;
231 }
232
233 /* detect compressed image and uncompress */
234 switch (header.magic1) {
235 case 0xf9:
236 case 0xfa:
237 /* DCM */
238 {
239 FILE *f2 = Util_tmpopen(sio_tmpbuf[diskno - 1]);
240 if (f2 == NULL)
241 return FALSE;
242 Util_rewind(f);
243 if (!CompFile_DCMtoATR(f, f2)) {
244 Util_fclose(f2, sio_tmpbuf[diskno - 1]);
245 fclose(f);
246 return FALSE;
247 }
248 fclose(f);
249 f = f2;
250 }
251 Util_rewind(f);
252 if (fread(&header, 1, sizeof(struct AFILE_ATR_Header), f) != sizeof(struct AFILE_ATR_Header)) {
253 Util_fclose(f, sio_tmpbuf[diskno - 1]);
254 return FALSE;
255 }
256 status = SIO_READ_ONLY;
257 /* XXX: status = b_open_readonly ? SIO_READ_ONLY : SIO_READ_WRITE; */
258 break;
259 case 0x1f:
260 if (header.magic2 == 0x8b) {
261 /* ATZ/ATR.GZ, XFZ/XFD.GZ */
262 fclose(f);
263 f = Util_tmpopen(sio_tmpbuf[diskno - 1]);
264 if (f == NULL)
265 return FALSE;
266 if (!CompFile_ExtractGZ(filename, f)) {
267 Util_fclose(f, sio_tmpbuf[diskno - 1]);
268 return FALSE;
269 }
270 Util_rewind(f);
271 if (fread(&header, 1, sizeof(struct AFILE_ATR_Header), f) != sizeof(struct AFILE_ATR_Header)) {
272 Util_fclose(f, sio_tmpbuf[diskno - 1]);
273 return FALSE;
274 }
275 status = SIO_READ_ONLY;
276 /* XXX: status = b_open_readonly ? SIO_READ_ONLY : SIO_READ_WRITE; */
277 }
278 break;
279 default:
280 break;
281 }
282
283 boot_sectors_type[diskno - 1] = BOOT_SECTORS_LOGICAL;
284
285 if (header.magic1 == AFILE_ATR_MAGIC1 && header.magic2 == AFILE_ATR_MAGIC2) {
286 /* ATR (may be temporary from DCM or ATR/ATR.GZ) */
287 image_type[diskno - 1] = IMAGE_TYPE_ATR;
288
289 sectorsize[diskno - 1] = (header.secsizehi << 8) + header.secsizelo;
290 if (sectorsize[diskno - 1] != 128 && sectorsize[diskno - 1] != 256) {
291 Util_fclose(f, sio_tmpbuf[diskno - 1]);
292 return FALSE;
293 }
294
295 if (header.writeprotect != 0 && !ignore_header_writeprotect)
296 status = SIO_READ_ONLY;
297
298 /* ATR header contains length in 16-byte chunks. */
299 /* First compute number of 128-byte chunks
300 - it's number of sectors on single density disk */
301 sectorcount[diskno - 1] = ((header.hiseccounthi << 24)
302 + (header.hiseccountlo << 16)
303 + (header.seccounthi << 8)
304 + header.seccountlo) >> 3;
305
306 /* Fix number of sectors if double density */
307 if (sectorsize[diskno - 1] == 256) {
308 if ((sectorcount[diskno - 1] & 1) != 0)
309 /* logical (128-byte) boot sectors */
310 sectorcount[diskno - 1] += 3;
311 else {
312 /* 256-byte boot sectors */
313 /* check if physical or SIO2PC: physical if there's
314 a non-zero byte in bytes 0x190-0x30f of the ATR file */
315 UBYTE buffer[0x180];
316 int i;
317 fseek(f, 0x190, SEEK_SET);
318 if (fread(buffer, 1, 0x180, f) != 0x180) {
319 Util_fclose(f, sio_tmpbuf[diskno - 1]);
320 return FALSE;
321 }
322 boot_sectors_type[diskno - 1] = BOOT_SECTORS_SIO2PC;
323 for (i = 0; i < 0x180; i++)
324 if (buffer[i] != 0) {
325 boot_sectors_type[diskno - 1] = BOOT_SECTORS_PHYSICAL;
326 break;
327 }
328 }
329 sectorcount[diskno - 1] >>= 1;
330 }
331 }
332 else if (header.magic1 == 'A' && header.magic2 == 'T' && header.seccountlo == '8' &&
333 header.seccounthi == 'X') {
334 int file_length = Util_flen(f);
335 vapi_additional_info_t *info;
336 vapi_file_header_t fileheader;
337 vapi_track_header_t trackheader;
338 int trackoffset, totalsectors;
339
340 /* .atx is read only for now */
341 #ifndef VAPI_WRITE_ENABLE
342 if (!b_open_readonly) {
343 fclose(f);
344 f = Util_fopen(filename, "rb", sio_tmpbuf[diskno - 1]);
345 if (f == NULL)
346 return FALSE;
347 status = SIO_READ_ONLY;
348 }
349 #endif
350
351 image_type[diskno - 1] = IMAGE_TYPE_VAPI;
352 sectorsize[diskno - 1] = 128;
353 sectorcount[diskno - 1] = 720;
354 fseek(f,0,SEEK_SET);
355 if (fread(&fileheader,1,sizeof(fileheader),f) != sizeof(fileheader)) {
356 Util_fclose(f, sio_tmpbuf[diskno - 1]);
357 Log_print("VAPI: Bad File Header");
358 return(FALSE);
359 }
360 trackoffset = VAPI_32(fileheader.startdata);
361 if (trackoffset > file_length) {
362 Util_fclose(f, sio_tmpbuf[diskno - 1]);
363 Log_print("VAPI: Bad Track Offset");
364 return(FALSE);
365 }
366 #ifdef DEBUG_VAPI
367 Log_print("VAPI File Version %d.%d",fileheader.majorver,fileheader.minorver);
368 #endif
369 /* Read all of the track headers to get the total sector count */
370 totalsectors = 0;
371 while (trackoffset > 0 && trackoffset < file_length) {
372 ULONG next;
373 UWORD tracktype;
374
375 fseek(f,trackoffset,SEEK_SET);
376 if (fread(&trackheader,1,sizeof(trackheader),f) != sizeof(trackheader)) {
377 Util_fclose(f, sio_tmpbuf[diskno - 1]);
378 Log_print("VAPI: Bad Track Header");
379 return(FALSE);
380 }
381 next = VAPI_32(trackheader.next);
382 tracktype = VAPI_16(trackheader.type);
383 if (tracktype == 0) {
384 totalsectors += VAPI_16(trackheader.sectorcnt);
385 }
386 trackoffset += next;
387 }
388
389 info = Util_malloc(sizeof(vapi_additional_info_t));
390 additional_info[diskno-1] = info;
391 info->sectors = Util_malloc(sectorcount[diskno - 1] *
392 sizeof(vapi_sec_info_t));
393 memset(info->sectors, 0, sectorcount[diskno - 1] *
394 sizeof(vapi_sec_info_t));
395
396 /* Now read all the sector data */
397 trackoffset = VAPI_32(fileheader.startdata);
398 while (trackoffset > 0 && trackoffset < file_length) {
399 int sectorcnt, seclistdata,next;
400 vapi_sector_list_header_t sectorlist;
401 vapi_sector_header_t sectorheader;
402 vapi_sec_info_t *sector;
403 UWORD tracktype;
404 int j;
405
406 fseek(f,trackoffset,SEEK_SET);
407 if (fread(&trackheader,1,sizeof(trackheader),f) != sizeof(trackheader)) {
408 free(info->sectors);
409 free(info);
410 Util_fclose(f, sio_tmpbuf[diskno - 1]);
411 Log_print("VAPI: Bad Track Header while reading sectors");
412 return(FALSE);
413 }
414 next = VAPI_32(trackheader.next);
415 sectorcnt = VAPI_16(trackheader.sectorcnt);
416 tracktype = VAPI_16(trackheader.type);
417 seclistdata = VAPI_32(trackheader.startdata) + trackoffset;
418 #ifdef DEBUG_VAPI
419 Log_print("Track %d: next %x type %d seccnt %d secdata %x",trackheader.tracknum,
420 trackoffset + next,VAPI_16(trackheader.type),sectorcnt,seclistdata);
421 #endif
422 if (tracktype == 0) {
423 if (seclistdata > file_length) {
424 free(info->sectors);
425 free(info);
426 Util_fclose(f, sio_tmpbuf[diskno - 1]);
427 Log_print("VAPI: Bad Sector List Offset");
428 return(FALSE);
429 }
430 fseek(f,seclistdata,SEEK_SET);
431 if (fread(§orlist,1,sizeof(sectorlist),f) != sizeof(sectorlist)) {
432 free(info->sectors);
433 free(info);
434 Util_fclose(f, sio_tmpbuf[diskno - 1]);
435 Log_print("VAPI: Bad Sector List");
436 return(FALSE);
437 }
438 #ifdef DEBUG_VAPI
439 Log_print("Size sec list %x type %d",VAPI_32(sectorlist.sizelist),sectorlist.type);
440 #endif
441 for (j=0;j<sectorcnt;j++) {
442 double percent_rot;
443
444 if (fread(§orheader,1,sizeof(sectorheader),f) != sizeof(sectorheader)) {
445 free(info->sectors);
446 free(info);
447 Util_fclose(f, sio_tmpbuf[diskno - 1]);
448 Log_print("VAPI: Bad Sector Header");
449 return(FALSE);
450 }
451 if (sectorheader.sectornum > 18) {
452 Util_fclose(f, sio_tmpbuf[diskno - 1]);
453 Log_print("VAPI: Bad Sector Index: Track %d Sec Num %d Index %d",
454 trackheader.tracknum,j,sectorheader.sectornum);
455 return(FALSE);
456 }
457 sector = &info->sectors[trackheader.tracknum * 18 + sectorheader.sectornum - 1];
458
459 percent_rot = ((double) VAPI_16(sectorheader.sectorpos))/VAPI_BYTES_PER_TRACK;
460 sector->sec_rot_pos[sector->sec_count] = (unsigned int) (percent_rot * VAPI_CYCLES_PER_ROT);
461 sector->sec_offset[sector->sec_count] = VAPI_32(sectorheader.startdata) + trackoffset;
462 sector->sec_status[sector->sec_count] = ~sectorheader.sectorstatus;
463 sector->sec_count++;
464 if (sector->sec_count > MAX_VAPI_PHANTOM_SEC) {
465 free(info->sectors);
466 free(info);
467 Util_fclose(f, sio_tmpbuf[diskno - 1]);
468 Log_print("VAPI: Too many Phantom Sectors");
469 return(FALSE);
470 }
471 #ifdef DEBUG_VAPI
472 Log_print("Sector %d status %x position %f %d %d data %x",sectorheader.sectornum,
473 sector->sec_status[sector->sec_count-1],percent_rot,
474 sector->sec_rot_pos[sector->sec_count-1],
475 VAPI_16(sectorheader.sectorpos),
476 sector->sec_offset[sector->sec_count-1]);
477 #endif
478 }
479 #ifdef DEBUG_VAPI
480 Log_flushlog();
481 #endif
482 } else {
483 Log_print("Unknown VAPI track type Track:%d Type:%d",trackheader.tracknum,tracktype);
484 }
485 trackoffset += next;
486 }
487 }
488 else {
489 int file_length = Util_flen(f);
490 /* check for PRO */
491 if ((file_length-16)%(128+12) == 0 &&
492 (header.magic1*256 + header.magic2 == (file_length-16)/(128+12)) &&
493 header.seccountlo == 'P') {
494 pro_additional_info_t *info;
495 /* .pro is read only for now */
496 if (!b_open_readonly) {
497 fclose(f);
498 f = Util_fopen(filename, "rb", sio_tmpbuf[diskno - 1]);
499 if (f == NULL)
500 return FALSE;
501 status = SIO_READ_ONLY;
502 }
503 image_type[diskno - 1] = IMAGE_TYPE_PRO;
504 sectorsize[diskno - 1] = 128;
505 if (file_length >= 1040*(128+12)+16) {
506 /* assume enhanced density */
507 sectorcount[diskno - 1] = 1040;
508 }
509 else {
510 /* assume single density */
511 sectorcount[diskno - 1] = 720;
512 }
513
514 info = Util_malloc(sizeof(pro_additional_info_t));
515 additional_info[diskno-1] = info;
516 info->count = Util_malloc(sectorcount[diskno - 1]);
517 memset(info->count, 0, sectorcount[diskno -1]);
518 info->max_sector = (file_length-16)/(128+12);
519 }
520 else {
521 /* XFD (may be temporary from XFZ/XFD.GZ) */
522
523 image_type[diskno - 1] = IMAGE_TYPE_XFD;
524
525 if (file_length <= (1040 * 128)) {
526 /* single density */
527 sectorsize[diskno - 1] = 128;
528 sectorcount[diskno - 1] = file_length >> 7;
529 }
530 else {
531 /* double density */
532 sectorsize[diskno - 1] = 256;
533 if ((file_length & 0xff) == 0) {
534 boot_sectors_type[diskno - 1] = BOOT_SECTORS_PHYSICAL;
535 sectorcount[diskno - 1] = file_length >> 8;
536 }
537 else
538 sectorcount[diskno - 1] = (file_length + 0x180) >> 8;
539 }
540 }
541 }
542
543 #ifdef DEBUG
544 Log_print("sectorcount = %d, sectorsize = %d",
545 sectorcount[diskno - 1], sectorsize[diskno - 1]);
546 #endif
547 SIO_format_sectorsize[diskno - 1] = sectorsize[diskno - 1];
548 SIO_format_sectorcount[diskno - 1] = sectorcount[diskno - 1];
549 strcpy(SIO_filename[diskno - 1], filename);
550 SIO_drive_status[diskno - 1] = status;
551 disk[diskno - 1] = f;
552 return TRUE;
553 }
554
SIO_Dismount(int diskno)555 void SIO_Dismount(int diskno)
556 {
557 if (disk[diskno - 1] != NULL) {
558 Util_fclose(disk[diskno - 1], sio_tmpbuf[diskno - 1]);
559 disk[diskno - 1] = NULL;
560 SIO_drive_status[diskno - 1] = SIO_NO_DISK;
561 strcpy(SIO_filename[diskno - 1], "Empty");
562 if (image_type[diskno - 1] == IMAGE_TYPE_PRO) {
563 free(((pro_additional_info_t *)additional_info[diskno-1])->count);
564 }
565 else if (image_type[diskno - 1] == IMAGE_TYPE_VAPI) {
566 free(((vapi_additional_info_t *)additional_info[diskno-1])->sectors);
567 }
568 free(additional_info[diskno - 1]);
569 additional_info[diskno - 1] = 0;
570 }
571 }
572
SIO_DisableDrive(int diskno)573 void SIO_DisableDrive(int diskno)
574 {
575 SIO_Dismount(diskno);
576 SIO_drive_status[diskno - 1] = SIO_OFF;
577 strcpy(SIO_filename[diskno - 1], "Off");
578 }
579
SIO_SizeOfSector(UBYTE unit,int sector,int * sz,ULONG * ofs)580 void SIO_SizeOfSector(UBYTE unit, int sector, int *sz, ULONG *ofs)
581 {
582 int size;
583 ULONG offset;
584 int header_size = (image_type[unit] == IMAGE_TYPE_ATR ? 16 : 0);
585
586 if (BINLOAD_start_binloading) {
587 if (sz)
588 *sz = 128;
589 if (ofs)
590 *ofs = 0;
591 return;
592 }
593
594 if (image_type[unit] == IMAGE_TYPE_PRO) {
595 size = 128;
596 offset = 16 + (128+12)*(sector -1); /* returns offset of header */
597 }
598 else if (image_type[unit] == IMAGE_TYPE_VAPI) {
599 vapi_additional_info_t *info;
600 vapi_sec_info_t *secinfo;
601
602 size = 128;
603 info = additional_info[unit];
604 if (info == NULL)
605 offset = 0;
606 else if (sector > sectorcount[unit])
607 offset = 0;
608 else {
609 secinfo = &info->sectors[sector-1];
610 if (secinfo->sec_count == 0 )
611 offset = 0;
612 else
613 offset = secinfo->sec_offset[0];
614 }
615 }
616 else if (sector < 4) {
617 /* special case for first three sectors in ATR and XFD image */
618 size = 128;
619 offset = header_size + (sector - 1) * (boot_sectors_type[unit] == BOOT_SECTORS_PHYSICAL ? 256 : 128);
620 }
621 else {
622 size = sectorsize[unit];
623 offset = header_size + (boot_sectors_type[unit] == BOOT_SECTORS_LOGICAL ? 0x180 : 0x300) + (sector - 4) * size;
624 }
625
626 if (sz)
627 *sz = size;
628
629 if (ofs)
630 *ofs = offset;
631 }
632
SeekSector(int unit,int sector)633 static int SeekSector(int unit, int sector)
634 {
635 ULONG offset;
636 int size;
637
638 SIO_last_sector = sector;
639 snprintf(SIO_status, sizeof(SIO_status), "%d: %d", unit + 1, sector);
640 SIO_SizeOfSector((UBYTE) unit, sector, &size, &offset);
641 fseek(disk[unit], offset, SEEK_SET);
642
643 return size;
644 }
645
646 /* Unit counts from zero up */
SIO_ReadSector(int unit,int sector,UBYTE * buffer)647 int SIO_ReadSector(int unit, int sector, UBYTE *buffer)
648 {
649 int size;
650 if (BINLOAD_start_binloading)
651 return BINLOAD_LoaderStart(buffer);
652
653 io_success[unit] = -1;
654 if (SIO_drive_status[unit] == SIO_OFF)
655 return 0;
656 if (disk[unit] == NULL)
657 return 'N';
658 if (sector <= 0 || sector > sectorcount[unit])
659 return 'E';
660 SIO_last_op = SIO_LAST_READ;
661 SIO_last_op_time = 1;
662 SIO_last_drive = unit + 1;
663 /* FIXME: what sector size did the user expect? */
664 size = SeekSector(unit, sector);
665 if (image_type[unit] == IMAGE_TYPE_PRO) {
666 pro_additional_info_t *info;
667 unsigned char *count;
668 info = (pro_additional_info_t *)additional_info[unit];
669 count = info->count;
670 if (fread(buffer, 1, 12, disk[unit]) < 12) {
671 Log_print("Error in header of .pro image: sector:%d", sector);
672 return 'E';
673 }
674 /* handle duplicate sectors */
675 if (buffer[5] != 0) {
676 int dupnum = count[sector];
677 #ifdef DEBUG_PRO
678 Log_print("duplicate sector:%d dupnum:%d",sector, dupnum);
679 #endif
680 count[sector] = (count[sector]+1) % (buffer[5]+1);
681 if (dupnum != 0) {
682 sector = sectorcount[unit] + buffer[6+dupnum];
683 /* can dupnum be 5? */
684 if (dupnum > 4 || sector <= 0 || sector > info->max_sector) {
685 Log_print("Error in .pro image: sector:%d dupnum:%d", sector, dupnum);
686 return 'E';
687 }
688 size = SeekSector(unit, sector);
689 /* read sector header */
690 if (fread(buffer, 1, 12, disk[unit]) < 12) {
691 Log_print("Error in header2 of .pro image: sector:%d dupnum:%d", sector, dupnum);
692 return 'E';
693 }
694 }
695 }
696 /* bad sector */
697 if (buffer[1] != 0xff) {
698 if (fread(buffer, 1, size, disk[unit]) < size) {
699 Log_print("Error in bad sector of .pro image: sector:%d", sector);
700 }
701 io_success[unit] = sector;
702 #ifdef DEBUG_PRO
703 Log_print("bad sector:%d", sector);
704 #endif
705 return 'E';
706 }
707 }
708 else if (image_type[unit] == IMAGE_TYPE_VAPI) {
709 vapi_additional_info_t *info;
710 vapi_sec_info_t *secinfo;
711 ULONG secindex = 0;
712 static int lasttrack = 0;
713 unsigned int currpos, time, delay, rotations, bestdelay;
714 /* unsigned char beststatus;*/
715 int fromtrack, trackstostep, j;
716
717 info = (vapi_additional_info_t *)additional_info[unit];
718 info->vapi_delay_time = 0;
719
720 if (sector > sectorcount[unit]) {
721 #ifdef DEBUG_VAPI
722 Log_print("bad sector num:%d", sector);
723 #endif
724 info->sec_stat_buff[0] = 9;
725 info->sec_stat_buff[1] = 0xFF;
726 info->sec_stat_buff[2] = 0xe0;
727 info->sec_stat_buff[3] = 0;
728 info->vapi_delay_time= VAPI_CYCLES_BAD_SECTOR_NUM;
729 return 'E';
730 }
731
732 secinfo = &info->sectors[sector-1];
733 fromtrack = lasttrack;
734 lasttrack = (sector-1)/18;
735
736 if (secinfo->sec_count == 0) {
737 #ifdef DEBUG_VAPI
738 Log_print("missing sector:%d", sector);
739 #endif
740 info->sec_stat_buff[0] = 0xC;
741 info->sec_stat_buff[1] = 0xEF;
742 info->sec_stat_buff[2] = 0xe0;
743 info->sec_stat_buff[3] = 0;
744 info->vapi_delay_time= VAPI_CYCLES_MISSING_SECTOR;
745 return 'E';
746 }
747
748 trackstostep = abs((sector-1)/18 - fromtrack);
749 time = (unsigned int) ANTIC_CPU_CLOCK;
750 if (trackstostep)
751 time += trackstostep * VAPI_CYCLES_PER_TRACK_STEP + VAPI_CYCLES_HEAD_SETTLE ;
752 time += VAPI_CYCLES_CMD_ACK_TRANS;
753 rotations = time/VAPI_CYCLES_PER_ROT;
754 currpos = time - rotations*VAPI_CYCLES_PER_ROT;
755
756 #ifdef DEBUG_VAPI
757 Log_print(" sector:%d sector count :%d time %d", sector,secinfo->sec_count,ANTIC_CPU_CLOCK);
758 #endif
759
760 bestdelay = 10 * VAPI_CYCLES_PER_ROT;
761 /* beststatus = 0;*/
762 for (j=0;j<secinfo->sec_count;j++) {
763 if (secinfo->sec_rot_pos[j] < currpos)
764 delay = (VAPI_CYCLES_PER_ROT - currpos) + secinfo->sec_rot_pos[j];
765 else
766 delay = secinfo->sec_rot_pos[j] - currpos;
767 #ifdef DEBUG_VAPI
768 Log_print("%d %d %d %d %d %x",j,secinfo->sec_rot_pos[j],
769 ((unsigned int) ANTIC_CPU_CLOCK) - ((((unsigned int) ANTIC_CPU_CLOCK)/VAPI_CYCLES_PER_ROT)*VAPI_CYCLES_PER_ROT),
770 currpos,delay,secinfo->sec_status[j]);
771 #endif
772 if (delay < bestdelay) {
773 bestdelay = delay;
774 /* beststatus = secinfo->sec_status[j];*/
775 secindex = j;
776 }
777 }
778 if (trackstostep)
779 info->vapi_delay_time = bestdelay + trackstostep * VAPI_CYCLES_PER_TRACK_STEP +
780 VAPI_CYCLES_HEAD_SETTLE + VAPI_CYCLES_TRACK_READ_DELTA +
781 VAPI_CYCLES_CMD_ACK_TRANS + VAPI_CYCLES_SECTOR_READ;
782 else
783 info->vapi_delay_time = bestdelay +
784 VAPI_CYCLES_CMD_ACK_TRANS + VAPI_CYCLES_SECTOR_READ;
785 #ifdef DEBUG_VAPI
786 Log_print("Bestdelay = %d VapiDelay = %d",bestdelay,info->vapi_delay_time);
787 if (secinfo->sec_count > 1)
788 Log_print("duplicate sector:%d dupnum:%d delay:%d",sector, secindex,info->vapi_delay_time);
789 #endif
790 fseek(disk[unit],secinfo->sec_offset[secindex],SEEK_SET);
791 info->sec_stat_buff[0] = 0x8 | ((secinfo->sec_status[secindex] == 0xFF) ? 0 : 0x04);
792 info->sec_stat_buff[1] = secinfo->sec_status[secindex];
793 info->sec_stat_buff[2] = 0xe0;
794 info->sec_stat_buff[3] = 0;
795 if (secinfo->sec_status[secindex] != 0xFF) {
796 if (fread(buffer, 1, size, disk[unit]) < size) {
797 Log_print("error reading sector:%d", sector);
798 }
799 io_success[unit] = sector;
800 info->vapi_delay_time += VAPI_CYCLES_PER_ROT + 10000;
801 #ifdef DEBUG_VAPI
802 Log_print("bad sector:%d 0x%0X delay:%d", sector, secinfo->sec_status[secindex],info->vapi_delay_time );
803 #endif
804 {
805 int i;
806 if (secinfo->sec_status[secindex] == 0xB7) {
807 for (i=0;i<128;i++) {
808 Log_print("0x%02x",buffer[i]);
809 if (buffer[i] == 0x33)
810 buffer[i] = rand() & 0xFF;
811 }
812 }
813 }
814 return 'E';
815 }
816 #ifdef DEBUG_VAPI
817 Log_flushlog();
818 #endif
819 }
820 if (fread(buffer, 1, size, disk[unit]) < size) {
821 Log_print("incomplete sector num:%d", sector);
822 }
823 io_success[unit] = 0;
824 return 'C';
825 }
826
SIO_WriteSector(int unit,int sector,const UBYTE * buffer)827 int SIO_WriteSector(int unit, int sector, const UBYTE *buffer)
828 {
829 int size;
830 io_success[unit] = -1;
831 if (SIO_drive_status[unit] == SIO_OFF)
832 return 0;
833 if (disk[unit] == NULL)
834 return 'N';
835 if (SIO_drive_status[unit] != SIO_READ_WRITE || sector <= 0 || sector > sectorcount[unit])
836 return 'E';
837 SIO_last_op = SIO_LAST_WRITE;
838 SIO_last_op_time = 1;
839 SIO_last_drive = unit + 1;
840 #ifdef VAPI_WRITE_ENABLE
841 if (image_type[unit] == IMAGE_TYPE_VAPI) {
842 vapi_additional_info_t *info;
843 vapi_sec_info_t *secinfo;
844
845 info = (vapi_additional_info_t *)additional_info[unit];
846 secinfo = &info->sectors[sector-1];
847
848 if (secinfo->sec_count != 1) {
849 /* No writes to sectors with duplicates or missing sectors */
850 return 'E';
851 }
852
853 if (secinfo->sec_status[0] != 0xFF) {
854 /* No writes to bad sectors */
855 return 'E';
856 }
857
858 size = SeekSector(unit, sector);
859 fseek(disk[unit],secinfo->sec_offset[0],SEEK_SET);
860 fwrite(buffer, 1, size, disk[unit]);
861 io_success[unit] = 0;
862 return 'C';
863 #if 0
864 } else if (image_type[unit] == IMAGE_TYPE_PRO) {
865 pro_additional_info_t *info;
866 pro_phantom_sec_info_t *phantom;
867
868 info = (pro_additional_info_t *)additional_info[unit];
869 phantom = &info->phantom[sector-1];
870
871 if (phantom->phantom_count != 0) {
872 /* No writes to sectors with duplicates */
873 return 'E';
874 }
875
876 size = SeekSector(unit, sector);
877 if (buffer[1] != 0xff) {
878 #endif
879 }
880 #endif
881 size = SeekSector(unit, sector);
882 fwrite(buffer, 1, size, disk[unit]);
883 io_success[unit] = 0;
884 return 'C';
885 }
886
887 int SIO_FormatDisk(int unit, UBYTE *buffer, int sectsize, int sectcount)
888 {
889 char fname[FILENAME_MAX];
890 int is_atr;
891 int save_boot_sectors_type;
892 int bootsectsize;
893 int bootsectcount;
894 FILE *f;
895 int i;
896 io_success[unit] = -1;
897 if (SIO_drive_status[unit] == SIO_OFF)
898 return 0;
899 if (disk[unit] == NULL)
900 return 'N';
901 if (SIO_drive_status[unit] != SIO_READ_WRITE)
902 return 'E';
903 /* Note formatting the disk can change size of the file.
904 There is no portable way to truncate the file at given position.
905 We have to close the "rb+" open file and open it in "wb" mode.
906 First get the information about the disk image, because we are going
907 to umount it. */
908 memcpy(fname, SIO_filename[unit], FILENAME_MAX);
909 is_atr = (image_type[unit] == IMAGE_TYPE_ATR);
910 save_boot_sectors_type = boot_sectors_type[unit];
911 bootsectsize = 128;
912 if (sectsize == 256 && save_boot_sectors_type != BOOT_SECTORS_LOGICAL)
913 bootsectsize = 256;
914 bootsectcount = sectcount < 3 ? sectcount : 3;
915 /* Umount the file and open it in "wb" mode (it will truncate the file) */
916 SIO_Dismount(unit + 1);
917 f = fopen(fname, "wb");
918 if (f == NULL) {
919 Log_print("SIO_FormatDisk: failed to open %s for writing", fname);
920 return 'E';
921 }
922 /* Write ATR header if necessary */
923 if (is_atr) {
924 struct AFILE_ATR_Header header;
925 ULONG disksize = (bootsectsize * bootsectcount + sectsize * (sectcount - bootsectcount)) >> 4;
926 memset(&header, 0, sizeof(header));
927 header.magic1 = AFILE_ATR_MAGIC1;
928 header.magic2 = AFILE_ATR_MAGIC2;
929 header.secsizelo = (UBYTE) sectsize;
930 header.secsizehi = (UBYTE) (sectsize >> 8);
931 header.seccountlo = (UBYTE) disksize;
932 header.seccounthi = (UBYTE) (disksize >> 8);
933 header.hiseccountlo = (UBYTE) (disksize >> 16);
934 header.hiseccounthi = (UBYTE) (disksize >> 24);
935 fwrite(&header, 1, sizeof(header), f);
936 }
937 /* Write boot sectors */
938 memset(buffer, 0, sectsize);
939 for (i = 1; i <= bootsectcount; i++)
940 fwrite(buffer, 1, bootsectsize, f);
941 /* Write regular sectors */
942 for ( ; i <= sectcount; i++)
943 fwrite(buffer, 1, sectsize, f);
944 /* Close file and mount the disk back */
945 fclose(f);
946 SIO_Mount(unit + 1, fname, FALSE);
947 /* We want to keep the current PHYSICAL/SIO2PC boot sectors type
948 (since the image is blank it can't be figured out by SIO_Mount) */
949 if (bootsectsize == 256)
950 boot_sectors_type[unit] = save_boot_sectors_type;
951 /* Return information for Atari (buffer filled with ff's - no bad sectors) */
952 memset(buffer, 0xff, sectsize);
953 io_success[unit] = 0;
954 return 'C';
955 }
956
957 /* Set density and number of sectors
958 This function is used before the format (0x21) command
959 to set how the disk will be formatted.
960 Note this function does *not* affect the currently attached disk
961 (previously sectorsize/sectorcount were used which could result in
962 a corrupted image).
963 */
964 int SIO_WriteStatusBlock(int unit, const UBYTE *buffer)
965 {
966 int size;
967 #ifdef DEBUG
968 Log_print("Write Status-Block: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
969 buffer[0], buffer[1], buffer[2], buffer[3],
970 buffer[4], buffer[5], buffer[6], buffer[7],
971 buffer[8], buffer[9], buffer[10], buffer[11]);
972 #endif
973 if (SIO_drive_status[unit] == SIO_OFF)
974 return 0;
975 /* We only care about the density and the sector count here.
976 Setting everything else right here seems to be non-sense.
977 I'm not sure about this density settings, my XF551
978 honors only the sector size and ignores the density */
979 size = buffer[6] * 256 + buffer[7];
980 if (size == 128 || size == 256)
981 SIO_format_sectorsize[unit] = size;
982 /* Note that the number of heads are minus 1 */
983 SIO_format_sectorcount[unit] = buffer[0] * (buffer[2] * 256 + buffer[3]) * (buffer[4] + 1);
984 if (SIO_format_sectorcount[unit] < 1 || SIO_format_sectorcount[unit] > 65535)
985 SIO_format_sectorcount[unit] = 720;
986 return 'C';
987 }
988
989 int SIO_ReadStatusBlock(int unit, UBYTE *buffer)
990 {
991 UBYTE tracks;
992 UBYTE heads;
993 int spt;
994 if (SIO_drive_status[unit] == SIO_OFF)
995 return 0;
996 /* default to 1 track, 1 side for non-standard images */
997 tracks = 1;
998 heads = 1;
999 spt = sectorcount[unit];
1000
1001 if (spt % 40 == 0) {
1002 /* standard disk */
1003 tracks = 40;
1004 spt /= 40;
1005 if (spt > 26 && spt % 2 == 0) {
1006 /* double-sided */
1007 heads = 2;
1008 spt >>= 1;
1009 if (spt > 26 && spt % 2 == 0) {
1010 /* double-sided, 80 tracks */
1011 tracks = 80;
1012 spt >>= 1;
1013 }
1014 }
1015 }
1016
1017 buffer[0] = tracks; /* # of tracks */
1018 buffer[1] = 1; /* step rate */
1019 buffer[2] = (UBYTE) (spt >> 8); /* sectors per track. HI byte */
1020 buffer[3] = (UBYTE) spt; /* sectors per track. LO byte */
1021 buffer[4] = (UBYTE) (heads - 1); /* # of heads minus 1 */
1022 /* FM for single density, MFM otherwise */
1023 buffer[5] = (sectorsize[unit] == 128 && sectorcount[unit] <= 720) ? 0 : 4;
1024 buffer[6] = (UBYTE) (sectorsize[unit] >> 8); /* bytes per sector. HI byte */
1025 buffer[7] = (UBYTE) sectorsize[unit]; /* bytes per sector. LO byte */
1026 buffer[8] = 1; /* drive is online */
1027 buffer[9] = 192; /* transfer speed, whatever this means */
1028 buffer[10] = 0;
1029 buffer[11] = 0;
1030 return 'C';
1031 }
1032
1033 /*
1034 Status Request from Atari 400/800 Technical Reference Notes
1035
1036 DVSTAT + 0 Command Status
1037 DVSTAT + 1 Hardware Status
1038 DVSTAT + 2 Timeout
1039 DVSTAT + 3 Unused
1040
1041 Command Status Bits
1042
1043 Bit 0 = 1 indicates an invalid command frame was received
1044 Bit 1 = 1 indicates an invalid data frame was received
1045 Bit 2 = 1 indicates that last read/write operation was unsuccessful
1046 Bit 3 = 1 indicates that the diskette is write protected
1047 Bit 4 = 1 indicates active/standby
1048
1049 plus
1050
1051 Bit 5 = 1 indicates double density
1052 Bit 7 = 1 indicates dual density disk (1050 format)
1053 */
1054 int SIO_DriveStatus(int unit, UBYTE *buffer)
1055 {
1056 if (BINLOAD_start_binloading) {
1057 buffer[0] = 16 + 8;
1058 buffer[1] = 255;
1059 buffer[2] = 1;
1060 buffer[3] = 0 ;
1061 return 'C';
1062 }
1063
1064 if (SIO_drive_status[unit] == SIO_OFF)
1065 return 0;
1066
1067 /* .PRO contains status information in the sector header */
1068 if (io_success[unit] != 0 && image_type[unit] == IMAGE_TYPE_PRO) {
1069 int sector = io_success[unit];
1070 SeekSector(unit, sector);
1071 if (fread(buffer, 1, 4, disk[unit]) < 4) {
1072 Log_print("SIO_DriveStatus: failed to read sector header");
1073 }
1074 return 'C';
1075 }
1076 else if (io_success[unit] != 0 && image_type[unit] == IMAGE_TYPE_VAPI &&
1077 SIO_drive_status[unit] != SIO_NO_DISK) {
1078 vapi_additional_info_t *info;
1079 info = (vapi_additional_info_t *)additional_info[unit];
1080 buffer[0] = info->sec_stat_buff[0];
1081 buffer[1] = info->sec_stat_buff[1];
1082 buffer[2] = info->sec_stat_buff[2];
1083 buffer[3] = info->sec_stat_buff[3];
1084 Log_print("Drive Status unit %d %x %x %x %x",unit,buffer[0], buffer[1], buffer[2], buffer[3]);
1085 return 'C';
1086 }
1087 buffer[0] = 16; /* drive active */
1088 buffer[1] = disk[unit] != NULL ? 255 /* WD 177x OK */ : 127 /* no disk */;
1089 if (io_success[unit] != 0)
1090 buffer[0] |= 4; /* failed RW-operation */
1091 if (SIO_drive_status[unit] == SIO_READ_ONLY)
1092 buffer[0] |= 8; /* write protection */
1093 if (SIO_format_sectorsize[unit] == 256)
1094 buffer[0] |= 32; /* double density */
1095 if (SIO_format_sectorcount[unit] == 1040)
1096 buffer[0] |= 128; /* 1050 enhanced density */
1097 buffer[2] = 1;
1098 buffer[3] = 0;
1099 return 'C';
1100 }
1101
1102 #ifndef NO_SECTOR_DELAY
1103 /* A hack for the "Overmind" demo. This demo verifies if sectors aren't read
1104 faster than with a typical disk drive. We introduce a delay
1105 of SECTOR_DELAY scanlines between successive reads of sector 1. */
1106 #define SECTOR_DELAY 3200
1107 static int delay_counter = 0;
1108 static int last_ypos = 0;
1109 #endif
1110
1111 /* SIO patch emulation routine */
1112 void SIO_Handler(void)
1113 {
1114 int sector = MEMORY_dGetWordAligned(0x30a);
1115 UBYTE unit = (MEMORY_dGetByte(0x300) + MEMORY_dGetByte(0x301) + 0xff ) - 0x31;
1116 UBYTE result = 0x00;
1117 UWORD data = MEMORY_dGetWordAligned(0x304);
1118 int length = MEMORY_dGetWordAligned(0x308);
1119 int realsize = 0;
1120 int cmd = MEMORY_dGetByte(0x302);
1121
1122 if ((unsigned int)MEMORY_dGetByte(0x300) + (unsigned int)MEMORY_dGetByte(0x301) > 0xff) {
1123 /* carry */
1124 unit++;
1125 }
1126 /* A real atari just adds the bytes and 0xff. The result could wrap.*/
1127 /* XL OS: E99D: LDA $0300 ADC $0301 ADC #$FF STA 023A */
1128 /* Disk 1 is ASCII '1' = 0x31 etc */
1129 /* Disk 1 -> unit = 0 */
1130 if (MEMORY_dGetByte(0x300) != 0x60 && unit < SIO_MAX_DRIVES && (SIO_drive_status[unit] != SIO_OFF || BINLOAD_start_binloading)) { /* UBYTE range ! */
1131 #ifdef DEBUG
1132 Log_print("SIO disk command is %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
1133 cmd, MEMORY_dGetByte(0x303), MEMORY_dGetByte(0x304), MEMORY_dGetByte(0x305), MEMORY_dGetByte(0x306),
1134 MEMORY_dGetByte(0x308), MEMORY_dGetByte(0x309), MEMORY_dGetByte(0x30a), MEMORY_dGetByte(0x30b),
1135 MEMORY_dGetByte(0x30c), MEMORY_dGetByte(0x30d));
1136 #endif
1137 switch (cmd) {
1138 case 0x4e: /* Read Status Block */
1139 if (12 == length) {
1140 result = SIO_ReadStatusBlock(unit, DataBuffer);
1141 if (result == 'C')
1142 MEMORY_CopyToMem(DataBuffer, data, 12);
1143 }
1144 else
1145 result = 'E';
1146 break;
1147 case 0x4f: /* Write Status Block */
1148 if (12 == length) {
1149 MEMORY_CopyFromMem(data, DataBuffer, 12);
1150 result = SIO_WriteStatusBlock(unit, DataBuffer);
1151 }
1152 else
1153 result = 'E';
1154 break;
1155 case 0x50: /* Write */
1156 case 0x57:
1157 case 0xD0: /* xf551 hispeed */
1158 case 0xD7:
1159 SIO_SizeOfSector(unit, sector, &realsize, NULL);
1160 if (realsize == length) {
1161 MEMORY_CopyFromMem(data, DataBuffer, realsize);
1162 result = SIO_WriteSector(unit, sector, DataBuffer);
1163 }
1164 else
1165 result = 'E';
1166 break;
1167 case 0x52: /* Read */
1168 case 0xD2: /* xf551 hispeed */
1169 #ifndef NO_SECTOR_DELAY
1170 if (sector == 1) {
1171 if (delay_counter > 0) {
1172 if (last_ypos != ANTIC_ypos) {
1173 last_ypos = ANTIC_ypos;
1174 delay_counter--;
1175 }
1176 CPU_regPC = 0xe459; /* stay at SIO patch */
1177 return;
1178 }
1179 delay_counter = SECTOR_DELAY;
1180 }
1181 else {
1182 delay_counter = 0;
1183 }
1184 #endif
1185 SIO_SizeOfSector(unit, sector, &realsize, NULL);
1186 if (realsize == length) {
1187 result = SIO_ReadSector(unit, sector, DataBuffer);
1188 if (result == 'C')
1189 MEMORY_CopyToMem(DataBuffer, data, realsize);
1190 }
1191 else
1192 result = 'E';
1193 break;
1194 case 0x53: /* Status */
1195 if (4 == length) {
1196 result = SIO_DriveStatus(unit, DataBuffer);
1197 if (result == 'C') {
1198 MEMORY_CopyToMem(DataBuffer, data, 4);
1199 }
1200 }
1201 else
1202 result = 'E';
1203 break;
1204 /*case 0x66:*/ /* US Doubler Format - I think! */
1205 case 0x21: /* Format Disk */
1206 case 0xA1: /* xf551 hispeed */
1207 realsize = SIO_format_sectorsize[unit];
1208 if (realsize == length) {
1209 result = SIO_FormatDisk(unit, DataBuffer, realsize, SIO_format_sectorcount[unit]);
1210 if (result == 'C')
1211 MEMORY_CopyToMem(DataBuffer, data, realsize);
1212 }
1213 else {
1214 /* there are programs which send the format-command but don't wait for the result (eg xf-tools) */
1215 SIO_FormatDisk(unit, DataBuffer, realsize, SIO_format_sectorcount[unit]);
1216 result = 'E';
1217 }
1218 break;
1219 case 0x22: /* Enhanced Density Format */
1220 case 0xA2: /* xf551 hispeed */
1221 realsize = 128;
1222 if (realsize == length) {
1223 result = SIO_FormatDisk(unit, DataBuffer, 128, 1040);
1224 if (result == 'C')
1225 MEMORY_CopyToMem(DataBuffer, data, realsize);
1226 }
1227 else {
1228 SIO_FormatDisk(unit, DataBuffer, 128, 1040);
1229 result = 'E';
1230 }
1231 break;
1232 default:
1233 result = 'N';
1234 }
1235 }
1236 /* cassette i/o */
1237 else if (MEMORY_dGetByte(0x300) == 0x60) {
1238 UBYTE gaps = MEMORY_dGetByte(0x30b);
1239 switch (cmd){
1240 case 0x52: /* read */
1241 SIO_last_op = SIO_LAST_READ;
1242 SIO_last_drive = 0x61;
1243 SIO_last_op_time = 0x10;
1244 /* set expected Gap */
1245 CASSETTE_AddGap(gaps == 0 ? 2000 : 160);
1246 /* get record from storage medium */
1247 if (CASSETTE_ReadToMemory(data, length))
1248 result = 'C';
1249 else
1250 result = 'E';
1251 break;
1252 case 0x57: /* write */
1253 SIO_last_op = SIO_LAST_WRITE;
1254 SIO_last_drive = 0x61;
1255 SIO_last_op_time = 0x10;
1256 /* add pregap length */
1257 CASSETTE_AddGap(gaps == 0 ? 3000 : 260);
1258 /* write full record to storage medium */
1259 if (CASSETTE_WriteFromMemory(data, length))
1260 result = 'C';
1261 else
1262 result = 'E';
1263 break;
1264 default:
1265 result = 'N';
1266 }
1267 }
1268
1269 switch (result) {
1270 case 0x00: /* Device disabled, generate timeout */
1271 CPU_regY = 138;
1272 CPU_SetN;
1273 break;
1274 case 'A': /* Device acknowledge */
1275 case 'C': /* Operation complete */
1276 CPU_regY = 1;
1277 CPU_ClrN;
1278 break;
1279 case 'N': /* Device NAK */
1280 CPU_regY = 144;
1281 CPU_SetN;
1282 break;
1283 case 'E': /* Device error */
1284 default:
1285 CPU_regY = 146;
1286 CPU_SetN;
1287 break;
1288 }
1289 CPU_regA = 0; /* MMM */
1290 MEMORY_dPutByte(0x0303, CPU_regY);
1291 MEMORY_dPutByte(0x42,0);
1292 CPU_SetC;
1293
1294 /* After each SIO operation a routine called SENDDS ($EC5F in OSB) is
1295 invoked, which, among other functions, silences the sound
1296 generators. With SIO patch we don't call SIOV and in effect SENDDS
1297 is not called either, but this causes a problem with tape saving.
1298 During tape saving sound generators are enabled before calling
1299 SIOV, but are not disabled later (no call to SENDDS). The effect is
1300 that after saving to tape the unwanted SIO sounds are left audible.
1301 To avoid the problem, we silence the sound registers by hand. */
1302 POKEY_PutByte(POKEY_OFFSET_AUDC1, 0);
1303 POKEY_PutByte(POKEY_OFFSET_AUDC2, 0);
1304 POKEY_PutByte(POKEY_OFFSET_AUDC3, 0);
1305 POKEY_PutByte(POKEY_OFFSET_AUDC4, 0);
1306 }
1307
1308 UBYTE SIO_ChkSum(const UBYTE *buffer, int length)
1309 {
1310 #if 0
1311 /* old, less efficient version */
1312 int i;
1313 int checksum = 0;
1314 for (i = 0; i < length; i++, buffer++) {
1315 checksum += *buffer;
1316 while (checksum > 255)
1317 checksum -= 255;
1318 }
1319 #else
1320 int checksum = 0;
1321 while (--length >= 0)
1322 checksum += *buffer++;
1323 do
1324 checksum = (checksum & 0xff) + (checksum >> 8);
1325 while (checksum > 255);
1326 #endif
1327 return checksum;
1328 }
1329
1330 static UBYTE Command_Frame(void)
1331 {
1332 int unit;
1333 int sector;
1334 int realsize;
1335
1336 sector = CommandFrame[2] | (((UWORD) CommandFrame[3]) << 8);
1337 unit = CommandFrame[0] - '1';
1338
1339 if (unit < 0 || unit >= SIO_MAX_DRIVES) {
1340 /* Unknown device */
1341 Log_print("Unknown command frame: %02x %02x %02x %02x %02x",
1342 CommandFrame[0], CommandFrame[1], CommandFrame[2],
1343 CommandFrame[3], CommandFrame[4]);
1344 TransferStatus = SIO_NoFrame;
1345 return 0;
1346 }
1347 switch (CommandFrame[1]) {
1348 case 0x4e: /* Read Status */
1349 #ifdef DEBUG
1350 Log_print("Read-status frame: %02x %02x %02x %02x %02x",
1351 CommandFrame[0], CommandFrame[1], CommandFrame[2],
1352 CommandFrame[3], CommandFrame[4]);
1353 #endif
1354 DataBuffer[0] = SIO_ReadStatusBlock(unit, DataBuffer + 1);
1355 DataBuffer[13] = SIO_ChkSum(DataBuffer + 1, 12);
1356 DataIndex = 0;
1357 ExpectedBytes = 14;
1358 TransferStatus = SIO_ReadFrame;
1359 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL;
1360 return 'A';
1361 case 0x4f: /* Write status */
1362 #ifdef DEBUG
1363 Log_print("Write-status frame: %02x %02x %02x %02x %02x",
1364 CommandFrame[0], CommandFrame[1], CommandFrame[2],
1365 CommandFrame[3], CommandFrame[4]);
1366 #endif
1367 ExpectedBytes = 13;
1368 DataIndex = 0;
1369 TransferStatus = SIO_WriteFrame;
1370 return 'A';
1371 case 0x50: /* Write */
1372 case 0x57:
1373 case 0xD0: /* xf551 hispeed */
1374 case 0xD7:
1375 #ifdef DEBUG
1376 Log_print("Write-sector frame: %02x %02x %02x %02x %02x",
1377 CommandFrame[0], CommandFrame[1], CommandFrame[2],
1378 CommandFrame[3], CommandFrame[4]);
1379 #endif
1380 SIO_SizeOfSector((UBYTE) unit, sector, &realsize, NULL);
1381 ExpectedBytes = realsize + 1;
1382 DataIndex = 0;
1383 TransferStatus = SIO_WriteFrame;
1384 SIO_last_op = SIO_LAST_WRITE;
1385 SIO_last_op_time = 10;
1386 SIO_last_drive = unit + 1;
1387 return 'A';
1388 case 0x52: /* Read */
1389 case 0xD2: /* xf551 hispeed */
1390 #ifdef DEBUG
1391 Log_print("Read-sector frame: %02x %02x %02x %02x %02x",
1392 CommandFrame[0], CommandFrame[1], CommandFrame[2],
1393 CommandFrame[3], CommandFrame[4]);
1394 #endif
1395 SIO_SizeOfSector((UBYTE) unit, sector, &realsize, NULL);
1396 DataBuffer[0] = SIO_ReadSector(unit, sector, DataBuffer + 1);
1397 DataBuffer[1 + realsize] = SIO_ChkSum(DataBuffer + 1, realsize);
1398 DataIndex = 0;
1399 ExpectedBytes = 2 + realsize;
1400 TransferStatus = SIO_ReadFrame;
1401 /* wait longer before confirmation because bytes could be lost */
1402 /* before the buffer was set (see $E9FB & $EA37 in XL-OS) */
1403 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL << 2;
1404 if (image_type[unit] == IMAGE_TYPE_VAPI) {
1405 vapi_additional_info_t *info;
1406 info = (vapi_additional_info_t *)additional_info[unit];
1407 if (info == NULL)
1408 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL << 2;
1409 else
1410 POKEY_DELAYED_SERIN_IRQ = ((info->vapi_delay_time + 114/2) / 114) - 12;
1411 }
1412 #ifndef NO_SECTOR_DELAY
1413 else if (sector == 1) {
1414 POKEY_DELAYED_SERIN_IRQ += delay_counter;
1415 delay_counter = SECTOR_DELAY;
1416 }
1417 else {
1418 delay_counter = 0;
1419 }
1420 #endif
1421 SIO_last_op = SIO_LAST_READ;
1422 SIO_last_op_time = 10;
1423 SIO_last_drive = unit + 1;
1424 return 'A';
1425 case 0x53: /* Status */
1426 #ifdef DEBUG
1427 Log_print("Status frame: %02x %02x %02x %02x %02x",
1428 CommandFrame[0], CommandFrame[1], CommandFrame[2],
1429 CommandFrame[3], CommandFrame[4]);
1430 #endif
1431 DataBuffer[0] = SIO_DriveStatus(unit, DataBuffer + 1);
1432 DataBuffer[1 + 4] = SIO_ChkSum(DataBuffer + 1, 4);
1433 DataIndex = 0;
1434 ExpectedBytes = 6;
1435 TransferStatus = SIO_ReadFrame;
1436 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL;
1437 return 'A';
1438 /*case 0x66:*/ /* US Doubler Format - I think! */
1439 case 0x21: /* Format Disk */
1440 case 0xa1: /* xf551 hispeed */
1441 #ifdef DEBUG
1442 Log_print("Format-disk frame: %02x %02x %02x %02x %02x",
1443 CommandFrame[0], CommandFrame[1], CommandFrame[2],
1444 CommandFrame[3], CommandFrame[4]);
1445 #endif
1446 realsize = SIO_format_sectorsize[unit];
1447 DataBuffer[0] = SIO_FormatDisk(unit, DataBuffer + 1, realsize, SIO_format_sectorcount[unit]);
1448 DataBuffer[1 + realsize] = SIO_ChkSum(DataBuffer + 1, realsize);
1449 DataIndex = 0;
1450 ExpectedBytes = 2 + realsize;
1451 TransferStatus = SIO_FormatFrame;
1452 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL;
1453 return 'A';
1454 case 0x22: /* Dual Density Format */
1455 case 0xa2: /* xf551 hispeed */
1456 #ifdef DEBUG
1457 Log_print("Format-Medium frame: %02x %02x %02x %02x %02x",
1458 CommandFrame[0], CommandFrame[1], CommandFrame[2],
1459 CommandFrame[3], CommandFrame[4]);
1460 #endif
1461 DataBuffer[0] = SIO_FormatDisk(unit, DataBuffer + 1, 128, 1040);
1462 DataBuffer[1 + 128] = SIO_ChkSum(DataBuffer + 1, 128);
1463 DataIndex = 0;
1464 ExpectedBytes = 2 + 128;
1465 TransferStatus = SIO_FormatFrame;
1466 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL;
1467 return 'A';
1468 default:
1469 /* Unknown command for a disk drive */
1470 #ifdef DEBUG
1471 Log_print("Command frame: %02x %02x %02x %02x %02x",
1472 CommandFrame[0], CommandFrame[1], CommandFrame[2],
1473 CommandFrame[3], CommandFrame[4]);
1474 #endif
1475 TransferStatus = SIO_NoFrame;
1476 return 'E';
1477 }
1478 }
1479
1480 /* Enable/disable the Tape Motor */
1481 void SIO_TapeMotor(int onoff)
1482 {
1483 CASSETTE_TapeMotor(onoff);
1484 if (onoff) {
1485 /* set frame to cassette frame, if not */
1486 /* in a transfer with an intelligent peripheral */
1487 if (TransferStatus == SIO_NoFrame || TransferStatus == SIO_CasReadWrite)
1488 TransferStatus = SIO_CasReadWrite;
1489 SIO_last_drive = 0x60;
1490 SIO_last_op_time = 0x10;
1491 }
1492 else {
1493 /* set frame to none */
1494 if (TransferStatus == SIO_CasReadWrite)
1495 TransferStatus = SIO_NoFrame;
1496 SIO_last_op_time = 0;
1497 }
1498 }
1499
1500 /* Enable/disable the command frame */
1501 void SIO_SwitchCommandFrame(int onoff)
1502 {
1503 if (onoff) { /* Enabled */
1504 if (TransferStatus != SIO_NoFrame)
1505 Log_print("Unexpected command frame at state %x.", TransferStatus);
1506 CommandIndex = 0;
1507 DataIndex = 0;
1508 ExpectedBytes = 5;
1509 TransferStatus = SIO_CommandFrame;
1510 }
1511 else {
1512 if (TransferStatus != SIO_StatusRead && TransferStatus != SIO_NoFrame &&
1513 TransferStatus != SIO_ReadFrame) {
1514 if (!(TransferStatus == SIO_CommandFrame && CommandIndex == 0))
1515 Log_print("Command frame %02x unfinished.", TransferStatus);
1516 TransferStatus = SIO_NoFrame;
1517 }
1518 CommandIndex = 0;
1519 }
1520 }
1521
1522 static UBYTE WriteSectorBack(void)
1523 {
1524 UWORD sector;
1525 UBYTE unit;
1526
1527 sector = CommandFrame[2] + (CommandFrame[3] << 8);
1528 unit = CommandFrame[0] - '1';
1529 if (unit >= SIO_MAX_DRIVES) /* UBYTE range ! */
1530 return 0;
1531 switch (CommandFrame[1]) {
1532 case 0x4f: /* Write Status Block */
1533 return SIO_WriteStatusBlock(unit, DataBuffer);
1534 case 0x50: /* Write */
1535 case 0x57:
1536 case 0xD0: /* xf551 hispeed */
1537 case 0xD7:
1538 return SIO_WriteSector(unit, sector, DataBuffer);
1539 default:
1540 return 'E';
1541 }
1542 }
1543
1544 /* Put a byte that comes out of POKEY. So get it here... */
1545 void SIO_PutByte(int byte)
1546 {
1547 switch (TransferStatus) {
1548 case SIO_CommandFrame:
1549 if (CommandIndex < ExpectedBytes) {
1550 CommandFrame[CommandIndex++] = byte;
1551 if (CommandIndex >= ExpectedBytes) {
1552 if (CommandFrame[0] >= 0x31 && CommandFrame[0] <= 0x38 && (SIO_drive_status[CommandFrame[0]-0x31] != SIO_OFF || BINLOAD_start_binloading)) {
1553 TransferStatus = SIO_StatusRead;
1554 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL + SIO_ACK_INTERVAL;
1555 }
1556 else
1557 TransferStatus = SIO_NoFrame;
1558 }
1559 }
1560 else {
1561 Log_print("Invalid command frame!");
1562 TransferStatus = SIO_NoFrame;
1563 }
1564 break;
1565 case SIO_WriteFrame: /* Expect data */
1566 if (DataIndex < ExpectedBytes) {
1567 DataBuffer[DataIndex++] = byte;
1568 if (DataIndex >= ExpectedBytes) {
1569 UBYTE sum = SIO_ChkSum(DataBuffer, ExpectedBytes - 1);
1570 if (sum == DataBuffer[ExpectedBytes - 1]) {
1571 UBYTE result = WriteSectorBack();
1572 if (result != 0) {
1573 DataBuffer[0] = 'A';
1574 DataBuffer[1] = result;
1575 DataIndex = 0;
1576 ExpectedBytes = 2;
1577 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL + SIO_ACK_INTERVAL;
1578 TransferStatus = SIO_FinalStatus;
1579 }
1580 else
1581 TransferStatus = SIO_NoFrame;
1582 }
1583 else {
1584 DataBuffer[0] = 'E';
1585 DataIndex = 0;
1586 ExpectedBytes = 1;
1587 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL + SIO_ACK_INTERVAL;
1588 TransferStatus = SIO_FinalStatus;
1589 }
1590 }
1591 }
1592 else {
1593 Log_print("Invalid data frame!");
1594 }
1595 break;
1596 case SIO_CasReadWrite:
1597 CASSETTE_PutByte(byte);
1598 break;
1599 }
1600 /* POKEY_DELAYED_SEROUT_IRQ = SIO_SEROUT_INTERVAL; */ /* already set in pokey.c */
1601 }
1602
1603 /* Get a byte from the floppy to the pokey. */
1604 int SIO_GetByte(void)
1605 {
1606 int byte = 0;
1607
1608 switch (TransferStatus) {
1609 case SIO_StatusRead:
1610 byte = Command_Frame(); /* Handle now the command */
1611 break;
1612 case SIO_FormatFrame:
1613 TransferStatus = SIO_ReadFrame;
1614 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL << 3;
1615 /* FALL THROUGH */
1616 case SIO_ReadFrame:
1617 if (DataIndex < ExpectedBytes) {
1618 byte = DataBuffer[DataIndex++];
1619 if (DataIndex >= ExpectedBytes) {
1620 TransferStatus = SIO_NoFrame;
1621 }
1622 else {
1623 /* set delay using the expected transfer speed */
1624 POKEY_DELAYED_SERIN_IRQ = (DataIndex == 1) ? SIO_SERIN_INTERVAL
1625 : ((SIO_SERIN_INTERVAL * POKEY_AUDF[POKEY_CHAN3] - 1) / 0x28 + 1);
1626 }
1627 }
1628 else {
1629 Log_print("Invalid read frame!");
1630 TransferStatus = SIO_NoFrame;
1631 }
1632 break;
1633 case SIO_FinalStatus:
1634 if (DataIndex < ExpectedBytes) {
1635 byte = DataBuffer[DataIndex++];
1636 if (DataIndex >= ExpectedBytes) {
1637 TransferStatus = SIO_NoFrame;
1638 }
1639 else {
1640 if (DataIndex == 0)
1641 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL + SIO_ACK_INTERVAL;
1642 else
1643 POKEY_DELAYED_SERIN_IRQ = SIO_SERIN_INTERVAL;
1644 }
1645 }
1646 else {
1647 Log_print("Invalid read frame!");
1648 TransferStatus = SIO_NoFrame;
1649 }
1650 break;
1651 case SIO_CasReadWrite:
1652 byte = CASSETTE_GetByte();
1653 break;
1654 default:
1655 break;
1656 }
1657 return byte;
1658 }
1659
1660 #if !defined(BASIC) && !defined(__PLUS)
1661 int SIO_RotateDisks(void)
1662 {
1663 char tmp_filenames[SIO_MAX_DRIVES][FILENAME_MAX];
1664 int i;
1665 int bSuccess = TRUE;
1666
1667 for (i = 0; i < SIO_MAX_DRIVES; i++) {
1668 strcpy(tmp_filenames[i], SIO_filename[i]);
1669 SIO_Dismount(i + 1);
1670 }
1671
1672 for (i = 1; i < SIO_MAX_DRIVES; i++) {
1673 if (strcmp(tmp_filenames[i], "None") && strcmp(tmp_filenames[i], "Off") && strcmp(tmp_filenames[i], "Empty") ) {
1674 if (!SIO_Mount(i, tmp_filenames[i], FALSE)) /* Note that this is NOT i-1 because SIO_Mount is 1 indexed */
1675 bSuccess = FALSE;
1676 }
1677 }
1678
1679 i = SIO_MAX_DRIVES - 1;
1680 while (i > -1 && (!strcmp(tmp_filenames[i], "None") || !strcmp(tmp_filenames[i], "Off") || !strcmp(tmp_filenames[i], "Empty")) ) {
1681 i--;
1682 }
1683
1684 if (i > -1) {
1685 if (!SIO_Mount(i + 1, tmp_filenames[0], FALSE))
1686 bSuccess = FALSE;
1687 }
1688
1689 return bSuccess;
1690 }
1691 #endif /* !defined(BASIC) && !defined(__PLUS) */
1692
1693 #ifndef BASIC
1694
1695 void SIO_StateSave(void)
1696 {
1697 int i;
1698
1699 for (i = 0; i < 8; i++) {
1700 StateSav_SaveINT((int *) &SIO_drive_status[i], 1);
1701 StateSav_SaveFNAME(SIO_filename[i]);
1702 }
1703 }
1704
1705 void SIO_StateRead(void)
1706 {
1707 int i;
1708
1709 for (i = 0; i < 8; i++) {
1710 int saved_drive_status;
1711 char filename[FILENAME_MAX];
1712
1713 StateSav_ReadINT(&saved_drive_status, 1);
1714 SIO_drive_status[i] = (SIO_UnitStatus)saved_drive_status;
1715
1716 StateSav_ReadFNAME(filename);
1717 if (filename[0] == 0)
1718 continue;
1719
1720 /* If the disk drive wasn't empty or off when saved,
1721 mount the disk */
1722 switch (saved_drive_status) {
1723 case SIO_READ_ONLY:
1724 SIO_Mount(i + 1, filename, TRUE);
1725 break;
1726 case SIO_READ_WRITE:
1727 SIO_Mount(i + 1, filename, FALSE);
1728 break;
1729 default:
1730 break;
1731 }
1732 }
1733 }
1734
1735 #endif /* BASIC */
1736
1737 /*
1738 vim:ts=4:sw=4:
1739 */
1740