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  }