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