Sat, 17 Nov 2012 19:13:08 +0000
Improve floppy disc support
Patch-Author: Andrew Warkentin <andreww591!gmail>
Patch-Message-ID: <50A772FC.8020009@gmail.com>
src/main.c | file | annotate | diff | revisions | |
src/wd279x.c | file | annotate | diff | revisions | |
src/wd279x.h | file | annotate | diff | revisions |
1.1 diff -r acea4b2f396f -r 4c85846b09cd src/main.c 1.2 --- a/src/main.c Thu Dec 08 23:44:19 2011 +0000 1.3 +++ b/src/main.c Sat Nov 17 19:13:08 2012 +0000 1.4 @@ -19,6 +19,26 @@ 1.5 exit(EXIT_FAILURE); 1.6 } 1.7 1.8 +static int load_fd() 1.9 +{ 1.10 + 1.11 + int writeable = 1; 1.12 + state.fdc_disc = fopen("discim", "r+b"); 1.13 + if (!state.fdc_disc){ 1.14 + writeable = 0; 1.15 + state.fdc_disc = fopen("discim", "rb"); 1.16 + } 1.17 + if (!state.fdc_disc){ 1.18 + fprintf(stderr, "ERROR loading disc image 'discim'.\n"); 1.19 + state.fdc_disc = NULL; 1.20 + return (0); 1.21 + }else{ 1.22 + wd2797_load(&state.fdc_ctx, state.fdc_disc, 512, 10, 2, writeable); 1.23 + fprintf(stderr, "Disc image loaded.\n"); 1.24 + return (1); 1.25 + } 1.26 +} 1.27 + 1.28 /** 1.29 * @brief Set the pixel at (x, y) to the given value 1.30 * @note The surface must be locked before calling this! 1.31 @@ -140,14 +160,7 @@ 1.32 state.fdc_disc = NULL; 1.33 fprintf(stderr, "Disc image unloaded.\n"); 1.34 } else { 1.35 - state.fdc_disc = fopen("discim", "rb"); 1.36 - if (!state.fdc_disc) { 1.37 - fprintf(stderr, "ERROR loading disc image 'discim'.\n"); 1.38 - state.fdc_disc = NULL; 1.39 - } else { 1.40 - wd2797_load(&state.fdc_ctx, state.fdc_disc, 512, 10, 2); 1.41 - fprintf(stderr, "Disc image loaded.\n"); 1.42 - } 1.43 + load_fd(); 1.44 } 1.45 break; 1.46 case SDLK_F12: 1.47 @@ -214,12 +227,7 @@ 1.48 SDL_WM_SetCaption("FreeBee 3B1 emulator", "FreeBee"); 1.49 1.50 // Load a disc image 1.51 - state.fdc_disc = fopen("discim", "rb"); 1.52 - if (!state.fdc_disc) { 1.53 - fprintf(stderr, "ERROR loading disc image 'discim'.\n"); 1.54 - return -4; 1.55 - } 1.56 - wd2797_load(&state.fdc_ctx, state.fdc_disc, 512, 10, 2); 1.57 + load_fd(); 1.58 1.59 /*** 1.60 * The 3B1 CPU runs at 10MHz, with DMA running at 1MHz and video refreshing at 1.61 @@ -345,8 +353,11 @@ 1.62 // state.dma_count = 0; 1.63 state.dmaen = false; 1.64 } 1.65 + }else if (wd2797_get_drq(&state.fdc_ctx)){ 1.66 + wd2797_dma_miss(&state.fdc_ctx); 1.67 } 1.68 1.69 + 1.70 // Any interrupts? --> TODO: masking 1.71 /* if (!lastirq_fdc) { 1.72 if (wd2797_get_irq(&state.fdc_ctx)) { 1.73 @@ -354,12 +365,13 @@ 1.74 m68k_set_irq(2); 1.75 } 1.76 */ 1.77 - if (keyboard_get_irq(&state.kbd)) { 1.78 + if (wd2797_get_irq(&state.fdc_ctx)){ 1.79 + m68k_set_irq(2); 1.80 + }else if (keyboard_get_irq(&state.kbd)) { 1.81 m68k_set_irq(3); 1.82 } else { 1.83 - lastirq_fdc = wd2797_get_irq(&state.fdc_ctx); 1.84 // if (!state.timer_asserted){ 1.85 -// m68k_set_irq(0); 1.86 + m68k_set_irq(0); 1.87 // } 1.88 } 1.89
2.1 diff -r acea4b2f396f -r 4c85846b09cd src/wd279x.c 2.2 --- a/src/wd279x.c Thu Dec 08 23:44:19 2011 +0000 2.3 +++ b/src/wd279x.c Sat Nov 17 19:13:08 2012 +0000 2.4 @@ -35,6 +35,7 @@ 2.5 { 2.6 // track, head and sector unknown 2.7 ctx->track = ctx->head = ctx->sector = 0; 2.8 + ctx->track_reg = 0; 2.9 2.10 // no IRQ pending 2.11 ctx->irq = false; 2.12 @@ -47,6 +48,9 @@ 2.13 ctx->status = 0; 2.14 ctx->cmd_has_drq = false; 2.15 2.16 + // No format command in progress 2.17 + ctx->formatting = false; 2.18 + 2.19 // Clear data register 2.20 ctx->data_reg = 0; 2.21 2.22 @@ -63,6 +67,7 @@ 2.23 { 2.24 // track, head and sector unknown 2.25 ctx->track = ctx->head = ctx->sector = 0; 2.26 + ctx->track_reg = 0; 2.27 2.28 // no IRQ pending 2.29 ctx->irq = false; 2.30 @@ -99,14 +104,13 @@ 2.31 return ctx->irq; 2.32 } 2.33 2.34 - 2.35 bool wd2797_get_drq(WD2797_CTX *ctx) 2.36 { 2.37 return (ctx->data_pos < ctx->data_len); 2.38 } 2.39 2.40 2.41 -WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads) 2.42 +WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads, int writeable) 2.43 { 2.44 size_t filesize; 2.45 2.46 @@ -136,7 +140,7 @@ 2.47 ctx->geom_secsz = secsz; 2.48 ctx->geom_heads = heads; 2.49 ctx->geom_spt = spt; 2.50 - 2.51 + ctx->writeable = writeable; 2.52 return WD2797_ERR_OK; 2.53 } 2.54 2.55 @@ -160,6 +164,7 @@ 2.56 uint8_t wd2797_read_reg(WD2797_CTX *ctx, uint8_t addr) 2.57 { 2.58 uint8_t temp = 0; 2.59 + m68k_end_timeslice(); 2.60 2.61 switch (addr & 0x03) { 2.62 case WD2797_REG_STATUS: // Status register 2.63 @@ -176,12 +181,12 @@ 2.64 temp = ctx->status & ~0x01; 2.65 } 2.66 // FDC is busy if there is still data in the buffer 2.67 - temp |= (ctx->data_pos < ctx->data_len) ? 0x01 : 0x00; // if data in buffer, then DMA hasn't copied it yet, and we're still busy! 2.68 + temp |= (ctx->data_pos < ctx->data_len) ? 0x81 : 0x00; // if data in buffer, then DMA hasn't copied it yet, and we're still busy! 2.69 // TODO: also if seek delay / read delay hasn't passed (but that's for later) 2.70 return temp; 2.71 2.72 case WD2797_REG_TRACK: // Track register 2.73 - return ctx->track; 2.74 + return ctx->track_reg; 2.75 2.76 case WD2797_REG_SECTOR: // Sector register 2.77 return ctx->sector; 2.78 @@ -198,7 +203,7 @@ 2.79 return ctx->data[ctx->data_pos++]; 2.80 } else { 2.81 // command finished 2.82 - return 0xff; 2.83 + return ctx->data_reg; 2.84 } 2.85 2.86 default: 2.87 @@ -215,7 +220,6 @@ 2.88 size_t lba; 2.89 bool is_type1 = false; 2.90 int temp; 2.91 - 2.92 m68k_end_timeslice(); 2.93 2.94 switch (addr) { 2.95 @@ -235,14 +239,14 @@ 2.96 case CMD_RESTORE: 2.97 // Restore. Set track to 0 and throw an IRQ. 2.98 is_type1 = true; 2.99 - ctx->track = 0; 2.100 + ctx->track = ctx->track_reg = 0; 2.101 break; 2.102 2.103 case CMD_SEEK: 2.104 // Seek. Seek to the track specced in the Data Register. 2.105 is_type1 = true; 2.106 if (ctx->data_reg < ctx->geom_tracks) { 2.107 - ctx->track = ctx->data_reg; 2.108 + ctx->track = ctx->track_reg = ctx->data_reg; 2.109 } else { 2.110 // Seek error. :( 2.111 ctx->status = 0x10; 2.112 @@ -256,26 +260,17 @@ 2.113 2.114 case CMD_STEPIN: 2.115 case CMD_STEPOUT: 2.116 - // TODO! deal with trk0! 2.117 - // Need to keep a copy of the track register; when it hits 0, set the TRK0 flag. 2.118 - if (cmd == CMD_STEPIN) { 2.119 - ctx->last_step_dir = 1; 2.120 - } else { 2.121 - ctx->last_step_dir = -1; 2.122 - } 2.123 - is_type1 = true; 2.124 - break; 2.125 - 2.126 case CMD_STEP_TU: 2.127 case CMD_STEPIN_TU: 2.128 case CMD_STEPOUT_TU: 2.129 // if this is a Step In or Step Out cmd, set the step-direction 2.130 - if (cmd == CMD_STEPIN_TU) { 2.131 + if ((cmd & ~0x10) == CMD_STEPIN) { 2.132 ctx->last_step_dir = 1; 2.133 - } else if (cmd == CMD_STEPOUT_TU) { 2.134 + } else if ((cmd & ~0x10) == CMD_STEPOUT) { 2.135 ctx->last_step_dir = -1; 2.136 } 2.137 2.138 + 2.139 // Seek one step in the last direction used. 2.140 ctx->track += ctx->last_step_dir; 2.141 if (ctx->track < 0) ctx->track = 0; 2.142 @@ -284,6 +279,10 @@ 2.143 ctx->status = 0x10; 2.144 ctx->track = ctx->geom_tracks - 1; 2.145 } 2.146 + if (cmd & 0x10){ 2.147 + ctx->track_reg = ctx->track; 2.148 + } 2.149 + 2.150 is_type1 = true; 2.151 break; 2.152 2.153 @@ -329,8 +328,7 @@ 2.154 } 2.155 2.156 // If this is a Write command, check write protect status too 2.157 - // TODO! 2.158 - if (false) { 2.159 + if (!ctx->writeable) { 2.160 // Write protected disc... 2.161 if ((cmd == CMD_WRITE_SECTOR) || (cmd == CMD_WRITE_SECTOR_MULTI) || (cmd == CMD_FORMAT_TRACK)) { 2.162 // Set Write Protect bit and bail. 2.163 @@ -388,9 +386,9 @@ 2.164 ctx->geom_tracks-1, ctx->geom_heads-1, ctx->geom_spt); 2.165 // CHS parameters exceed limits 2.166 ctx->status = 0x10; // Record Not Found 2.167 - break; 2.168 // Set IRQ 2.169 ctx->irq = true; 2.170 + break; 2.171 } 2.172 2.173 // reset data pointers 2.174 @@ -430,12 +428,14 @@ 2.175 case CMD_READ_TRACK: 2.176 // Read Track 2.177 // TODO! implement this 2.178 - ctx->head = (val & 0x02) ? 1 : 0; 2.179 - ctx->status = 0; 2.180 + // ctx->head = (val & 0x02) ? 1 : 0; 2.181 + // ctx->status = 0; 2.182 // B6, B5, B4, B3 = 0 2.183 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated 2.184 // B1 = DRQ. Data request. 2.185 - ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00; 2.186 + // ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00; 2.187 + ctx->irq = true; 2.188 + ctx->status = 0x10; 2.189 break; 2.190 2.191 case CMD_WRITE_SECTOR: 2.192 @@ -444,12 +444,21 @@ 2.193 2.194 ctx->head = (val & 0x02) ? 1 : 0; 2.195 // reset data pointers 2.196 - ctx->data_pos = ctx->data_len = 0; 2.197 + ctx->data_pos = 0; 2.198 2.199 - // TODO: set "write pending" flag, and write LBA, and go from there. 2.200 + // Calculate number of sectors to write to disc 2.201 + if (cmd == CMD_WRITE_SECTOR_MULTI) 2.202 + /*XXX: is this the correct value?*/ 2.203 + temp = ctx->geom_spt; 2.204 + else 2.205 + temp = 1; 2.206 + ctx->data_len = temp * ctx->geom_secsz; 2.207 + 2.208 + lba = (((ctx->track * ctx->geom_heads * ctx->geom_spt) + (ctx->head * ctx->geom_spt) + ctx->sector)) - 1; 2.209 + ctx->write_pos = lba * ctx->geom_secsz; 2.210 2.211 ctx->status = 0; 2.212 - // B6 = Write Protect. FIXME -- emulate this! 2.213 + // B6 = Write Protect. This would have been set earlier. 2.214 // B5 = 0 2.215 // B4 = Record Not Found. We're not going to see this... FIXME-not emulated 2.216 // B3 = CRC Error. Not possible. 2.217 @@ -465,24 +474,35 @@ 2.218 // B6 = Write Protect. FIXME -- emulate this! 2.219 // B5, B4, B3 = 0 2.220 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated 2.221 + ctx->data_pos = 0; 2.222 + ctx->data_len = 7170; 2.223 // B1 = DRQ. Data request. 2.224 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00; 2.225 + ctx->formatting = true; 2.226 break; 2.227 2.228 case CMD_FORCE_INTERRUPT: 2.229 // Force Interrupt... 2.230 // Terminates current operation and sends an interrupt 2.231 // TODO! 2.232 - ctx->status = 0; 2.233 + ctx->status = 0x20; 2.234 + if (!ctx->writeable){ 2.235 + ctx->status |= 0x40; 2.236 + } 2.237 + if (ctx->track == 0){ 2.238 + ctx->status = 0x04; 2.239 + } 2.240 ctx->data_pos = ctx->data_len = 0; 2.241 - // Set IRQ 2.242 - ctx->irq = true; 2.243 + if (cmd & 8){ 2.244 + // Set IRQ 2.245 + ctx->irq = true; 2.246 + } 2.247 break; 2.248 } 2.249 break; 2.250 2.251 case WD2797_REG_TRACK: // Track register 2.252 - ctx->track = val; 2.253 + ctx->track = ctx->track_reg = val; 2.254 break; 2.255 2.256 case WD2797_REG_SECTOR: // Sector register 2.257 @@ -492,20 +512,35 @@ 2.258 case WD2797_REG_DATA: // Data register 2.259 // Save the value written into the data register 2.260 ctx->data_reg = val; 2.261 - 2.262 // If we're processing a write command, and there's space in the 2.263 // buffer, allow the write. 2.264 - if (ctx->data_pos < ctx->data_len) { 2.265 - // set IRQ if this is the last data byte 2.266 - if (ctx->data_pos == (ctx->data_len-1)) { 2.267 - // Set IRQ 2.268 + if (ctx->data_pos < ctx->data_len && (ctx->write_pos >= 0 || ctx->formatting)) { 2.269 + if (!ctx->formatting) ctx->data[ctx->data_pos] = val; 2.270 + // store data byte and increment pointer 2.271 + ctx->data_pos++; 2.272 + 2.273 + // set IRQ and write data if this is the last data byte 2.274 + if (ctx->data_pos == ctx->data_len) { 2.275 + if (!ctx->formatting){ 2.276 + fseek(ctx->disc_image, ctx->write_pos, SEEK_SET); 2.277 + fwrite(ctx->data, 1, ctx->data_len, ctx->disc_image); 2.278 + fflush(ctx->disc_image); 2.279 + } 2.280 + // Set IRQ and reset write pointer 2.281 ctx->irq = true; 2.282 + ctx->write_pos = -1; 2.283 + ctx->formatting = false; 2.284 } 2.285 2.286 - // store data byte and increment pointer 2.287 - ctx->data[ctx->data_pos++] = val; 2.288 } 2.289 break; 2.290 } 2.291 } 2.292 2.293 +void wd2797_dma_miss(WD2797_CTX *ctx) 2.294 +{ 2.295 + ctx->data_pos = ctx->data_len; 2.296 + ctx->write_pos = 0; 2.297 + ctx->status = 4; /* lost data */ 2.298 + ctx->irq = true; 2.299 +}
3.1 diff -r acea4b2f396f -r 4c85846b09cd src/wd279x.h 3.2 --- a/src/wd279x.h Thu Dec 08 23:44:19 2011 +0000 3.3 +++ b/src/wd279x.h Sat Nov 17 19:13:08 2012 +0000 3.4 @@ -25,6 +25,8 @@ 3.5 typedef struct { 3.6 // Current track, head and sector 3.7 int track, head, sector; 3.8 + // Track and sector registers 3.9 + int track_reg, sector_reg; 3.10 // Geometry of current disc 3.11 int geom_secsz, geom_spt, geom_heads, geom_tracks; 3.12 // IRQ status 3.13 @@ -42,6 +44,12 @@ 3.14 size_t data_pos, data_len; 3.15 // Current disc image file 3.16 FILE *disc_image; 3.17 + // Write protect flag 3.18 + int writeable; 3.19 + // LBA at which to start writing 3.20 + int write_pos; 3.21 + // True if a format command is in progress 3.22 + int formatting; 3.23 } WD2797_CTX; 3.24 3.25 /** 3.26 @@ -88,7 +96,7 @@ 3.27 * @param heads Number of heads (1 or 2). 3.28 * @return Error code; WD279X_E_OK if everything worked OK. 3.29 */ 3.30 -WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads); 3.31 +WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads, int writeable); 3.32 3.33 /** 3.34 * @brief Deassign the current image file. 3.35 @@ -111,5 +119,5 @@ 3.36 */ 3.37 void wd2797_write_reg(WD2797_CTX *ctx, uint8_t addr, uint8_t val); 3.38 3.39 - 3.40 +void wd2797_dma_miss(WD2797_CTX *ctx); 3.41 #endif