2015-11-05 20:23:46 +00:00
|
|
|
/*
|
2016-02-04 06:37:39 +00:00
|
|
|
GSPLUS - Advanced Apple IIGS Emulator Environment
|
|
|
|
Copyright (C) 2016 - Dagen Brock
|
2015-11-05 20:23:46 +00:00
|
|
|
|
2016-02-08 05:01:25 +00:00
|
|
|
Copyright (C) 2010 by GSport contributors
|
|
|
|
|
2015-11-05 20:23:46 +00:00
|
|
|
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
|
|
|
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
IWM_READ_ROUT (Disk *dsk, int fast_disk_emul, double dcycs)
|
|
|
|
{
|
|
|
|
Trk *trk;
|
|
|
|
double dcycs_last_read;
|
|
|
|
int pos;
|
|
|
|
int pos2;
|
|
|
|
int size;
|
|
|
|
int next_size;
|
|
|
|
int qtr_track;
|
|
|
|
int skip_nibs;
|
|
|
|
int track_len;
|
|
|
|
byte ret;
|
|
|
|
int shift;
|
|
|
|
int skip;
|
|
|
|
int cycs_this_nib;
|
|
|
|
int cycs_passed;
|
|
|
|
double dcycs_this_nib;
|
|
|
|
double dcycs_next_nib;
|
|
|
|
double dcycs_passed;
|
|
|
|
double track_dcycs;
|
|
|
|
double dtmp;
|
|
|
|
|
|
|
|
iwm.previous_write_bits = 0;
|
|
|
|
|
|
|
|
qtr_track = dsk->cur_qtr_track;
|
|
|
|
|
|
|
|
#if IWM_DISK_525
|
|
|
|
qtr_track = qtr_track & -4; /* round to nearest whole trk! */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
trk = 0;
|
|
|
|
track_len = 0;
|
|
|
|
if(dsk->trks) {
|
|
|
|
trk = &(dsk->trks[qtr_track]);
|
|
|
|
track_len = trk->track_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
dcycs_last_read = dsk->dcycs_last_read;
|
|
|
|
dcycs_passed = dcycs - dcycs_last_read;
|
|
|
|
|
|
|
|
cycs_passed = (int)dcycs_passed;
|
|
|
|
|
|
|
|
if(track_len == 0) {
|
|
|
|
ret = (cycs_passed & 0x7f) + 0x80;
|
|
|
|
iwm_printf("Reading c0ec, track_len 0, returning %02x\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = dsk->nib_pos;
|
|
|
|
if(pos >= track_len) {
|
|
|
|
/* Arm may have moved from inner 3.5 track to outer one, */
|
|
|
|
/* and so must make pos fit on smaller sized track */
|
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = trk->nib_area[pos];
|
|
|
|
|
|
|
|
while(size == 0) {
|
|
|
|
pos += 2;
|
|
|
|
if(pos >= track_len) {
|
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
size = trk->nib_area[pos];
|
|
|
|
}
|
|
|
|
|
|
|
|
cycs_this_nib = size * (2 * IWM_CYC_MULT);
|
|
|
|
dcycs_this_nib = (double)cycs_this_nib;
|
|
|
|
|
|
|
|
if(fast_disk_emul) {
|
|
|
|
cycs_passed = cycs_this_nib;
|
|
|
|
dcycs_passed = dcycs_this_nib;
|
|
|
|
|
|
|
|
/* pull a trick to make disk motor-on test pass ($bd34 RWTS) */
|
|
|
|
/* if this would be a sync byte, and we didn't just do this */
|
|
|
|
/* then don't return whole byte */
|
|
|
|
/* BUT, don't do this if g_fast_disk_unnib, since it will */
|
|
|
|
/* cause the dsk->unix routines to break */
|
|
|
|
if(size > 8 && !g_fast_disk_unnib && (g_iwm_fake_fast == 0)) {
|
|
|
|
cycs_passed = cycs_passed >> 1;
|
|
|
|
dcycs_passed = dcycs_passed * 0.5;
|
|
|
|
g_iwm_fake_fast = 1;
|
|
|
|
} else {
|
|
|
|
g_iwm_fake_fast = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
skip = 0;
|
|
|
|
if(cycs_passed >= (cycs_this_nib + 11)) {
|
|
|
|
/* skip some bits? */
|
|
|
|
skip = 1;
|
|
|
|
if(iwm.iwm_mode & 1) {
|
|
|
|
/* latch mode */
|
|
|
|
|
|
|
|
pos2 = pos + 2;
|
|
|
|
if(pos2 >= track_len) {
|
|
|
|
pos2 = 0;
|
|
|
|
}
|
|
|
|
next_size = trk->nib_area[pos2];
|
|
|
|
while(next_size == 0) {
|
|
|
|
pos2 += 2;
|
|
|
|
if(pos2 >= track_len) {
|
|
|
|
pos2 = 0;
|
|
|
|
}
|
|
|
|
next_size = trk->nib_area[pos2];
|
|
|
|
}
|
|
|
|
|
|
|
|
dcycs_next_nib = next_size * (2 * IWM_CYC_MULT);
|
|
|
|
|
|
|
|
if(dcycs_passed < (dcycs_this_nib + dcycs_next_nib)) {
|
|
|
|
skip = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(skip) {
|
|
|
|
iwm_printf("skip since cycs_passed: %f, cycs_this_nib: %f\n",
|
|
|
|
dcycs_passed, dcycs_this_nib);
|
|
|
|
|
|
|
|
track_dcycs = IWM_CYC_MULT * (track_len * 8);
|
|
|
|
|
|
|
|
if(dcycs_passed >= track_dcycs) {
|
|
|
|
dtmp = (int)(dcycs_passed / track_dcycs);
|
|
|
|
dcycs_passed = dcycs_passed -
|
|
|
|
(dtmp * track_dcycs);
|
|
|
|
dcycs_last_read += (dtmp * track_dcycs);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(dcycs_passed >= track_dcycs || dcycs_passed < 0.0) {
|
|
|
|
dcycs_passed = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cycs_passed = (int)dcycs_passed;
|
|
|
|
|
|
|
|
skip_nibs = ((word32)cycs_passed) >> (4 + IWM_DISK_525);
|
|
|
|
|
|
|
|
pos += skip_nibs * 2;
|
|
|
|
while(pos >= track_len) {
|
|
|
|
pos -= track_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
dcycs_last_read += (skip_nibs * 16 * IWM_CYC_MULT);
|
|
|
|
|
|
|
|
dsk->dcycs_last_read = dcycs_last_read;
|
|
|
|
|
|
|
|
size = trk->nib_area[pos];
|
|
|
|
dcycs_passed = dcycs - dcycs_last_read;
|
|
|
|
if(dcycs_passed < 0.0 || dcycs_passed > 64.0) {
|
|
|
|
halt_printf("skip, last_read:%f, dcycs:%f, dcyc_p:%f\n",
|
|
|
|
dcycs_last_read, dcycs, dcycs_passed);
|
|
|
|
}
|
|
|
|
|
|
|
|
while(size == 0) {
|
|
|
|
pos += 2;
|
|
|
|
if(pos >= track_len) {
|
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
size = trk->nib_area[pos];
|
|
|
|
}
|
|
|
|
|
|
|
|
cycs_this_nib = size * (2 * IWM_CYC_MULT);
|
|
|
|
cycs_passed = (int)dcycs_passed;
|
|
|
|
dcycs_this_nib = cycs_this_nib;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(cycs_passed < cycs_this_nib) {
|
|
|
|
/* partial */
|
|
|
|
#if 0
|
|
|
|
iwm_printf("Disk partial, %f < %f, size: %d\n",
|
|
|
|
dcycs_passed, dcycs_this_nib, size);
|
|
|
|
#endif
|
|
|
|
shift = (cycs_passed) >> (1 + IWM_DISK_525);
|
|
|
|
ret = trk->nib_area[pos+1] >> (size - shift);
|
|
|
|
if(ret & 0x80) {
|
|
|
|
halt_printf("Bad shift in partial read: %02x, but "
|
|
|
|
"c_pass:%f, this_nib:%f, shift: %d, size: %d\n",
|
|
|
|
ret, dcycs_passed, dcycs_this_nib, shift, size);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* whole thing */
|
|
|
|
ret = trk->nib_area[pos+1];
|
|
|
|
pos += 2;
|
|
|
|
if(pos >= track_len) {
|
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
if(!fast_disk_emul) {
|
|
|
|
dsk->dcycs_last_read = dcycs_last_read + dcycs_this_nib;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dsk->nib_pos = pos;
|
|
|
|
if(pos < 0 || pos > track_len) {
|
|
|
|
halt_printf("I just set nib_pos: %d!\n", pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
iwm_printf("Disk read, returning: %02x\n", ret);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
IWM_WRITE_ROUT (Disk *dsk, word32 val, int fast_disk_emul, double dcycs)
|
|
|
|
{
|
|
|
|
double dcycs_last_read;
|
|
|
|
word32 bits_read;
|
|
|
|
word32 mask;
|
|
|
|
word32 prev_val;
|
|
|
|
double dcycs_this_nib;
|
|
|
|
double dcycs_passed;
|
|
|
|
double sdiff;
|
|
|
|
int prev_bits;
|
|
|
|
|
|
|
|
if((!dsk->file) || dsk->trks == 0) {
|
|
|
|
halt_printf("Tried to write to type: %d, drive: %d!\n",
|
|
|
|
IWM_DISK_525, dsk->drive, dsk->trks);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dcycs_last_read = dsk->dcycs_last_read;
|
|
|
|
|
|
|
|
dcycs_passed = dcycs - dcycs_last_read;
|
|
|
|
|
|
|
|
prev_val = iwm.previous_write_val;
|
|
|
|
prev_bits = iwm.previous_write_bits;
|
|
|
|
mask = 0x100;
|
|
|
|
iwm_printf("Iwm write: prev: %x,%d, new:%02x\n", prev_val, prev_bits,
|
|
|
|
val);
|
|
|
|
|
|
|
|
if(IWM_DISK_525) {
|
|
|
|
/* Activate slow write emulation mode */
|
|
|
|
g_dcycs_end_emul_wr = dcycs + 64.0;
|
|
|
|
if(!g_slow_525_emul_wr) {
|
|
|
|
set_halt(HALT_EVENT);
|
|
|
|
g_slow_525_emul_wr = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* disable slow writes on 3.5" drives */
|
|
|
|
if(g_slow_525_emul_wr) {
|
|
|
|
set_halt(HALT_EVENT);
|
|
|
|
printf("HACK3: g_slow_525_emul_wr set to 0\n");
|
|
|
|
g_slow_525_emul_wr = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(iwm.iwm_mode & 2) {
|
|
|
|
/* async mode = 3.5" default */
|
|
|
|
bits_read = 8;
|
|
|
|
} else {
|
|
|
|
/* sync mode, 5.25" drives */
|
|
|
|
bits_read = ((int)dcycs_passed) >> (1 + IWM_DISK_525);
|
|
|
|
if(bits_read < 8) {
|
|
|
|
bits_read = 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(fast_disk_emul) {
|
|
|
|
bits_read = 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
dcycs_this_nib = bits_read * (2 * IWM_CYC_MULT);
|
|
|
|
|
|
|
|
if(fast_disk_emul) {
|
|
|
|
dcycs_passed = dcycs_this_nib;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(prev_bits > 0) {
|
|
|
|
while((prev_val & 0x80) == 0 && bits_read > 0) {
|
|
|
|
/* previous byte needs some bits */
|
|
|
|
mask = mask >> 1;
|
|
|
|
prev_val = (prev_val << 1) + ((val & mask) !=0);
|
|
|
|
prev_bits++;
|
|
|
|
bits_read--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
val = val & (mask - 1);
|
|
|
|
if(prev_bits) {
|
|
|
|
/* force out prev_val if it had many bits before */
|
|
|
|
/* this prevents writes of 0 from messing us up */
|
|
|
|
if(((prev_val & 0x80) == 0) && (prev_bits < 10)) {
|
|
|
|
/* special case: we still don't have enough to go */
|
|
|
|
iwm_printf("iwm_write: zip2: %02x, %d, left:%02x,%d\n",
|
|
|
|
prev_val, prev_bits, val,bits_read);
|
|
|
|
val = prev_val;
|
|
|
|
bits_read = prev_bits;
|
|
|
|
} else {
|
|
|
|
iwm_printf("iwm_write: prev: %02x, %d, left:%02x, %d\n",
|
|
|
|
prev_val, prev_bits, val, bits_read);
|
|
|
|
disk_nib_out(dsk, prev_val, prev_bits);
|
|
|
|
}
|
|
|
|
} else if(val & 0x80) {
|
|
|
|
iwm_printf("iwm_write: new: %02x, %d\n", val,bits_read);
|
|
|
|
disk_nib_out(dsk, val, bits_read);
|
|
|
|
bits_read = 0;
|
|
|
|
} else {
|
|
|
|
iwm_printf("iwm_write: zip: %02x, %d, left:%02x,%d\n",
|
|
|
|
prev_val, prev_bits, val,bits_read);
|
|
|
|
}
|
|
|
|
|
|
|
|
iwm.previous_write_val = val;
|
|
|
|
iwm.previous_write_bits = bits_read;
|
|
|
|
if(bits_read < 0) {
|
|
|
|
halt_printf("iwm, bits_rd:%d, val:%08x, prev:%02x, prevb:%d\n",
|
|
|
|
bits_read, val, prev_val, prev_bits);
|
|
|
|
}
|
|
|
|
|
|
|
|
sdiff = dcycs - dcycs_last_read;
|
|
|
|
if(sdiff < (dcycs_this_nib) || (sdiff > (2*dcycs_this_nib)) ) {
|
|
|
|
dsk->dcycs_last_read = dcycs;
|
|
|
|
} else {
|
|
|
|
dsk->dcycs_last_read = dcycs_last_read + dcycs_this_nib;
|
|
|
|
}
|
|
|
|
}
|