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  }