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 static char sccsid[] = "$Id: fdc.c,v 1.2 2002/06/08 23:31:58 jhoenig Exp $"; 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 #include "diskapi.h" 26 27 28 //#define MEMDISC 1 29 #define DISK 1 30 31 #define DISKNULL \ 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\0" \ 36 "\0\0\0\0\0\0\0\0\0\0" \ 37 "\0\0\0\0\0\0\0\0\0\0" \ 38 "\0\0\0\0\0\0\0\0\0\0" \ 39 "\0\0\0\0\0\0\0\0\0" 40 41 int fdc_commands_executed=0; 42 43 44 /* 45 * FDC Registers 46 */ 47 extern int readdsk; 48 unsigned char fdc_data, fdc_track, fdc_sector, fdc_status, fdc_command, fdc_motor; 49 unsigned char fdc_int = 0; 50 char fdcdir=1; 51 unsigned char disk_ejected[2]={0,1}; 52 unsigned char disk_changed[2]; 53 struct Disk disk[2] = { 54 { NULL, DISKNULL, 0, SIDES, TRACKS, SECTORS, SECSIZE }, 55 { NULL, DISKNULL, 0, SIDES, TRACKS, SECTORS, SECSIZE }, 56 }; 57 58 typedef struct { 59 uint16 ID; // Word ID marker, should be $0E0F 60 uint16 SectorsPerTrack; // Word Sectors per track 61 uint16 Sides; // Word Sides (0 or 1; add 1 to this to get correct number of sides) 62 uint16 StartingTrack; // Word Starting track (0-based) 63 uint16 EndingTrack; // Word Ending track (0-based) 64 } MSAHEADERSTRUCT; 65 #define STMemory_Swap68000Int(val) ((val<<8)|(val>>8)) 66 67 68 unsigned char *disc[2]; 69 70 int discpos[2]; 71 72 //#define LOGGING 1 73 74 #ifdef LOGGING 75 //static FILE * log=NULL; 76 //#define LOG(format,val) if (!log) { \ 77 // log = fopen("log2.txt","wb"); \ 78 // } \ 79 // fprintf(log, "%s %d\n", format, val); 80 #define LOG(format,val) Serial.print(format); \ 81 Serial.println(val); 82 #else 83 #define LOG(format,va) 84 #endif 85 86 PROGMEM static void SetMemBBB (unsigned long address, unsigned char value) { 87 address &= MEMADDRMASK; 88 if (address<MEM1SIZE) 89 WriteB(address + membase, value); 90 else 91 WriteB(address-MEM1SIZE + membase2, value); 92 } 93 94 95 PROGMEM int discread(unsigned long address,int a,int len,int discn) 96 { 97 int i; 98 99 #ifdef MEMDISC 100 uint8 val1,val2,*dbuf; 101 uint8 *buf = (uint8 *)(membase + address); 102 dbuf=buf; 103 for (i=0;i<len;i++) *buf++=disc[discn][discpos[discn]+i]; 104 #ifdef BYTES_SWAP 105 for (i=0; i<len; i+=2) { 106 val1 = dbuf[i]; 107 val2 = dbuf[i+1]; 108 dbuf[i] = val2; 109 dbuf[i+1] =val1; 110 } 111 #endif 112 113 #else 114 115 LOG("disc read: ",len); 116 uint8 buf[256]; 117 int totlen = len; 118 while (totlen>=256) { 119 //fread(buf,1,256,disk[discn].file); 120 disk_Read(buf,256); 121 122 LOG("b read: ",buf[0]); 123 totlen -= 256; 124 for (i=0; i<256; i++) { 125 SetMemBBB(address, buf[i]); 126 address++; 127 } 128 } 129 if (totlen) { 130 //fread(buf,1,totlen,disk[discn].file); 131 disk_Read(buf,totlen); 132 LOG("b: ",buf[0]); 133 for (i=0; i<totlen; i++) { 134 SetMemBBB(address, buf[i]); 135 address++; 136 } 137 } 138 #endif 139 140 discpos[discn]=discpos[discn]+i; 141 readdsk |= ( discn + 1 ); 142 return len; 143 } 144 145 PROGMEM int discwrite(unsigned char *buf,int a,int len,int discn) 146 { 147 int i; 148 uint8 val1,val2,*dbuf; 149 dbuf=buf; 150 #ifdef MEMDISC 151 //for (i=0;i<len;i++) disc[discn][discpos[discn]+i]=*buf++; 152 #else 153 #endif 154 #ifdef BYTES_SWAP 155 for (i=0; i<len; i+=2) { 156 val1 = disc[discn][discpos[discn]+i]; 157 val2 = disc[discn][discpos[discn]+i+1]; 158 disc[discn][discpos[discn]+i] = val2; 159 disc[discn][discpos[discn]+i+1] =val1; 160 } 161 #endif 162 discpos[discn]=discpos[discn]+i; 163 return len; 164 } 165 166 int discseek(int discn,int pos,int a) 167 { 168 if (pos>(1050*1024)){ 169 return -1; 170 } 171 discpos[discn]=pos; 172 #ifdef MEMDISC 173 #else 174 if (disk[discn].file) disk_Seek(pos); //fseek(disk[discn].file,pos,SEEK_SET); 175 #endif 176 return 0; 177 } 178 179 180 181 182 183 PROGMEM int FDCInit(int i) 184 { 185 unsigned char *buf; 186 #ifdef MEMDISC 187 memset((void *)&disc[i][0],0,MAX_DISC_SIZE); 188 #else 189 memset((void *)&disc[i][0],0,256); 190 #endif 191 int len,len2,calcsides,calcsectors,calctracks,badbootsector; 192 discpos[i]=0; 193 194 //if (NULL != (disk[i].file = fopen (disk[i].name, "rb"))) { 195 //buf=&disc[i][0]; 196 //disk[i].file=fopen (disk[i].name, "rb"); 197 //fseek(disk[i].file,0,SEEK_END); 198 //len=ftell(disk[i].file); 199 //disk[i].disksize = len; 200 //fseek(disk[i].file,0,SEEK_SET); 201 len = disk_Size(disk[i].name); 202 disk[i].file = disk_Open(disk[i].name); 203 buf=&disc[i][0]; 204 disk[i].disksize = len; 205 #ifdef MEMDISC 206 //fread(buf,1,len,disk[i].file); 207 //fclose(disk[i].file); 208 #else 209 if (disk[i].file) { 210 //fread(buf,1,256,disk[i].file); 211 //fseek(disk[i].file,0,SEEK_SET); 212 disk_Read(buf, 256); 213 disk_Seek(0); 214 } 215 #endif 216 217 disk[i].head = 0; 218 disk[i].sides = (int) *(buf + 26); 219 disk[i].sectors = (int) *(buf + 24); 220 disk[i].secsize = 512; //(int) ((*(buf + 12) << 8) | *(buf + 11)); 221 if (disk[i].sectors * disk[i].sides) 222 disk[i].tracks = (int) ((*(buf + 20) << 8) | *(buf + 19)) / 223 (disk[i].sectors * disk[i].sides); 224 225 // Second Check more precise 226 if (len> (500*1024)) calcsides = 2; 227 else calcsides = 1; 228 if (!(((len/calcsides)/512)%9)&&(((len/calcsides)/512)/9)<86) calcsectors=9; 229 else if (!(((len/calcsides)/512)%10)&&(((len/calcsides)/512)/10)<86) calcsectors=10; 230 else if (!(((len/calcsides)/512)%11)&&(((len/calcsides)/512)/11)<86) calcsectors=11; 231 else if (!(((len/calcsides)/512)%12)) calcsectors=12; 232 calctracks =((len/calcsides)/512)/calcsectors; 233 234 if (disk[i].sides!=calcsides||disk[i].sectors!=calcsectors||disk[i].tracks!=calctracks){ 235 if (disk[i].sides==calcsides&&disk[i].sectors==calcsectors){ 236 disk[i].tracks=calctracks; 237 badbootsector=0; 238 }else{ 239 disk[i].sides=calcsides; 240 disk[i].tracks=calctracks; 241 disk[i].sectors=calcsectors; 242 badbootsector=(i<<24)|(calcsides<<16)|(calctracks<<8)|(calcsectors); 243 } 244 245 }else{ 246 badbootsector=0; 247 } 248 disk_ejected[i]=0; 249 disk_changed[i]=1; 250 fdc_status |= 0x40; 251 disk[i].head = 0; 252 fdc_track = 0; 253 //} 254 255 //dcastaway_disc_initsave(i); 256 257 return badbootsector; 258 } 259 260 PROGMEM void FDCchange(int i){ 261 disk[(i>>24)&0xff].sides=(i>>16)&0xff; 262 disk[(i>>24)&0xff].tracks=(i>>8)&0xff; 263 disk[(i>>24)&0xff].sectors=i&0xff; 264 } 265 266 PROGMEM void FDCeject(int num){ 267 int i; 268 269 #ifdef MEMDISC 270 for (i=0;i<1050*1024;i++) disc[num][i]=0; 271 #endif 272 disk[num].file = NULL; 273 sprintf(disk[num].name,"disk%01d",num); 274 disk[num].sides = SIDES; 275 disk[num].tracks = TRACKS; 276 disk[num].sectors = SECTORS; 277 disk[num].secsize = 512; 278 disk_ejected[num]=1; 279 fdc_status |= 0x40; 280 } 281 282 PROGMEM void FDCCommand(void) 283 { 284 static char motor = 1; 285 int sides, drives; 286 long address; /* dma target/source address */ 287 long offset; /* offset in disk file */ 288 unsigned long count; /* number of byte to transfer */ 289 char *buffer; 290 int n; 291 292 if (fdc_commands_executed<64) 293 fdc_commands_executed++; 294 /* DMA target/source address */ 295 address = (dma_adrh << 16) + (dma_adrm << 8) + dma_adrl; 296 /* if (address>MEMSIZE){ 297 #ifdef DISASS 298 StartDisass(); 299 exit(1); 300 #endif 301 fdc_status |= 0x10; 302 return; 303 304 305 306 } 307 */ 308 buffer = (char *)(membase + address); 309 /* status of side select and drive select lines */ 310 sides = (~psg[14]) & 0x1; 311 drives = (~psg[14]) & 0x6; 312 if (disk_ejected[drives>>2]==1) drives=2; 313 switch (drives) { 314 case 2: /* Drive A */ 315 drives = 0; 316 break; 317 case 4: /* Drive B */ 318 drives = 1; 319 break; 320 case 6: /* both, error */ 321 case 0: /* no drive selected */ 322 drives = -1; 323 break; 324 } 325 fdc_status = 0; /* clear fdc status */ 326 327 #if DISK 328 329 if (fdc_command < 0x80) { /* TYPE-I fdc commands */ 330 if (drives >= 0) { /* drive selected */ 331 switch (fdc_command & 0xf0) { 332 case 0x00: /* RESTORE */ 333 disk[drives].head = 0; 334 fdc_track = 0; 335 break; 336 case 0x10: /* SEEK */ 337 disk[drives].head += (fdc_data - fdc_track); 338 fdc_track = fdc_data; 339 if (disk[drives].head < 0 340 || disk[drives].head >= disk[drives].tracks) 341 disk[drives].head = 0; 342 break; 343 case 0x30: /* STEP */ 344 fdc_track += fdcdir; 345 case 0x20: 346 disk[drives].head += fdcdir; 347 break; 348 case 0x50: /* STEP-IN */ 349 fdc_track++; 350 case 0x40: 351 if (disk[drives].head < disk[drives].tracks) 352 disk[drives].head++; 353 fdcdir = 1; 354 break; 355 case 0x70: /* STEP-OUT */ 356 fdc_track--; 357 case 0x60: 358 if (disk[drives].head > 0) 359 disk[drives].head--; 360 fdcdir = -1; 361 break; 362 } 363 if (disk[drives].head == 0) { 364 fdc_status |= 0x4; 365 } 366 if (disk[drives].head != fdc_track && fdc_command & 0x4) { /* Verify? */ 367 fdc_status |= 0x10; 368 } 369 if (motor) { 370 fdc_status |= 0x20; /* spin-up flag */ 371 } 372 } else { /* no drive selected */ 373 fdc_status |= 0x10; 374 } 375 } else if ((fdc_command & 0xf0) == 0xd0) { /* FORCE INTERRUPT */ 376 if (fdc_command == 0xd8) { 377 fdc_int = 1; 378 } else if (fdc_command == 0xd0) { 379 fdc_int = 0; 380 } 381 } else { /* OTHERS */ 382 if (drives >= 0) { /* drive selected */ 383 /* offset within floppy-file */ 384 offset = disk[drives].secsize * 385 (((disk[drives].sectors * disk[drives].sides * disk[drives].head)) 386 + (disk[drives].sectors * sides) + (fdc_sector - 1)); 387 switch (fdc_command & 0xf0) { 388 case 0x80: /* READ SECTOR */ 389 count = 512; 390 if (!discseek (drives, offset, 0)) { 391 if (address<MEMSIZE){ 392 if (count == discread (address, 1, count, drives)) { 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 }else{ 402 address += count; 403 dma_adrl = address & 0xff; 404 dma_adrm = (address >> 8) & 0xff; 405 dma_adrh = (address >> 16) & 0xff; 406 dma_scr = 0; 407 dma_sr = 1; 408 mfp_gpip |= 0x20; 409 fdc_status |= 0x1; 410 break; 411 } 412 } 413 fdc_status |= 0x10; 414 dma_sr = 1; 415 break; 416 case 0x90: /* READ SECTOR multiple */ 417 count = dma_scr * 512; 418 if (count+(fdc_sector-1)*512>disk[drives].sectors*512) count=disk[drives].sectors*512-(fdc_sector-1)*512; 419 if (!discseek (drives, offset, 0)) { 420 if (address<MEMSIZE){ 421 if (count == discread (address, 1, count, drives)) { 422 address += count; 423 dma_adrl = address & 0xff; 424 dma_adrm = (address >> 8) & 0xff; 425 dma_adrh = (address >> 16) & 0xff; 426 dma_scr = 0; 427 dma_sr = 1; 428 fdc_sector += count/disk[drives].secsize; 429 break; 430 } 431 }else{ 432 address += count; 433 dma_adrl = address & 0xff; 434 dma_adrm = (address >> 8) & 0xff; 435 dma_adrh = (address >> 16) & 0xff; 436 dma_scr = 0; 437 dma_sr = 1; 438 mfp_gpip |= 0x20; 439 fdc_status |= 0x1; 440 break; 441 } 442 } 443 fdc_status |= 0x10; 444 dma_sr = 1; 445 break; 446 case 0xa0: /* WRITE SECTOR */ 447 count = dma_scr * 512; 448 if (!discseek (drives, offset, 0)) { 449 if (count == discwrite ((unsigned char *)buffer, 1, count, drives)) { 450 address += count; 451 dma_adrl = address & 0xff; 452 dma_adrm = (address >> 8) & 0xff; 453 dma_adrh = (address >> 16) & 0xff; 454 dma_scr = 0; 455 dma_sr = 1; 456 break; 457 } 458 } 459 fdc_status |= 0x10; 460 dma_sr = 1; 461 break; 462 case 0xb0: /* WRITE SECTOR multiple */ 463 count = dma_scr * 512; 464 if (!discseek (drives, offset, 0)) { 465 if (count == discwrite ((unsigned char *)buffer, 1, count, drives)) { 466 address += count; 467 dma_adrl = address & 0xff; 468 dma_adrm = (address >> 8) & 0xff; 469 dma_adrh = (address >> 16) & 0xff; 470 dma_scr = 0; 471 dma_sr = 1; 472 fdc_sector += dma_scr * (512 / disk[drives].secsize); 473 break; 474 } 475 } 476 fdc_status |= 0x10; 477 dma_sr = 1; 478 break; 479 case 0xc0: /* READ ADDRESS */ 480 fdc_status |= 0x10; 481 break; 482 case 0xe0: /* READ TRACK */ 483 count = disk[drives].sectors * 512; 484 offset = disk[drives].secsize * 485 (((disk[drives].sectors * disk[drives].sides * disk[drives].head)) 486 + (disk[drives].sectors * sides)); 487 if (!discseek (drives, offset, 0)) { 488 if (address<MEMSIZE){ 489 if (dma_scr==0x1f){ 490 count=0; 491 address += 302; 492 } 493 if (count == discread (address, 1, count, drives)) { 494 dma_adrl = address & 0xff; 495 dma_adrm = (address >> 8) & 0xff; 496 dma_adrh = (address >> 16) & 0xff; 497 dma_scr = 0; 498 dma_sr = 1; 499 break; 500 } 501 }else{ 502 address += 302; 503 dma_adrl = address & 0xff; 504 dma_adrm = (address >> 8) & 0xff; 505 dma_adrh = (address >> 16) & 0xff; 506 dma_scr = 0; 507 dma_sr = 1; 508 mfp_gpip |= 0x20; 509 fdc_status |= 0x1; 510 break; 511 } 512 } 513 fdc_status |= 0x10; 514 dma_sr = 1; 515 break; 516 case 0xf0: /* WRITE TRACK */ 517 fdc_status |= 0x10; 518 break; 519 } 520 if (disk[drives].head != fdc_track) { 521 fdc_status |= 0x10; 522 } 523 } else { 524 fdc_status |= 0x10; /* no drive selected */ 525 } 526 } 527 #endif 528 if (motor) { 529 fdc_status |= 0x80; /* motor on flag */ 530 fdc_motor=1; 531 } 532 if (!(fdc_status & 0x01)) { /* not busy */ 533 mfp_iprb |= (0x80 & mfp_ierb); /* Request Interrupt */ 534 mfp_gpip &= ~0x20; 535 } 536 }