src/wd279x.c

Tue, 15 Nov 2011 10:12:37 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 15 Nov 2011 10:12:37 +0000
changeset 109
2f8afb9e5baa
parent 79
674226015c8a
child 111
4c85846b09cd
permissions
-rw-r--r--

[musashi] Fix handling of bus errors

Patch-Author: Andrew Warkentin <andreww591!gmail>
Patch-MessageID: <4EC200CE.2020304@gmail.com>

I have fixed the first page fault test failure in FreeBee (the page fault test now hangs rather than errors out, because it is trying to read from the hard drive to test DMA page faults).

There were actually two bugs (the first bug was masking the second one).

First, the ancient version of Musashi that you used is unable to properly resume from bus errors that happen in the middle of certain instructions (some instructions are fetched in stages, with the PC being advanced to each part of the instruction, so basically what happens is the CPU core attempts to read the memory location referenced by the first operand, the bus error occurs, causing the PC to jump to the exception vector, but the faulting instruction is still in the middle of being fetched, so the PC is then advanced past the beginning of the exception handler). I fixed this by delaying the jump to the bus error vector until after the faulting instruction finishes.

The second bug is simpler - you had the UDS and LDS bits in BSR0 inverted (they are supposed to be active low).

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