mirror of
https://github.com/jamessanford/kegs.git
synced 2024-08-28 22:29:58 +00:00
2337 lines
48 KiB
C
2337 lines
48 KiB
C
|
/************************************************************************/
|
||
|
/* KEGS: Apple //gs Emulator */
|
||
|
/* Copyright 2002 by Kent Dickey */
|
||
|
/* */
|
||
|
/* This code is covered by the GNU GPL */
|
||
|
/* */
|
||
|
/* The KEGS web page is kegs.sourceforge.net */
|
||
|
/* You may contact the author at: kadickey@alumni.princeton.edu */
|
||
|
/************************************************************************/
|
||
|
|
||
|
const char rcsid_iwm_c[] = "@(#)$KmKId: iwm.c,v 1.119 2004-11-21 17:44:14-05 kentd Exp $";
|
||
|
|
||
|
#include "defc.h"
|
||
|
|
||
|
extern int Verbose;
|
||
|
extern int g_vbl_count;
|
||
|
extern int g_c036_val_speed;
|
||
|
|
||
|
const byte phys_to_dos_sec[] = {
|
||
|
0x00, 0x07, 0x0e, 0x06, 0x0d, 0x05, 0x0c, 0x04,
|
||
|
0x0b, 0x03, 0x0a, 0x02, 0x09, 0x01, 0x08, 0x0f
|
||
|
};
|
||
|
|
||
|
const byte phys_to_prodos_sec[] = {
|
||
|
0x00, 0x08, 0x01, 0x09, 0x02, 0x0a, 0x03, 0x0b,
|
||
|
0x04, 0x0c, 0x05, 0x0d, 0x06, 0x0e, 0x07, 0x0f
|
||
|
};
|
||
|
|
||
|
|
||
|
const byte to_disk_byte[] = {
|
||
|
0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6,
|
||
|
0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3,
|
||
|
/* 0x10 */
|
||
|
0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc,
|
||
|
0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3,
|
||
|
/* 0x20 */
|
||
|
0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
|
||
|
0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec,
|
||
|
/* 0x30 */
|
||
|
0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
|
||
|
0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||
|
};
|
||
|
|
||
|
int g_track_bytes_35[] = {
|
||
|
0x200*12,
|
||
|
0x200*11,
|
||
|
0x200*10,
|
||
|
0x200*9,
|
||
|
0x200*8
|
||
|
};
|
||
|
|
||
|
int g_track_nibs_35[] = {
|
||
|
816*12,
|
||
|
816*11,
|
||
|
816*10,
|
||
|
816*9,
|
||
|
816*8
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
int g_fast_disk_emul = 1;
|
||
|
int g_slow_525_emul_wr = 0;
|
||
|
double g_dcycs_end_emul_wr = 0.0;
|
||
|
int g_fast_disk_unnib = 0;
|
||
|
int g_iwm_fake_fast = 0;
|
||
|
|
||
|
|
||
|
int from_disk_byte[256];
|
||
|
int from_disk_byte_valid = 0;
|
||
|
|
||
|
Iwm iwm;
|
||
|
|
||
|
extern int g_c031_disk35;
|
||
|
|
||
|
int g_iwm_motor_on = 0;
|
||
|
|
||
|
int g_check_nibblization = 0;
|
||
|
|
||
|
/* prototypes for IWM special routs */
|
||
|
int iwm_read_data_35(Disk *dsk, int fast_disk_emul, double dcycs);
|
||
|
int iwm_read_data_525(Disk *dsk, int fast_disk_emul, double dcycs);
|
||
|
void iwm_write_data_35(Disk *dsk, word32 val, int fast_disk_emul, double dcycs);
|
||
|
void iwm_write_data_525(Disk *dsk, word32 val, int fast_disk_emul,double dcycs);
|
||
|
|
||
|
void
|
||
|
iwm_init_drive(Disk *dsk, int smartport, int drive, int disk_525)
|
||
|
{
|
||
|
dsk->dcycs_last_read = 0.0;
|
||
|
dsk->name_ptr = 0;
|
||
|
dsk->partition_name = 0;
|
||
|
dsk->partition_num = -1;
|
||
|
dsk->fd = -1;
|
||
|
dsk->force_size = 0;
|
||
|
dsk->image_start = 0;
|
||
|
dsk->image_size = 0;
|
||
|
dsk->smartport = smartport;
|
||
|
dsk->disk_525 = disk_525;
|
||
|
dsk->drive = drive;
|
||
|
dsk->cur_qtr_track = 0;
|
||
|
dsk->image_type = 0;
|
||
|
dsk->vol_num = 254;
|
||
|
dsk->write_prot = 1;
|
||
|
dsk->write_through_to_unix = 0;
|
||
|
dsk->disk_dirty = 0;
|
||
|
dsk->just_ejected = 0;
|
||
|
dsk->last_phase = 0;
|
||
|
dsk->nib_pos = 0;
|
||
|
dsk->num_tracks = 0;
|
||
|
dsk->trks = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
void
|
||
|
disk_set_num_tracks(Disk *dsk, int num_tracks)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if(dsk->trks != 0) {
|
||
|
/* This should not be necessary! */
|
||
|
free(dsk->trks);
|
||
|
halt_printf("Needed to free dsk->trks: %p\n", dsk->trks);
|
||
|
}
|
||
|
dsk->num_tracks = num_tracks;
|
||
|
dsk->trks = (Trk *)malloc(num_tracks * sizeof(Trk));
|
||
|
|
||
|
for(i = 0; i < num_tracks; i++) {
|
||
|
dsk->trks[i].dsk = dsk;
|
||
|
dsk->trks[i].nib_area = 0;
|
||
|
dsk->trks[i].track_dirty = 0;
|
||
|
dsk->trks[i].overflow_size = 0;
|
||
|
dsk->trks[i].track_len = 0;
|
||
|
dsk->trks[i].unix_pos = -1;
|
||
|
dsk->trks[i].unix_len = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_init()
|
||
|
{
|
||
|
int val;
|
||
|
int i;
|
||
|
|
||
|
for(i = 0; i < 2; i++) {
|
||
|
iwm_init_drive(&(iwm.drive525[i]), 0, i, 1);
|
||
|
iwm_init_drive(&(iwm.drive35[i]), 0, i, 0);
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < MAX_C7_DISKS; i++) {
|
||
|
iwm_init_drive(&(iwm.smartport[i]), 1, i, 0);
|
||
|
}
|
||
|
|
||
|
if(from_disk_byte_valid == 0) {
|
||
|
for(i = 0; i < 256; i++) {
|
||
|
from_disk_byte[i] = -1;
|
||
|
}
|
||
|
for(i = 0; i < 64; i++) {
|
||
|
val = to_disk_byte[i];
|
||
|
from_disk_byte[val] = i;
|
||
|
}
|
||
|
from_disk_byte_valid = 1;
|
||
|
} else {
|
||
|
halt_printf("iwm_init called twice!\n");
|
||
|
}
|
||
|
|
||
|
iwm_reset();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_reset()
|
||
|
{
|
||
|
iwm.q6 = 0;
|
||
|
iwm.q7 = 0;
|
||
|
iwm.motor_on = 0;
|
||
|
iwm.motor_on35 = 0;
|
||
|
iwm.motor_off = 0;
|
||
|
iwm.motor_off_vbl_count = 0;
|
||
|
iwm.step_direction35 = 0;
|
||
|
iwm.head35 = 0;
|
||
|
iwm.drive_select = 0;
|
||
|
iwm.iwm_mode = 0;
|
||
|
iwm.enable2 = 0;
|
||
|
iwm.reset = 0;
|
||
|
iwm.iwm_phase[0] = 0;
|
||
|
iwm.iwm_phase[1] = 0;
|
||
|
iwm.iwm_phase[2] = 0;
|
||
|
iwm.iwm_phase[3] = 0;
|
||
|
iwm.previous_write_val = 0;
|
||
|
iwm.previous_write_bits = 0;
|
||
|
|
||
|
g_iwm_motor_on = 0;
|
||
|
g_c031_disk35 = 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
draw_iwm_status(int line, char *buf)
|
||
|
{
|
||
|
char *flag[2][2];
|
||
|
int apple35_sel;
|
||
|
|
||
|
flag[0][0] = " ";
|
||
|
flag[0][1] = " ";
|
||
|
flag[1][0] = " ";
|
||
|
flag[1][1] = " ";
|
||
|
|
||
|
apple35_sel = (g_c031_disk35 >> 6) & 1;
|
||
|
if(g_iwm_motor_on) {
|
||
|
flag[apple35_sel][iwm.drive_select] = "*";
|
||
|
}
|
||
|
|
||
|
sprintf(buf, "s6d1:%2d%s s6d2:%2d%s s5d1:%2d/%d%s "
|
||
|
"s5d2:%2d/%d%s fast_disk_emul:%d,%d c036:%02x",
|
||
|
iwm.drive525[0].cur_qtr_track >> 2, flag[0][0],
|
||
|
iwm.drive525[1].cur_qtr_track >> 2, flag[0][1],
|
||
|
iwm.drive35[0].cur_qtr_track >> 1,
|
||
|
iwm.drive35[0].cur_qtr_track & 1, flag[1][0],
|
||
|
iwm.drive35[1].cur_qtr_track >> 1,
|
||
|
iwm.drive35[1].cur_qtr_track & 1, flag[1][1],
|
||
|
g_fast_disk_emul, g_slow_525_emul_wr, g_c036_val_speed);
|
||
|
|
||
|
video_update_status_line(line, buf);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
iwm_flush_disk_to_unix(Disk *dsk)
|
||
|
{
|
||
|
byte buffer[0x4000];
|
||
|
int num_dirty;
|
||
|
int j;
|
||
|
int ret;
|
||
|
int unix_pos;
|
||
|
int unix_len;
|
||
|
|
||
|
if(dsk->disk_dirty == 0 || dsk->write_through_to_unix == 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
printf("Writing disk %s to Unix\n", dsk->name_ptr);
|
||
|
dsk->disk_dirty = 0;
|
||
|
num_dirty = 0;
|
||
|
|
||
|
/* Dirty data! */
|
||
|
for(j = 0; j < dsk->num_tracks; j++) {
|
||
|
|
||
|
ret = disk_track_to_unix(dsk, j, &(buffer[0]));
|
||
|
|
||
|
if(ret != 1 && ret != 0) {
|
||
|
printf("iwm_flush_disk_to_unix ret: %d, cannot write "
|
||
|
"image to unix\n", ret);
|
||
|
halt_printf("Adjusting image not to write through!\n");
|
||
|
dsk->write_through_to_unix = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(ret != 1) {
|
||
|
/* not at an even track, or not dirty */
|
||
|
continue;
|
||
|
}
|
||
|
if((j & 3) != 0 && dsk->disk_525) {
|
||
|
halt_printf("Valid data on a non-whole trk: %03x\n", j);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
num_dirty++;
|
||
|
|
||
|
/* Write it out */
|
||
|
unix_pos = dsk->trks[j].unix_pos;
|
||
|
unix_len = dsk->trks[j].unix_len;
|
||
|
if(unix_pos < 0 || unix_len < 0x1000) {
|
||
|
halt_printf("Disk:%s trk:%d, unix_pos:%08x, len:%08x\n",
|
||
|
dsk->name_ptr, j, unix_pos, unix_len);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ret = lseek(dsk->fd, unix_pos, SEEK_SET);
|
||
|
if(ret != unix_pos) {
|
||
|
halt_printf("lseek 525: %08x, errno: %d\n", ret, errno);
|
||
|
}
|
||
|
|
||
|
ret = write(dsk->fd, &(buffer[0]), unix_len);
|
||
|
if(ret != unix_len) {
|
||
|
printf("write: %08x, errno:%d, qtrk: %02x, disk: %s\n",
|
||
|
ret, errno, j, dsk->name_ptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(num_dirty == 0) {
|
||
|
halt_printf("Drive %s was dirty, but no track was dirty!\n",
|
||
|
dsk->name_ptr);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/* Check for dirty disk 3 times a second */
|
||
|
|
||
|
void
|
||
|
iwm_vbl_update(int doit_3_persec)
|
||
|
{
|
||
|
Disk *dsk;
|
||
|
int motor_on;
|
||
|
int i;
|
||
|
|
||
|
if(iwm.motor_on && iwm.motor_off) {
|
||
|
if(iwm.motor_off_vbl_count <= g_vbl_count) {
|
||
|
printf("Disk timer expired, drive off: %08x\n",
|
||
|
g_vbl_count);
|
||
|
iwm.motor_on = 0;
|
||
|
iwm.motor_off = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!doit_3_persec) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
motor_on = iwm.motor_on;
|
||
|
if(g_c031_disk35 & 0x40) {
|
||
|
motor_on = iwm.motor_on35;
|
||
|
}
|
||
|
|
||
|
if(motor_on == 0 || iwm.motor_off) {
|
||
|
/* Disk not spinning, see if any dirty tracks to flush */
|
||
|
/* out to Unix */
|
||
|
for(i = 0; i < 2; i++) {
|
||
|
dsk = &(iwm.drive525[i]);
|
||
|
iwm_flush_disk_to_unix(dsk);
|
||
|
}
|
||
|
for(i = 0; i < 2; i++) {
|
||
|
dsk = &(iwm.drive35[i]);
|
||
|
iwm_flush_disk_to_unix(dsk);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
iwm_show_stats()
|
||
|
{
|
||
|
printf("IWM stats: q7,q6: %d, %d, reset,enable2: %d,%d, mode: %02x\n",
|
||
|
iwm.q7, iwm.q6, iwm.reset, iwm.enable2, iwm.iwm_mode);
|
||
|
printf("motor: %d,%d, motor35:%d drive: %d, c031:%02x "
|
||
|
"phs: %d %d %d %d\n",
|
||
|
iwm.motor_on, iwm.motor_off, g_iwm_motor_on,
|
||
|
iwm.drive_select, g_c031_disk35,
|
||
|
iwm.iwm_phase[0], iwm.iwm_phase[1], iwm.iwm_phase[2],
|
||
|
iwm.iwm_phase[3]);
|
||
|
printf("iwm.drive525[0].fd: %d, [1].fd: %d\n",
|
||
|
iwm.drive525[0].fd, iwm.drive525[1].fd);
|
||
|
printf("iwm.drive525[0].last_phase: %d, [1].last_phase: %d\n",
|
||
|
iwm.drive525[0].last_phase, iwm.drive525[1].last_phase);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_touch_switches(int loc, double dcycs)
|
||
|
{
|
||
|
Disk *dsk;
|
||
|
int phase;
|
||
|
int on;
|
||
|
int drive;
|
||
|
|
||
|
if(iwm.reset) {
|
||
|
iwm_printf("IWM under reset: %d, enable2: %d\n", iwm.reset,
|
||
|
iwm.enable2);
|
||
|
}
|
||
|
|
||
|
on = loc & 1;
|
||
|
drive = iwm.drive_select;
|
||
|
phase = loc >> 1;
|
||
|
if(g_c031_disk35 & 0x40) {
|
||
|
dsk = &(iwm.drive35[drive]);
|
||
|
} else {
|
||
|
dsk = &(iwm.drive525[drive]);
|
||
|
}
|
||
|
|
||
|
|
||
|
if(loc < 8) {
|
||
|
/* phase adjustments. See if motor is on */
|
||
|
|
||
|
iwm.iwm_phase[phase] = on;
|
||
|
iwm_printf("Iwm phase %d=%d, all phases: %d %d %d %d (%f)\n",
|
||
|
phase, on, iwm.iwm_phase[0], iwm.iwm_phase[1],
|
||
|
iwm.iwm_phase[2], iwm.iwm_phase[3], dcycs);
|
||
|
|
||
|
if(iwm.motor_on) {
|
||
|
if(g_c031_disk35 & 0x40) {
|
||
|
if(phase == 3 && on) {
|
||
|
iwm_do_action35(dcycs);
|
||
|
}
|
||
|
} else if(on) {
|
||
|
/* Move apple525 head */
|
||
|
iwm525_phase_change(drive, phase);
|
||
|
}
|
||
|
}
|
||
|
/* See if enable or reset is asserted */
|
||
|
if(iwm.iwm_phase[0] && iwm.iwm_phase[2]) {
|
||
|
iwm.reset = 1;
|
||
|
iwm_printf("IWM reset active\n");
|
||
|
} else {
|
||
|
iwm.reset = 0;
|
||
|
}
|
||
|
if(iwm.iwm_phase[1] && iwm.iwm_phase[3]) {
|
||
|
iwm.enable2 = 1;
|
||
|
iwm_printf("IWM ENABLE2 active\n");
|
||
|
} else {
|
||
|
iwm.enable2 = 0;
|
||
|
}
|
||
|
} else {
|
||
|
/* loc >= 8 */
|
||
|
switch(loc) {
|
||
|
case 0x8:
|
||
|
iwm_printf("Turning IWM motor off!\n");
|
||
|
if(iwm.iwm_mode & 0x04) {
|
||
|
/* Turn off immediately */
|
||
|
iwm.motor_off = 0;
|
||
|
iwm.motor_on = 0;
|
||
|
} else {
|
||
|
/* 1 second delay */
|
||
|
if(iwm.motor_on && !iwm.motor_off) {
|
||
|
iwm.motor_off = 1;
|
||
|
iwm.motor_off_vbl_count = g_vbl_count
|
||
|
+ 60;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(g_iwm_motor_on || g_slow_525_emul_wr) {
|
||
|
/* recalc current speed */
|
||
|
set_halt(HALT_EVENT);
|
||
|
}
|
||
|
|
||
|
g_iwm_motor_on = 0;
|
||
|
g_slow_525_emul_wr = 0;
|
||
|
break;
|
||
|
case 0x9:
|
||
|
iwm_printf("Turning IWM motor on!\n");
|
||
|
iwm.motor_on = 1;
|
||
|
iwm.motor_off = 0;
|
||
|
|
||
|
if(g_iwm_motor_on == 0) {
|
||
|
/* recalc current speed */
|
||
|
set_halt(HALT_EVENT);
|
||
|
}
|
||
|
g_iwm_motor_on = 1;
|
||
|
|
||
|
break;
|
||
|
case 0xa:
|
||
|
case 0xb:
|
||
|
iwm.drive_select = on;
|
||
|
break;
|
||
|
case 0xc:
|
||
|
case 0xd:
|
||
|
iwm.q6 = on;
|
||
|
break;
|
||
|
case 0xe:
|
||
|
case 0xf:
|
||
|
iwm.q7 = on;
|
||
|
break;
|
||
|
default:
|
||
|
printf("iwm_touch_switches: loc: %02x unknown!\n", loc);
|
||
|
exit(2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!iwm.q7) {
|
||
|
iwm.previous_write_bits = 0;
|
||
|
}
|
||
|
|
||
|
if((dcycs > g_dcycs_end_emul_wr) && g_slow_525_emul_wr) {
|
||
|
set_halt(HALT_EVENT);
|
||
|
g_slow_525_emul_wr = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_move_to_track(Disk *dsk, int new_track)
|
||
|
{
|
||
|
int disk_525;
|
||
|
int dr;
|
||
|
|
||
|
disk_525 = dsk->disk_525;
|
||
|
|
||
|
if(new_track < 0) {
|
||
|
new_track = 0;
|
||
|
}
|
||
|
if(new_track >= dsk->num_tracks) {
|
||
|
if(disk_525) {
|
||
|
new_track = dsk->num_tracks - 4;
|
||
|
} else {
|
||
|
new_track = dsk->num_tracks - 2 + iwm.head35;
|
||
|
}
|
||
|
|
||
|
if(new_track <= 0) {
|
||
|
new_track = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(dsk->cur_qtr_track != new_track) {
|
||
|
dr = dsk->drive + 1;
|
||
|
if(disk_525) {
|
||
|
iwm_printf("s6d%d Track: %d.%02d\n", dr,
|
||
|
new_track >> 2, 25* (new_track & 3));
|
||
|
} else {
|
||
|
iwm_printf("s5d%d Track: %d Side: %d\n", dr,
|
||
|
new_track >> 1, new_track & 1);
|
||
|
}
|
||
|
|
||
|
dsk->cur_qtr_track = new_track;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm525_phase_change(int drive, int phase)
|
||
|
{
|
||
|
Disk *dsk;
|
||
|
int qtr_track;
|
||
|
int last_phase;
|
||
|
int phase_up;
|
||
|
int phase_down;
|
||
|
int delta;
|
||
|
|
||
|
phase_up = (phase - 1) & 3;
|
||
|
phase_down = (phase + 1) & 3;
|
||
|
|
||
|
dsk = &(iwm.drive525[drive]);
|
||
|
last_phase = dsk->last_phase;
|
||
|
|
||
|
qtr_track = dsk->cur_qtr_track;
|
||
|
|
||
|
delta = 0;
|
||
|
if(last_phase == phase_up) {
|
||
|
delta = 2;
|
||
|
last_phase = phase;
|
||
|
} else if(last_phase == phase_down) {
|
||
|
delta = -2;
|
||
|
last_phase = phase;
|
||
|
}
|
||
|
|
||
|
qtr_track += delta;
|
||
|
if(qtr_track < 0) {
|
||
|
printf("GRIND...GRIND...GRIND\n");
|
||
|
qtr_track = 0;
|
||
|
last_phase = 0;
|
||
|
}
|
||
|
if(qtr_track > 4*34) {
|
||
|
printf("Disk arm moved past track 34, moving it back\n");
|
||
|
qtr_track = 4*34;
|
||
|
last_phase = 0;
|
||
|
}
|
||
|
|
||
|
iwm_move_to_track(dsk, qtr_track);
|
||
|
|
||
|
dsk->last_phase = last_phase;
|
||
|
|
||
|
iwm_printf("Moving drive to qtr track: %04x (trk:%d.%02d), %d, %d, %d, "
|
||
|
"%d %d %d %d\n", qtr_track, qtr_track>>2, 25*(qtr_track & 3),
|
||
|
phase, delta, last_phase, iwm.iwm_phase[0],
|
||
|
iwm.iwm_phase[1], iwm.iwm_phase[2], iwm.iwm_phase[3]);
|
||
|
|
||
|
/* sanity check stepping algorithm */
|
||
|
if((qtr_track & 7) == 0) {
|
||
|
/* check for just access phase 0 */
|
||
|
if(last_phase != 0 ) {
|
||
|
halt_printf("last_phase: %d!\n", last_phase);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
iwm_read_status35(double dcycs)
|
||
|
{
|
||
|
Disk *dsk;
|
||
|
int drive;
|
||
|
int state;
|
||
|
int tmp;
|
||
|
|
||
|
drive = iwm.drive_select;
|
||
|
dsk = &(iwm.drive35[drive]);
|
||
|
|
||
|
if(iwm.motor_on) {
|
||
|
/* Read status */
|
||
|
state = (iwm.iwm_phase[1] << 3) + (iwm.iwm_phase[0] << 2) +
|
||
|
((g_c031_disk35 >> 6) & 2) + iwm.iwm_phase[2];
|
||
|
|
||
|
iwm_printf("Iwm status read state: %02x\n", state);
|
||
|
|
||
|
switch(state) {
|
||
|
case 0x00: /* step direction */
|
||
|
return iwm.step_direction35;
|
||
|
break;
|
||
|
case 0x01: /* lower head activate */
|
||
|
/* also return instantaneous data from head */
|
||
|
iwm.head35 = 0;
|
||
|
iwm_move_to_track(dsk, (dsk->cur_qtr_track & (-2)));
|
||
|
return (((int)dcycs) & 1);
|
||
|
break;
|
||
|
case 0x02: /* disk in place */
|
||
|
/* 1 = no disk, 0 = disk */
|
||
|
iwm_printf("read disk in place, num_tracks: %d\n",
|
||
|
dsk->num_tracks);
|
||
|
tmp = (dsk->num_tracks <= 0);
|
||
|
return tmp;
|
||
|
break;
|
||
|
case 0x03: /* upper head activate */
|
||
|
/* also return instantaneous data from head */
|
||
|
iwm.head35 = 1;
|
||
|
iwm_move_to_track(dsk, (dsk->cur_qtr_track | 1));
|
||
|
return (((int)dcycs) & 1);
|
||
|
break;
|
||
|
case 0x04: /* disk is stepping? */
|
||
|
/* 1 = not stepping, 0 = stepping */
|
||
|
return 1;
|
||
|
break;
|
||
|
case 0x05: /* Unknown function of ROM 03? */
|
||
|
/* 1 = or $20 into 0xe1/f24+drive, 0 = don't */
|
||
|
return 1;
|
||
|
break;
|
||
|
case 0x06: /* disk is locked */
|
||
|
/* 0 = locked, 1 = unlocked */
|
||
|
return (!dsk->write_prot);
|
||
|
break;
|
||
|
case 0x08: /* motor on */
|
||
|
/* 0 = on, 1 = off */
|
||
|
return !iwm.motor_on35;
|
||
|
break;
|
||
|
case 0x09: /* number of sides */
|
||
|
/* 1 = 2 sides, 0 = 1 side */
|
||
|
return 1;
|
||
|
break;
|
||
|
case 0x0a: /* at track 0 */
|
||
|
/* 1 = not at track 0, 0 = there */
|
||
|
tmp = (dsk->cur_qtr_track != 0);
|
||
|
iwm_printf("Read at track0_35: %d\n", tmp);
|
||
|
return tmp;
|
||
|
break;
|
||
|
case 0x0b: /* disk ready??? */
|
||
|
/* 0 = ready, 1 = not ready? */
|
||
|
tmp = !iwm.motor_on35;
|
||
|
iwm_printf("Read disk ready, ret: %d\n", tmp);
|
||
|
return tmp;
|
||
|
break;
|
||
|
case 0x0c: /* disk switched?? */
|
||
|
/* 0 = not switched, 1 = switched? */
|
||
|
tmp = (dsk->just_ejected != 0);
|
||
|
iwm_printf("Read disk switched: %d\n", tmp);
|
||
|
return tmp;
|
||
|
break;
|
||
|
case 0x0d: /* false read when ejecting disk */
|
||
|
return 1;
|
||
|
case 0x0e: /* tachometer */
|
||
|
halt_printf("Reading tachometer!\n");
|
||
|
return (((int)dcycs) & 1);
|
||
|
break;
|
||
|
case 0x0f: /* drive installed? */
|
||
|
/* 0 = drive exists, 1 = no drive */
|
||
|
if(drive) {
|
||
|
/* pretend no drive 1 */
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
break;
|
||
|
default:
|
||
|
halt_printf("Read 3.5 status, state: %02x\n", state);
|
||
|
return 1;
|
||
|
}
|
||
|
} else {
|
||
|
iwm_printf("Read 3.5 status with drive off!\n");
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_do_action35(double dcycs)
|
||
|
{
|
||
|
Disk *dsk;
|
||
|
int drive;
|
||
|
int state;
|
||
|
|
||
|
drive = iwm.drive_select;
|
||
|
dsk = &(iwm.drive35[drive]);
|
||
|
|
||
|
if(iwm.motor_on) {
|
||
|
/* Perform action */
|
||
|
state = (iwm.iwm_phase[1] << 3) + (iwm.iwm_phase[0] << 2) +
|
||
|
((g_c031_disk35 >> 6) & 2) + iwm.iwm_phase[2];
|
||
|
switch(state) {
|
||
|
case 0x00: /* Set step direction inward */
|
||
|
/* towards higher tracks */
|
||
|
iwm.step_direction35 = 0;
|
||
|
iwm_printf("Iwm set step dir35 = 0\n");
|
||
|
break;
|
||
|
case 0x01: /* Set step direction outward */
|
||
|
/* towards lower tracks */
|
||
|
iwm.step_direction35 = 1;
|
||
|
iwm_printf("Iwm set step dir35 = 1\n");
|
||
|
break;
|
||
|
case 0x03: /* reset disk-switched flag? */
|
||
|
iwm_printf("Iwm reset disk switch\n");
|
||
|
dsk->just_ejected = 0;
|
||
|
/* set_halt(1); */
|
||
|
break;
|
||
|
case 0x04: /* step disk */
|
||
|
if(iwm.step_direction35) {
|
||
|
iwm_move_to_track(dsk, dsk->cur_qtr_track - 2);
|
||
|
} else {
|
||
|
iwm_move_to_track(dsk, dsk->cur_qtr_track + 2);
|
||
|
}
|
||
|
break;
|
||
|
case 0x08: /* turn motor on */
|
||
|
iwm_printf("Iwm set motor_on35 = 1\n");
|
||
|
iwm.motor_on35 = 1;
|
||
|
break;
|
||
|
case 0x09: /* turn motor off */
|
||
|
iwm_printf("Iwm set motor_on35 = 0\n");
|
||
|
iwm.motor_on35 = 0;
|
||
|
break;
|
||
|
case 0x0d: /* eject disk */
|
||
|
eject_disk(dsk);
|
||
|
break;
|
||
|
case 0x02:
|
||
|
case 0x07:
|
||
|
case 0x0b: /* hacks to allow AE 1.6MB driver to not crash me */
|
||
|
break;
|
||
|
default:
|
||
|
halt_printf("Do 3.5 action, state: %02x\n", state);
|
||
|
return;
|
||
|
}
|
||
|
} else {
|
||
|
halt_printf("Set 3.5 status with drive off!\n");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
iwm_read_c0ec(double dcycs)
|
||
|
{
|
||
|
Disk *dsk;
|
||
|
int drive;
|
||
|
|
||
|
iwm.q6 = 0;
|
||
|
|
||
|
if(iwm.q7 == 0 && iwm.enable2 == 0 && iwm.motor_on) {
|
||
|
drive = iwm.drive_select;
|
||
|
if(g_c031_disk35 & 0x40) {
|
||
|
dsk = &(iwm.drive35[drive]);
|
||
|
return iwm_read_data_35(dsk, g_fast_disk_emul, dcycs);
|
||
|
} else {
|
||
|
dsk = &(iwm.drive525[drive]);
|
||
|
return iwm_read_data_525(dsk, g_fast_disk_emul, dcycs);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return read_iwm(0xc, dcycs);
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
read_iwm(int loc, double dcycs)
|
||
|
{
|
||
|
Disk *dsk;
|
||
|
word32 status;
|
||
|
double diff_dcycs;
|
||
|
double dcmp;
|
||
|
int on;
|
||
|
int state;
|
||
|
int drive;
|
||
|
int val;
|
||
|
|
||
|
loc = loc & 0xf;
|
||
|
on = loc & 1;
|
||
|
|
||
|
if(loc == 0xc) {
|
||
|
iwm.q6 = 0;
|
||
|
} else {
|
||
|
iwm_touch_switches(loc, dcycs);
|
||
|
}
|
||
|
|
||
|
state = (iwm.q7 << 1) + iwm.q6;
|
||
|
drive = iwm.drive_select;
|
||
|
if(g_c031_disk35 & 0x40) {
|
||
|
dsk = &(iwm.drive35[drive]);
|
||
|
} else {
|
||
|
dsk = &(iwm.drive525[drive]);
|
||
|
}
|
||
|
|
||
|
if(on) {
|
||
|
/* odd address, return 0 */
|
||
|
return 0;
|
||
|
} else {
|
||
|
/* even address */
|
||
|
switch(state) {
|
||
|
case 0x00: /* q7 = 0, q6 = 0 */
|
||
|
if(iwm.enable2) {
|
||
|
return iwm_read_enable2(dcycs);
|
||
|
} else {
|
||
|
if(iwm.motor_on) {
|
||
|
return iwm_read_data(dsk,
|
||
|
g_fast_disk_emul, dcycs);
|
||
|
} else {
|
||
|
iwm_printf("read iwm st 0, m off!\n");
|
||
|
/* HACK!!!! */
|
||
|
return 0xff;
|
||
|
//return (((int)dcycs) & 0x7f) + 0x80;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 0x01: /* q7 = 0, q6 = 1 */
|
||
|
/* read IWM status reg */
|
||
|
if(iwm.enable2) {
|
||
|
iwm_printf("Read status under enable2: 1\n");
|
||
|
status = 1;
|
||
|
} else {
|
||
|
if(g_c031_disk35 & 0x40) {
|
||
|
status = iwm_read_status35(dcycs);
|
||
|
} else {
|
||
|
status = dsk->write_prot;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
val = (status << 7) + (iwm.motor_on << 5) +
|
||
|
iwm.iwm_mode;
|
||
|
iwm_printf("Read status: %02x\n", val);
|
||
|
|
||
|
return val;
|
||
|
break;
|
||
|
case 0x02: /* q7 = 1, q6 = 0 */
|
||
|
/* read handshake register */
|
||
|
if(iwm.enable2) {
|
||
|
return iwm_read_enable2_handshake(dcycs);
|
||
|
} else {
|
||
|
status = 0xc0;
|
||
|
diff_dcycs = dcycs - dsk->dcycs_last_read;
|
||
|
dcmp = 16.0;
|
||
|
if(dsk->disk_525 == 0) {
|
||
|
dcmp = 32.0;
|
||
|
}
|
||
|
if(diff_dcycs > dcmp) {
|
||
|
iwm_printf("Write underrun!\n");
|
||
|
iwm_printf("cur: %f, dc_last: %f\n",
|
||
|
dcycs, dsk->dcycs_last_read);
|
||
|
status = status & 0xbf;
|
||
|
}
|
||
|
return status;
|
||
|
}
|
||
|
break;
|
||
|
case 0x03: /* q7 = 1, q6 = 1 */
|
||
|
halt_printf("read iwm state 3!\n");
|
||
|
return 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
halt_printf("Got to end of read_iwm, loc: %02x!\n", loc);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
write_iwm(int loc, int val, double dcycs)
|
||
|
{
|
||
|
Disk *dsk;
|
||
|
int on;
|
||
|
int state;
|
||
|
int drive;
|
||
|
int fast_writes;
|
||
|
|
||
|
loc = loc & 0xf;
|
||
|
on = loc & 1;
|
||
|
|
||
|
iwm_touch_switches(loc, dcycs);
|
||
|
|
||
|
state = (iwm.q7 << 1) + iwm.q6;
|
||
|
drive = iwm.drive_select;
|
||
|
fast_writes = g_fast_disk_emul;
|
||
|
if(g_c031_disk35 & 0x40) {
|
||
|
dsk = &(iwm.drive35[drive]);
|
||
|
} else {
|
||
|
dsk = &(iwm.drive525[drive]);
|
||
|
fast_writes = !g_slow_525_emul_wr && fast_writes;
|
||
|
}
|
||
|
|
||
|
if(on) {
|
||
|
/* odd address, write something */
|
||
|
if(state == 0x03) {
|
||
|
/* q7, q6 = 1,1 */
|
||
|
if(iwm.motor_on) {
|
||
|
if(iwm.enable2) {
|
||
|
iwm_write_enable2(val, dcycs);
|
||
|
} else {
|
||
|
iwm_write_data(dsk, val,
|
||
|
fast_writes, dcycs);
|
||
|
}
|
||
|
} else {
|
||
|
/* write mode register */
|
||
|
val = val & 0x1f;
|
||
|
iwm.iwm_mode = val;
|
||
|
if(val != 0 && val != 0x0f && val != 0x07 &&
|
||
|
val != 0x04 && val != 0x0b) {
|
||
|
halt_printf("set iwm_mode:%02x!\n",val);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if(iwm.enable2) {
|
||
|
iwm_write_enable2(val, dcycs);
|
||
|
} else {
|
||
|
#if 0
|
||
|
// Flobynoid writes to 0xc0e9 causing these messages...
|
||
|
printf("Write iwm1, st: %02x, loc: %x: %02x\n",
|
||
|
state, loc, val);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
} else {
|
||
|
/* even address */
|
||
|
if(iwm.enable2) {
|
||
|
iwm_write_enable2(val, dcycs);
|
||
|
} else {
|
||
|
iwm_printf("Write iwm2, st: %02x, loc: %x: %02x\n",
|
||
|
state, loc, val);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int
|
||
|
iwm_read_enable2(double dcycs)
|
||
|
{
|
||
|
iwm_printf("Read under enable2!\n");
|
||
|
return 0xff;
|
||
|
}
|
||
|
|
||
|
int g_cnt_enable2_handshake = 0;
|
||
|
|
||
|
int
|
||
|
iwm_read_enable2_handshake(double dcycs)
|
||
|
{
|
||
|
int val;
|
||
|
|
||
|
iwm_printf("Read handshake under enable2!\n");
|
||
|
|
||
|
val = 0xc0;
|
||
|
g_cnt_enable2_handshake++;
|
||
|
if(g_cnt_enable2_handshake > 3) {
|
||
|
g_cnt_enable2_handshake = 0;
|
||
|
val = 0x80;
|
||
|
}
|
||
|
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_write_enable2(int val, double dcycs)
|
||
|
{
|
||
|
iwm_printf("Write under enable2: %02x!\n", val);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
iwm_read_data(Disk *dsk, int fast_disk_emul, double dcycs)
|
||
|
{
|
||
|
if(dsk->disk_525) {
|
||
|
return iwm_read_data_525(dsk, fast_disk_emul, dcycs);
|
||
|
} else {
|
||
|
return iwm_read_data_35(dsk, fast_disk_emul, dcycs);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_write_data(Disk *dsk, word32 val, int fast_disk_emul, double dcycs)
|
||
|
{
|
||
|
if(dsk->disk_525) {
|
||
|
iwm_write_data_525(dsk, val, fast_disk_emul, dcycs);
|
||
|
} else {
|
||
|
iwm_write_data_35(dsk, val, fast_disk_emul, dcycs);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#undef IWM_READ_ROUT
|
||
|
#undef IWM_WRITE_ROUT
|
||
|
#undef IWM_CYC_MULT
|
||
|
#undef IWM_DISK_525
|
||
|
|
||
|
#define IWM_READ_ROUT iwm_read_data_35
|
||
|
#define IWM_WRITE_ROUT iwm_write_data_35
|
||
|
#define IWM_CYC_MULT 1
|
||
|
#define IWM_DISK_525 0
|
||
|
|
||
|
#define INCLUDE_IWM_RCSID_C
|
||
|
#include "iwm_35_525.h"
|
||
|
#undef INCLUDE_IWM_RCSID_C
|
||
|
|
||
|
#undef IWM_READ_ROUT
|
||
|
#undef IWM_WRITE_ROUT
|
||
|
#undef IWM_CYC_MULT
|
||
|
#undef IWM_DISK_525
|
||
|
|
||
|
#define IWM_READ_ROUT iwm_read_data_525
|
||
|
#define IWM_WRITE_ROUT iwm_write_data_525
|
||
|
#define IWM_CYC_MULT 2
|
||
|
#define IWM_DISK_525 1
|
||
|
#include "iwm_35_525.h"
|
||
|
|
||
|
#undef IWM_READ_ROUT
|
||
|
#undef IWM_WRITE_ROUT
|
||
|
#undef IWM_CYC_MULT
|
||
|
#undef IWM_DISK_525
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* c600 */
|
||
|
void
|
||
|
sector_to_partial_nib(byte *in, byte *nib_ptr)
|
||
|
{
|
||
|
byte *aux_buf;
|
||
|
byte *nib_out;
|
||
|
int val;
|
||
|
int val2;
|
||
|
int x;
|
||
|
int i;
|
||
|
|
||
|
/* Convert 256(+1) data bytes to 342+1 disk nibbles */
|
||
|
|
||
|
aux_buf = nib_ptr;
|
||
|
nib_out = nib_ptr + 0x56;
|
||
|
|
||
|
for(i = 0; i < 0x56; i++) {
|
||
|
aux_buf[i] = 0;
|
||
|
}
|
||
|
|
||
|
x = 0x55;
|
||
|
for(i = 0x101; i >= 0; i--) {
|
||
|
val = in[i];
|
||
|
if(i >= 0x100) {
|
||
|
val = 0;
|
||
|
}
|
||
|
val2 = (aux_buf[x] << 1) + (val & 1);
|
||
|
val = val >> 1;
|
||
|
val2 = (val2 << 1) + (val & 1);
|
||
|
val = val >> 1;
|
||
|
nib_out[i] = val;
|
||
|
aux_buf[x] = val2;
|
||
|
x--;
|
||
|
if(x < 0) {
|
||
|
x = 0x55;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
disk_unnib_4x4(Disk *dsk)
|
||
|
{
|
||
|
int val1;
|
||
|
int val2;
|
||
|
|
||
|
val1 = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = iwm_read_data(dsk, 1, 0);
|
||
|
|
||
|
return ((val1 << 1) + 1) & val2;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
iwm_denib_track525(Disk *dsk, Trk *trk, int qtr_track, byte *outbuf)
|
||
|
{
|
||
|
byte aux_buf[0x80];
|
||
|
byte *buf;
|
||
|
int sector_done[16];
|
||
|
int num_sectors_done;
|
||
|
int track_len;
|
||
|
int vol, track, phys_sec, log_sec, cksum;
|
||
|
int val;
|
||
|
int val2;
|
||
|
int prev_val;
|
||
|
int x;
|
||
|
int my_nib_cnt;
|
||
|
int save_qtr_track;
|
||
|
int save_nib_pos;
|
||
|
int tmp_nib_pos;
|
||
|
int status;
|
||
|
int i;
|
||
|
|
||
|
save_qtr_track = dsk->cur_qtr_track;
|
||
|
save_nib_pos = dsk->nib_pos;
|
||
|
|
||
|
iwm_move_to_track(dsk, qtr_track);
|
||
|
|
||
|
dsk->nib_pos = 0;
|
||
|
g_fast_disk_unnib = 1;
|
||
|
|
||
|
track_len = trk->track_len;
|
||
|
|
||
|
for(i = 0; i < 16; i++) {
|
||
|
sector_done[i] = 0;
|
||
|
}
|
||
|
|
||
|
num_sectors_done = 0;
|
||
|
|
||
|
val = 0;
|
||
|
status = -1;
|
||
|
my_nib_cnt = 0;
|
||
|
while(my_nib_cnt++ < 2*track_len) {
|
||
|
/* look for start of a sector */
|
||
|
if(val != 0xd5) {
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
if(val != 0xaa) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
if(val != 0x96) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* It's a sector start */
|
||
|
vol = disk_unnib_4x4(dsk);
|
||
|
track = disk_unnib_4x4(dsk);
|
||
|
phys_sec = disk_unnib_4x4(dsk);
|
||
|
if(phys_sec < 0 || phys_sec > 15) {
|
||
|
printf("Track %02x, read sec as %02x\n", qtr_track>>2,
|
||
|
phys_sec);
|
||
|
break;
|
||
|
}
|
||
|
if(dsk->image_type == DSK_TYPE_DOS33) {
|
||
|
log_sec = phys_to_dos_sec[phys_sec];
|
||
|
} else {
|
||
|
log_sec = phys_to_prodos_sec[phys_sec];
|
||
|
}
|
||
|
cksum = disk_unnib_4x4(dsk);
|
||
|
if((vol ^ track ^ phys_sec ^ cksum) != 0) {
|
||
|
/* not correct format */
|
||
|
printf("Track %02x not DOS 3.3 since hdr cksum, %02x "
|
||
|
"%02x %02x %02x\n",
|
||
|
qtr_track>>2, vol, track, phys_sec, cksum);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* see what sector it is */
|
||
|
if(track != (qtr_track>>2) || (phys_sec < 0)||(phys_sec > 15)) {
|
||
|
printf("Track %02x bad since track: %02x, sec: %02x\n",
|
||
|
qtr_track>>2, track, phys_sec);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(sector_done[phys_sec]) {
|
||
|
printf("Already done sector %02x on track %02x!\n",
|
||
|
phys_sec, qtr_track>>2);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* So far so good, let's do it! */
|
||
|
val = 0;
|
||
|
i = 0;
|
||
|
while(i < NIBS_FROM_ADDR_TO_DATA) {
|
||
|
i++;
|
||
|
if(val != 0xd5) {
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
if(val != 0xaa) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
if(val != 0xad) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* got it, just break */
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(i >= NIBS_FROM_ADDR_TO_DATA) {
|
||
|
printf("No data header, track %02x, sec %02x\n",
|
||
|
qtr_track>>2, phys_sec);
|
||
|
printf("nib_pos: %08x\n", dsk->nib_pos);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
buf = outbuf + 0x100*log_sec;
|
||
|
|
||
|
/* Data start! */
|
||
|
prev_val = 0;
|
||
|
for(i = 0x55; i >= 0; i--) {
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = from_disk_byte[val];
|
||
|
if(val2 < 0) {
|
||
|
printf("Bad data area1, val:%02x,val2:%02x\n",
|
||
|
val, val2);
|
||
|
printf(" i:%03x,n_pos:%04x\n", i, dsk->nib_pos);
|
||
|
break;
|
||
|
}
|
||
|
prev_val = val2 ^ prev_val;
|
||
|
aux_buf[i] = prev_val;
|
||
|
}
|
||
|
|
||
|
/* rest of data area */
|
||
|
for(i = 0; i < 0x100; i++) {
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = from_disk_byte[val];
|
||
|
if(val2 < 0) {
|
||
|
printf("Bad data area2, read: %02x\n", val);
|
||
|
printf(" nib_pos: %04x\n", dsk->nib_pos);
|
||
|
break;
|
||
|
}
|
||
|
prev_val = val2 ^ prev_val;
|
||
|
buf[i] = prev_val;
|
||
|
}
|
||
|
|
||
|
/* checksum */
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = from_disk_byte[val];
|
||
|
if(val2 < 0) {
|
||
|
printf("Bad data area3, read: %02x\n", val);
|
||
|
printf(" nib_pos: %04x\n", dsk->nib_pos);
|
||
|
break;
|
||
|
}
|
||
|
if(val2 != prev_val) {
|
||
|
printf("Bad data cksum, got %02x, wanted: %02x\n",
|
||
|
val2, prev_val);
|
||
|
printf(" nib_pos: %04x\n", dsk->nib_pos);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Got this far, data is good, merge aux_buf into buf */
|
||
|
x = 0x55;
|
||
|
for(i = 0; i < 0x100; i++) {
|
||
|
val = aux_buf[x];
|
||
|
val2 = (buf[i] << 1) + (val & 1);
|
||
|
val = val >> 1;
|
||
|
val2 = (val2 << 1) + (val & 1);
|
||
|
buf[i] = val2;
|
||
|
val = val >> 1;
|
||
|
aux_buf[x] = val;
|
||
|
x--;
|
||
|
if(x < 0) {
|
||
|
x = 0x55;
|
||
|
}
|
||
|
}
|
||
|
sector_done[phys_sec] = 1;
|
||
|
num_sectors_done++;
|
||
|
if(num_sectors_done >= 16) {
|
||
|
status = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tmp_nib_pos = dsk->nib_pos;
|
||
|
iwm_move_to_track(dsk, save_qtr_track);
|
||
|
dsk->nib_pos = save_nib_pos;
|
||
|
g_fast_disk_unnib = 0;
|
||
|
|
||
|
if(status == 0) {
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
printf("Nibblization not done, %02x sectors found on track %02x\n",
|
||
|
num_sectors_done, qtr_track>>2);
|
||
|
printf("my_nib_cnt: %04x, nib_pos: %04x, trk_len: %04x\n", my_nib_cnt,
|
||
|
tmp_nib_pos, track_len);
|
||
|
for(i = 0; i < 16; i++) {
|
||
|
printf("sector_done[%d] = %d\n", i, sector_done[i]);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
iwm_denib_track35(Disk *dsk, Trk *trk, int qtr_track, byte *outbuf)
|
||
|
{
|
||
|
word32 buf_c00[0x100];
|
||
|
word32 buf_d00[0x100];
|
||
|
word32 buf_e00[0x100];
|
||
|
byte *buf;
|
||
|
word32 tmp_5c, tmp_5d, tmp_5e;
|
||
|
word32 tmp_66, tmp_67;
|
||
|
int sector_done[16];
|
||
|
int num_sectors_done;
|
||
|
int track_len;
|
||
|
int phys_track, phys_sec, phys_side, phys_capacity, cksum;
|
||
|
int tmp;
|
||
|
int track, side;
|
||
|
int num_sectors;
|
||
|
int val;
|
||
|
int val2;
|
||
|
int x, y;
|
||
|
int carry;
|
||
|
int my_nib_cnt;
|
||
|
int save_qtr_track;
|
||
|
int save_nib_pos;
|
||
|
int status;
|
||
|
int i;
|
||
|
|
||
|
save_qtr_track = dsk->cur_qtr_track;
|
||
|
save_nib_pos = dsk->nib_pos;
|
||
|
|
||
|
iwm_move_to_track(dsk, qtr_track);
|
||
|
|
||
|
dsk->nib_pos = 0;
|
||
|
g_fast_disk_unnib = 1;
|
||
|
|
||
|
track_len = trk->track_len;
|
||
|
|
||
|
num_sectors = g_track_bytes_35[qtr_track >> 5] >> 9;
|
||
|
|
||
|
for(i = 0; i < num_sectors; i++) {
|
||
|
sector_done[i] = 0;
|
||
|
}
|
||
|
|
||
|
num_sectors_done = 0;
|
||
|
|
||
|
val = 0;
|
||
|
status = -1;
|
||
|
my_nib_cnt = 0;
|
||
|
|
||
|
track = qtr_track >> 1;
|
||
|
side = qtr_track & 1;
|
||
|
|
||
|
while(my_nib_cnt++ < 2*track_len) {
|
||
|
/* look for start of a sector */
|
||
|
if(val != 0xd5) {
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
if(val != 0xaa) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
if(val != 0x96) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* It's a sector start */
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
phys_track = from_disk_byte[val];
|
||
|
if(phys_track != (track & 0x3f)) {
|
||
|
printf("Track %02x.%d, read track %02x, %02x\n",
|
||
|
track, side, phys_track, val);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
phys_sec = from_disk_byte[iwm_read_data(dsk, 1, 0)];
|
||
|
if(phys_sec < 0 || phys_sec >= num_sectors) {
|
||
|
printf("Track %02x.%d, read sector %02x??\n",
|
||
|
track, side, phys_sec);
|
||
|
break;
|
||
|
}
|
||
|
phys_side = from_disk_byte[iwm_read_data(dsk, 1, 0)];
|
||
|
|
||
|
if(phys_side != ((side << 5) + (track >> 6))) {
|
||
|
printf("Track %02x.%d, read side %02x??\n",
|
||
|
track, side, phys_side);
|
||
|
break;
|
||
|
}
|
||
|
phys_capacity = from_disk_byte[iwm_read_data(dsk, 1, 0)];
|
||
|
if(phys_capacity != 0x24 && phys_capacity != 0x22) {
|
||
|
printf("Track %02x.%x capacity: %02x != 0x24/22\n",
|
||
|
track, side, phys_capacity);
|
||
|
}
|
||
|
cksum = from_disk_byte[iwm_read_data(dsk, 1, 0)];
|
||
|
|
||
|
tmp = phys_track ^ phys_sec ^ phys_side ^ phys_capacity;
|
||
|
if(cksum != tmp) {
|
||
|
printf("Track %02x.%d, sector %02x, cksum: %02x.%02x\n",
|
||
|
track, side, phys_sec, cksum, tmp);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
if(sector_done[phys_sec]) {
|
||
|
printf("Already done sector %02x on track %02x.%x!\n",
|
||
|
phys_sec, track, side);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* So far so good, let's do it! */
|
||
|
val = 0;
|
||
|
for(i = 0; i < 38; i++) {
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
if(val == 0xd5) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if(val != 0xd5) {
|
||
|
printf("No data header, track %02x.%x, sec %02x\n",
|
||
|
track, side, phys_sec);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
if(val != 0xaa) {
|
||
|
printf("Bad data hdr1,val:%02x trk %02x.%x, sec %02x\n",
|
||
|
val, track, side, phys_sec);
|
||
|
printf("nib_pos: %08x\n", dsk->nib_pos);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
if(val != 0xad) {
|
||
|
printf("Bad data hdr2,val:%02x trk %02x.%x, sec %02x\n",
|
||
|
val, track, side, phys_sec);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
buf = outbuf + (phys_sec << 9);
|
||
|
|
||
|
/* check sector again */
|
||
|
val = from_disk_byte[iwm_read_data(dsk, 1, 0)];
|
||
|
if(val != phys_sec) {
|
||
|
printf("Bad data hdr3,val:%02x trk %02x.%x, sec %02x\n",
|
||
|
val, track, side, phys_sec);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Data start! */
|
||
|
tmp_5c = 0;
|
||
|
tmp_5d = 0;
|
||
|
tmp_5e = 0;
|
||
|
y = 0xaf;
|
||
|
carry = 0;
|
||
|
|
||
|
while(y > 0) {
|
||
|
/* 626f */
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = from_disk_byte[val];
|
||
|
if(val2 < 0) {
|
||
|
printf("Bad data area1b, read: %02x\n", val);
|
||
|
printf(" i:%03x,n_pos:%04x\n", i, dsk->nib_pos);
|
||
|
break;
|
||
|
}
|
||
|
tmp_66 = val2;
|
||
|
|
||
|
tmp_5c = tmp_5c << 1;
|
||
|
carry = (tmp_5c >> 8);
|
||
|
tmp_5c = (tmp_5c + carry) & 0xff;
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = from_disk_byte[val];
|
||
|
if(val2 < 0) {
|
||
|
printf("Bad data area2, read: %02x\n", val);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
val2 = val2 + ((tmp_66 << 2) & 0xc0);
|
||
|
|
||
|
val2 = val2 ^ tmp_5c;
|
||
|
buf_c00[y] = val2;
|
||
|
|
||
|
tmp_5e = val2 + tmp_5e + carry;
|
||
|
carry = (tmp_5e >> 8);
|
||
|
tmp_5e = tmp_5e & 0xff;
|
||
|
/* 62b8 */
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = from_disk_byte[val];
|
||
|
val2 = val2 + ((tmp_66 << 4) & 0xc0);
|
||
|
val2 = val2 ^ tmp_5e;
|
||
|
buf_d00[y] = val2;
|
||
|
tmp_5d = val2 + tmp_5d + carry;
|
||
|
|
||
|
carry = (tmp_5d >> 8);
|
||
|
tmp_5d = tmp_5d & 0xff;
|
||
|
|
||
|
y--;
|
||
|
if(y <= 0) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* 6274 */
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = from_disk_byte[val];
|
||
|
val2 = val2 + ((tmp_66 << 6) & 0xc0);
|
||
|
val2 = val2 ^ tmp_5d;
|
||
|
buf_e00[y+1] = val2;
|
||
|
|
||
|
tmp_5c = val2 + tmp_5c + carry;
|
||
|
carry = (tmp_5c >> 8);
|
||
|
tmp_5c = tmp_5c & 0xff;
|
||
|
}
|
||
|
|
||
|
/* 62d0 */
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = from_disk_byte[val];
|
||
|
|
||
|
tmp_66 = (val2 << 6) & 0xc0;
|
||
|
tmp_67 = (val2 << 4) & 0xc0;
|
||
|
val2 = (val2 << 2) & 0xc0;
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = from_disk_byte[val] + val2;
|
||
|
if(tmp_5e != (word32)val2) {
|
||
|
printf("Checksum 5e bad: %02x vs %02x\n", tmp_5e, val2);
|
||
|
printf("val:%02x trk %02x.%x, sec %02x\n",
|
||
|
val, track, side, phys_sec);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = from_disk_byte[val] + tmp_67;
|
||
|
if(tmp_5d != (word32)val2) {
|
||
|
printf("Checksum 5d bad: %02x vs %02x\n", tmp_5e, val2);
|
||
|
printf("val:%02x trk %02x.%x, sec %02x\n",
|
||
|
val, track, side, phys_sec);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
val2 = from_disk_byte[val] + tmp_66;
|
||
|
if(tmp_5c != (word32)val2) {
|
||
|
printf("Checksum 5c bad: %02x vs %02x\n", tmp_5e, val2);
|
||
|
printf("val:%02x trk %02x.%x, sec %02x\n",
|
||
|
val, track, side, phys_sec);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Whew, got it!...check for DE AA */
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
if(val != 0xde) {
|
||
|
printf("Bad data epi1,val:%02x trk %02x.%x, sec %02x\n",
|
||
|
val, track, side, phys_sec);
|
||
|
printf("nib_pos: %08x\n", dsk->nib_pos);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
val = iwm_read_data(dsk, 1, 0);
|
||
|
if(val != 0xaa) {
|
||
|
printf("Bad data epi2,val:%02x trk %02x.%x, sec %02x\n",
|
||
|
val, track, side, phys_sec);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Now, convert buf_c/d/e to output */
|
||
|
/* 6459 */
|
||
|
y = 0;
|
||
|
for(x = 0xab; x >= 0; x--) {
|
||
|
*buf++ = buf_c00[x];
|
||
|
y++;
|
||
|
if(y >= 0x200) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
*buf++ = buf_d00[x];
|
||
|
y++;
|
||
|
if(y >= 0x200) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
*buf++ = buf_e00[x];
|
||
|
y++;
|
||
|
if(y >= 0x200) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sector_done[phys_sec] = 1;
|
||
|
num_sectors_done++;
|
||
|
if(num_sectors_done >= num_sectors) {
|
||
|
status = 0;
|
||
|
break;
|
||
|
}
|
||
|
val = 0;
|
||
|
}
|
||
|
|
||
|
if(status < 0) {
|
||
|
printf("dsk->nib_pos: %04x, status: %d\n", dsk->nib_pos,
|
||
|
status);
|
||
|
for(i = 0; i < num_sectors; i++) {
|
||
|
printf("sector done[%d] = %d\n", i, sector_done[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
iwm_move_to_track(dsk, save_qtr_track);
|
||
|
dsk->nib_pos = save_nib_pos;
|
||
|
g_fast_disk_unnib = 0;
|
||
|
|
||
|
if(status == 0) {
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
printf("Nibblization not done, %02x sectors found on track %02x\n",
|
||
|
num_sectors_done, qtr_track>>2);
|
||
|
return -1;
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
/* ret = 1 -> dirty data written out */
|
||
|
/* ret = 0 -> not dirty, no error */
|
||
|
/* ret < 0 -> error */
|
||
|
int
|
||
|
disk_track_to_unix(Disk *dsk, int qtr_track, byte *outbuf)
|
||
|
{
|
||
|
Trk *trk;
|
||
|
int disk_525;
|
||
|
|
||
|
disk_525 = dsk->disk_525;
|
||
|
|
||
|
trk = &(dsk->trks[qtr_track]);
|
||
|
|
||
|
if(trk->track_len == 0 || trk->track_dirty == 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
trk->track_dirty = 0;
|
||
|
|
||
|
if((qtr_track & 3) && disk_525) {
|
||
|
halt_printf("You wrote to phase %02x! Can't wr bk to unix!\n",
|
||
|
qtr_track);
|
||
|
dsk->write_through_to_unix = 0;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if(disk_525) {
|
||
|
return iwm_denib_track525(dsk, trk, qtr_track, outbuf);
|
||
|
} else {
|
||
|
return iwm_denib_track35(dsk, trk, qtr_track, outbuf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
show_hex_data(byte *buf, int count)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for(i = 0; i < count; i += 16) {
|
||
|
printf("%04x: %02x %02x %02x %02x %02x %02x %02x %02x "
|
||
|
"%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
|
||
|
buf[i+0], buf[i+1], buf[i+2], buf[i+3],
|
||
|
buf[i+4], buf[i+5], buf[i+6], buf[i+7],
|
||
|
buf[i+8], buf[i+9], buf[i+10], buf[i+11],
|
||
|
buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void
|
||
|
disk_check_nibblization(Disk *dsk, int qtr_track, byte *buf, int size)
|
||
|
{
|
||
|
byte buffer[0x3000];
|
||
|
Trk *trk;
|
||
|
int ret, ret2;
|
||
|
int i;
|
||
|
|
||
|
if(size > 0x3000) {
|
||
|
printf("size %08x is > 0x3000, disk_check_nibblization\n",size);
|
||
|
exit(3);
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < size; i++) {
|
||
|
buffer[i] = 0;
|
||
|
}
|
||
|
|
||
|
trk = &(dsk->trks[qtr_track]);
|
||
|
|
||
|
if(dsk->disk_525) {
|
||
|
ret = iwm_denib_track525(dsk, trk, qtr_track, &(buffer[0]));
|
||
|
} else {
|
||
|
ret = iwm_denib_track35(dsk, trk, qtr_track, &(buffer[0]));
|
||
|
}
|
||
|
|
||
|
ret2 = -1;
|
||
|
for(i = 0; i < size; i++) {
|
||
|
if(buffer[i] != buf[i]) {
|
||
|
printf("buffer[%04x]: %02x != %02x\n", i, buffer[i],
|
||
|
buf[i]);
|
||
|
ret2 = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(ret != 1 || ret2 >= 0) {
|
||
|
printf("disk_check_nib ret:%d, ret2:%d for q_track %03x\n",
|
||
|
ret, ret2, qtr_track);
|
||
|
show_hex_data(buf, 0x1000);
|
||
|
show_hex_data(buffer, 0x1000);
|
||
|
iwm_show_a_track(&(dsk->trks[qtr_track]));
|
||
|
|
||
|
exit(2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#define TRACK_BUF_LEN 0x2000
|
||
|
|
||
|
void
|
||
|
disk_unix_to_nib(Disk *dsk, int qtr_track, int unix_pos, int unix_len,
|
||
|
int nib_len)
|
||
|
{
|
||
|
byte track_buf[TRACK_BUF_LEN];
|
||
|
Trk *trk;
|
||
|
int must_clear_track;
|
||
|
int ret;
|
||
|
int len;
|
||
|
int i;
|
||
|
|
||
|
/* Read track from dsk int track_buf */
|
||
|
|
||
|
must_clear_track = 0;
|
||
|
|
||
|
if(unix_len > TRACK_BUF_LEN) {
|
||
|
printf("diks_unix_to_nib: requested len of image %s = %05x\n",
|
||
|
dsk->name_ptr, unix_len);
|
||
|
}
|
||
|
|
||
|
if(unix_pos >= 0) {
|
||
|
ret = lseek(dsk->fd, unix_pos, SEEK_SET);
|
||
|
if(ret != unix_pos) {
|
||
|
printf("lseek of disk %s len 0x%x ret: %d, errno: %d\n",
|
||
|
dsk->name_ptr, unix_pos, ret, errno);
|
||
|
must_clear_track = 1;
|
||
|
}
|
||
|
|
||
|
len = read(dsk->fd, track_buf, unix_len);
|
||
|
if(len != unix_len) {
|
||
|
printf("read of disk %s q_trk %d ret: %d, errno: %d\n",
|
||
|
dsk->name_ptr, qtr_track, ret, errno);
|
||
|
must_clear_track = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(must_clear_track) {
|
||
|
for(i = 0; i < TRACK_BUF_LEN; i++) {
|
||
|
track_buf[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
printf("Q_track %02x dumped out\n", qtr_track);
|
||
|
|
||
|
for(i = 0; i < 4096; i += 32) {
|
||
|
printf("%04x: %02x%02x%02x%02x%02x%02x%02x%02x "
|
||
|
"%02x%02x%02x%02x%02x%02x%02x%02x "
|
||
|
"%02x%02x%02x%02x%02x%02x%02x%02x "
|
||
|
"%02x%02x%02x%02x%02x%02x%02x%02x\n", i,
|
||
|
track_buf[i+0], track_buf[i+1], track_buf[i+2],
|
||
|
track_buf[i+3], track_buf[i+4], track_buf[i+5],
|
||
|
track_buf[i+6], track_buf[i+7], track_buf[i+8],
|
||
|
track_buf[i+9], track_buf[i+10], track_buf[i+11],
|
||
|
track_buf[i+12], track_buf[i+13], track_buf[i+14],
|
||
|
track_buf[i+15], track_buf[i+16], track_buf[i+17],
|
||
|
track_buf[i+18], track_buf[i+19], track_buf[i+20],
|
||
|
track_buf[i+21], track_buf[i+22], track_buf[i+23],
|
||
|
track_buf[i+24], track_buf[i+25], track_buf[i+26],
|
||
|
track_buf[i+27], track_buf[i+28], track_buf[i+29],
|
||
|
track_buf[i+30], track_buf[i+31]);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
dsk->nib_pos = 0; /* for consistency */
|
||
|
|
||
|
trk = &(dsk->trks[qtr_track]);
|
||
|
trk->track_dirty = 0;
|
||
|
trk->overflow_size = 0;
|
||
|
trk->track_len = 2*nib_len;
|
||
|
trk->unix_pos = unix_pos;
|
||
|
trk->unix_len = unix_len;
|
||
|
trk->dsk = dsk;
|
||
|
trk->nib_area = (byte *)malloc(trk->track_len);
|
||
|
|
||
|
/* create nibblized image */
|
||
|
|
||
|
if(dsk->disk_525 && dsk->image_type == DSK_TYPE_NIB) {
|
||
|
iwm_nibblize_track_nib525(dsk, trk, track_buf, qtr_track);
|
||
|
} else if(dsk->disk_525) {
|
||
|
iwm_nibblize_track_525(dsk, trk, track_buf, qtr_track);
|
||
|
} else {
|
||
|
iwm_nibblize_track_35(dsk, trk, track_buf, qtr_track);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_nibblize_track_nib525(Disk *dsk, Trk *trk, byte *track_buf, int qtr_track)
|
||
|
{
|
||
|
byte *nib_ptr;
|
||
|
byte *trk_ptr;
|
||
|
int len;
|
||
|
int i;
|
||
|
|
||
|
len = trk->track_len;
|
||
|
trk_ptr = track_buf;
|
||
|
nib_ptr = &(trk->nib_area[0]);
|
||
|
for(i = 0; i < len; i += 2) {
|
||
|
nib_ptr[i] = 8;
|
||
|
nib_ptr[i+1] = *trk_ptr++;;
|
||
|
}
|
||
|
|
||
|
iwm_printf("Nibblized q_track %02x\n", qtr_track);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_nibblize_track_525(Disk *dsk, Trk *trk, byte *track_buf, int qtr_track)
|
||
|
{
|
||
|
byte partial_nib_buf[0x300];
|
||
|
word32 *word_ptr;
|
||
|
word32 val;
|
||
|
word32 last_val;
|
||
|
int phys_sec;
|
||
|
int log_sec;
|
||
|
int num_sync;
|
||
|
int i;
|
||
|
|
||
|
|
||
|
word_ptr = (word32 *)&(trk->nib_area[0]);
|
||
|
#ifdef KEGS_LITTLE_ENDIAN
|
||
|
val = 0xff08ff08;
|
||
|
#else
|
||
|
val = 0x08ff08ff;
|
||
|
#endif
|
||
|
for(i = 0; i < trk->track_len; i += 4) {
|
||
|
*word_ptr++ = val;
|
||
|
}
|
||
|
|
||
|
|
||
|
for(phys_sec = 0; phys_sec < 16; phys_sec++) {
|
||
|
if(dsk->image_type == DSK_TYPE_DOS33) {
|
||
|
log_sec = phys_to_dos_sec[phys_sec];
|
||
|
} else {
|
||
|
log_sec = phys_to_prodos_sec[phys_sec];
|
||
|
}
|
||
|
|
||
|
/* Create sync headers */
|
||
|
if(phys_sec == 0) {
|
||
|
num_sync = 70;
|
||
|
} else {
|
||
|
num_sync = 14;
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < num_sync; i++) {
|
||
|
disk_nib_out(dsk, 0xff, 10);
|
||
|
}
|
||
|
disk_nib_out(dsk, 0xd5, 10); /* prolog */
|
||
|
disk_nib_out(dsk, 0xaa, 8); /* prolog */
|
||
|
disk_nib_out(dsk, 0x96, 8); /* prolog */
|
||
|
disk_4x4_nib_out(dsk, dsk->vol_num);
|
||
|
disk_4x4_nib_out(dsk, qtr_track >> 2);
|
||
|
disk_4x4_nib_out(dsk, phys_sec);
|
||
|
disk_4x4_nib_out(dsk, dsk->vol_num ^ (qtr_track>>2) ^ phys_sec);
|
||
|
disk_nib_out(dsk, 0xde, 8); /* epi */
|
||
|
disk_nib_out(dsk, 0xaa, 8); /* epi */
|
||
|
disk_nib_out(dsk, 0xeb, 8); /* epi */
|
||
|
|
||
|
/* Inter sync */
|
||
|
disk_nib_out(dsk, 0xff, 8);
|
||
|
for(i = 0; i < 5; i++) {
|
||
|
disk_nib_out(dsk, 0xff, 10);
|
||
|
}
|
||
|
disk_nib_out(dsk, 0xd5, 10); /* data prolog */
|
||
|
disk_nib_out(dsk, 0xaa, 8); /* data prolog */
|
||
|
disk_nib_out(dsk, 0xad, 8); /* data prolog */
|
||
|
|
||
|
sector_to_partial_nib( &(track_buf[log_sec*256]),
|
||
|
&(partial_nib_buf[0]));
|
||
|
|
||
|
last_val = 0;
|
||
|
for(i = 0; i < 0x156; i++) {
|
||
|
val = partial_nib_buf[i];
|
||
|
disk_nib_out(dsk, to_disk_byte[last_val ^ val], 8);
|
||
|
last_val = val;
|
||
|
}
|
||
|
disk_nib_out(dsk, to_disk_byte[last_val], 8);
|
||
|
|
||
|
/* data epilog */
|
||
|
disk_nib_out(dsk, 0xde, 8); /* epi */
|
||
|
disk_nib_out(dsk, 0xaa, 8); /* epi */
|
||
|
disk_nib_out(dsk, 0xeb, 8); /* epi */
|
||
|
disk_nib_out(dsk, 0xff, 8);
|
||
|
for(i = 0; i < 6; i++) {
|
||
|
disk_nib_out(dsk, 0xff, 10);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* finish nibblization */
|
||
|
disk_nib_end_track(dsk);
|
||
|
|
||
|
iwm_printf("Nibblized q_track %02x\n", qtr_track);
|
||
|
|
||
|
if(g_check_nibblization) {
|
||
|
disk_check_nibblization(dsk, qtr_track, &(track_buf[0]),0x1000);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_nibblize_track_35(Disk *dsk, Trk *trk, byte *track_buf, int qtr_track)
|
||
|
{
|
||
|
int phys_to_log_sec[16];
|
||
|
word32 buf_c00[0x100];
|
||
|
word32 buf_d00[0x100];
|
||
|
word32 buf_e00[0x100];
|
||
|
byte *buf;
|
||
|
word32 *word_ptr;
|
||
|
word32 val;
|
||
|
int num_sectors;
|
||
|
int unix_len;
|
||
|
int log_sec;
|
||
|
int phys_sec;
|
||
|
int track;
|
||
|
int side;
|
||
|
int interleave;
|
||
|
int num_sync;
|
||
|
word32 phys_track, phys_side, capacity, cksum;
|
||
|
word32 tmp_5c, tmp_5d, tmp_5e, tmp_5f;
|
||
|
word32 tmp_63, tmp_64, tmp_65;
|
||
|
word32 acc_hi;
|
||
|
int carry;
|
||
|
int x, y;
|
||
|
int i;
|
||
|
|
||
|
word_ptr = (word32 *)&(trk->nib_area[0]);
|
||
|
#ifdef KEGS_LITTLE_ENDIAN
|
||
|
val = 0xff08ff08;
|
||
|
#else
|
||
|
val = 0x08ff08ff;
|
||
|
#endif
|
||
|
if(trk->track_len & 3) {
|
||
|
halt_printf("track_len: %08x is not a multiple of 4\n",
|
||
|
trk->track_len);
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < trk->track_len; i += 4) {
|
||
|
*word_ptr++ = val;
|
||
|
}
|
||
|
|
||
|
unix_len = trk->unix_len;
|
||
|
|
||
|
num_sectors = (unix_len >> 9);
|
||
|
|
||
|
for(i = 0; i < num_sectors; i++) {
|
||
|
phys_to_log_sec[i] = -1;
|
||
|
}
|
||
|
|
||
|
phys_sec = 0;
|
||
|
interleave = 2;
|
||
|
for(log_sec = 0; log_sec < num_sectors; log_sec++) {
|
||
|
while(phys_to_log_sec[phys_sec] >= 0) {
|
||
|
phys_sec++;
|
||
|
if(phys_sec >= num_sectors) {
|
||
|
phys_sec = 0;
|
||
|
}
|
||
|
}
|
||
|
phys_to_log_sec[phys_sec] = log_sec;
|
||
|
phys_sec += interleave;
|
||
|
if(phys_sec >= num_sectors) {
|
||
|
phys_sec -= num_sectors;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
track = qtr_track >> 1;
|
||
|
side = qtr_track & 1;
|
||
|
for(phys_sec = 0; phys_sec < num_sectors; phys_sec++) {
|
||
|
|
||
|
log_sec = phys_to_log_sec[phys_sec];
|
||
|
if(log_sec < 0) {
|
||
|
printf("Track: %02x.%x phys_sec: %02x = %d!\n",
|
||
|
track, side, phys_sec, log_sec);
|
||
|
exit(2);
|
||
|
}
|
||
|
|
||
|
/* Create sync headers */
|
||
|
if(phys_sec == 0) {
|
||
|
num_sync = 400;
|
||
|
} else {
|
||
|
num_sync = 54;
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < num_sync; i++) {
|
||
|
disk_nib_out(dsk, 0xff, 10);
|
||
|
}
|
||
|
|
||
|
disk_nib_out(dsk, 0xd5, 10); /* prolog */
|
||
|
disk_nib_out(dsk, 0xaa, 8); /* prolog */
|
||
|
disk_nib_out(dsk, 0x96, 8); /* prolog */
|
||
|
|
||
|
phys_track = track & 0x3f;
|
||
|
phys_side = (side << 5) + (track >> 6);
|
||
|
capacity = 0x22;
|
||
|
disk_nib_out(dsk, to_disk_byte[phys_track], 8); /* trk */
|
||
|
disk_nib_out(dsk, to_disk_byte[log_sec], 8); /* sec */
|
||
|
disk_nib_out(dsk, to_disk_byte[phys_side], 8); /* sides+trk */
|
||
|
disk_nib_out(dsk, to_disk_byte[capacity], 8); /* capacity*/
|
||
|
|
||
|
cksum = (phys_track ^ log_sec ^ phys_side ^ capacity) & 0x3f;
|
||
|
disk_nib_out(dsk, to_disk_byte[cksum], 8); /* cksum*/
|
||
|
|
||
|
disk_nib_out(dsk, 0xde, 8); /* epi */
|
||
|
disk_nib_out(dsk, 0xaa, 8); /* epi */
|
||
|
|
||
|
/* Inter sync */
|
||
|
for(i = 0; i < 5; i++) {
|
||
|
disk_nib_out(dsk, 0xff, 10);
|
||
|
}
|
||
|
disk_nib_out(dsk, 0xd5, 10); /* data prolog */
|
||
|
disk_nib_out(dsk, 0xaa, 8); /* data prolog */
|
||
|
disk_nib_out(dsk, 0xad, 8); /* data prolog */
|
||
|
disk_nib_out(dsk, to_disk_byte[log_sec], 8); /* sec again */
|
||
|
|
||
|
/* do nibblizing! */
|
||
|
buf = track_buf + (log_sec << 9);
|
||
|
|
||
|
/* 6320 */
|
||
|
tmp_5e = 0;
|
||
|
tmp_5d = 0;
|
||
|
tmp_5c = 0;
|
||
|
y = 0;
|
||
|
x = 0xaf;
|
||
|
buf_c00[0] = 0;
|
||
|
buf_d00[0] = 0;
|
||
|
buf_e00[0] = 0;
|
||
|
buf_e00[1] = 0;
|
||
|
for(y = 0x4; y > 0; y--) {
|
||
|
buf_c00[x] = 0;
|
||
|
buf_d00[x] = 0;
|
||
|
buf_e00[x] = 0;
|
||
|
x--;
|
||
|
}
|
||
|
|
||
|
while(x >= 0) {
|
||
|
/* 6338 */
|
||
|
tmp_5c = tmp_5c << 1;
|
||
|
carry = (tmp_5c >> 8);
|
||
|
tmp_5c = (tmp_5c + carry) & 0xff;
|
||
|
|
||
|
val = buf[y];
|
||
|
tmp_5e = val + tmp_5e + carry;
|
||
|
carry = (tmp_5e >> 8);
|
||
|
tmp_5e = tmp_5e & 0xff;
|
||
|
|
||
|
val = val ^ tmp_5c;
|
||
|
buf_c00[x] = val;
|
||
|
y++;
|
||
|
/* 634c */
|
||
|
val = buf[y];
|
||
|
tmp_5d = tmp_5d + val + carry;
|
||
|
carry = (tmp_5d >> 8);
|
||
|
tmp_5d = tmp_5d & 0xff;
|
||
|
val = val ^ tmp_5e;
|
||
|
buf_d00[x] = val;
|
||
|
y++;
|
||
|
x--;
|
||
|
if(x <= 0) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* 632a */
|
||
|
val = buf[y];
|
||
|
tmp_5c = tmp_5c + val + carry;
|
||
|
carry = (tmp_5c >> 8);
|
||
|
tmp_5c = tmp_5c & 0xff;
|
||
|
|
||
|
val = val ^ tmp_5d;
|
||
|
buf_e00[x+1] = val;
|
||
|
y++;
|
||
|
}
|
||
|
|
||
|
/* 635f */
|
||
|
val = ((tmp_5c >> 2) ^ tmp_5d) & 0x3f;
|
||
|
/* 6367 */
|
||
|
val = (val ^ tmp_5d) >> 2;
|
||
|
/* 636b */
|
||
|
val = (val ^ tmp_5e) & 0x3f;
|
||
|
/* 636f */
|
||
|
val = (val ^ tmp_5e) >> 2;
|
||
|
/* 6373 */
|
||
|
tmp_5f = val;
|
||
|
/* 6375 */
|
||
|
tmp_63 = 0;
|
||
|
tmp_64 = 0;
|
||
|
tmp_65 = 0;
|
||
|
acc_hi = 0;
|
||
|
|
||
|
|
||
|
y = 0xae;
|
||
|
while(y >= 0) {
|
||
|
/* 63e4 */
|
||
|
/* write out acc_hi */
|
||
|
val = to_disk_byte[acc_hi & 0x3f];
|
||
|
disk_nib_out(dsk, val, 8);
|
||
|
|
||
|
/* 63f2 */
|
||
|
val = to_disk_byte[tmp_63 & 0x3f];
|
||
|
tmp_63 = buf_c00[y];
|
||
|
acc_hi = tmp_63 >> 6;
|
||
|
disk_nib_out(dsk, val, 8);
|
||
|
/* 640b */
|
||
|
val = to_disk_byte[tmp_64 & 0x3f];
|
||
|
tmp_64 = buf_d00[y];
|
||
|
acc_hi = (acc_hi << 2) + (tmp_64 >> 6);
|
||
|
disk_nib_out(dsk, val, 8);
|
||
|
y--;
|
||
|
if(y < 0) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* 63cb */
|
||
|
val = to_disk_byte[tmp_65 & 0x3f];
|
||
|
tmp_65 = buf_e00[y+1];
|
||
|
acc_hi = (acc_hi << 2) + (tmp_65 >> 6);
|
||
|
disk_nib_out(dsk, val, 8);
|
||
|
}
|
||
|
/* 6429 */
|
||
|
val = to_disk_byte[tmp_5f & 0x3f];
|
||
|
disk_nib_out(dsk, val, 8);
|
||
|
|
||
|
val = to_disk_byte[tmp_5e & 0x3f];
|
||
|
disk_nib_out(dsk, val, 8);
|
||
|
|
||
|
val = to_disk_byte[tmp_5d & 0x3f];
|
||
|
disk_nib_out(dsk, val, 8);
|
||
|
|
||
|
val = to_disk_byte[tmp_5c & 0x3f];
|
||
|
disk_nib_out(dsk, val, 8);
|
||
|
|
||
|
/* 6440 */
|
||
|
/* data epilog */
|
||
|
disk_nib_out(dsk, 0xde, 8); /* epi */
|
||
|
disk_nib_out(dsk, 0xaa, 8); /* epi */
|
||
|
disk_nib_out(dsk, 0xff, 8);
|
||
|
}
|
||
|
|
||
|
|
||
|
disk_nib_end_track(dsk);
|
||
|
|
||
|
if(g_check_nibblization) {
|
||
|
disk_check_nibblization(dsk, qtr_track, &(track_buf[0]),
|
||
|
unix_len);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
disk_4x4_nib_out(Disk *dsk, word32 val)
|
||
|
{
|
||
|
disk_nib_out(dsk, 0xaa | (val >> 1), 8);
|
||
|
disk_nib_out(dsk, 0xaa | val, 8);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
disk_nib_out(Disk *dsk, byte val, int size)
|
||
|
{
|
||
|
Trk *trk;
|
||
|
int pos;
|
||
|
int old_size;
|
||
|
int track_len;
|
||
|
int overflow_size;
|
||
|
int qtr_track;
|
||
|
|
||
|
|
||
|
qtr_track = dsk->cur_qtr_track;
|
||
|
|
||
|
track_len = 0;
|
||
|
trk = 0;
|
||
|
if(dsk->trks != 0) {
|
||
|
trk = &(dsk->trks[qtr_track]);
|
||
|
track_len = trk->track_len;
|
||
|
}
|
||
|
|
||
|
if(track_len <= 10) {
|
||
|
printf("Writing to an invalid qtr track: %02x!\n", qtr_track);
|
||
|
printf("name: %s, track_len: %08x, val: %08x, size: %d\n",
|
||
|
dsk->name_ptr, track_len, val, size);
|
||
|
exit(1);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
trk->track_dirty = 1;
|
||
|
dsk->disk_dirty = 1;
|
||
|
|
||
|
pos = trk->dsk->nib_pos;
|
||
|
overflow_size = trk->overflow_size;
|
||
|
if(pos >= track_len) {
|
||
|
pos = 0;
|
||
|
}
|
||
|
|
||
|
old_size = trk->nib_area[pos];
|
||
|
|
||
|
|
||
|
while(size >= (10 + old_size)) {
|
||
|
size = size - old_size;
|
||
|
pos += 2;
|
||
|
if(pos >= track_len) {
|
||
|
pos = 0;
|
||
|
}
|
||
|
old_size = trk->nib_area[pos];
|
||
|
}
|
||
|
|
||
|
if(size > 10) {
|
||
|
size = 10;
|
||
|
}
|
||
|
|
||
|
if((val & 0x80) == 0) {
|
||
|
val |= 0x80;
|
||
|
}
|
||
|
|
||
|
trk->nib_area[pos++] = size;
|
||
|
trk->nib_area[pos++] = val;
|
||
|
if(pos >= track_len) {
|
||
|
pos = 0;
|
||
|
}
|
||
|
|
||
|
overflow_size += (size - old_size);
|
||
|
if((overflow_size > 8) && (size > 8)) {
|
||
|
overflow_size -= trk->nib_area[pos];
|
||
|
trk->nib_area[pos++] = 0;
|
||
|
trk->nib_area[pos++] = 0;
|
||
|
if(pos >= track_len) {
|
||
|
pos = 0;
|
||
|
}
|
||
|
} else if(overflow_size < -64) {
|
||
|
halt_printf("overflow_sz:%03x, pos:%02x\n",overflow_size,pos);
|
||
|
}
|
||
|
|
||
|
trk->dsk->nib_pos = pos;
|
||
|
trk->overflow_size = overflow_size;
|
||
|
|
||
|
if((val & 0x80) == 0 || size < 8) {
|
||
|
halt_printf("disk_nib_out, wrote %02x, size: %d\n", val, size);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
disk_nib_end_track(Disk *dsk)
|
||
|
{
|
||
|
int qtr_track;
|
||
|
|
||
|
dsk->nib_pos = 0;
|
||
|
qtr_track = dsk->cur_qtr_track;
|
||
|
dsk->trks[qtr_track].track_dirty = 0;
|
||
|
|
||
|
dsk->disk_dirty = 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_show_track(int slot_drive, int track)
|
||
|
{
|
||
|
Disk *dsk;
|
||
|
Trk *trk;
|
||
|
int drive;
|
||
|
int sel35;
|
||
|
int qtr_track;
|
||
|
|
||
|
if(slot_drive < 0) {
|
||
|
drive = iwm.drive_select;
|
||
|
sel35 = (g_c031_disk35 >> 6) & 1;
|
||
|
} else {
|
||
|
drive = slot_drive & 1;
|
||
|
sel35 = !((slot_drive >> 1) & 1);
|
||
|
}
|
||
|
|
||
|
if(sel35) {
|
||
|
dsk = &(iwm.drive35[drive]);
|
||
|
} else {
|
||
|
dsk = &(iwm.drive525[drive]);
|
||
|
}
|
||
|
|
||
|
if(track < 0) {
|
||
|
qtr_track = dsk->cur_qtr_track;
|
||
|
} else {
|
||
|
qtr_track = track;
|
||
|
}
|
||
|
if(dsk->trks == 0) {
|
||
|
return;
|
||
|
}
|
||
|
trk = &(dsk->trks[qtr_track]);
|
||
|
|
||
|
if(trk->track_len <= 0) {
|
||
|
printf("Track_len: %d\n", trk->track_len);
|
||
|
printf("No track for type: %d, drive: %d, qtrk: 0x%02x\n",
|
||
|
sel35, drive, qtr_track);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
printf("Current drive: %d, q_track: 0x%02x\n", drive, qtr_track);
|
||
|
|
||
|
iwm_show_a_track(trk);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
iwm_show_a_track(Trk *trk)
|
||
|
{
|
||
|
int sum;
|
||
|
int len;
|
||
|
int pos;
|
||
|
int i;
|
||
|
|
||
|
printf(" Showtrack:dirty: %d, pos: %04x, ovfl: %04x, len: %04x\n",
|
||
|
trk->track_dirty, trk->dsk->nib_pos,
|
||
|
trk->overflow_size, trk->track_len);
|
||
|
|
||
|
len = trk->track_len;
|
||
|
printf("Track len in bytes: %04x\n", len);
|
||
|
if(len >= 2*15000) {
|
||
|
len = 2*15000;
|
||
|
printf("len too big, using %04x\n", len);
|
||
|
}
|
||
|
|
||
|
pos = 0;
|
||
|
for(i = 0; i < len; i += 16) {
|
||
|
printf("%04x: %2d,%02x %2d,%02x %2d,%02x %2d,%02x "
|
||
|
"%2d,%02x %2d,%02x %2d,%02x %2d,%02x\n", pos,
|
||
|
trk->nib_area[pos], trk->nib_area[pos+1],
|
||
|
trk->nib_area[pos+2], trk->nib_area[pos+3],
|
||
|
trk->nib_area[pos+4], trk->nib_area[pos+5],
|
||
|
trk->nib_area[pos+6], trk->nib_area[pos+7],
|
||
|
trk->nib_area[pos+8], trk->nib_area[pos+9],
|
||
|
trk->nib_area[pos+10], trk->nib_area[pos+11],
|
||
|
trk->nib_area[pos+12], trk->nib_area[pos+13],
|
||
|
trk->nib_area[pos+14], trk->nib_area[pos+15]);
|
||
|
pos += 16;
|
||
|
if(pos >= len) {
|
||
|
pos -= len;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sum = 0;
|
||
|
for(i = 0; i < len; i += 2) {
|
||
|
sum += trk->nib_area[i];
|
||
|
}
|
||
|
|
||
|
printf("bit_sum: %d, expected: %d, overflow_size: %d\n",
|
||
|
sum, len*8/2, trk->overflow_size);
|
||
|
}
|
||
|
|