1.1 --- a/src/wd279x.c Thu Dec 08 23:44:19 2011 +0000 1.2 +++ b/src/wd279x.c Sat Nov 17 19:13:08 2012 +0000 1.3 @@ -35,6 +35,7 @@ 1.4 { 1.5 // track, head and sector unknown 1.6 ctx->track = ctx->head = ctx->sector = 0; 1.7 + ctx->track_reg = 0; 1.8 1.9 // no IRQ pending 1.10 ctx->irq = false; 1.11 @@ -47,6 +48,9 @@ 1.12 ctx->status = 0; 1.13 ctx->cmd_has_drq = false; 1.14 1.15 + // No format command in progress 1.16 + ctx->formatting = false; 1.17 + 1.18 // Clear data register 1.19 ctx->data_reg = 0; 1.20 1.21 @@ -63,6 +67,7 @@ 1.22 { 1.23 // track, head and sector unknown 1.24 ctx->track = ctx->head = ctx->sector = 0; 1.25 + ctx->track_reg = 0; 1.26 1.27 // no IRQ pending 1.28 ctx->irq = false; 1.29 @@ -99,14 +104,13 @@ 1.30 return ctx->irq; 1.31 } 1.32 1.33 - 1.34 bool wd2797_get_drq(WD2797_CTX *ctx) 1.35 { 1.36 return (ctx->data_pos < ctx->data_len); 1.37 } 1.38 1.39 1.40 -WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads) 1.41 +WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads, int writeable) 1.42 { 1.43 size_t filesize; 1.44 1.45 @@ -136,7 +140,7 @@ 1.46 ctx->geom_secsz = secsz; 1.47 ctx->geom_heads = heads; 1.48 ctx->geom_spt = spt; 1.49 - 1.50 + ctx->writeable = writeable; 1.51 return WD2797_ERR_OK; 1.52 } 1.53 1.54 @@ -160,6 +164,7 @@ 1.55 uint8_t wd2797_read_reg(WD2797_CTX *ctx, uint8_t addr) 1.56 { 1.57 uint8_t temp = 0; 1.58 + m68k_end_timeslice(); 1.59 1.60 switch (addr & 0x03) { 1.61 case WD2797_REG_STATUS: // Status register 1.62 @@ -176,12 +181,12 @@ 1.63 temp = ctx->status & ~0x01; 1.64 } 1.65 // FDC is busy if there is still data in the buffer 1.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! 1.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! 1.68 // TODO: also if seek delay / read delay hasn't passed (but that's for later) 1.69 return temp; 1.70 1.71 case WD2797_REG_TRACK: // Track register 1.72 - return ctx->track; 1.73 + return ctx->track_reg; 1.74 1.75 case WD2797_REG_SECTOR: // Sector register 1.76 return ctx->sector; 1.77 @@ -198,7 +203,7 @@ 1.78 return ctx->data[ctx->data_pos++]; 1.79 } else { 1.80 // command finished 1.81 - return 0xff; 1.82 + return ctx->data_reg; 1.83 } 1.84 1.85 default: 1.86 @@ -215,7 +220,6 @@ 1.87 size_t lba; 1.88 bool is_type1 = false; 1.89 int temp; 1.90 - 1.91 m68k_end_timeslice(); 1.92 1.93 switch (addr) { 1.94 @@ -235,14 +239,14 @@ 1.95 case CMD_RESTORE: 1.96 // Restore. Set track to 0 and throw an IRQ. 1.97 is_type1 = true; 1.98 - ctx->track = 0; 1.99 + ctx->track = ctx->track_reg = 0; 1.100 break; 1.101 1.102 case CMD_SEEK: 1.103 // Seek. Seek to the track specced in the Data Register. 1.104 is_type1 = true; 1.105 if (ctx->data_reg < ctx->geom_tracks) { 1.106 - ctx->track = ctx->data_reg; 1.107 + ctx->track = ctx->track_reg = ctx->data_reg; 1.108 } else { 1.109 // Seek error. :( 1.110 ctx->status = 0x10; 1.111 @@ -256,26 +260,17 @@ 1.112 1.113 case CMD_STEPIN: 1.114 case CMD_STEPOUT: 1.115 - // TODO! deal with trk0! 1.116 - // Need to keep a copy of the track register; when it hits 0, set the TRK0 flag. 1.117 - if (cmd == CMD_STEPIN) { 1.118 - ctx->last_step_dir = 1; 1.119 - } else { 1.120 - ctx->last_step_dir = -1; 1.121 - } 1.122 - is_type1 = true; 1.123 - break; 1.124 - 1.125 case CMD_STEP_TU: 1.126 case CMD_STEPIN_TU: 1.127 case CMD_STEPOUT_TU: 1.128 // if this is a Step In or Step Out cmd, set the step-direction 1.129 - if (cmd == CMD_STEPIN_TU) { 1.130 + if ((cmd & ~0x10) == CMD_STEPIN) { 1.131 ctx->last_step_dir = 1; 1.132 - } else if (cmd == CMD_STEPOUT_TU) { 1.133 + } else if ((cmd & ~0x10) == CMD_STEPOUT) { 1.134 ctx->last_step_dir = -1; 1.135 } 1.136 1.137 + 1.138 // Seek one step in the last direction used. 1.139 ctx->track += ctx->last_step_dir; 1.140 if (ctx->track < 0) ctx->track = 0; 1.141 @@ -284,6 +279,10 @@ 1.142 ctx->status = 0x10; 1.143 ctx->track = ctx->geom_tracks - 1; 1.144 } 1.145 + if (cmd & 0x10){ 1.146 + ctx->track_reg = ctx->track; 1.147 + } 1.148 + 1.149 is_type1 = true; 1.150 break; 1.151 1.152 @@ -329,8 +328,7 @@ 1.153 } 1.154 1.155 // If this is a Write command, check write protect status too 1.156 - // TODO! 1.157 - if (false) { 1.158 + if (!ctx->writeable) { 1.159 // Write protected disc... 1.160 if ((cmd == CMD_WRITE_SECTOR) || (cmd == CMD_WRITE_SECTOR_MULTI) || (cmd == CMD_FORMAT_TRACK)) { 1.161 // Set Write Protect bit and bail. 1.162 @@ -388,9 +386,9 @@ 1.163 ctx->geom_tracks-1, ctx->geom_heads-1, ctx->geom_spt); 1.164 // CHS parameters exceed limits 1.165 ctx->status = 0x10; // Record Not Found 1.166 - break; 1.167 // Set IRQ 1.168 ctx->irq = true; 1.169 + break; 1.170 } 1.171 1.172 // reset data pointers 1.173 @@ -430,12 +428,14 @@ 1.174 case CMD_READ_TRACK: 1.175 // Read Track 1.176 // TODO! implement this 1.177 - ctx->head = (val & 0x02) ? 1 : 0; 1.178 - ctx->status = 0; 1.179 + // ctx->head = (val & 0x02) ? 1 : 0; 1.180 + // ctx->status = 0; 1.181 // B6, B5, B4, B3 = 0 1.182 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated 1.183 // B1 = DRQ. Data request. 1.184 - ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00; 1.185 + // ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00; 1.186 + ctx->irq = true; 1.187 + ctx->status = 0x10; 1.188 break; 1.189 1.190 case CMD_WRITE_SECTOR: 1.191 @@ -444,12 +444,21 @@ 1.192 1.193 ctx->head = (val & 0x02) ? 1 : 0; 1.194 // reset data pointers 1.195 - ctx->data_pos = ctx->data_len = 0; 1.196 + ctx->data_pos = 0; 1.197 1.198 - // TODO: set "write pending" flag, and write LBA, and go from there. 1.199 + // Calculate number of sectors to write to disc 1.200 + if (cmd == CMD_WRITE_SECTOR_MULTI) 1.201 + /*XXX: is this the correct value?*/ 1.202 + temp = ctx->geom_spt; 1.203 + else 1.204 + temp = 1; 1.205 + ctx->data_len = temp * ctx->geom_secsz; 1.206 + 1.207 + lba = (((ctx->track * ctx->geom_heads * ctx->geom_spt) + (ctx->head * ctx->geom_spt) + ctx->sector)) - 1; 1.208 + ctx->write_pos = lba * ctx->geom_secsz; 1.209 1.210 ctx->status = 0; 1.211 - // B6 = Write Protect. FIXME -- emulate this! 1.212 + // B6 = Write Protect. This would have been set earlier. 1.213 // B5 = 0 1.214 // B4 = Record Not Found. We're not going to see this... FIXME-not emulated 1.215 // B3 = CRC Error. Not possible. 1.216 @@ -465,24 +474,35 @@ 1.217 // B6 = Write Protect. FIXME -- emulate this! 1.218 // B5, B4, B3 = 0 1.219 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated 1.220 + ctx->data_pos = 0; 1.221 + ctx->data_len = 7170; 1.222 // B1 = DRQ. Data request. 1.223 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00; 1.224 + ctx->formatting = true; 1.225 break; 1.226 1.227 case CMD_FORCE_INTERRUPT: 1.228 // Force Interrupt... 1.229 // Terminates current operation and sends an interrupt 1.230 // TODO! 1.231 - ctx->status = 0; 1.232 + ctx->status = 0x20; 1.233 + if (!ctx->writeable){ 1.234 + ctx->status |= 0x40; 1.235 + } 1.236 + if (ctx->track == 0){ 1.237 + ctx->status = 0x04; 1.238 + } 1.239 ctx->data_pos = ctx->data_len = 0; 1.240 - // Set IRQ 1.241 - ctx->irq = true; 1.242 + if (cmd & 8){ 1.243 + // Set IRQ 1.244 + ctx->irq = true; 1.245 + } 1.246 break; 1.247 } 1.248 break; 1.249 1.250 case WD2797_REG_TRACK: // Track register 1.251 - ctx->track = val; 1.252 + ctx->track = ctx->track_reg = val; 1.253 break; 1.254 1.255 case WD2797_REG_SECTOR: // Sector register 1.256 @@ -492,20 +512,35 @@ 1.257 case WD2797_REG_DATA: // Data register 1.258 // Save the value written into the data register 1.259 ctx->data_reg = val; 1.260 - 1.261 // If we're processing a write command, and there's space in the 1.262 // buffer, allow the write. 1.263 - if (ctx->data_pos < ctx->data_len) { 1.264 - // set IRQ if this is the last data byte 1.265 - if (ctx->data_pos == (ctx->data_len-1)) { 1.266 - // Set IRQ 1.267 + if (ctx->data_pos < ctx->data_len && (ctx->write_pos >= 0 || ctx->formatting)) { 1.268 + if (!ctx->formatting) ctx->data[ctx->data_pos] = val; 1.269 + // store data byte and increment pointer 1.270 + ctx->data_pos++; 1.271 + 1.272 + // set IRQ and write data if this is the last data byte 1.273 + if (ctx->data_pos == ctx->data_len) { 1.274 + if (!ctx->formatting){ 1.275 + fseek(ctx->disc_image, ctx->write_pos, SEEK_SET); 1.276 + fwrite(ctx->data, 1, ctx->data_len, ctx->disc_image); 1.277 + fflush(ctx->disc_image); 1.278 + } 1.279 + // Set IRQ and reset write pointer 1.280 ctx->irq = true; 1.281 + ctx->write_pos = -1; 1.282 + ctx->formatting = false; 1.283 } 1.284 1.285 - // store data byte and increment pointer 1.286 - ctx->data[ctx->data_pos++] = val; 1.287 } 1.288 break; 1.289 } 1.290 } 1.291 1.292 +void wd2797_dma_miss(WD2797_CTX *ctx) 1.293 +{ 1.294 + ctx->data_pos = ctx->data_len; 1.295 + ctx->write_pos = 0; 1.296 + ctx->status = 4; /* lost data */ 1.297 + ctx->irq = true; 1.298 +}