fdc.cpp
1 /* 2 * Castaway 3 * (C) 1994 - 2002 Martin Doering, Joachim Hoenig 4 * 5 * fdc.c - wd1772/dma emulation 6 * 7 * This file is distributed under the GPL, version 2 or at your 8 * option any later version. See doc/license.txt for details. 9 * 10 * revision history 11 * 23.05.2002 0.02.00 JH FAST1.0.1 code import: KR -> ANSI, restructuring 12 * 09.06.2002 0.02.00 JH Renamed io.c to st.c again (io.h conflicts with system headers) 13 */ 14 15 #include <Arduino.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include "dcastaway.h" 20 #include "st.h" 21 #include "mem.h" 22 #include "m68k_intrf.h" 23 24 #include "emuapi.h" 25 26 27 #define DISKNULL \ 28 "\0\0\0\0\0\0\0\0\0\0" \ 29 "\0\0\0\0\0\0\0\0\0\0" \ 30 "\0\0\0\0\0\0\0\0\0\0" \ 31 "\0\0\0\0\0\0\0\0\0\0" \ 32 "\0\0\0\0\0\0\0\0\0\0" \ 33 "\0\0\0\0\0\0\0\0\0\0" \ 34 "\0\0\0\0\0\0\0\0\0\0" \ 35 "\0\0\0\0\0\0\0\0\0" 36 37 38 39 /* 40 * FDC Registers 41 */ 42 unsigned char fdc_data, fdc_track, fdc_sector, fdc_status, fdc_command, fdc_motor; 43 unsigned char fdc_int = 0; 44 45 static char fdcdir=1; 46 static int fdc_commands_executed=0; 47 static unsigned char disk_ejected[2]={0,1}; 48 static unsigned char disk_changed[2]; 49 static int discpos[2]; 50 51 struct Disk disk[2] = { 52 { NULL, DISKNULL, 0, SIDES, TRACKS, SECTORS, SECSIZE }, 53 { NULL, DISKNULL, 0, SIDES, TRACKS, SECTORS, SECSIZE }, 54 }; 55 56 57 PROGMEM static void SetMemBBB (unsigned long address, unsigned char value) { 58 address &= MEMADDRMASK; 59 WriteB(address + membase, value); 60 } 61 62 PROGMEM static unsigned char GetMemBBB (unsigned long address) { 63 address &= MEMADDRMASK; 64 return (ReadB(address + membase)); 65 } 66 67 PROGMEM int discread(unsigned long address,int len,int discn) 68 { 69 int i; 70 int totlen = len; 71 unsigned char buf[256]; 72 while (totlen>=256) { 73 emu_FileRead(buf,256, disk[discn].file); 74 totlen -= 256; 75 for (i=0; i<256; i++) { 76 SetMemBBB(address, buf[i]); 77 address++; 78 } 79 } 80 if (totlen) { 81 emu_FileRead(buf,totlen, disk[discn].file); 82 for (i=0; i<totlen; i++) { 83 SetMemBBB(address, buf[i]); 84 address++; 85 } 86 } 87 discpos[discn]=discpos[discn]+len; 88 89 emu_FileClose(disk[discn].file); 90 disk[discn].file = emu_FileOpen(disk[discn].name,"a+rw"); 91 emu_FileSeek(disk[discn].file,discpos[discn],SEEK_SET); 92 return len; 93 } 94 95 PROGMEM int discwrite(unsigned long address, int len,int discn) 96 { 97 int i; 98 int totlen = len; 99 unsigned char buf[256]; 100 101 while (totlen>=256) { 102 for (i=0; i<256; i++) { 103 buf[i] = GetMemBBB(address); 104 address++; 105 } 106 emu_FileWrite(buf,256, disk[discn].file); 107 totlen -= 256; 108 } 109 if (totlen) { 110 for (i=0; i<totlen; i++) { 111 buf[i] = GetMemBBB(address); 112 address++; 113 } 114 emu_FileWrite(buf,totlen, disk[discn].file); 115 } 116 discpos[discn]=discpos[discn]+len; 117 118 emu_FileClose(disk[discn].file); 119 disk[discn].file = emu_FileOpen(disk[discn].name,"a+rw"); 120 emu_FileSeek(disk[discn].file,discpos[discn],SEEK_SET); 121 return len; 122 } 123 124 int discseek(int discn,int pos) 125 { 126 if (pos>(1050*1024)){ 127 return -1; 128 } 129 discpos[discn]=pos; 130 if (disk[discn].file) emu_FileSeek(disk[discn].file,pos,SEEK_SET); 131 return 0; 132 } 133 134 135 PROGMEM int FDCInit(int i) 136 { 137 int len2,calcsides,calcsectors,calctracks,badbootsector; 138 139 discpos[i]=0; 140 141 int len = emu_FileSize(disk[i].name); 142 143 disk[i].file = emu_FileOpen(disk[i].name,"a+rw"); 144 disk[i].disksize = len; 145 146 unsigned char buf[256]; 147 if (disk[i].file) { 148 emu_FileRead(buf, 256, disk[i].file); 149 emu_FileSeek(disk[i].file,0,SEEK_SET); 150 } 151 152 disk[i].head = 0; 153 disk[i].sides = (int) *(buf + 26); 154 disk[i].sectors = (int) *(buf + 24); 155 disk[i].secsize = 512; //(int) ((*(buf + 12) << 8) | *(buf + 11)); 156 157 if (disk[i].sectors * disk[i].sides) { 158 disk[i].tracks = (int) ((*(buf + 20) << 8) | *(buf + 19)) / (disk[i].sectors * disk[i].sides); 159 } 160 161 // Second Check more precise 162 if (len> (500*1024)) calcsides = 2; 163 else calcsides = 1; 164 165 if (!(((len/calcsides)/512)%9)&&(((len/calcsides)/512)/9)<86) calcsectors=9; 166 else if (!(((len/calcsides)/512)%10)&&(((len/calcsides)/512)/10)<86) calcsectors=10; 167 else if (!(((len/calcsides)/512)%11)&&(((len/calcsides)/512)/11)<86) calcsectors=11; 168 else if (!(((len/calcsides)/512)%12)) calcsectors=12; 169 calctracks =((len/calcsides)/512)/calcsectors; 170 171 if (disk[i].sides!=calcsides||disk[i].sectors!=calcsectors||disk[i].tracks!=calctracks){ 172 if (disk[i].sides==calcsides&&disk[i].sectors==calcsectors){ 173 disk[i].tracks=calctracks; 174 badbootsector=0; 175 }else{ 176 disk[i].sides=calcsides; 177 disk[i].tracks=calctracks; 178 disk[i].sectors=calcsectors; 179 badbootsector=(i<<24)|(calcsides<<16)|(calctracks<<8)|(calcsectors); 180 } 181 182 }else{ 183 badbootsector=0; 184 } 185 disk_ejected[i]=0; 186 disk_changed[i]=1; 187 fdc_status |= 0x40; 188 disk[i].head = 0; 189 fdc_track = 0; 190 191 return badbootsector; 192 } 193 194 PROGMEM void FDCchange(int i){ 195 disk[(i>>24)&0xff].sides=(i>>16)&0xff; 196 disk[(i>>24)&0xff].tracks=(i>>8)&0xff; 197 disk[(i>>24)&0xff].sectors=i&0xff; 198 } 199 200 PROGMEM void FDCeject(int num){ 201 int i; 202 203 disk[num].file = NULL; 204 sprintf(disk[num].name,"disk%01d",num); 205 disk[num].sides = SIDES; 206 disk[num].tracks = TRACKS; 207 disk[num].sectors = SECTORS; 208 disk[num].secsize = 512; 209 disk_ejected[num]=1; 210 fdc_status |= 0x40; 211 } 212 213 PROGMEM void FDCCommand(void) 214 { 215 static char motor = 1; 216 int sides, drives; 217 long address; /* dma target/source address */ 218 long offset; /* offset in disk file */ 219 unsigned long count; /* number of byte to transfer */ 220 int n; 221 222 if (fdc_commands_executed<64) 223 fdc_commands_executed++; 224 /* DMA target/source address */ 225 address = (dma_adrh << 16) + (dma_adrm << 8) + dma_adrl; 226 /* 227 if (address>MEMSIZE) { 228 fdc_status |= 0x10; 229 return; 230 } 231 */ 232 233 /* status of side select and drive select lines */ 234 sides = (~psg[14]) & 0x1; 235 drives = (~psg[14]) & 0x6; 236 if (disk_ejected[drives>>2]==1) drives=2; 237 238 switch (drives) 239 { 240 case 2: /* Drive A */ 241 drives = 0; 242 break; 243 case 4: /* Drive B */ 244 drives = 1; 245 break; 246 case 6: /* both, error */ 247 case 0: /* no drive selected */ 248 drives = -1; 249 break; 250 } 251 252 fdc_status = 0; /* clear fdc status */ 253 if (fdc_command < 0x80) { /* TYPE-I fdc commands */ 254 if (drives >= 0) { /* drive selected */ 255 switch (fdc_command & 0xf0) { 256 case 0x00: /* RESTORE */ 257 disk[drives].head = 0; 258 fdc_track = 0; 259 break; 260 case 0x10: /* SEEK */ 261 disk[drives].head += (fdc_data - fdc_track); 262 fdc_track = fdc_data; 263 if (disk[drives].head < 0 || disk[drives].head >= disk[drives].tracks) 264 disk[drives].head = 0; 265 break; 266 case 0x30: /* STEP */ 267 fdc_track += fdcdir; 268 case 0x20: 269 disk[drives].head += fdcdir; 270 break; 271 case 0x50: /* STEP-IN */ 272 fdc_track++; 273 case 0x40: 274 if (disk[drives].head < disk[drives].tracks) 275 disk[drives].head++; 276 fdcdir = 1; 277 break; 278 case 0x70: /* STEP-OUT */ 279 fdc_track--; 280 case 0x60: 281 if (disk[drives].head > 0) 282 disk[drives].head--; 283 fdcdir = -1; 284 break; 285 } 286 287 if (disk[drives].head == 0) { 288 fdc_status |= 0x4; 289 } 290 if (disk[drives].head != fdc_track && fdc_command & 0x4) { /* Verify? */ 291 fdc_status |= 0x10; 292 } 293 if (motor) { 294 fdc_status |= 0x20; /* spin-up flag */ 295 } 296 } 297 else { /* no drive selected */ 298 fdc_status |= 0x10; 299 } 300 } 301 302 else if ((fdc_command & 0xf0) == 0xd0) { /* FORCE INTERRUPT */ 303 if (fdc_command == 0xd8) 304 { 305 fdc_int = 1; 306 } else if (fdc_command == 0xd0) 307 { 308 fdc_int = 0; 309 } 310 } 311 312 else { /* OTHERS */ 313 if (drives >= 0) { /* drive selected */ 314 /* offset within floppy-file */ 315 offset = disk[drives].secsize * (((disk[drives].sectors * disk[drives].sides * disk[drives].head)) + (disk[drives].sectors * sides) + (fdc_sector - 1)); 316 switch (fdc_command & 0xf0) 317 { 318 case 0x80: /* READ SECTOR */ 319 count = 512; 320 if (!discseek (drives, offset)) 321 { 322 if (address<MEMSIZE) 323 { 324 if (count == discread (address, count, drives)) 325 { 326 address += count; 327 dma_adrl = address & 0xff; 328 dma_adrm = (address >> 8) & 0xff; 329 dma_adrh = (address >> 16) & 0xff; 330 dma_scr = 0; 331 dma_sr = 1; 332 break; 333 } 334 } 335 else 336 { 337 address += count; 338 dma_adrl = address & 0xff; 339 dma_adrm = (address >> 8) & 0xff; 340 dma_adrh = (address >> 16) & 0xff; 341 dma_scr = 0; 342 dma_sr = 1; 343 mfp_gpip |= 0x20; 344 fdc_status |= 0x1; 345 break; 346 } 347 } 348 fdc_status |= 0x10; 349 dma_sr = 1; 350 break; 351 352 case 0x90: /* READ SECTOR multiple */ 353 count = dma_scr * 512; 354 if (count+(fdc_sector-1)*512>disk[drives].sectors*512) count=disk[drives].sectors*512-(fdc_sector-1)*512; 355 if (!discseek (drives, offset)) 356 { 357 if (address<MEMSIZE) 358 { 359 if (count == discread (address, count, drives)) 360 { 361 address += count; 362 dma_adrl = address & 0xff; 363 dma_adrm = (address >> 8) & 0xff; 364 dma_adrh = (address >> 16) & 0xff; 365 dma_scr = 0; 366 dma_sr = 1; 367 fdc_sector += count/disk[drives].secsize; 368 break; 369 } 370 } 371 else 372 { 373 address += count; 374 dma_adrl = address & 0xff; 375 dma_adrm = (address >> 8) & 0xff; 376 dma_adrh = (address >> 16) & 0xff; 377 dma_scr = 0; 378 dma_sr = 1; 379 mfp_gpip |= 0x20; 380 fdc_status |= 0x1; 381 break; 382 } 383 } 384 fdc_status |= 0x10; 385 dma_sr = 1; 386 break; 387 388 case 0xa0: /* WRITE SECTOR */ 389 count = dma_scr * 512; 390 if (!discseek (drives, offset)) { 391 if (count == discwrite (address, count, drives)) 392 { 393 address += count; 394 dma_adrl = address & 0xff; 395 dma_adrm = (address >> 8) & 0xff; 396 dma_adrh = (address >> 16) & 0xff; 397 dma_scr = 0; 398 dma_sr = 1; 399 break; 400 } 401 } 402 fdc_status |= 0x10; 403 dma_sr = 1; 404 break; 405 406 case 0xb0: /* WRITE SECTOR multiple */ 407 count = dma_scr * 512; 408 if (!discseek (drives, offset)) 409 { 410 if (count == discwrite (address, count, drives)) { 411 address += count; 412 dma_adrl = address & 0xff; 413 dma_adrm = (address >> 8) & 0xff; 414 dma_adrh = (address >> 16) & 0xff; 415 dma_scr = 0; 416 dma_sr = 1; 417 fdc_sector += dma_scr * (512 / disk[drives].secsize); 418 break; 419 } 420 } 421 fdc_status |= 0x10; 422 dma_sr = 1; 423 break; 424 425 case 0xc0: /* READ ADDRESS */ 426 fdc_status |= 0x10; 427 break; 428 429 case 0xe0: /* READ TRACK */ 430 count = disk[drives].sectors * 512; 431 offset = disk[drives].secsize * (((disk[drives].sectors * disk[drives].sides * disk[drives].head)) + (disk[drives].sectors * sides)); 432 if (!discseek (drives, offset)) 433 { 434 if (address<MEMSIZE) 435 { 436 if (dma_scr==0x1f) 437 { 438 count=0; 439 address += 302; 440 } 441 if (count == discread (address, count, drives)) 442 { 443 dma_adrl = address & 0xff; 444 dma_adrm = (address >> 8) & 0xff; 445 dma_adrh = (address >> 16) & 0xff; 446 dma_scr = 0; 447 dma_sr = 1; 448 break; 449 } 450 } 451 else 452 { 453 address += 302; 454 dma_adrl = address & 0xff; 455 dma_adrm = (address >> 8) & 0xff; 456 dma_adrh = (address >> 16) & 0xff; 457 dma_scr = 0; 458 dma_sr = 1; 459 mfp_gpip |= 0x20; 460 fdc_status |= 0x1; 461 break; 462 } 463 } 464 fdc_status |= 0x10; 465 dma_sr = 1; 466 break; 467 468 case 0xf0: /* WRITE TRACK */ 469 fdc_status |= 0x10; 470 break; 471 } 472 473 if (disk[drives].head != fdc_track) 474 { 475 fdc_status |= 0x10; 476 } 477 } 478 else 479 { 480 fdc_status |= 0x10; /* no drive selected */ 481 } 482 } 483 484 if (motor) 485 { 486 fdc_status |= 0x80; /* motor on flag */ 487 fdc_motor=1; 488 } 489 if (!(fdc_status & 0x01)) 490 { /* not busy */ 491 mfp_iprb |= (0x80 & mfp_ierb); /* Request Interrupt */ 492 mfp_gpip &= ~0x20; 493 } 494 }