src/wd2010.c

Wed, 13 Mar 2013 01:10:34 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 13 Mar 2013 01:10:34 +0000
branch
experimental_memory_mapper_v2
changeset 135
159f937af10d
parent 132
8a7dc9b5b1db
parent 134
b826697f411a
child 145
2d6de28c6e6c
permissions
-rw-r--r--

merge changes from default

philpem@112 1 #include <stdint.h>
philpem@112 2 #include <stdbool.h>
philpem@112 3 #include <malloc.h>
philpem@112 4 #include "SDL.h"
philpem@112 5 #include "musashi/m68k.h"
philpem@112 6 #include "wd2010.h"
philpem@112 7
philpem@112 8 #define WD2010_DEBUG
philpem@112 9
philpem@112 10 #ifndef WD2010_DEBUG
philpem@112 11 #define NDEBUG
philpem@112 12 #endif
philpem@112 13 #include "utils.h"
philpem@112 14
philpem@126 15 #ifndef WD2010_SEEK_DELAY
philpem@126 16 #define WD2010_SEEK_DELAY 30
philpem@126 17 #endif
philpem@112 18
philpem@112 19 #define CMD_ENABLE_RETRY 0x01
philpem@112 20 #define CMD_LONG_MODE 0x02
philpem@112 21 #define CMD_MULTI_SECTOR 0x04
philpem@112 22 #define CMD_INTRQ_WHEN_COMPLETE 0x08
philpem@112 23
philpem@112 24 #define ER_BAD_BLOCK 0x80
philpem@112 25 #define ER_CRC 0x40
philpem@112 26 #define ER_ID_NOT_FOUND 0x10
philpem@112 27 #define ER_ABORTED_COMMAND 0x04
philpem@112 28 #define ER_NO_TK0 0x02
philpem@112 29 #define ER_NO_ADDRESS_MARK 0x01
philpem@112 30
philpem@112 31 #define SR_BUSY 0x80
philpem@112 32 #define SR_READY 0x40
philpem@112 33 #define SR_WRITE_FAULT 0x20
philpem@112 34 #define SR_SEEK_COMPLETE 0x10
philpem@112 35 #define SR_DRQ 0x08
philpem@112 36 #define SR_CORRECTED 0x04
philpem@112 37 #define SR_COMMAND_IN_PROGRESS 0x02
philpem@112 38 #define SR_ERROR 0x01
philpem@112 39
philpem@112 40 extern int cpu_log_enabled;
philpem@112 41
philpem@112 42 /// WD2010 command constants
philpem@112 43 enum {
philpem@112 44 CMD_MASK = 0xF0, ///< Bit mask to detect command bits
philpem@112 45 CMD_2010_EXT = 0x00, ///< WD2010 extended commands (compute correction, set parameter)
philpem@112 46 CMD_RESTORE = 0x10, ///< Restore (recalibrate, seek to track 0)
philpem@112 47 CMD_READ_SECTOR = 0x20, ///< Read sector
philpem@112 48 CMD_WRITE_SECTOR = 0x30, ///< Write sector
philpem@112 49 CMD_SCAN_ID = 0x40, ///< Scan ID
philpem@112 50 CMD_WRITE_FORMAT = 0x50, ///< Write format
philpem@112 51 CMD_SEEK = 0x70, ///< Seek to given track
philpem@112 52 };
philpem@112 53
philpem@112 54 int wd2010_init(WD2010_CTX *ctx, FILE *fp, int secsz, int spt, int heads)
philpem@112 55 {
philpem@122 56 size_t filesize;
philpem@122 57
philpem@112 58 wd2010_reset(ctx);
philpem@122 59
philpem@112 60 // Start by finding out how big the image file is
philpem@112 61 fseek(fp, 0, SEEK_END);
philpem@112 62 filesize = ftell(fp);
philpem@112 63 fseek(fp, 0, SEEK_SET);
philpem@112 64
philpem@112 65 // Now figure out how many tracks it contains
philpem@122 66 unsigned int tracks = filesize / secsz / spt / heads;
philpem@112 67 // Confirm...
philpem@112 68 if (tracks < 1) {
philpem@112 69 return WD2010_ERR_BAD_GEOM;
philpem@112 70 }
philpem@112 71
philpem@122 72 LOG("WD2010 initialised, %d cylinders, %d heads, %d sectors per track", tracks, heads, spt);
philpem@122 73
philpem@112 74 // Allocate enough memory to store one disc track
philpem@112 75 if (ctx->data) {
philpem@112 76 free(ctx->data);
philpem@112 77 }
philpem@112 78 ctx->data = malloc(secsz * spt);
philpem@112 79 if (!ctx->data)
philpem@112 80 return WD2010_ERR_NO_MEMORY;
philpem@112 81
philpem@112 82 // Load the image and the geometry data
philpem@112 83 ctx->disc_image = fp;
philpem@112 84 ctx->geom_tracks = tracks;
philpem@112 85 ctx->geom_secsz = secsz;
philpem@112 86 ctx->geom_heads = heads;
philpem@112 87 ctx->geom_spt = spt;
philpem@122 88
philpem@112 89 return WD2010_ERR_OK;
philpem@112 90 }
philpem@112 91
philpem@112 92 void wd2010_reset(WD2010_CTX *ctx)
philpem@112 93 {
philpem@112 94 // track, head and sector unknown
philpem@112 95 ctx->track = ctx->head = ctx->sector = 0;
philpem@112 96
philpem@112 97 // no IRQ pending
philpem@112 98 ctx->irq = false;
philpem@112 99
philpem@112 100 // no data available
philpem@112 101 ctx->data_pos = ctx->data_len = 0;
philpem@112 102
philpem@112 103 // Status register clear, not busy
philpem@112 104 ctx->status = 0;
philpem@112 105
philpem@112 106 ctx->sector_count = 0;
philpem@112 107 ctx->sector_number = 0;
philpem@112 108 ctx->cylinder_low_reg = 0;
philpem@112 109 ctx->cylinder_high_reg = 0;
philpem@112 110 ctx->sdh = 0;
philpem@116 111 ctx->mcr2_hdsel3 = 0;
philpem@116 112 ctx->mcr2_ddrive1 = 0;
philpem@112 113 }
philpem@112 114
philpem@112 115 void wd2010_done(WD2010_CTX *ctx)
philpem@112 116 {
philpem@112 117 // Reset the WD2010
philpem@112 118 wd2010_reset(ctx);
philpem@112 119
philpem@112 120 // Free any allocated memory
philpem@112 121 if (ctx->data) {
philpem@112 122 free(ctx->data);
philpem@112 123 ctx->data = NULL;
philpem@112 124 }
philpem@112 125 }
philpem@112 126
philpem@112 127
philpem@112 128 bool wd2010_get_irq(WD2010_CTX *ctx)
philpem@112 129 {
philpem@112 130 return ctx->irq;
philpem@112 131 }
philpem@112 132
philpem@112 133 bool wd2010_get_drq(WD2010_CTX *ctx)
philpem@112 134 {
philpem@112 135 return (ctx->drq && ctx->data_pos < ctx->data_len);
philpem@112 136 }
philpem@112 137
philpem@112 138 void wd2010_dma_miss(WD2010_CTX *ctx)
philpem@112 139 {
philpem@112 140 ctx->data_pos = ctx->data_len;
philpem@112 141 ctx->write_pos = 0;
philpem@112 142 ctx->status = SR_READY | SR_SEEK_COMPLETE;
philpem@112 143 ctx->irq = true;
philpem@112 144 }
philpem@112 145
philpem@112 146 uint8_t wd2010_read_data(WD2010_CTX *ctx)
philpem@112 147 {
philpem@112 148 // If there's data in the buffer, return it. Otherwise return 0xFF.
philpem@112 149 if (ctx->data_pos < ctx->data_len) {
philpem@123 150 if (ctx->multi_sector && (ctx->data_pos > 0) && ((ctx->data_pos % ctx->geom_secsz) == 0)){
philpem@112 151 ctx->sector_count--;
philpem@112 152 ctx->sector_number++;
philpem@112 153 }
philpem@112 154 // set IRQ if this is the last data byte
philpem@112 155 if (ctx->data_pos == (ctx->data_len-1)) {
philpem@112 156 ctx->status = SR_READY | SR_SEEK_COMPLETE;
philpem@112 157 // Set IRQ
philpem@112 158 ctx->irq = true;
philpem@112 159 ctx->drq = false;
philpem@112 160 }
philpem@112 161 // return data byte and increment pointer
philpem@112 162 return ctx->data[ctx->data_pos++];
philpem@112 163 } else {
philpem@112 164 // empty buffer (this shouldn't happen)
philpem@115 165 LOGS("WD2010: attempt to read from empty data buffer");
philpem@112 166 return 0xff;
philpem@112 167 }
philpem@112 168 }
philpem@112 169
philpem@112 170 void wd2010_write_data(WD2010_CTX *ctx, uint8_t val)
philpem@112 171 {
philpem@112 172 // If we're processing a write command, and there's space in the
philpem@112 173 // buffer, allow the write.
philpem@112 174 if (ctx->write_pos >= 0 && ctx->data_pos < ctx->data_len) {
philpem@112 175 // store data byte and increment pointer
philpem@123 176 if (ctx->multi_sector && (ctx->data_pos > 0) && ((ctx->data_pos % ctx->geom_secsz) == 0)){
philpem@112 177 ctx->sector_count--;
philpem@112 178 ctx->sector_number++;
philpem@112 179 }
philpem@112 180 ctx->data[ctx->data_pos++] = val;
philpem@112 181 // set IRQ and write data if this is the last data byte
philpem@112 182 if (ctx->data_pos == ctx->data_len) {
philpem@112 183 if (!ctx->formatting){
philpem@112 184 fseek(ctx->disc_image, ctx->write_pos, SEEK_SET);
philpem@112 185 fwrite(ctx->data, 1, ctx->data_len, ctx->disc_image);
philpem@112 186 fflush(ctx->disc_image);
philpem@112 187 }
philpem@112 188 ctx->formatting = false;
philpem@112 189 ctx->status = SR_READY | SR_SEEK_COMPLETE;
philpem@112 190 // Set IRQ and reset write pointer
philpem@112 191 ctx->irq = true;
philpem@112 192 ctx->write_pos = -1;
philpem@112 193 ctx->drq = false;
philpem@112 194 }
philpem@112 195 }else{
philpem@115 196 LOGS("WD2010: attempt to write to data buffer without a write command in progress");
philpem@112 197 }
philpem@112 198 }
philpem@112 199
philpem@112 200 uint32_t seek_complete(uint32_t interval, WD2010_CTX *ctx)
philpem@112 201 {
philpem@112 202 /*m68k_end_timeslice();*/
philpem@112 203 ctx->status = SR_READY | SR_SEEK_COMPLETE;
philpem@112 204 ctx->irq = true;
philpem@112 205 return (0);
philpem@112 206 }
philpem@112 207
philpem@112 208 uint32_t transfer_seek_complete(uint32_t interval, WD2010_CTX *ctx)
philpem@112 209 {
philpem@112 210 /*m68k_end_timeslice();*/
philpem@112 211 ctx->drq = true;
philpem@112 212 return (0);
philpem@112 213 }
philpem@112 214
philpem@112 215 uint8_t wd2010_read_reg(WD2010_CTX *ctx, uint8_t addr)
philpem@112 216 {
philpem@112 217 uint8_t temp = 0;
philpem@112 218
philpem@112 219 /*cpu_log_enabled = 1;*/
philpem@112 220
philpem@112 221 switch (addr & 0x07) {
philpem@112 222 case WD2010_REG_ERROR:
philpem@112 223 return ctx->error_reg;
philpem@112 224 case WD2010_REG_SECTOR_COUNT:
philpem@112 225 return ctx->sector_count;
philpem@112 226 case WD2010_REG_SECTOR_NUMBER:
philpem@112 227 return ctx->sector_number;
philpem@112 228 case WD2010_REG_CYLINDER_HIGH: // High byte of cylinder
philpem@112 229 return ctx->cylinder_high_reg;
philpem@112 230 case WD2010_REG_CYLINDER_LOW: // Low byte of cylinder
philpem@112 231 return ctx->cylinder_low_reg;
philpem@112 232 case WD2010_REG_SDH:
philpem@112 233 return ctx->sdh;
philpem@112 234 case WD2010_REG_STATUS: // Status register
philpem@112 235 // Read from status register clears IRQ
philpem@112 236 ctx->irq = false;
philpem@112 237 // Get current status flags (set by last command)
philpem@112 238 // DRQ bit
philpem@112 239 if (ctx->cmd_has_drq) {
philpem@112 240 temp = ctx->status & ~(SR_BUSY & SR_DRQ);
philpem@112 241 temp |= (ctx->data_pos < ctx->data_len) ? SR_DRQ : 0;
philpem@112 242 LOG("\tWDFDC rd sr, has drq, pos=%lu len=%lu, sr=0x%02X", ctx->data_pos, ctx->data_len, temp);
philpem@112 243 } else {
philpem@112 244 temp = ctx->status & ~0x80;
philpem@112 245 }
philpem@112 246 /*XXX: where should 0x02 (command in progress) be set? should it be set here instead of 0x80 (busy)?*/
philpem@112 247 // HDC is busy if there is still data in the buffer
philpem@112 248 temp |= (ctx->data_pos < ctx->data_len) ? SR_BUSY : 0; // if data in buffer, then DMA hasn't copied it yet, and we're still busy!
philpem@112 249 // TODO: also if seek delay / read delay hasn't passed (but that's for later)
philpem@112 250 /*XXX: should anything else be set here?*/
philpem@112 251 return temp;
philpem@112 252 default:
philpem@112 253 // shut up annoying compilers which don't recognise unreachable code when they see it
philpem@112 254 // (here's looking at you, gcc!)
philpem@112 255 return 0xff;
philpem@112 256 }
philpem@112 257 }
philpem@112 258
philpem@112 259
philpem@112 260 void wd2010_write_reg(WD2010_CTX *ctx, uint8_t addr, uint8_t val)
philpem@112 261 {
philpem@112 262 uint8_t cmd = val & CMD_MASK;
philpem@112 263 size_t lba;
philpem@112 264 int new_track;
philpem@112 265 int sector_count;
philpem@128 266 unsigned int ssz;
philpem@112 267
philpem@112 268 m68k_end_timeslice();
philpem@112 269
philpem@112 270 /*cpu_log_enabled = 1;*/
philpem@112 271
philpem@116 272 if (addr == UNIXPC_REG_MCR2) {
philpem@116 273 // The UNIX PC has an "MCR2" register with the following format:
philpem@116 274 // [ 7..2 ][1][0]
philpem@116 275 // Bits 7..2: Not used
philpem@116 276 // Bit 1: DDRIVE1 (hard disk drive 1 select - not used?)
philpem@116 277 // Bit 0: HDSEL3 (head-select bit 3)
philpem@116 278 ctx->mcr2_hdsel3 = ((val & 1) == 1);
philpem@116 279 ctx->mcr2_ddrive1 = ((val & 2) == 2);
philpem@116 280 return;
philpem@116 281 }
philpem@116 282
philpem@112 283 switch (addr & 0x07) {
philpem@112 284 case WD2010_REG_WRITE_PRECOMP_CYLINDER:
philpem@112 285 break;
philpem@112 286 case WD2010_REG_SECTOR_COUNT:
philpem@112 287 ctx->sector_count = val;
philpem@112 288 break;
philpem@112 289 case WD2010_REG_SECTOR_NUMBER:
philpem@112 290 ctx->sector_number = val;
philpem@112 291 break;
philpem@112 292 case WD2010_REG_CYLINDER_HIGH: // High byte of cylinder
philpem@112 293 ctx->cylinder_high_reg = val;
philpem@112 294 break;
philpem@112 295 case WD2010_REG_CYLINDER_LOW: // Low byte of cylinder
philpem@112 296 ctx->cylinder_low_reg = val;
philpem@112 297 break;
philpem@112 298 case WD2010_REG_SDH:
philpem@112 299 /*XXX: remove this once the DMA page fault test passes (unless this is actually the correct behavior here)*/
philpem@130 300 //ctx->data_pos = ctx->data_len = 0;
philpem@112 301 ctx->sdh = val;
philpem@112 302 break;
philpem@112 303 case WD2010_REG_COMMAND: // Command register
philpem@112 304 // write to command register clears interrupt request
philpem@112 305 ctx->irq = false;
philpem@112 306 ctx->error_reg = 0;
philpem@112 307
philpem@112 308 /*cpu_log_enabled = 1;*/
philpem@112 309 switch (cmd) {
philpem@112 310 case CMD_RESTORE:
philpem@112 311 // Restore. Set track to 0 and throw an IRQ.
philpem@112 312 ctx->track = 0;
philpem@126 313 SDL_AddTimer(WD2010_SEEK_DELAY, (SDL_NewTimerCallback)seek_complete, ctx);
philpem@112 314 break;
philpem@112 315 case CMD_SCAN_ID:
philpem@112 316 ctx->cylinder_high_reg = (ctx->track >> 8) & 0xff;
philpem@112 317 ctx->cylinder_low_reg = ctx->track & 0xff;
philpem@112 318 ctx->sector_number = ctx->sector;
philpem@112 319 ctx->sdh = (ctx->sdh & ~7) | (ctx->head & 7);
philpem@112 320 case CMD_WRITE_FORMAT:
philpem@112 321 case CMD_SEEK:
philpem@112 322 case CMD_READ_SECTOR:
philpem@112 323 case CMD_WRITE_SECTOR:
philpem@112 324 // Seek. Seek to the track specced in the cylinder
philpem@112 325 // registers.
philpem@112 326 new_track = (ctx->cylinder_high_reg << 8) | ctx->cylinder_low_reg;
philpem@112 327 if (new_track < ctx->geom_tracks) {
philpem@112 328 ctx->track = new_track;
philpem@112 329 } else {
philpem@112 330 // Seek error. :(
philpem@112 331 ctx->status = SR_ERROR;
philpem@112 332 ctx->error_reg = ER_ID_NOT_FOUND;
philpem@112 333 ctx->irq = true;
philpem@112 334 break;
philpem@112 335 }
philpem@116 336 // The SDH register provides 3 head select bits; the 4th comes from MCR2.
philpem@116 337 ctx->head = (ctx->sdh & 0x07) + (ctx->mcr2_hdsel3 ? 8 : 0);
philpem@112 338 ctx->sector = ctx->sector_number;
philpem@112 339
philpem@112 340 ctx->formatting = cmd == CMD_WRITE_FORMAT;
philpem@112 341 switch (cmd){
philpem@112 342 case CMD_SEEK:
philpem@126 343 SDL_AddTimer(WD2010_SEEK_DELAY, (SDL_NewTimerCallback)seek_complete, ctx);
philpem@112 344 break;
philpem@112 345 case CMD_READ_SECTOR:
philpem@112 346 /*XXX: does a separate function to set the head have to be added?*/
philpem@128 347 LOG("WD2010: READ SECTOR cmd=%02X sdh=0x%02X drive=%d ddrive1=%d chs=%d:%d:%d nsectors=%d", cmd, ctx->sdh, (ctx->sdh >> 3) & 3, ctx->mcr2_ddrive1, ctx->track, ctx->head, ctx->sector, val&CMD_MULTI_SECTOR ? ctx->sector_count : 1);
philpem@128 348
philpem@128 349 switch ((ctx->sdh >> 5) & 0x03) {
philpem@128 350 case 0: ssz = 256; break;
philpem@128 351 case 1: ssz = 512; break;
philpem@128 352 case 2: ssz = 1024; break;
philpem@128 353 case 3: ssz = 128; break;
philpem@128 354 }
philpem@128 355 if (ssz != ctx->geom_secsz)
philpem@128 356 LOG("WARNING: Geometry mismatch. WD2010 Write Sector with secsz %d != phys_secsz %d.", ssz, ctx->geom_secsz);
philpem@112 357
philpem@112 358 // Read Sector
philpem@112 359
philpem@112 360 // Check to see if the cyl, hd and sec are valid
philpem@128 361 if ((ctx->track > (ctx->geom_tracks-1)) || (ctx->head > (ctx->geom_heads-1)) || ((ctx->sector + ctx->sector_count - 1) > ctx->geom_spt-1) || (ssz != ctx->geom_secsz)) {
philpem@128 362 LOG("*** WD2010 ALERT: CHS parameter limit exceeded! dDrive1=%d CHS=%d:%d:%d, nSecs=%d, endSec=%d maxCHS=%d:%d:%d",
philpem@128 363 ctx->mcr2_ddrive1,
philpem@112 364 ctx->track, ctx->head, ctx->sector,
philpem@125 365 ctx->sector_count,
philpem@125 366 ctx->sector + ctx->sector_count - 1,
philpem@125 367 ctx->geom_tracks-1, ctx->geom_heads-1, ctx->geom_spt);
philpem@112 368 // CHS parameters exceed limits
philpem@112 369 ctx->status = SR_ERROR;
philpem@112 370 ctx->error_reg = ER_ID_NOT_FOUND;
philpem@112 371 // Set IRQ
philpem@112 372 ctx->irq = true;
philpem@112 373 break;
philpem@112 374 }
philpem@112 375
philpem@112 376 // reset data pointers
philpem@112 377 ctx->data_pos = ctx->data_len = 0;
philpem@112 378
philpem@112 379 if (val & CMD_MULTI_SECTOR){
philpem@112 380 ctx->multi_sector = 1;
philpem@112 381 sector_count = ctx->sector_count;
philpem@112 382 }else{
philpem@112 383 ctx->multi_sector = 0;
philpem@112 384 sector_count = 1;
philpem@112 385 }
philpem@112 386 for (int i=0; i<sector_count; i++) {
philpem@112 387 // Calculate the LBA address of the required sector
philpem@112 388 // LBA = (C * nHeads * nSectors) + (H * nSectors) + S - 1
philpem@112 389 lba = (((ctx->track * ctx->geom_heads * ctx->geom_spt) + (ctx->head * ctx->geom_spt) + ctx->sector) + i);
philpem@112 390 // convert LBA to byte address
philpem@112 391 lba *= ctx->geom_secsz;
philpem@112 392 LOG("\tREAD lba = %lu", lba);
philpem@112 393
philpem@112 394 // Read the sector from the file
philpem@112 395 fseek(ctx->disc_image, lba, SEEK_SET);
philpem@112 396 // TODO: check fread return value! if < secsz, BAIL! (call it a crc error or secnotfound maybe? also log to stderr)
philpem@112 397 ctx->data_len += fread(&ctx->data[ctx->data_len], 1, ctx->geom_secsz, ctx->disc_image);
philpem@112 398 LOG("\tREAD len=%lu, pos=%lu, ssz=%d", ctx->data_len, ctx->data_pos, ctx->geom_secsz);
philpem@112 399 }
philpem@112 400
philpem@112 401 ctx->status = 0;
philpem@112 402 ctx->status |= (ctx->data_pos < ctx->data_len) ? SR_DRQ | SR_COMMAND_IN_PROGRESS | SR_BUSY : 0x00;
philpem@126 403 SDL_AddTimer(WD2010_SEEK_DELAY, (SDL_NewTimerCallback)transfer_seek_complete, ctx);
philpem@112 404
philpem@112 405 break;
philpem@112 406 case CMD_WRITE_FORMAT:
philpem@112 407 ctx->sector = 0;
philpem@112 408 case CMD_WRITE_SECTOR:
philpem@128 409 LOG("WD2010: WRITE SECTOR cmd=%02X sdh=0x%02X drive=%d ddrive1=%d chs=%d:%d:%d nsectors=%d", cmd, ctx->sdh, (ctx->sdh >> 3) & 3, ctx->mcr2_ddrive1, ctx->track, ctx->head, ctx->sector, val&CMD_MULTI_SECTOR ? ctx->sector_count : 1);
philpem@124 410 // Write Sector
philpem@112 411
philpem@128 412 switch ((ctx->sdh >> 5) & 0x03) {
philpem@128 413 case 0: ssz = 256; break;
philpem@128 414 case 1: ssz = 512; break;
philpem@128 415 case 2: ssz = 1024; break;
philpem@128 416 case 3: ssz = 128; break;
philpem@128 417 }
philpem@128 418 if (ssz != ctx->geom_secsz)
philpem@128 419 LOG("WARNING: Geometry mismatch. WD2010 Write Sector with secsz %d != phys_secsz %d.", ssz, ctx->geom_secsz);
philpem@128 420
philpem@112 421 // Check to see if the cyl, hd and sec are valid
philpem@135 422 if ((cmd != CMD_WRITE_FORMAT) && ((ctx->track > (ctx->geom_tracks-1)) || (ctx->head > (ctx->geom_heads-1)) || ((ctx->sector + ctx->sector_count - 1) > ctx->geom_spt-1) || (ssz != ctx->geom_secsz))) {
philpem@128 423 LOG("*** WD2010 ALERT: CHS parameter limit exceeded! dDrive1=%d CHS=%d:%d:%d, nSecs=%d, endSec=%d maxCHS=%d:%d:%d",
philpem@128 424 ctx->mcr2_ddrive1,
philpem@112 425 ctx->track, ctx->head, ctx->sector,
philpem@125 426 ctx->sector_count,
philpem@125 427 ctx->sector + ctx->sector_count - 1,
philpem@112 428 ctx->geom_tracks-1, ctx->geom_heads-1, ctx->geom_spt);
philpem@112 429 // CHS parameters exceed limits
philpem@112 430 ctx->status = SR_ERROR;
philpem@112 431 ctx->error_reg = ER_ID_NOT_FOUND;
philpem@112 432 // Set IRQ
philpem@112 433 ctx->irq = true;
philpem@112 434 break;
philpem@112 435 }
philpem@112 436
philpem@112 437 // reset data pointers
philpem@112 438 ctx->data_pos = ctx->data_len = 0;
philpem@112 439
philpem@112 440 if (val & CMD_MULTI_SECTOR){
philpem@112 441 ctx->multi_sector = 1;
philpem@112 442 sector_count = ctx->sector_count;
philpem@112 443 }else{
philpem@112 444 ctx->multi_sector = 0;
philpem@112 445 sector_count = 1;
philpem@112 446 }
philpem@112 447 ctx->data_len = ctx->geom_secsz * sector_count;
philpem@112 448 lba = (((ctx->track * ctx->geom_heads * ctx->geom_spt) + (ctx->head * ctx->geom_spt) + ctx->sector));
philpem@112 449 // convert LBA to byte address
philpem@124 450 ctx->write_pos = (lba *= ctx->geom_secsz);
philpem@124 451 LOG("\tWRITE lba = %zu", lba);
philpem@112 452
philpem@112 453 ctx->status = 0;
philpem@112 454 ctx->status |= (ctx->data_pos < ctx->data_len) ? SR_DRQ | SR_COMMAND_IN_PROGRESS | SR_BUSY : 0x00;
philpem@126 455 SDL_AddTimer(WD2010_SEEK_DELAY, (SDL_NewTimerCallback)transfer_seek_complete, ctx);
philpem@112 456
philpem@112 457 break;
philpem@112 458 default:
philpem@112 459 LOG("WD2010: invalid seeking command %x (this shouldn't happen!)\n", cmd);
philpem@112 460 break;
philpem@112 461 }
philpem@112 462 break;
philpem@112 463 case CMD_2010_EXT: /* not implemented */
philpem@112 464 default:
philpem@112 465 LOG("WD2010: unknown command %x\n", cmd);
philpem@112 466 ctx->status = SR_ERROR;
philpem@112 467 ctx->error_reg = ER_ABORTED_COMMAND;
philpem@112 468 ctx->irq = true;
philpem@112 469 break;
philpem@112 470 }
philpem@112 471 break;
philpem@112 472
philpem@112 473 }
philpem@112 474 }
philpem@112 475