kegs/src/iwm.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);
}