1 /* 765: Library to emulate the uPD765a floppy controller (aka Intel 8272) 2 3 Copyright (C) 2000 John Elliott <jce@seasip.demon.co.uk> 4 5 Modifications to add dirty flags 6 (c) 2005 Philip Kendall <pak21-spectrum@srcf.ucam.org> 7 8 This library is free software; you can redistribute it and/or 9 modify it under the terms of the GNU Library General Public 10 License as published by the Free Software Foundation; either 11 version 2 of the License, or (at your option) any later version. 12 13 This library is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 Library General Public License for more details. 17 18 You should have received a copy of the GNU Library General Public 19 License along with this library; if not, write to the Free 20 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <limits.h> 28 #include "config.h" 29 #include "765.h" 30 31 32 33 typedef struct floppy_drive_vtable 34 { 35 fd_err_t (*fdv_seek_cylinder)(FDRV_PTR fd, int cylinder); 36 fd_err_t (*fdv_read_id) (FDRV_PTR fd, int head, 37 int sector, fdc_byte *buf); 38 fd_err_t (*fdv_read_sector )(FDRV_PTR fd, int xcylinder, 39 int xhead, int head, int sector, fdc_byte *buf, int len, 40 int *deleted, int skip_deleted, int mfm, int multi); 41 fd_err_t (*fdv_read_track )(FDRV_PTR fd, int xcylinder, 42 int xhead, int head, fdc_byte *buf, int *len); 43 fd_err_t (*fdv_write_sector )(FDRV_PTR fd, int xcylinder, 44 int xhead, int head, int sector, fdc_byte *buf, int len, 45 int deleted, int skip_deleted, int mfm, int multi); 46 fd_err_t (*fdv_format_track )(FDRV_PTR fd, int head, 47 int sectors, fdc_byte *buf, fdc_byte filler); 48 fdc_byte (*fdv_drive_status )(FDRV_PTR fd); 49 int (*fdv_isready)(FDRV_PTR fd); 50 int (*fdv_dirty )(FDRV_PTR fd); 51 void (*fdv_eject )(FDRV_PTR fd); 52 void (*fdv_set_datarate)(FDRV_PTR fd, fdc_byte rate); 53 void (*fdv_reset )(FDRV_PTR fd); 54 void (*fdv_destroy)(FDRV_PTR fd); 55 int (*fdv_changed)(FDRV_PTR fd); 56 } FLOPPY_DRIVE_VTABLE; 57 58 59 typedef struct floppy_drive 60 { 61 /* PRIVATE variables 62 * The following points to the drive's method table. You should not need 63 * to use this; instead, use the fd_*() wrapper functions below. */ 64 FLOPPY_DRIVE_VTABLE * fd_vtable; 65 /* PUBLIC members */ 66 /* You should set the first three of these immediately after calling 67 * fd_init() or fdd_init() on a drive.*/ 68 int fd_type; /* 0 for none, 1 for 3", 2 for 3.5", 3 for 5.25" */ 69 int fd_heads; /* No. of heads in the drive: 1 or 2 */ 70 int fd_cylinders; /* No. of cylinders the drive can access: 71 * eg: a nominally 40-track drive can usually go up 72 * to 42 tracks with a bit of "persuasion" */ 73 int fd_readonly; /* Is the drive (or the disc therein) set to R/O? */ 74 int fd_changed; /* Default changeline implementation. This will be 75 * set to 1 when drive is ejected, 0 at controller 76 * partial reset. If you can write a better 77 * implementation of the changeline, override 78 * fdv_changed(). */ 79 80 /* READONLY variables */ 81 int fd_motor; /* Is the motor for this drive running? */ 82 int fd_cylinder; /* Current cylinder. Note that if the drive is 83 * double-stepping, this is the "real" cylinder - 84 * so it could = 24 and be reading cylinder 12 85 * of a 40-track DSK file. */ 86 } FLOPPY_DRIVE; 87 88 /* Subclass of FLOPPY_DRIVE: a drive which emulates discs using the CPCEMU 89 * .DSK format */ 90 91 typedef struct dsk_floppy_drive 92 { 93 /* PUBLIC variables: */ 94 FLOPPY_DRIVE fdd; /* Base class */ 95 char fdd_filename[PATH_MAX]; /* Filename to .DSK file. Before 96 * changing this call fd_eject() on 97 * the drive */ 98 /* PRIVATE variables: */ 99 FILE *fdd_fp; /* File of the .DSK file */ 100 fdc_byte fdd_disk_header[256]; /* .DSK header */ 101 fdc_byte fdd_track_header[256]; /* .DSK track header */ 102 int fdd_dirty; /* Has this disk been written to? */ 103 } DSK_FLOPPY_DRIVE; 104 105 #ifdef DSK_ERR_OK /* LIBDSK headers included */ 106 typedef struct libdsk_floppy_drive 107 { 108 /* PUBLIC variables: */ 109 FLOPPY_DRIVE fdl; /* Base class */ 110 char fdl_filename[PATH_MAX]; /* Filename to .DSK file. Before 111 * changing this call fd_eject() on 112 * the drive */ 113 const char *fdl_type; /* LIBDSK drive type, NULL for auto */ 114 const char *fdl_compress; /* LIBDSK compression, NULL for auto */ 115 /* PRIVATE variables: */ 116 DSK_PDRIVER fdl_diskp; 117 DSK_GEOMETRY fdl_diskg; /* Autoprobed geometry */ 118 } LIBDSK_FLOPPY_DRIVE; 119 #endif /* ifdef DSK_ERR_OK */ 120 121 typedef struct nc9_floppy_drive 122 { 123 FLOPPY_DRIVE fdd; /* Base class */ 124 FLOPPY_DRIVE *nc9_fdd; /* Pointer to the 9256's B drive */ 125 } NC9_FLOPPY_DRIVE; 126 127 128 FDRV_PTR fd_inew(size_t size); 129 130 131 /* This class represents the controller itself. When you instantiate one, call 132 * fdc_reset() on it before doing anything else with it. */ 133 134 typedef struct fdc_765 135 { 136 /* PRIVATE variables */ 137 int fdc_interrupting; /* 0 => Not interrupting 138 * 1 => Entering result phase of 139 * Read/Write/Format/Scan 140 * 2 => Ready for data transfer 141 * (execution phase) 142 * 4 => End of Seek/Recalibrate command */ 143 /* The results from the SPECIFY command */ 144 int fdc_specify[2]; 145 /* The last sector for which a DD READ ID request was made */ 146 int fdc_lastidread; 147 148 /* Current WRITE command is for deleted data? */ 149 int fdc_write_deleted; 150 151 /* Command phase buffer */ 152 int fdc_cmd_id; /* Current command */ 153 int fdc_cmd_len; /* No. of bytes remaining to transfer */ 154 int fdc_cmd_pos; /* Next buffer position to write */ 155 fdc_byte fdc_cmd_buf[20]; /* The command as a byte string */ 156 157 /* Execution phase buffer */ 158 /* [0.4.2] If we are doing multisector reads, this needs to hold a 159 * whole track's worth of sectors: let's say 16k. (A normal HD disc 160 * holds 9k / track) */ 161 fdc_byte fdc_exec_buf[16384]; 162 int fdc_exec_len; /* No. of bytes remaining to transfer */ 163 int fdc_exec_pos; /* Position in buffer */ 164 165 /* Results phase buffer */ 166 fdc_byte fdc_result_buf[20]; 167 int fdc_result_len; /* No. of bytes remaining to transfer */ 168 int fdc_result_pos; /* Position in buffer */ 169 170 int fdc_terminal_count; /* Set to abort a transfer */ 171 int fdc_isr_countdown; /* Countdown to interrupt */ 172 173 int fdc_dor; /* Are we using that horrible kludge, the 174 * Digital Output Register, rather than 175 * proper drive select lines? */ 176 /* Drive pointers after the DOR has had its wicked way */ 177 FLOPPY_DRIVE *fdc_dor_drive[4]; 178 179 /* READONLY variables - these can be used in status displays */ 180 /* The four uPD765A status registers */ 181 int fdc_st0, fdc_st1, fdc_st2, fdc_st3; 182 /* The main status register */ 183 int fdc_mainstat; 184 int fdc_curunit, fdc_curhead; /* Currently active unit & head */ 185 186 /* Public variables */ 187 void (*fdc_isr)(struct fdc_765 *self, int status); 188 /* EXT: Called when interrupt line is raised or lowered. 189 * You must provide this if the FDC is to interrupt. */ 190 FLOPPY_DRIVE *fdc_drive[4]; 191 /* The FDC's four drives. You must set these pointers */ 192 193 } FDC_765; 194 195 196 197