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