Commit 83ded03c authored by Andre Leiradella's avatar Andre Leiradella
Browse files

first commit

parents
/* disk.c: Routines for handling disk images
Copyright (c) 2004 Stuart Brady
$Id$
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Author contact information:
E-mail: pak21-fuse@srcf.ucam.org
Postal address: 15 Crescent Road, Wokingham, Berks, RG40 2DB, England
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h> /* Needed for strncasecmp() on QNX6 */
#endif /* #ifdef HAVE_STRINGS_H */
#include "1770disk.h"
int disk_phys_to_linear( disk_info *disk, int layer, int track, int sector )
{
return ( layer * disk->numtracks + track ) * disk->numsectors + sector;
}
/* TODO: move byte reads from wd1770.c to disk.c
BYTE disk_read_byte( disk_info *disk, int layer, int track, int sector, int offset )
{
return 0;
}
*/
/* TODO: move byte writes from wd1770.c to disk.c
int disk_write_byte( disk_info *disk, int layer, int track, int sector, int offset )
{
return 0;
}
*/
int disk_sector_size( disk_info *disk, int layer, int track, int sector )
{
return disk->sectorsize;
}
int disk_image_write_sector( disk_info *disk, int layer, int track, int sector )
{
unsigned long fileofs;
BYTE *buffer;
int sectorbytes = disk->sectorsize * sizeof( BYTE );
long linear = disk_phys_to_linear( disk, layer, track, sector );
long bufofs = linear * sectorbytes;
if( layer >= disk->numlayers || track >= disk->numtracks || sector >= disk->numsectors )
return NULL;
bufofs = linear * sectorbytes;
buffer = &disk->buffer[ bufofs ];
if( disk->dirty[ linear ] )
{
if( !disk->alternatesides ) fileofs = linear;
else fileofs = ( disk->numlayers * track + layer ) * disk->numsectors + sector;
fileofs *= sectorbytes;
if( lseek( disk->fd, fileofs, SEEK_SET ) != fileofs ) return(1);
if( write( disk->fd, &disk->buffer[ bufofs ], sectorbytes ) != sectorbytes ) return(1);
disk->dirty[ linear ] = 0;
}
return 0;
}
BYTE *disk_image_read_sector( disk_info *disk, int layer, int track, int sector )
{
int sectorbytes, linear;
unsigned long bufofs, fileofs;
BYTE *buffer;
int numread, toread, readpos;
if( layer >= disk->numlayers || track >= disk->numtracks || sector >= disk->numsectors )
return NULL;
sectorbytes = disk->sectorsize * sizeof( BYTE );
linear = disk_phys_to_linear( disk, layer, track, sector );
bufofs = linear * sectorbytes;
buffer = &disk->buffer[ bufofs ];
if( !disk->present[ linear ] )
{
long temp;
FILE *f;
char *p;
if( !disk->alternatesides )
fileofs = linear;
else
fileofs = ( disk->numlayers * track + layer ) * disk->numsectors + sector;
fileofs *= sectorbytes;
if( lseek( disk->fd, fileofs, SEEK_SET ) != fileofs )
return NULL;
toread = sectorbytes;
readpos = 0;
while( readpos < sectorbytes )
{
if( ( numread = read( disk->fd, buffer + readpos, toread ) ) > 0 )
{
readpos += numread;
toread -= numread;
}
else
{
return NULL;
}
}
disk->present[ linear ] = 1;
disk->dirty[ linear ] = 0;
}
return buffer;
}
BYTE *disk_read_sector( disk_info *disk, int layer, int track, int sector )
{
return disk_image_read_sector( disk, layer, track, sector );
}
disk_info *disk_image_write( disk_info *disk)
{
int layer;
int track;
int sector;
if (disk->readonly) return(NULL);
if( disk->fd == -1 ) return(NULL);
if( lseek( disk->fd, 0, SEEK_SET ) != 0 ) return NULL;
if( !disk->alternatesides )
{
for( layer = 0; layer < disk->numlayers; layer++ )
for( track = 0; track < disk->numtracks; track++ )
for( sector = 0; sector < disk->numsectors; sector++ )
{
if( disk_image_write_sector( disk, layer, track, sector ) ) return NULL;
}
}
else
{
for( track = 0; track < disk->numtracks; track++ )
for( layer = 0; layer < disk->numlayers; layer++ )
for( sector = 0; sector < disk->numsectors; sector++ )
{
if( disk_image_write_sector( disk, layer, track, sector ) ) return NULL;
}
}
return disk;
}
/* disk.h: Routines for handling disk images
Copyright (c) 2004 Stuart Brady
$Id$
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Author contact information:
E-mail: pak21-fuse@srcf.ucam.org
Postal address: 15 Crescent Road, Wokingham, Berks, RG40 2DB, England
*/
#ifndef DISK_H
#define DISK_H
#include <dir.h>
#include "zx81config.h"
typedef struct disk_info
{
int fd;
char filename[ MAXPATH ];
int numlayers;
int numtracks;
int numsectors;
int sectorsize;
int alternatesides;
int readonly;
int changed;
BYTE *buffer;
BYTE *dirty;
BYTE *present;
} disk_info;
int disk_read_byte( disk_info *disk, int layer, int track, int sector, int offset );
int disk_write_byte( disk_info *disk, int layer, int track, int sector, int offset );
int disk_phys_to_linear( disk_info *disk, int layer, int track, int sector );
int disk_sector_size( disk_info *disk, int layer, int track, int sector );
BYTE *disk_read_sector( disk_info *disk, int layer, int track, int sector );
disk_info *disk_image_write( disk_info *disk);
#endif /* #ifndef FUSE_DISK_H */
/* wd1770.c: Routines for handling the WD1770 floppy disk controller
Copyright (c) 2002-2005 Stuart Brady, Fredrick Meunier, Philip Kendall,
Dmitry Sanarin
$Id$
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Author contact information:
E-mail: pak21-fuse@srcf.ucam.org
Postal address: 15 Crescent Road, Wokingham, Berks, RG40 2DB, England
*/
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <limits.h>
#include <sys/stat.h>
#include "wd1770.h"
void wd1770_reset(wd1770_drive *d)
{
d->busy_counter=d->NMICounter=0;
d->index_pulse=d->index_interrupt=0;
d->rates[0]=d->rates[1]=d->rates[2]=d->rates[3]=0;
d->spin_cycles=d->track=d->side=d->direction=0;
d->state=wd1770_state_none;
d->status_type=wd1770_status_type1;
d->data_track=d->data_sector=d->data_side=d->data_multisector=d->data_offset=0;
d->status_register=d->track_register=d->sector_register=d->data_register=0;
d->set_cmdint=d->reset_cmdint=d->set_datarq=d->reset_datarq=d->iface=NULL;
d->cmdint = d->datarq = 0;
//disk_info *disk;
}
void wd1770_set_cmdint( wd1770_drive *d )
{
d->cmdint=1;
if( d->set_cmdint ) d->set_cmdint( d );
}
void wd1770_reset_cmdint( wd1770_drive *d )
{
d->cmdint=0;
if( d->reset_cmdint ) d->reset_cmdint( d );
}
void wd1770_set_datarq( wd1770_drive *d )
{
d->datarq=1;
d->status_register |= WD1770_SR_IDX_DRQ;
if( d->set_datarq ) d->set_datarq( d );
}
void wd1770_reset_datarq( wd1770_drive *d )
{
d->datarq=0;
d->status_register &= ~WD1770_SR_IDX_DRQ;
if( d->reset_datarq ) d->reset_datarq( d );
}
static void wd1770_seek( wd1770_drive *d, int track, int update, int verify )
{
if( track < d->track )
{
d->direction = -1;
if( d->track_register == 0 ) d->track_register = 255;
else if( update )
{
int trk = d->track_register;
trk += track - d->track + 256;
trk %= 256;
d->track_register = trk;
}
}
else if( track > d->track )
{
d->direction = 1;
if( d->track_register == 255 ) d->track_register = 0;
else if( update )
{
int trk = d->track_register;
trk += track - d->track;
trk %= 256;
d->track_register = trk;
}
}
if( verify )
{
if( track < 0 )
d->status_register |= WD1770_SR_RNF;
else if( track >= d->disk->numtracks )
d->status_register |= WD1770_SR_RNF;
else
d->status_register &= ~WD1770_SR_RNF;
}
else
d->status_register &= ~WD1770_SR_RNF;
if( track < 0 ) track = 0;
if( track > 255 ) track = 255;
d->track = track;
d->status_register &= ~WD1770_SR_LOST;
if( d->track == 0 ) d->status_register |= WD1770_SR_LOST;
}
BYTE wd1770_sr_read( wd1770_drive *d )
{
int temp;
//temp=d->status_register;
//RDPRINTF( "wd1770_%s()\n", "sr_read" );
d->status_register &= ~( WD1770_SR_MOTORON | WD1770_SR_SPINUP | WD1770_SR_WRPROT | WD1770_SR_CRCERR );
if( d->status_type == wd1770_status_type1 )
{
d->status_register &= ~WD1770_SR_IDX_DRQ;
if( d->disk->fd == -1 || d->index_pulse )
d->status_register |= WD1770_SR_IDX_DRQ;
}
//if (d->state != wd1770_state_none) d->status_register |= WD1770_SR_MOTORON;
//if( d->status_type == wd1770_status_type2)
//{
// if( d->disk->fd == -1)
// {
// d->status_register &= ~(WD1770_SR_IDX_DRQ);
// }
//}
return d->status_register;
}
void wd1770_cr_write( wd1770_drive *d, BYTE b )
{
//DPRINTF( "wd1770_%s( 0x%02x )\n", "cr_write", b );
//if (d->state == wd1770_state_read) d->state = wd1770_state_none;
d->type_III_len=0;
/* command register: */
if( ( b & 0xf0 ) == 0xd0 )
{ /* Type IV - Force Interrupt */
d->status_register &= ~WD1770_SR_BUSY;
d->status_register &= ~WD1770_SR_WRPROT;
d->status_register &= ~WD1770_SR_CRCERR;
d->status_register &= ~WD1770_SR_IDX_DRQ;
d->state = wd1770_state_none;
d->status_type = wd1770_status_type1;
d->status_register &= ~WD1770_SR_LOST;
if( d->track == 0 ) d->status_register |= WD1770_SR_LOST;
wd1770_reset_datarq( d );
if( b & 0x08 ) wd1770_set_cmdint( d );
if( b & 0x04 ) d->index_interrupt = 1;
return;
}
if( d->status_register & WD1770_SR_BUSY ) return;
d->status_register |= WD1770_SR_BUSY;
d->busy_counter=3500;
//event_add( tstates + 10 * machine_current->timings.processor_speed / 1000, EVENT_TYPE_DISCIPLE_CMD_DONE );
if( !( b & 0x08 ) )
{
d->spin_cycles = 5;
d->status_register |= WD1770_SR_MOTORON;
d->status_register |= WD1770_SR_SPINUP;
}
if( !( b & 0x80 ) )
{ /* Type I */
int update = b & 0x10 ? 1 : 0;
int verify = b & 0x04 ? 1 : 0;
int rate = b & 0x03 ? 1 : 0;
switch( ( b >> 5 ) & 0x03 )
{
case 0x00:
if( !( b & 0x10 ) )
{ /* Restore */
d->track_register = d->track;
wd1770_seek( d, 0, update, verify );
}
else
{ /* Seek */
wd1770_seek( d, d->data_register, 0, verify );
}
d->direction = 1;
break;
case 0x01: /* Step */
wd1770_seek( d, d->track + d->direction, update, verify );
break;
case 0x02: /* Step In */
wd1770_seek( d, d->track + 1, update, verify );
break;
case 0x03: /* Step Out */
wd1770_seek( d, d->track - 1, update, verify );
break;
}
d->status_type = wd1770_status_type1;
wd1770_set_cmdint( d );
wd1770_reset_datarq( d );
}
else if( !( b & 0x40 ) )
{ /* Type II */
int multisector = b & 0x10 ? 1 : 0;
int delay = b & 0x04 ? 1 : 0;
if( !( b & 0x20 ) )
{ /* Read Sector */
if (d->disk->fd!=-1) d->state = wd1770_state_read;
}
else
{ /* Write Sector */
int dammark = b & 0x01;
if (d->disk->fd!=-1) d->state = wd1770_state_write;
}
if( d->sector_register >= d->disk->numsectors + 1
|| d->sector_register < 1
|| d->track >= d->disk->numtracks
|| d->track < 0 )
{
d->status_register |= WD1770_SR_RNF;
wd1770_set_cmdint( d );
wd1770_reset_datarq( d );
}
else
{
wd1770_set_datarq( d );
d->status_register |= WD1770_SR_BUSY;
d->status_register &= ~( WD1770_SR_WRPROT | WD1770_SR_RNF | WD1770_SR_CRCERR | WD1770_SR_LOST );
d->status_type = wd1770_status_type2;
d->data_track = d->track;
d->data_sector = d->sector_register - 1;
d->data_side = d->side;
d->data_offset = 0;
d->data_multisector = multisector;
}
}
else if( ( b & 0xf0 ) != 0xd0 )
{ /* Type III */
int delay = b & 0x04;
switch( b & 0xf0 )
{
case 0xe0: /* Read Track */
fprintf( stderr, "read track not yet implemented\n" );
break;
case 0xf0: /* Write Track */
fprintf( stderr, "write track not yet implemented\n" );
break;
case 0xc0: /* Read Address */
d->state = wd1770_state_readid;
wd1770_set_datarq( d );
d->status_register |= WD1770_SR_BUSY;
d->status_register &= ~( WD1770_SR_WRPROT | WD1770_SR_RNF | WD1770_SR_CRCERR | WD1770_SR_LOST );
d->status_type = wd1770_status_type2;
d->data_track = d->track;
d->data_sector = d->sector_register - 1;
d->data_side = d->side;
d->data_offset = 0;
d->data_multisector = 0;
d->type_III_len=6;
d->type_III_buffer[0]=d->track;
d->type_III_buffer[1]=d->side;
d->type_III_buffer[2]=random(16)+1;
switch(d->disk->sectorsize)
{
case 128: d->type_III_buffer[3]=0; break;
case 256: d->type_III_buffer[3]=1; break;
case 512: d->type_III_buffer[3]=2; break;
case 1024: d->type_III_buffer[3]=3; break;
default: d->type_III_buffer[3]=1; break;
}
d->type_III_buffer[4]=255;
d->type_III_buffer[5]=255;
break;
}
d->status_type = wd1770_status_type2;
}
}
BYTE wd1770_tr_read( wd1770_drive *d )
{
//DPRINTF( "wd1770_%s()\n", "tr_read" );
return d->track_register;
}
void wd1770_tr_write( wd1770_drive *d, BYTE b )
{
//DPRINTF( "wd1770_%s( %i )\n", "tr_write", b );
//if (d->state == wd1770_state_read) d->state = wd1770_state_none;
d->track_register = b;
}
BYTE wd1770_sec_read( wd1770_drive *d )
{
//DPRINTF( "wd1770_%s()\n", "sec_read" );
//if (d->state == wd1770_state_read) d->state = wd1770_state_none;
return d->sector_register;
}
void wd1770_sec_write( wd1770_drive *d, BYTE b )
{
//DPRINTF( "wd1770_%s( %i )\n", "sec_write", b );
//if (d->state == wd1770_state_read) d->state = wd1770_state_none;
d->sector_register = b;
}
BYTE wd1770_dr_read( wd1770_drive *d )
{
BYTE *sec;
//RDPRINTF( "wd1770_%s()\n", "dr_read" );
if (d->state!=wd1770_state_read && d->state!=wd1770_state_readid)
return(d->data_register);
if( d->disk->fd == -1
|| d->data_track >= d->disk->numtracks
|| d->data_side >= 2 )
{
d->status_register |= WD1770_SR_RNF;
d->type_III_len=0;
fprintf( stderr, "read from non-existant sector\n" );
return(d->data_register);
}
if (d->state==wd1770_state_readid)
{
if( d->data_offset < d->type_III_len )
{
d->data_register = d->type_III_buffer[d->data_offset];
if( d->data_offset == d->disk->sectorsize )
{
d->status_register =0;//&= ~WD1770_SR_BUSY;
d->status_type = wd1770_status_type2;
d->state