src/wd279x.c

Sun, 12 Dec 2010 23:47:35 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 12 Dec 2010 23:47:35 +0000
changeset 55
ba6b8e570062
parent 54
57c6ef81ae81
child 57
feb84193a43a
child 76
2ef98ea1e944
permissions
-rw-r--r--

improve error and DMA handling

philpem@48 1 #include <stdint.h>
philpem@48 2 #include <stdbool.h>
philpem@49 3 #include <malloc.h>
philpem@53 4 #include "musashi/m68k.h"
philpem@48 5 #include "wd279x.h"
philpem@48 6
philpem@48 7 /// WD2797 command constants
philpem@48 8 enum {
philpem@48 9 CMD_MASK = 0xF0, ///< Bit mask to detect command bits
philpem@48 10 CMD_RESTORE = 0x00, ///< Restore (recalibrate, seek to track 0)
philpem@48 11 CMD_SEEK = 0x10, ///< Seek to given track
philpem@48 12 CMD_STEP = 0x20, ///< Step
philpem@48 13 CMD_STEP_TU = 0x30, ///< Step and update track register
philpem@48 14 CMD_STEPIN = 0x40, ///< Step In
philpem@48 15 CMD_STEPIN_TU = 0x50, ///< Step In and update track register
philpem@48 16 CMD_STEPOUT = 0x60, ///< Step Out
philpem@48 17 CMD_STEPOUT_TU = 0x70, ///< Step Out and update track register
philpem@48 18 CMD_READ_SECTOR = 0x80, ///< Read Sector
philpem@48 19 CMD_READ_SECTOR_MULTI = 0x90, ///< Read Multiple Sectors
philpem@48 20 CMD_WRITE_SECTOR = 0xA0, ///< Write Sector
philpem@48 21 CMD_WRITE_SECTOR_MULTI = 0xB0, ///< Write Multiple Sectors
philpem@48 22 CMD_READ_ADDRESS = 0xC0, ///< Read Address (IDAM contents)
philpem@48 23 CMD_FORCE_INTERRUPT = 0xD0, ///< Force Interrupt
philpem@48 24 CMD_READ_TRACK = 0xE0, ///< Read Track
philpem@48 25 CMD_FORMAT_TRACK = 0xF0 ///< Format Track
philpem@48 26 };
philpem@48 27
philpem@48 28
philpem@49 29 void wd2797_init(WD2797_CTX *ctx)
philpem@48 30 {
philpem@48 31 // track, head and sector unknown
philpem@49 32 ctx->track = ctx->head = ctx->sector = 0;
philpem@48 33
philpem@49 34 // no IRQ pending
philpem@49 35 ctx->irql = ctx->irqe = false;
philpem@48 36
philpem@48 37 // no data available
philpem@49 38 ctx->data_pos = ctx->data_len = 0;
philpem@49 39 ctx->data = NULL;
philpem@49 40
philpem@49 41 // Status register clear, not busy
philpem@49 42 ctx->status = 0;
philpem@49 43
philpem@49 44 // Clear data register
philpem@49 45 ctx->data_reg = 0;
philpem@49 46
philpem@49 47 // Last step direction
philpem@49 48 ctx->last_step_dir = -1;
philpem@48 49
philpem@48 50 // No disc image loaded
philpem@48 51 ctx->disc_image = NULL;
philpem@49 52 ctx->geom_secsz = ctx->geom_spt = ctx->geom_heads = ctx->geom_tracks = 0;
philpem@48 53 }
philpem@48 54
philpem@48 55
philpem@49 56 void wd2797_reset(WD2797_CTX *ctx)
philpem@49 57 {
philpem@49 58 // track, head and sector unknown
philpem@49 59 ctx->track = ctx->head = ctx->sector = 0;
philpem@49 60
philpem@49 61 // no IRQ pending
philpem@49 62 ctx->irql = ctx->irqe = false;
philpem@49 63
philpem@49 64 // no data available
philpem@49 65 ctx->data_pos = ctx->data_len = 0;
philpem@49 66
philpem@49 67 // Status register clear, not busy
philpem@49 68 ctx->status = 0;
philpem@49 69
philpem@49 70 // Clear data register
philpem@49 71 ctx->data_reg = 0;
philpem@49 72
philpem@49 73 // Last step direction
philpem@49 74 ctx->last_step_dir = -1;
philpem@49 75 }
philpem@49 76
philpem@49 77
philpem@49 78 void wd2797_done(WD2797_CTX *ctx)
philpem@49 79 {
philpem@49 80 // Reset the WD2797
philpem@49 81 wd2797_reset(ctx);
philpem@49 82
philpem@49 83 // Free any allocated memory
philpem@49 84 if (ctx->data) {
philpem@49 85 free(ctx->data);
philpem@49 86 ctx->data = NULL;
philpem@49 87 }
philpem@49 88 }
philpem@49 89
philpem@49 90
philpem@49 91 bool wd2797_get_irq(WD2797_CTX *ctx)
philpem@48 92 {
philpem@48 93 // If an IRQ is pending, clear it and return true, otherwise return false
philpem@48 94 if (ctx->irqe) {
philpem@48 95 ctx->irqe = false;
philpem@48 96 return true;
philpem@48 97 } else {
philpem@48 98 return false;
philpem@48 99 }
philpem@48 100 }
philpem@48 101
philpem@48 102
philpem@49 103 bool wd2797_get_drq(WD2797_CTX *ctx)
philpem@48 104 {
philpem@48 105 return (ctx->data_pos < ctx->data_len);
philpem@48 106 }
philpem@48 107
philpem@48 108
philpem@49 109 WD2797_ERR wd2797_load(WD2797_CTX *ctx, FILE *fp, int secsz, int spt, int heads)
philpem@49 110 {
philpem@49 111 size_t filesize;
philpem@49 112
philpem@49 113 // Start by finding out how big the image file is
philpem@49 114 fseek(fp, 0, SEEK_END);
philpem@49 115 filesize = ftell(fp);
philpem@49 116 fseek(fp, 0, SEEK_SET);
philpem@49 117
philpem@49 118 // Now figure out how many tracks it contains
philpem@49 119 int tracks = filesize / secsz / spt / heads;
philpem@49 120 // Confirm...
philpem@49 121 if (tracks < 1) {
philpem@49 122 return WD2797_ERR_BAD_GEOM;
philpem@49 123 }
philpem@49 124
philpem@49 125 // Allocate enough memory to store one disc track
philpem@49 126 if (ctx->data) {
philpem@49 127 free(ctx->data);
philpem@49 128 }
philpem@49 129 ctx->data = malloc(secsz * spt);
philpem@49 130 if (!ctx->data)
philpem@49 131 return WD2797_ERR_NO_MEMORY;
philpem@49 132
philpem@49 133 // Load the image and the geometry data
philpem@49 134 ctx->disc_image = fp;
philpem@49 135 ctx->geom_tracks = tracks;
philpem@49 136 ctx->geom_secsz = secsz;
philpem@49 137 ctx->geom_heads = heads;
philpem@49 138 ctx->geom_spt = spt;
philpem@49 139
philpem@49 140 return WD2797_ERR_OK;
philpem@49 141 }
philpem@49 142
philpem@49 143
philpem@49 144 void wd2797_unload(WD2797_CTX *ctx)
philpem@49 145 {
philpem@49 146 // Free memory buffer
philpem@49 147 if (ctx->data) {
philpem@49 148 free(ctx->data);
philpem@49 149 ctx->data = NULL;
philpem@49 150 }
philpem@49 151
philpem@49 152 // Clear file pointer
philpem@49 153 ctx->disc_image = NULL;
philpem@49 154
philpem@49 155 // Clear the disc geometry
philpem@49 156 ctx->geom_tracks = ctx->geom_secsz = ctx->geom_spt = ctx->geom_heads = 0;
philpem@49 157 }
philpem@49 158
philpem@49 159
philpem@49 160 uint8_t wd2797_read_reg(WD2797_CTX *ctx, uint8_t addr)
philpem@48 161 {
philpem@48 162 uint8_t temp = 0;
philpem@48 163
philpem@48 164 switch (addr & 0x03) {
philpem@49 165 case WD2797_REG_STATUS: // Status register
philpem@48 166 // Read from status register clears IRQ
philpem@48 167 ctx->irql = false;
philpem@53 168 ctx->irqe = false;
philpem@48 169
philpem@48 170 // Get current status flags (set by last command)
philpem@48 171 // DRQ bit
philpem@53 172 if (ctx->cmd_has_drq) {
philpem@53 173 printf("\tWDFDC rd sr, has drq, pos=%lu len=%lu\n", ctx->data_pos, ctx->data_len);
philpem@53 174 temp = ctx->status & ~0x03;
philpem@48 175 temp |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@53 176 } else {
philpem@53 177 temp = ctx->status & ~0x01;
philpem@53 178 }
philpem@48 179 // FDC is busy if there is still data in the buffer
philpem@48 180 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!
philpem@49 181 // TODO: also if seek delay / read delay hasn't passed (but that's for later)
philpem@48 182 return temp;
philpem@48 183
philpem@49 184 case WD2797_REG_TRACK: // Track register
philpem@48 185 return ctx->track;
philpem@48 186
philpem@49 187 case WD2797_REG_SECTOR: // Sector register
philpem@48 188 return ctx->sector;
philpem@48 189
philpem@49 190 case WD2797_REG_DATA: // Data register
philpem@48 191 // If there's data in the buffer, return it. Otherwise return 0xFF.
philpem@48 192 if (ctx->data_pos < ctx->data_len) {
philpem@53 193 // set IRQ if this is the last data byte
philpem@53 194 if (ctx->data_pos == (ctx->data_len-1)) {
philpem@53 195 // Set IRQ only if IRQL has been cleared (no pending IRQs)
philpem@53 196 ctx->irqe = ctx->irql ? ctx->irqe : true;
philpem@53 197 ctx->irql = true;
philpem@53 198 }
philpem@48 199 // return data byte and increment pointer
philpem@48 200 return ctx->data[ctx->data_pos++];
philpem@48 201 } else {
philpem@53 202 // command finished
philpem@48 203 return 0xff;
philpem@48 204 }
philpem@48 205
philpem@48 206 default:
philpem@48 207 // shut up annoying compilers which don't recognise unreachable code when they see it
philpem@48 208 // (here's looking at you, gcc!)
philpem@48 209 return 0xff;
philpem@48 210 }
philpem@48 211 }
philpem@48 212
philpem@48 213
philpem@49 214 void wd2797_write_reg(WD2797_CTX *ctx, uint8_t addr, uint8_t val)
philpem@48 215 {
philpem@48 216 uint8_t cmd = val & CMD_MASK;
philpem@48 217 size_t lba;
philpem@48 218 bool is_type1 = false;
philpem@49 219 int temp;
philpem@48 220
philpem@53 221 m68k_end_timeslice();
philpem@53 222
philpem@48 223 switch (addr) {
philpem@49 224 case WD2797_REG_COMMAND: // Command register
philpem@48 225 // write to command register clears interrupt request
philpem@48 226 ctx->irql = false;
philpem@48 227
philpem@48 228 // Is the drive ready?
philpem@48 229 if (ctx->disc_image == NULL) {
philpem@48 230 // No disc image, thus the drive is busy.
philpem@48 231 ctx->status = 0x80;
philpem@48 232 return;
philpem@48 233 }
philpem@48 234
philpem@48 235 // Handle Type 1 commands
philpem@48 236 switch (cmd) {
philpem@48 237 case CMD_RESTORE:
philpem@48 238 // Restore. Set track to 0 and throw an IRQ.
philpem@48 239 is_type1 = true;
philpem@48 240 ctx->track = 0;
philpem@48 241 break;
philpem@48 242
philpem@48 243 case CMD_SEEK:
philpem@48 244 // Seek. Seek to the track specced in the Data Register.
philpem@48 245 is_type1 = true;
philpem@48 246 if (ctx->data_reg < ctx->geom_tracks) {
philpem@48 247 ctx->track = ctx->data_reg;
philpem@48 248 } else {
philpem@48 249 // Seek error. :(
philpem@48 250 ctx->status = 0x10;
philpem@48 251 }
philpem@48 252
philpem@48 253 case CMD_STEP:
philpem@48 254 // TODO! deal with trk0!
philpem@48 255 // Need to keep a copy of the track register; when it hits 0, set the TRK0 flag.
philpem@48 256 is_type1 = true;
philpem@48 257 break;
philpem@48 258
philpem@48 259 case CMD_STEPIN:
philpem@48 260 case CMD_STEPOUT:
philpem@48 261 // TODO! deal with trk0!
philpem@48 262 // Need to keep a copy of the track register; when it hits 0, set the TRK0 flag.
philpem@48 263 if (cmd == CMD_STEPIN) {
philpem@48 264 ctx->last_step_dir = 1;
philpem@48 265 } else {
philpem@48 266 ctx->last_step_dir = -1;
philpem@48 267 }
philpem@48 268 is_type1 = true;
philpem@48 269 break;
philpem@48 270
philpem@48 271 case CMD_STEP_TU:
philpem@48 272 case CMD_STEPIN_TU:
philpem@48 273 case CMD_STEPOUT_TU:
philpem@48 274 // if this is a Step In or Step Out cmd, set the step-direction
philpem@48 275 if (cmd == CMD_STEPIN_TU) {
philpem@48 276 ctx->last_step_dir = 1;
philpem@48 277 } else if (cmd == CMD_STEPOUT_TU) {
philpem@48 278 ctx->last_step_dir = -1;
philpem@48 279 }
philpem@48 280
philpem@48 281 // Seek one step in the last direction used.
philpem@48 282 ctx->track += ctx->last_step_dir;
philpem@48 283 if (ctx->track < 0) ctx->track = 0;
philpem@48 284 if (ctx->track >= ctx->geom_tracks) {
philpem@48 285 // Seek past end of disc... that'll be a Seek Error then.
philpem@48 286 ctx->status = 0x10;
philpem@48 287 ctx->track = ctx->geom_tracks - 1;
philpem@48 288 }
philpem@48 289 is_type1 = true;
philpem@48 290 break;
philpem@48 291
philpem@48 292 default:
philpem@48 293 break;
philpem@48 294 }
philpem@48 295
philpem@48 296 if (is_type1) {
philpem@48 297 // Terminate any sector reads or writes
philpem@48 298 ctx->data_len = ctx->data_pos = 0;
philpem@48 299
philpem@48 300 // No DRQ bit for these commands.
philpem@48 301 ctx->cmd_has_drq = false;
philpem@48 302
philpem@48 303 // Type1 status byte...
philpem@48 304 ctx->status = 0;
philpem@48 305 // S7 = Not Ready. Command executed, therefore the drive was ready... :)
philpem@48 306 // S6 = Write Protect. TODO: add this
philpem@48 307 // S5 = Head Loaded. For certain emulation-related reasons, the heads are always loaded...
philpem@48 308 ctx->status |= 0x20;
philpem@48 309 // S4 = Seek Error. Not bloody likely if we got down here...!
philpem@48 310 // S3 = CRC Error. Not gonna happen on a disc image!
philpem@48 311 // S2 = Track 0
philpem@48 312 ctx->status |= (ctx->track == 0) ? 0x04 : 0x00;
philpem@48 313 // S1 = Index Pulse. TODO -- need periodics to emulate this
philpem@48 314 // S0 = Busy. We just exec'd the command, thus we're not busy.
philpem@48 315 // TODO: Set a timer for seeks, and ONLY clear BUSY when that timer expires. Need periodics for that.
philpem@48 316
philpem@48 317 // Set IRQ only if IRQL has been cleared (no pending IRQs)
philpem@53 318 ctx->irqe = ctx->irql ? ctx->irqe : true;
philpem@48 319 ctx->irql = true;
philpem@48 320 return;
philpem@48 321 }
philpem@48 322
philpem@48 323 // That's the Type 1 (seek) commands sorted. Now for the others.
philpem@48 324
philpem@53 325 // All these commands return the DRQ bit...
philpem@53 326 ctx->cmd_has_drq = true;
philpem@53 327
philpem@48 328 // If drive isn't ready, then set status B7 and exit
philpem@48 329 if (ctx->disc_image == NULL) {
philpem@48 330 ctx->status = 0x80;
philpem@48 331 return;
philpem@48 332 }
philpem@48 333
philpem@48 334 // If this is a Write command, check write protect status too
philpem@48 335 // TODO!
philpem@48 336 if (false) {
philpem@48 337 // Write protected disc...
philpem@48 338 if ((cmd == CMD_WRITE_SECTOR) || (cmd == CMD_WRITE_SECTOR_MULTI) || (cmd == CMD_FORMAT_TRACK)) {
philpem@48 339 // Set Write Protect bit and bail.
philpem@48 340 ctx->status = 0x40;
philpem@48 341
philpem@48 342 // Set IRQ only if IRQL has been cleared (no pending IRQs)
philpem@53 343 ctx->irqe = ctx->irql ? ctx->irqe : true;
philpem@48 344 ctx->irql = true;
philpem@48 345
philpem@48 346 return;
philpem@48 347 }
philpem@48 348 }
philpem@48 349
philpem@48 350 // Disc is ready to go. Parse the command word.
philpem@48 351 switch (cmd) {
philpem@48 352 case CMD_READ_ADDRESS:
philpem@48 353 // Read Address
philpem@54 354 ctx->head = (val & 0x02) ? 1 : 0;
philpem@48 355
philpem@48 356 // reset data pointers
philpem@48 357 ctx->data_pos = ctx->data_len = 0;
philpem@48 358
philpem@48 359 // load data buffer
philpem@48 360 ctx->data[ctx->data_len++] = ctx->track;
philpem@48 361 ctx->data[ctx->data_len++] = ctx->head;
philpem@48 362 ctx->data[ctx->data_len++] = ctx->sector;
philpem@48 363 switch (ctx->geom_secsz) {
philpem@48 364 case 128: ctx->data[ctx->data_len++] = 0; break;
philpem@48 365 case 256: ctx->data[ctx->data_len++] = 1; break;
philpem@48 366 case 512: ctx->data[ctx->data_len++] = 2; break;
philpem@48 367 case 1024: ctx->data[ctx->data_len++] = 3; break;
philpem@48 368 default: ctx->data[ctx->data_len++] = 0xFF; break; // TODO: deal with invalid values better
philpem@48 369 }
philpem@48 370 ctx->data[ctx->data_len++] = 0; // TODO: IDAM CRC!
philpem@48 371 ctx->data[ctx->data_len++] = 0;
philpem@48 372
philpem@53 373 ctx->status = 0;
philpem@48 374 // B6, B5 = 0
philpem@48 375 // B4 = Record Not Found. We're not going to see this... FIXME-not emulated
philpem@48 376 // B3 = CRC Error. Not possible.
philpem@48 377 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
philpem@48 378 // B1 = DRQ. Data request.
philpem@48 379 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@48 380 break;
philpem@48 381
philpem@48 382 case CMD_READ_SECTOR:
philpem@48 383 case CMD_READ_SECTOR_MULTI:
philpem@54 384 ctx->head = (val & 0x02) ? 1 : 0;
philpem@54 385 printf("WD279X: READ SECTOR cmd=%02X chs=%d:%d:%d\n", cmd, ctx->track, ctx->head, ctx->sector);
philpem@48 386 // Read Sector or Read Sector Multiple
philpem@48 387 // reset data pointers
philpem@48 388 ctx->data_pos = ctx->data_len = 0;
philpem@48 389
philpem@49 390 // Calculate number of sectors to read from disc
philpem@49 391 if (cmd == CMD_READ_SECTOR_MULTI)
philpem@49 392 temp = ctx->geom_spt;
philpem@49 393 else
philpem@49 394 temp = 1;
philpem@48 395
philpem@49 396 for (int i=0; i<temp; i++) {
philpem@49 397 // Calculate the LBA address of the required sector
philpem@51 398 lba = ((((ctx->track * ctx->geom_heads) + ctx->head) * ctx->geom_spt) + ((ctx->sector + i - 1) % ctx->geom_spt)) * ctx->geom_secsz;
philpem@53 399 printf("\tREAD lba = %lu\n", lba);
philpem@49 400
philpem@49 401 // Read the sector from the file
philpem@49 402 fseek(ctx->disc_image, lba, SEEK_SET);
philpem@49 403 ctx->data_len += fread(&ctx->data[ctx->data_len], 1, ctx->geom_secsz, ctx->disc_image);
philpem@53 404 printf("\tREAD len=%lu, pos=%lu, ssz=%d\n", ctx->data_len, ctx->data_pos, ctx->geom_secsz);
philpem@49 405 // TODO: check fread return value! if < secsz, BAIL! (call it a crc error or secnotfound maybe? also log to stderr)
philpem@49 406 }
philpem@48 407
philpem@53 408 ctx->status = 0;
philpem@48 409 // B6 = 0
philpem@48 410 // B5 = Record Type -- 1 = deleted, 0 = normal. We can't emulate anything but normal data blocks.
philpem@48 411 // B4 = Record Not Found. We're not going to see this... FIXME-not emulated
philpem@48 412 // B3 = CRC Error. Not possible.
philpem@48 413 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
philpem@48 414 // B1 = DRQ. Data request.
philpem@48 415 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@48 416 break;
philpem@48 417
philpem@48 418 case CMD_READ_TRACK:
philpem@48 419 // Read Track
philpem@49 420 // TODO! implement this
philpem@54 421 ctx->head = (val & 0x02) ? 1 : 0;
philpem@53 422 ctx->status = 0;
philpem@48 423 // B6, B5, B4, B3 = 0
philpem@48 424 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
philpem@48 425 // B1 = DRQ. Data request.
philpem@48 426 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@48 427 break;
philpem@48 428
philpem@48 429 case CMD_WRITE_SECTOR:
philpem@48 430 case CMD_WRITE_SECTOR_MULTI:
philpem@48 431 // Write Sector or Write Sector Multiple
philpem@48 432
philpem@54 433 ctx->head = (val & 0x02) ? 1 : 0;
philpem@48 434 // reset data pointers
philpem@48 435 ctx->data_pos = ctx->data_len = 0;
philpem@48 436
philpem@48 437 // TODO: set "write pending" flag, and write LBA, and go from there.
philpem@48 438
philpem@53 439 ctx->status = 0;
philpem@48 440 // B6 = Write Protect. FIXME -- emulate this!
philpem@48 441 // B5 = 0
philpem@48 442 // B4 = Record Not Found. We're not going to see this... FIXME-not emulated
philpem@48 443 // B3 = CRC Error. Not possible.
philpem@48 444 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
philpem@48 445 // B1 = DRQ. Data request.
philpem@48 446 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@48 447 break;
philpem@48 448
philpem@48 449 case CMD_FORMAT_TRACK:
philpem@48 450 // Write Track (aka Format Track)
philpem@54 451 ctx->head = (val & 0x02) ? 1 : 0;
philpem@53 452 ctx->status = 0;
philpem@48 453 // B6 = Write Protect. FIXME -- emulate this!
philpem@48 454 // B5, B4, B3 = 0
philpem@48 455 // B2 = Lost Data. Caused if DRQ isn't serviced in time. FIXME-not emulated
philpem@48 456 // B1 = DRQ. Data request.
philpem@48 457 ctx->status |= (ctx->data_pos < ctx->data_len) ? 0x02 : 0x00;
philpem@48 458 break;
philpem@48 459
philpem@48 460 case CMD_FORCE_INTERRUPT:
philpem@48 461 // Force Interrupt...
philpem@49 462 // Terminates current operation and sends an interrupt
philpem@49 463 // TODO!
philpem@53 464 ctx->status = 0;
philpem@49 465 ctx->data_pos = ctx->data_len = 0;
philpem@49 466 // Set IRQ only if IRQL has been cleared (no pending IRQs)
philpem@53 467 ctx->irqe = ctx->irql ? ctx->irqe : true;
philpem@49 468 ctx->irql = true;
philpem@48 469 break;
philpem@48 470 }
philpem@48 471 break;
philpem@48 472
philpem@49 473 case WD2797_REG_TRACK: // Track register
philpem@48 474 ctx->track = val;
philpem@48 475 break;
philpem@48 476
philpem@49 477 case WD2797_REG_SECTOR: // Sector register
philpem@48 478 ctx->sector = val;
philpem@48 479 break;
philpem@48 480
philpem@49 481 case WD2797_REG_DATA: // Data register
philpem@48 482 // Save the value written into the data register
philpem@48 483 ctx->data_reg = val;
philpem@48 484
philpem@48 485 // If we're processing a write command, and there's space in the
philpem@48 486 // buffer, allow the write.
philpem@48 487 if (ctx->data_pos < ctx->data_len) {
philpem@53 488 // set IRQ if this is the last data byte
philpem@53 489 if (ctx->data_pos == (ctx->data_len-1)) {
philpem@53 490 // Set IRQ only if IRQL has been cleared (no pending IRQs)
philpem@53 491 ctx->irqe = ctx->irql ? ctx->irqe : true;
philpem@53 492 ctx->irql = true;
philpem@53 493 }
philpem@53 494
philpem@48 495 // store data byte and increment pointer
philpem@48 496 ctx->data[ctx->data_pos++] = val;
philpem@48 497 }
philpem@48 498 break;
philpem@48 499 }
philpem@48 500 }
philpem@48 501