4509 lines
135 KiB
JavaScript
4509 lines
135 KiB
JavaScript
/*-------------------------------------------------------------------------
|
|
| SAE - Scripted Amiga Emulator
|
|
| https://github.com/naTmeg/ScriptedAmigaEmulator
|
|
|
|
|
| Copyright (C) 2012-2016 Rupert Hausberger
|
|
|
|
|
| This program is free software; you can redistribute it and/or
|
|
| modify it under the terms of the GNU General Public License
|
|
| as published by the Free Software Foundation; either version 2
|
|
| of the License, or (at your option) any later version.
|
|
|
|
|
| This program is distributed in the hope that it will be useful,
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| GNU General Public License for more details.
|
|
|
|
|
| Note: ported from WinUAE 3.2.x
|
|
-------------------------------------------------------------------------*/
|
|
/* global constants */
|
|
|
|
const SAEC_Disk_Create_Mode_Normal = 1;
|
|
const SAEC_Disk_Create_Mode_Custom = 2;
|
|
|
|
const SAEC_Disk_Create_Type_35_DD = 1;
|
|
const SAEC_Disk_Create_Type_35_HD = 2;
|
|
const SAEC_Disk_Create_Type_35_DD_PC = 3;
|
|
const SAEC_Disk_Create_Type_35_HD_PC = 4;
|
|
const SAEC_Disk_Create_Type_525_SD = 5;
|
|
|
|
/*---------------------------------*/
|
|
/* global objects */
|
|
|
|
function SAEO_DiskInfo() { //struct diskinfo
|
|
this.diskname = "";
|
|
this.hd = false;
|
|
|
|
this.crc32 = 0;
|
|
|
|
this.bootblock = new Uint8Array(1024);
|
|
this.bootblockChecksum = false;
|
|
this.bootblockChecksumValid = false;
|
|
this.bootblockType = 0;
|
|
|
|
this.unreadable = false;
|
|
|
|
this.clr = function() {
|
|
this.diskname = "";
|
|
this.hd = false;
|
|
|
|
this.crc32 = 0;
|
|
|
|
SAEF_memset(this.bootblock,0, 0, 1024);
|
|
this.bootblockChecksum = 0;
|
|
this.bootblockChecksumValid = false;
|
|
this.bootblockType = 0;
|
|
|
|
this.unreadable = false;
|
|
};
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function SAEO_Disk() {
|
|
/*#define DISK_DEBUG_DMA_READ 1
|
|
#define DISK_DEBUG_DMA_WRITE 2
|
|
#define DISK_DEBUG_PIO 4
|
|
const disk_debug_mode = 0;
|
|
const disk_debug_track = -1;*/
|
|
const disk_debug_logging = 0;
|
|
|
|
const DEBUG_DRIVE_ID = 0;
|
|
const REVOLUTION_DEBUG = 0;
|
|
|
|
/*---------------------------------*/
|
|
|
|
const FLOPPY_WRITE_MAXLEN = 0x3800;
|
|
/* writable track length with normal 2us bitcell/300RPM motor, 12667 PAL, 12797 NTSC */
|
|
//function FLOPPY_WRITE_LEN() { return SAEV_config.floppy.writeLength > 256 ? SAEV_config.floppy.writeLength / 2 : (SAEV_config.chipset.ntsc ? (12798 / 2) : (12668 / 2)); }
|
|
//function FLOPPY_WRITE_LEN() { return SAEV_config.chipset.ntsc ? 12798 / 2 : 12668 / 2; }
|
|
function FLOPPY_WRITE_LEN() { return SAEV_config.chipset.ntsc ? 6399 : 6334; }
|
|
//function FLOPPY_GAP_LEN() { return FLOPPY_WRITE_LEN() - 11 * 544; } /* This works out to 350 */
|
|
function FLOPPY_GAP_LEN() { return SAEV_config.chipset.ntsc ? 415 : 350; } /* This works out to 415/350 */
|
|
|
|
/* (cycles/bitcell) << 8, normal = ((2us/280ns)<<8) = ~1828.5714 */
|
|
function NORMAL_FLOPPY_SPEED() { return SAEV_config.chipset.ntsc ? 1812 : 1829; }
|
|
|
|
const DDHDMULT = 2;
|
|
const MAX_SECTORS = DDHDMULT * 11;
|
|
const MAX_FLOPPY_DRIVES = 4;
|
|
|
|
const MIN_STEPLIMIT_CYCLE = 140 * SAEC_Events_CYCLE_UNIT;
|
|
|
|
const exeheader = [0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00];
|
|
|
|
/*---------------------------------*/
|
|
|
|
var side = 0, direction = 0, reserved_side = 0;
|
|
var selected = 15, disabled = 0, reserved = 0; //u8
|
|
|
|
var writebuffer = new Uint8Array(544 * MAX_SECTORS);
|
|
var longwritemode = 0;
|
|
|
|
const DISK_INDEXSYNC = 1;
|
|
const DISK_WORDSYNC = 2;
|
|
const DISK_REVOLUTION = 4; /* 8,16,32,64 */
|
|
|
|
const DSKREADY_UP_TIME = 18;
|
|
const DSKREADY_DOWN_TIME = 24;
|
|
const WORDSYNC_TIME = 11;
|
|
|
|
const DSKDMA_OFF = 0;
|
|
const DSKDMA_INIT = 1;
|
|
const DSKDMA_READ = 2;
|
|
const DSKDMA_WRITE = 3;
|
|
|
|
var dskdmaen = 0, dsklength = 0, dsklength2 = 0, dsklen = 0;
|
|
var dskbytr_val = 0; //u16
|
|
var dskpt = 0; //u32
|
|
var fifo_filled = false;
|
|
var fifo = new Uint16Array(3);
|
|
var fifo_inuse = new Int8Array(3); //int [3]
|
|
var dma_enable = 0, bitoffset = 0, syncoffset = 0;
|
|
var word = 0, dsksync = 0; //u16
|
|
var dsksync_cycles = 0; //ulong
|
|
var disk_hpos = 0;
|
|
var disk_jitter = 0;
|
|
var indexdecay = 0;
|
|
var prev_data = 0; //u8
|
|
var prev_step = 0;
|
|
var initial_disk_statusline = false;
|
|
//var disk_info_data = new SAEO_DiskInfo();
|
|
var amax_enabled = false;
|
|
var linecounter = 0;
|
|
var prev_days = 0, prev_mins = 0, prev_ticks = 0;
|
|
var warned_ext2 = false;
|
|
var warned_trackspeed = 0;
|
|
var driveNames = ["","","",""]; //OWN
|
|
|
|
/*---------------------------------*/
|
|
|
|
const MAX_TRACKS = 2 * 83;
|
|
|
|
const TRACK_AMIGADOS = 0;
|
|
const TRACK_RAW = 1;
|
|
const TRACK_RAW1 = 2;
|
|
const TRACK_PCDOS = 3;
|
|
const TRACK_DISKSPARE = 4;
|
|
const TRACK_NONE = 5;
|
|
|
|
function trackid() {
|
|
this.len = 0; //u16
|
|
this.offs = 0; //u32
|
|
this.bitlen = 0;
|
|
this.track = 0;
|
|
this.sync = 0; //u16
|
|
this.type = TRACK_NONE;
|
|
this.revolutions = 0;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
/* We have three kinds of Amiga floppy drives
|
|
* - internal A500/A2000 drive:
|
|
* ID is always DRIVE_ID_NONE (S.T.A.G expects this)
|
|
* - HD drive (A3000/A4000):
|
|
* ID is DRIVE_ID_35DD if DD floppy is inserted or drive is empty
|
|
* ID is DRIVE_ID_35HD if HD floppy is inserted
|
|
* - regular external drive:
|
|
* ID is always DRIVE_ID_35DD
|
|
*/
|
|
const DRIVE_ID_NONE = 0x00000000;
|
|
const DRIVE_ID_35DD = 0xFFFFFFFF;
|
|
const DRIVE_ID_35HD = 0xAAAAAAAA;
|
|
const DRIVE_ID_525SD = 0x55555555; /* 40 track 5.25 drive , kickstart does not recognize this */
|
|
|
|
const ADF_NONE = -1;
|
|
const ADF_NORMAL = 0;
|
|
const ADF_EXT1 = 1;
|
|
const ADF_EXT2 = 2;
|
|
//const ADF_FDI = 3; /* not implemented */
|
|
//const ADF_IPF = 4; /* not implemented */
|
|
const ADF_SCP = 5;
|
|
//const ADF_CATWEASEL = 6; /* not implemented (support not possible with javascript) */
|
|
const ADF_PCDOS = 7;
|
|
const ADF_KICK = 8;
|
|
const ADF_SKICK = 9;
|
|
|
|
function drive(num) {
|
|
this.num = num; //OWN
|
|
this.diskfile = null; //zfile *
|
|
this.writediskfile = null;
|
|
this.pcdecodedfile = null;
|
|
this.filetype = ADF_NONE;
|
|
this.trackdata = new Array(MAX_TRACKS);
|
|
this.writetrackdata = new Array(MAX_TRACKS);
|
|
for (var vi = 0; vi < MAX_TRACKS; vi++) {
|
|
this.trackdata[vi] = new trackid();
|
|
this.writetrackdata[vi] = new trackid();
|
|
}
|
|
this.buffered_cyl = 0;
|
|
this.buffered_side = 0;
|
|
this.cyl = 0;
|
|
this.motoroff = false;
|
|
this.motordelay = 0; /* dskrdy needs some clock cycles before it changes after switching off motor */
|
|
this.state = false;
|
|
this.wrprot = false;
|
|
this.forcedwrprot = false;
|
|
this.bigmfmbuf = new Uint16Array(0x4000 * DDHDMULT);
|
|
this.tracktiming = new Uint16Array(0x4000 * DDHDMULT);
|
|
this.multi_revolution = 0;
|
|
this.revolution_check = 0;
|
|
this.skipoffset = 0;
|
|
this.mfmpos = 0;
|
|
this.indexoffset = 0;
|
|
this.tracklen = 0;
|
|
this.revolutions = 0;
|
|
this.prevtracklen = 0;
|
|
this.trackspeed = 0;
|
|
this.num_tracks = 0;
|
|
this.write_num_tracks = 0;
|
|
this.num_secs = 0;
|
|
this.num_heads = 0;
|
|
this.hard_num_cyls = 0;
|
|
this.dskeject = false;
|
|
this.dskchange = false;
|
|
this.dskchange_time = 0;
|
|
this.dskchange_request = false; //OWN
|
|
this.dskready = false;
|
|
this.dskready_up_time = 0;
|
|
this.dskready_down_time = 0;
|
|
this.writtento = 0;
|
|
this.steplimit = 0;
|
|
this.steplimitcycle = 0; //frame_time_t
|
|
this.indexhack = false;
|
|
this.indexhackmode = 0;
|
|
this.ddhd = 0; /* 1=DD 2=HD */
|
|
this.drive_id_scnt = 0; /* drive id shift counter */
|
|
this.idbit = 0;
|
|
this.drive_id = 0; /* drive id to be reported */
|
|
//this.newname = ""; /* storage space for new filename during eject delay */
|
|
//this.newnamewriteprotected = false;
|
|
this.newfile = null; //OWN
|
|
this.crc32 = 0;
|
|
//FDI *fdi;
|
|
this.useturbo = 0;
|
|
this.floppybitcounter = 0; /* number of bits left */
|
|
this.amax = false;
|
|
this.lastdataacesstrack = 0;
|
|
this.lastrev = 0;
|
|
this.track_access_done = false;
|
|
}
|
|
var floppy = new Array(MAX_FLOPPY_DRIVES);
|
|
for (var vi = 0; vi < MAX_FLOPPY_DRIVES; vi++)
|
|
floppy[vi] = new drive(vi);
|
|
|
|
var bigmfmbufw = new Uint16Array(0x4000 * DDHDMULT);
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* SECT drive AMAX-support */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
const data_scramble = [ 3, 2, 4, 5, 7, 6, 0, 1 ];
|
|
const addr_scramble = [ 14, 12, 2, 10, 15, 13, 1, 0, 7, 6, 5, 4, 8, 9, 11, 3 ];
|
|
|
|
var amax_rom_ptr = 0;
|
|
var amax_rom = null; //u8 *
|
|
var amax_rom_size = 0;
|
|
var amax_rom_oddeven = 0;
|
|
//u8
|
|
var amax_data = 0;
|
|
var amax_bfd100 = 0;
|
|
//var amax_bfe001 = 0;
|
|
var amax_bfe001_ov = 0;
|
|
var amax_select = 0;
|
|
|
|
var amax_lastbit = 0;
|
|
var amax_is_active = false;
|
|
|
|
const AMAX_LOG = 0;
|
|
|
|
function amax_load_byte() {
|
|
var v = 0xff;
|
|
var addr = 0;
|
|
for (var i = 0; i < 16; i++) {
|
|
if (amax_rom_ptr & (1 << i))
|
|
addr |= 1 << addr_scramble[i];
|
|
}
|
|
if (amax_rom_oddeven < 0)
|
|
amax_data = v;
|
|
else {
|
|
var v = amax_rom[addr * 2 + amax_rom_oddeven];
|
|
val = 0;
|
|
for (i = 0; i < 8; i++) {
|
|
if (v & (1 << data_scramble[i]))
|
|
val |= 1 << i;
|
|
}
|
|
amax_data = val;
|
|
}
|
|
if (AMAX_LOG > 0) SAEF_log("disk.amax_load_byte() amax_rom=%d addr=%06x (%06x) data=%02x (%02x) PC=%08x", amax_rom_oddeven, amax_rom_ptr, addr, v, val, SAER_CPU_getPC());
|
|
}
|
|
|
|
function amax_check() {
|
|
/* DIR low = reset address counter */
|
|
if (amax_bfd100 & 2) {
|
|
if (amax_rom_ptr && AMAX_LOG > 0) SAEF_log("disk.amax_check() counter reset PC=%08x", SAER_CPU_getPC());
|
|
amax_rom_ptr = 0;
|
|
amax_is_active = false;
|
|
}
|
|
}
|
|
|
|
function amax_diskwrite(w) {
|
|
/* this is weird, 1->0 transition in disk write line increases address pointer.. */
|
|
for (var i = 0; i < 16; i++) {
|
|
if (amax_lastbit && !(w & 0x8000)) {
|
|
amax_rom_ptr++;
|
|
if (AMAX_LOG > 0) SAEF_log("disk.amax_diskwrite() counter increase %d PC=%08x", amax_rom_ptr, SAER_CPU_getPC());
|
|
}
|
|
amax_lastbit = (w & 0x8000) ? 1 : 0;
|
|
w = (w << 1) & 0xffff;
|
|
}
|
|
amax_rom_ptr &= amax_rom_size - 1;
|
|
amax_check();
|
|
}
|
|
|
|
this.amax_bfe001_write = function(pra, dra) {
|
|
var v = dra & pra;
|
|
|
|
//amax_bfe001 = v;
|
|
|
|
/* CHNG low -> high: shift data register */
|
|
if ((v & 4) && !(amax_bfe001_ov & 4)) {
|
|
amax_data = ((amax_data << 1) | 1) & 0xff;
|
|
if (AMAX_LOG > 0) SAEF_log("disk.amax_bfe001_write() data shifted");
|
|
}
|
|
/* TK0 = even, WPRO = odd */
|
|
amax_rom_oddeven = -1;
|
|
if ((v & (8 | 16)) != (8 | 16)) {
|
|
amax_rom_oddeven = 0;
|
|
if (!(v & 16))
|
|
amax_rom_oddeven = 1;
|
|
}
|
|
amax_bfe001_ov = v;
|
|
amax_check();
|
|
}
|
|
|
|
function amax_disk_select(v, ov, num) {
|
|
amax_bfd100 = v;
|
|
|
|
amax_select = 1 << (num + 3);
|
|
if (!(amax_bfd100 & amax_select) && (ov & amax_select)) {
|
|
amax_is_active = true;
|
|
amax_load_byte();
|
|
}
|
|
amax_check();
|
|
}
|
|
|
|
function amax_disk_status(st) {
|
|
if (!(amax_data & 0x80))
|
|
st &= ~0x20;
|
|
return st;
|
|
}
|
|
|
|
function amax_active() {
|
|
return amax_is_active;
|
|
}
|
|
|
|
function amax_reset() {
|
|
amax_rom_ptr = 0;
|
|
amax_rom_oddeven = 0;
|
|
amax_bfe001_ov = 0;
|
|
amax_lastbit = 0;
|
|
amax_data = 0xff;
|
|
//xfree(amax_rom);
|
|
amax_rom = null;
|
|
amax_select = 0;
|
|
}
|
|
|
|
function amax_init() {
|
|
//var z = null;
|
|
|
|
//if (is_device_rom(&currprefs, SAEC_RomType_AMAX, 0) < 0) return;
|
|
if (SAEV_config.memory.amaxRom.size == 0) return;
|
|
|
|
amax_reset();
|
|
//if (is_device_rom(SAEV_config, SAEC_RomType_AMAX, 0) > 0) z = read_device_rom(SAEV_config, SAEC_RomType_AMAX, 0, null);
|
|
var z = SAEF_ZFile_fopen_file(SAEV_config.memory.amaxRom);
|
|
if (z !== null) {
|
|
SAEF_ZFile_fseek(z, 0, SEEK_END);
|
|
amax_rom_size = SAEF_ZFile_ftell(z);
|
|
SAEF_ZFile_fseek(z, 0, SEEK_SET);
|
|
} else {
|
|
SAEF_log("disk.amax_init() failed to load rom");
|
|
amax_rom_size = 262144;
|
|
}
|
|
amax_rom = new Uint8Array(amax_rom_size);
|
|
if (z !== null) {
|
|
SAEF_ZFile_fread(amax_rom,0, amax_rom_size, 1, z);
|
|
SAEF_ZFile_fclose(z);
|
|
}
|
|
SAEF_log("disk.amax_init() loaded %d bytes (%dK ROM)", amax_rom_size, amax_rom_size >> 10);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* SECT drive SCP-support */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
/* Support for reading .SCP (Supercard Pro) disk flux dumps.
|
|
* Based on version by Keir Fraser */
|
|
|
|
const MAX_REVS = 5;
|
|
|
|
//enum pll_mode {
|
|
const PLL_fixed_clock = 0; /* Fixed clock, snap phase to flux transitions. */
|
|
const PLL_variable_clock = 1; /* Variable clock, snap phase to flux transitions. */
|
|
const PLL_authentic = 2; /* Variable clock, do not snap phase to flux transition. */
|
|
//};
|
|
|
|
function scpDrive_def(num) {
|
|
this.num = num
|
|
this.zf = null;
|
|
|
|
this.track = 0; /* Current track number. */
|
|
|
|
this.dat = null; /* u16 *, Raw track data. */
|
|
this.dat8 = null; //OWN
|
|
this.dat16 = null; //OWN
|
|
this.datsz = 0;
|
|
|
|
this.revs = 0; /* stored disk revolutions */
|
|
this.dat_idx = 0; /* current index into dat[] */
|
|
this.index_pos = 0; /* next index offset */
|
|
this.nr_index = 0;
|
|
this.index_off = new Uint32Array(MAX_REVS); /* data offsets of each index */
|
|
|
|
this.latency = 0; /* u64, Accumulated read latency in nanosecs. */
|
|
|
|
this.pll_mode = 0; /* Flux-based streams: Authentic emulation of FDC PLL behaviour? */
|
|
|
|
this.flux = 0; /* signed, Nanoseconds to next flux reversal */
|
|
this.clock = 0; /* signed, Clock base value in nanoseconds */
|
|
this.clock_centre = 0; //signed
|
|
this.clocked_zeros = 0;
|
|
|
|
this.clr = function() {
|
|
this.zf = null;
|
|
this.track = 0;
|
|
this.dat16 = null;
|
|
this.dat8 = null;
|
|
this.dat = null;
|
|
this.datsz = 0;
|
|
this.revs = 0;
|
|
this.dat_idx = 0;
|
|
this.index_pos = 0;
|
|
this.nr_index = 0;
|
|
this.index_off = new Uint32Array(MAX_REVS);
|
|
this.latency = 0;
|
|
this.pll_mode = 0;
|
|
this.flux = 0;
|
|
this.clock = 0;
|
|
this.clock_centre = 0;
|
|
this.clocked_zeros = 0;
|
|
};
|
|
};
|
|
var scpdrive = new Array(4);
|
|
for (var vi = 0; vi < 4; vi++)
|
|
scpdrive[vi] = new scpDrive_def(-1);
|
|
|
|
const CLOCK_CENTRE = 2000; /* 2000ns = 2us */
|
|
const CLOCK_MAX_ADJ = 10; /* +/- 10% adjustment */
|
|
function CLOCK_MIN(c) { return Math.truncate((c * (100 - CLOCK_MAX_ADJ)) / 100); }
|
|
function CLOCK_MAX(c) { return Math.truncate((c * (100 + CLOCK_MAX_ADJ)) / 100); }
|
|
|
|
const SCK_NS_PER_TICK = 25;
|
|
|
|
function scp_open(zf, drv) { //, *num_tracks) {
|
|
var d = scpdrive[drv];
|
|
var header = new Uint8Array(0x10); header[0] = 0;
|
|
|
|
scp_close(drv);
|
|
|
|
SAEF_ZFile_fread(header,0, header.length, 1, zf);
|
|
if (SAEF_CompareArray(header, SAEF_String2Array("SCP"), 3) != 0) {
|
|
SAEF_warn("disk.scp_open() header missing");
|
|
return false;
|
|
}
|
|
if (header[5] == 0) {
|
|
SAEF_warn("disk.scp_open() invalid revolution count (%d)", header[5]);
|
|
return false;
|
|
}
|
|
if (header[9] != 0 && header[9] != 16) {
|
|
SAEF_warn("disk.scp_open() unsupported bit cell time width (%d)", header[9]);
|
|
return false;
|
|
}
|
|
d.zf = zf;
|
|
d.revs = Math.min(header[5], MAX_REVS);
|
|
|
|
floppy[drv].num_tracks = header[7] + 1; // *num_tracks = header[7] + 1;
|
|
SAEF_log("disk.scp_open() ok, %d tracks", floppy[drv].num_tracks);
|
|
return true;
|
|
}
|
|
|
|
function scp_close(drv) {
|
|
var d = scpdrive[drv];
|
|
if (d.revs) {
|
|
//xfree(d.dat);
|
|
d.clr(); //memset(d, 0, sizeof(*d));
|
|
}
|
|
}
|
|
|
|
//function scp_loadtrack(uae_u16 *mfmbuf, uae_u16 *tracktiming, int drv, int track, int *tracklength, int *multirev, int *gapoffset, int *nextrev, bool setrev) {
|
|
function scp_loadtrack(mfmbuf, tracktiming, drv, track, setrev) {
|
|
var d = scpdrive[drv];
|
|
var trk_header = new Uint8Array(4);
|
|
var longwords = new ArrayBuffer(3 * 4);
|
|
var longwords8 = new Uint8Array(longwords);
|
|
var longwords32 = new Uint32Array(longwords);
|
|
var trkoffset = new Uint32Array(MAX_REVS); //uint
|
|
var hdr_offset, tdh_offset; //u32
|
|
var rev;
|
|
|
|
floppy[drv].multi_revolution = 1; // *multirev = 1;
|
|
floppy[drv].skipoffset = -1; // *gapoffset = -1;
|
|
|
|
//xfree(d.dat);
|
|
d.dat16 = null;
|
|
d.dat8 = null;
|
|
d.dat = null;
|
|
d.datsz = 0;
|
|
|
|
//hdr_offset = 0x10 + track * sizeof(uint32_t);
|
|
hdr_offset = 0x10 + track * 4;
|
|
SAEF_ZFile_fseek(d.zf, hdr_offset, SEEK_SET);
|
|
|
|
SAEF_ZFile_fread(longwords8,0, longwords.byteLength, 1, d.zf);
|
|
tdh_offset = SAEF_le32toh(longwords32[0]);
|
|
|
|
SAEF_ZFile_fseek(d.zf, tdh_offset, SEEK_SET);
|
|
SAEF_ZFile_fread(trk_header,0, trk_header.length, 1, d.zf);
|
|
if (SAEF_CompareArray(trk_header, SAEF_String2Array("TRK"), 3) != 0) {
|
|
SAEF_warn("disk.scp_loadtrack() track header not found");
|
|
return false;
|
|
}
|
|
if (trk_header[3] != track) {
|
|
SAEF_warn("disk.scp_loadtrack() track error (%d != %d)", trk_header[3], track);
|
|
return false;
|
|
}
|
|
for (rev = 0 ; rev < d.revs ; rev++) {
|
|
SAEF_ZFile_fread(longwords8,0, longwords.byteLength, 1, d.zf);
|
|
trkoffset[rev] = tdh_offset + SAEF_le32toh(longwords32[2]);
|
|
d.index_off[rev] = SAEF_le32toh(longwords32[1]);
|
|
d.datsz += d.index_off[rev];
|
|
}
|
|
|
|
//d.dat = xmalloc(uint16_t, d.datsz * sizeof(d.dat[0]));
|
|
d.dat = new ArrayBuffer(d.datsz * 2);
|
|
d.dat8 = new Uint8Array(d.dat);
|
|
d.dat16 = new Uint16Array(d.dat);
|
|
d.datsz = 0;
|
|
|
|
for (rev = 0 ; rev < d.revs ; rev++) {
|
|
SAEF_ZFile_fseek(d.zf, trkoffset[rev], SEEK_SET);
|
|
SAEF_ZFile_fread(d.dat8,d.datsz * 2, d.index_off[rev] * 2, 1, d.zf);
|
|
d.datsz += d.index_off[rev];
|
|
d.index_off[rev] = d.datsz;
|
|
}
|
|
|
|
d.track = track;
|
|
d.pll_mode = PLL_authentic;
|
|
d.dat_idx = 0;
|
|
d.index_pos = d.index_off[0];
|
|
d.clock = d.clock_centre = CLOCK_CENTRE;
|
|
d.nr_index = 0;
|
|
d.flux = 0;
|
|
d.clocked_zeros = 0;
|
|
|
|
scp_loadrevolution(mfmbuf, drv, tracktiming); //, tracklength);
|
|
return true;
|
|
}
|
|
|
|
function next_flux(d) {
|
|
var val = 0; //u32
|
|
|
|
for (;;) {
|
|
if (d.dat_idx >= d.index_pos) {
|
|
var rev = d.nr_index++ % d.revs;
|
|
d.index_pos = d.index_off[rev];
|
|
d.dat_idx = rev ? d.index_off[rev - 1] : 0;
|
|
return -1;
|
|
}
|
|
|
|
var t = SAEF_be16toh(d.dat16[d.dat_idx++]);
|
|
if (t == 0) { // overflow
|
|
val += 0x10000; if (val > 0xffffffff) val -= 0x100000000;
|
|
continue;
|
|
}
|
|
val += t; if (val > 0xffffffff) val -= 0x100000000;
|
|
break;
|
|
}
|
|
var flux = val * SCK_NS_PER_TICK; while (flux > 0xffffffff) flux -= 0x100000000;
|
|
return (flux & 0x80000000) ? flux - 0x100000000 : flux;
|
|
}
|
|
|
|
function flux_next_bit(d) {
|
|
var new_flux;
|
|
|
|
while (d.flux < Math.truncate(d.clock / 2)) { //ATT
|
|
if ((new_flux = next_flux(d)) == -1)
|
|
return -1;
|
|
|
|
d.flux += new_flux;
|
|
d.clocked_zeros = 0;
|
|
}
|
|
d.latency += d.clock;
|
|
d.flux -= d.clock;
|
|
|
|
if (d.flux >= Math.truncate(d.clock / 2)) { //ATT
|
|
d.clocked_zeros++;
|
|
return 0;
|
|
}
|
|
|
|
if (d.pll_mode != PLL_fixed_clock) {
|
|
// PLL: Adjust clock frequency according to phase mismatch.
|
|
if ((d.clocked_zeros >= 1) && (d.clocked_zeros <= 3)) {
|
|
// In sync: adjust base clock by 10% of phase mismatch.
|
|
var diff = Math.truncate(d.flux / (d.clocked_zeros + 1)); //ATT
|
|
d.clock += Math.truncate(diff / 10); //ATT
|
|
} else {
|
|
// Out of sync: adjust base clock towards centre.
|
|
d.clock += Math.truncate((d.clock_centre - d.clock) / 10); //ATT
|
|
}
|
|
|
|
// Clamp the clock's adjustment range.
|
|
d.clock = Math.max(CLOCK_MIN(d.clock_centre), Math.min(CLOCK_MAX(d.clock_centre), d.clock));
|
|
} else
|
|
d.clock = d.clock_centre;
|
|
|
|
// Authentic PLL: Do not snap the timing window to each flux transition.
|
|
new_flux = d.pll_mode == PLL_authentic ? Math.truncate(d.flux / 2) : 0; //ATT
|
|
d.latency += d.flux - new_flux;
|
|
d.flux = new_flux;
|
|
return 1;
|
|
}
|
|
|
|
//void scp_loadrevolution(uae_u16 *mfmbuf, int drv, uae_u16 *tracktiming, int *tracklength) {
|
|
function scp_loadrevolution(mfmbuf, drv, tracktiming) {
|
|
var d = scpdrive[drv];
|
|
var prev_latency; //u64
|
|
var av_latency; //u32
|
|
var i, j, b;
|
|
|
|
d.latency = prev_latency = 0;
|
|
for (i = 0; (b = flux_next_bit(d)) != -1; i++) {
|
|
if ((i & 15) == 0)
|
|
mfmbuf[i >> 4] = 0;
|
|
if (b)
|
|
mfmbuf[i >> 4] |= 0x8000 >> (i & 15);
|
|
|
|
if ((i & 7) == 7) {
|
|
tracktiming[i >> 3] = d.latency - prev_latency;
|
|
prev_latency = d.latency;
|
|
}
|
|
}
|
|
if (i & 7)
|
|
tracktiming[i >> 3] = Math.floor((d.latency - prev_latency) * 8 / (i & 7)); //ATT
|
|
|
|
av_latency = Math.floor(prev_latency / (i >> 3)); //ATT
|
|
|
|
for (j = 0; j < (i + 7) >> 3; j++)
|
|
tracktiming[j] = Math.floor((tracktiming[j] * 1000) / av_latency); //ATT
|
|
|
|
floppy[drv].tracklen = i; // *tracklength = i;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* SECT drive */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
function get_floppy_speed() {
|
|
var m = SAEV_config.floppy.speed;
|
|
if (m <= 10) m = 100;
|
|
return Math.floor(NORMAL_FLOPPY_SPEED() * 100 / m);
|
|
}
|
|
|
|
function get_floppy_speed2(drv) {
|
|
var m = Math.truncate(get_floppy_speed() * drv.tracklen / (FLOPPY_WRITE_LEN() * 2 * drv.ddhd * 8));
|
|
if (m <= 0)
|
|
m = 1;
|
|
return m;
|
|
}
|
|
|
|
function drive_id_name(drv) {
|
|
switch(drv.drive_id) {
|
|
case DRIVE_ID_35HD : return "3.5HD";
|
|
case DRIVE_ID_525SD: return "5.25SD";
|
|
case DRIVE_ID_35DD : return "3.5DD";
|
|
case DRIVE_ID_NONE : return "NONE";
|
|
}
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
/* Simulate exact behaviour of an A3000T 3.5 HD disk drive.
|
|
* The drive reports to be a 3.5 DD drive whenever there is no
|
|
* disk or a 3.5 DD disk is inserted. Only 3.5 HD drive id is reported
|
|
* when a real 3.5 HD disk is inserted. -Adil */
|
|
function drive_settype_id(drv) {
|
|
var t = SAEV_config.floppy.drive[drv.num].type;
|
|
|
|
switch (t) {
|
|
case SAEC_Config_Floppy_Type_35_HD: {
|
|
if (drv.diskfile === null || drv.ddhd <= 1)
|
|
drv.drive_id = DRIVE_ID_35DD;
|
|
else
|
|
drv.drive_id = DRIVE_ID_35HD;
|
|
break;
|
|
}
|
|
case SAEC_Config_Floppy_Type_35_DD_ESCOM:
|
|
case SAEC_Config_Floppy_Type_35_DD:
|
|
default:
|
|
drv.drive_id = DRIVE_ID_35DD;
|
|
break;
|
|
case SAEC_Config_Floppy_Type_525_SD:
|
|
drv.drive_id = DRIVE_ID_525SD;
|
|
break;
|
|
case SAEC_Config_Floppy_Type_None:
|
|
case SAEC_Config_Floppy_Type_35_DD_PC:
|
|
case SAEC_Config_Floppy_Type_35_HD_PC:
|
|
drv.drive_id = DRIVE_ID_NONE;
|
|
break;
|
|
}
|
|
if (DEBUG_DRIVE_ID) SAEF_log("disk.drive_settype_id() DF%d: set to %s", drv.num, drive_id_name(drv));
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
function drive_image_free(drv) {
|
|
switch (drv.filetype) {
|
|
case ADF_SCP:
|
|
scp_close(drv.num);
|
|
break;
|
|
/*case ADF_FDI:
|
|
fdi2raw_header_free(drv.fdi);
|
|
drv.fdi = 0;
|
|
break;*/
|
|
}
|
|
drv.filetype = ADF_NONE;
|
|
SAEF_ZFile_fclose(drv.diskfile);
|
|
drv.diskfile = null;
|
|
//SAEF_ZFile_fclose(drv.writediskfile);
|
|
drv.writediskfile = null;
|
|
//SAEF_ZFile_fclose(drv.pcdecodedfile);
|
|
drv.pcdecodedfile = null;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
function reset_drive_gui(num) {
|
|
var gd = SAER.gui.data;
|
|
|
|
gd.df[num] = "";
|
|
gd.crc32[num] = 0;
|
|
gd.drive_disabled[num] = false;
|
|
if (SAEV_config.floppy.drive[num].type <= SAEC_Config_Floppy_Type_None)
|
|
gd.drive_disabled[num] = true;
|
|
}
|
|
|
|
function update_drive_gui(num, force) {
|
|
var drv = floppy[num];
|
|
var writ = dskdmaen == DSKDMA_WRITE && drv.state && !((selected | disabled) & (1 << num));
|
|
var gd = SAER.gui.data;
|
|
|
|
if (!force && drv.state == gd.drive_motor[num]
|
|
&& drv.cyl == gd.drive_track[num]
|
|
&& side == gd.drive_side
|
|
&& drv.crc32 == gd.crc32[num]
|
|
&& writ == gd.drive_writing[num]
|
|
&& gd.df[num] == SAEV_config.floppy.drive[num].file.name
|
|
) return;
|
|
|
|
gd.df[num] = SAEV_config.floppy.drive[num].file.name;
|
|
gd.crc32[num] = drv.crc32;
|
|
gd.drive_motor[num] = drv.state;
|
|
gd.drive_track[num] = drv.cyl;
|
|
if (reserved & (1 << num))
|
|
gd.drive_side = reserved_side;
|
|
else
|
|
gd.drive_side = side;
|
|
gd.drive_writing[num] = writ;
|
|
|
|
SAER.gui.led(num + SAEC_GUI_LED_DF0, (gd.drive_motor[num] ? 1 : 0) | (gd.drive_writing[num] ? 2 : 0), -1);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* reset */
|
|
|
|
function reset_drive(num) {
|
|
var drv = floppy[num];
|
|
|
|
drv.amax = false;
|
|
drive_image_free(drv);
|
|
drv.motoroff = true;
|
|
drv.idbit = 0;
|
|
drv.drive_id = 0;
|
|
drv.drive_id_scnt = 0;
|
|
drv.lastdataacesstrack = -1;
|
|
|
|
disabled &= ~(1 << num);
|
|
if (SAEV_config.floppy.drive[num].type <= SAEC_Config_Floppy_Type_None || SAEV_config.floppy.drive[num].type >= SAEC_Config_Floppy_Type_35_DD_PC)
|
|
disabled |= 1 << num;
|
|
reserved &= ~(1 << num);
|
|
if (SAEV_config.floppy.drive[num].type >= SAEC_Config_Floppy_Type_35_DD_PC)
|
|
reserved |= 1 << num;
|
|
|
|
reset_drive_gui(num);
|
|
|
|
/* most internal Amiga floppy drives won't enable
|
|
* diskready until motor is running at full speed
|
|
* and next indexsync has been passed
|
|
*/
|
|
drv.indexhackmode = 0;
|
|
if (num == 0 && SAEV_config.floppy.drive[num].type == SAEC_Config_Floppy_Type_35_DD)
|
|
drv.indexhackmode = 1;
|
|
drv.dskchange_time = 0;
|
|
drv.dskchange_request = false;
|
|
drv.dskchange = false;
|
|
drv.dskready_down_time = 0;
|
|
drv.dskready_up_time = 0;
|
|
drv.buffered_cyl = -1;
|
|
drv.buffered_side = -1;
|
|
|
|
SAER.gui.led(num + SAEC_GUI_LED_DF0, 0, -1);
|
|
drive_settype_id(drv);
|
|
//SAEV_config.floppy.drive[num].name = changed_prefs.floppyslots[num].name;
|
|
//drv.newname = "";
|
|
//drv.newnamewriteprotected = false;
|
|
drv.newfile = null;
|
|
if (!drive_insert(drv, SAEV_config, num, SAEV_config.floppy.drive[num].file, false))
|
|
SAER.disk.eject(num);
|
|
}
|
|
|
|
function setamax() {
|
|
amax_enabled = false;
|
|
//if (is_device_rom(SAEV_config, SAEC_RomType_AMAX, 0) > 0) {
|
|
if (SAEV_config.memory.amaxRom.data.length > 0) {
|
|
amax_enabled = true;
|
|
// Put A-Max as last drive in drive chain
|
|
var i;
|
|
for (i = 0; i < MAX_FLOPPY_DRIVES; i++)
|
|
if (floppy[i].amax)
|
|
return;
|
|
for (i = 0; i < MAX_FLOPPY_DRIVES; i++) {
|
|
if ((1 << i) & disabled) {
|
|
floppy[i].amax = true;
|
|
SAEF_log("disk.setamax() using DF%d", i);
|
|
return;
|
|
}
|
|
}
|
|
SAEF_warn("disk.setamax() no drive available. (disable an drive to make it working)");
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* insert / eject */
|
|
|
|
//function DISK_validate_filename(p, fname, leave_open, get_wrprot, get_crc, get_zf) {
|
|
function DISK_validate_filename(p, file, leave_open, get_wrprot, get_crc, get_zf) {
|
|
var wrprot = false;
|
|
var crc32 = 0;
|
|
var zf = null;
|
|
|
|
if (get_zf)
|
|
zf = null;
|
|
if (get_crc)
|
|
crc32 = 0;
|
|
if (get_wrprot)
|
|
wrprot = p.floppy.readOnly ? true : false;
|
|
|
|
if (leave_open || !get_zf) {
|
|
/*var f = SAEF_ZFile_fopen(fname, "r+b", ZFD_NORMAL | ZFD_DISKHISTORY);
|
|
if (!f) {
|
|
if (get_wrprot) wrprot = true;
|
|
f = SAEF_ZFile_fopen(fname, "rb", ZFD_NORMAL | ZFD_DISKHISTORY);
|
|
}*/
|
|
var f = SAEF_ZFile_fopen_file(file);
|
|
if (f !== null) {
|
|
if (get_crc) {
|
|
if (file.crc32 !== false)
|
|
crc32 = file.crc32;
|
|
else
|
|
crc32 = SAEF_ZFile_crc32(f);
|
|
}
|
|
if (get_zf)
|
|
zf = f;
|
|
else
|
|
SAEF_ZFile_fclose(f);
|
|
|
|
return [true, wrprot, crc32, zf];
|
|
}
|
|
return [false, false, 0, null];
|
|
} else {
|
|
/*if (SAEF_ZFile_exists(fname)) {
|
|
if (get_wrprot && !p.floppy.readOnly)
|
|
wrprot = false;
|
|
if (get_crc) {
|
|
var f = SAEF_ZFile_fopen(fname, "rb", ZFD_NORMAL | ZFD_DISKHISTORY);
|
|
if (f) crc32 = SAEF_ZFile_crc32(f);
|
|
SAEF_ZFile_fclose(f);
|
|
}
|
|
return [true, wrprot, crc32, zf];
|
|
} else {
|
|
if (get_wrprot) wrprot = true;
|
|
return [false, wrprot, crc32, zf];
|
|
}*/
|
|
}
|
|
}
|
|
|
|
function updatemfmpos(drv) {
|
|
if (drv.prevtracklen) {
|
|
drv.mfmpos = Math.floor(drv.mfmpos * Math.floor(drv.tracklen * 1000 / drv.prevtracklen) / 1000); //ATT
|
|
if (drv.mfmpos >= drv.tracklen)
|
|
drv.mfmpos = drv.tracklen - 1;
|
|
}
|
|
drv.mfmpos %= drv.tracklen;
|
|
drv.prevtracklen = drv.tracklen;
|
|
}
|
|
|
|
function track_reset(drv) {
|
|
drv.tracklen = FLOPPY_WRITE_LEN() * 2 * drv.ddhd * 8;
|
|
drv.revolutions = 1;
|
|
drv.trackspeed = get_floppy_speed();
|
|
drv.buffered_side = -1;
|
|
drv.skipoffset = -1;
|
|
drv.tracktiming[0] = 0;
|
|
//memset(drv.bigmfmbuf, 0xaa, FLOPPY_WRITE_LEN() * 2 * drv.ddhd);
|
|
SAEF_memset(drv.bigmfmbuf,0, 0xaaaa, FLOPPY_WRITE_LEN() * 2 * drv.ddhd >> 1);
|
|
updatemfmpos(drv);
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
//static int read_header_ext2(struct zfile *diskfile, trackid *trackdata, int *num_tracks, int *ddhd) {
|
|
function read_header_ext2(drv, ddhd) {
|
|
var buffer = new Uint8Array(2 + 2 + 4 + 4);
|
|
|
|
SAEF_ZFile_fseek(drv.diskfile, 0, SEEK_SET);
|
|
SAEF_ZFile_fread(buffer,0, 1, 8, drv.diskfile);
|
|
if (SAEF_CompareArray(buffer, SAEF_String2Array("UAE-1ADF"), 8) != 0)
|
|
return 0;
|
|
SAEF_ZFile_fread(buffer,0, 1, 4, drv.diskfile);
|
|
drv.num_tracks = buffer[2] * 256 + buffer[3];
|
|
var offs = 8 + 2 + 2 + drv.num_tracks * (2 + 2 + 4 + 4);
|
|
|
|
for (var i = 0; i < drv.num_tracks; i++) {
|
|
var tid = drv.trackdata[i];
|
|
SAEF_ZFile_fread(buffer,0, 2 + 2 + 4 + 4, 1, drv.diskfile);
|
|
tid.type = buffer[3];
|
|
tid.revolutions = buffer[2] + 1;
|
|
tid.len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7];
|
|
tid.bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11];
|
|
tid.offs = offs;
|
|
if (tid.len > 20000 && ddhd)
|
|
drv.ddhd = 2;
|
|
tid.track = i;
|
|
offs += tid.len;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
/*static void saveimagecutpathpart(TCHAR *name) {
|
|
int i;
|
|
|
|
i = _tcslen (name) - 1;
|
|
while (i > 0) {
|
|
if (name[i] == '/' || name[i] == '\\') {
|
|
name[i] = 0;
|
|
break;
|
|
}
|
|
if (name[i] == '.') {
|
|
name[i] = 0;
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
while (i > 0) {
|
|
if (name[i] == '/' || name[i] == '\\') {
|
|
name[i] = 0;
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
}
|
|
static void saveimagecutfilepart(TCHAR *name) {
|
|
TCHAR tmp[MAX_DPATH];
|
|
int i;
|
|
|
|
_tcscpy(tmp, name);
|
|
i = _tcslen (tmp) - 1;
|
|
while (i > 0) {
|
|
if (tmp[i] == '/' || tmp[i] == '\\') {
|
|
_tcscpy(name, tmp + i + 1);
|
|
break;
|
|
}
|
|
if (tmp[i] == '.') {
|
|
tmp[i] = 0;
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
while (i > 0) {
|
|
if (tmp[i] == '/' || tmp[i] == '\\') {
|
|
_tcscpy(name, tmp + i + 1);
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
}
|
|
static void saveimageaddfilename(TCHAR *dst, const TCHAR *src, int type) {
|
|
_tcscat(dst, src);
|
|
if (type)
|
|
_tcscat(dst, _T(".save_adf"));
|
|
else
|
|
_tcscat(dst, _T("_save.adf"));
|
|
}
|
|
|
|
static TCHAR *DISK_get_default_saveimagepath (const TCHAR *name) {
|
|
TCHAR name1[MAX_DPATH];
|
|
TCHAR path[MAX_DPATH];
|
|
_tcscpy(name1, name);
|
|
saveimagecutfilepart(name1);
|
|
fetch_saveimagepath (path, sizeof path / sizeof (TCHAR), 1);
|
|
saveimageaddfilename(path, name1, 0);
|
|
return my_strdup(path);
|
|
}
|
|
// -2 = existing, if not, use 0.
|
|
// -1 = as configured
|
|
// 0 = saveimages-dir
|
|
// 1 = image dir
|
|
TCHAR *DISK_get_saveimagepath(const TCHAR *name, int type) {
|
|
int typev = type;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
if (typev == 1 || (typev == -1 && saveimageoriginalpath) || (typev == -2 && (saveimageoriginalpath || i == 1))) {
|
|
TCHAR si_name[MAX_DPATH], si_path[MAX_DPATH];
|
|
_tcscpy(si_name, name);
|
|
_tcscpy(si_path, name);
|
|
saveimagecutfilepart(si_name);
|
|
saveimagecutpathpart(si_path);
|
|
_tcscat(si_path, FSDB_DIR_SEPARATOR_S);
|
|
saveimageaddfilename(si_path, si_name, 1);
|
|
if (typev != -2 || (typev == -2 && SAEF_ZFile_exists(si_path)))
|
|
return my_strdup(si_path);
|
|
}
|
|
if (typev == 2 || (typev == -1 && !saveimageoriginalpath) || (typev == -2 && (!saveimageoriginalpath || i == 1))) {
|
|
TCHAR *p = DISK_get_default_saveimagepath(name);
|
|
if (typev != -2 || (typev == -2 && SAEF_ZFile_exists(p)))
|
|
return p;
|
|
xfree(p);
|
|
}
|
|
}
|
|
return DISK_get_saveimagepath(name, -1);
|
|
}
|
|
static struct zfile *getexistingwritefile(struct uae_prefs *p, const TCHAR *name, bool *wrprot) {
|
|
struct zfile *zf = null;
|
|
TCHAR *path;
|
|
path = DISK_get_saveimagepath(name, saveimageoriginalpath);
|
|
DISK_validate_filename (p, path, 1, wrprot, null, &zf);
|
|
xfree(path);
|
|
if (zf)
|
|
return zf;
|
|
path = DISK_get_saveimagepath(name, !saveimageoriginalpath);
|
|
DISK_validate_filename (p, path, 1, wrprot, null, &zf);
|
|
xfree(path);
|
|
return zf;
|
|
}
|
|
static int openwritefile (struct uae_prefs *p, drive *drv, int create) {
|
|
bool wrprot = 0;
|
|
|
|
drv->writediskfile = getexistingwritefile(p, SAEV_config.floppy.drive[drv.num].name, &wrprot);
|
|
if (drv->writediskfile) {
|
|
drv->wrprot = wrprot;
|
|
if (!read_header_ext2(drv->writediskfile, drv->writetrackdata, &drv->write_num_tracks, 0)) {
|
|
SAEF_ZFile_fclose (drv->writediskfile);
|
|
drv->writediskfile = 0;
|
|
drv->wrprot = 1;
|
|
} else {
|
|
if (drv->write_num_tracks > drv->num_tracks)
|
|
drv->num_tracks = drv->write_num_tracks;
|
|
}
|
|
} else if (SAEF_ZFile_iscompressed (drv->diskfile)) {
|
|
drv->wrprot = 1;
|
|
}
|
|
return drv->writediskfile ? 1 : 0;
|
|
}*/
|
|
|
|
/*---------------------------------*/
|
|
|
|
function isrecognizedext(name) {
|
|
var last = name.lastIndexOf(".");
|
|
if (last != -1 && last + 1 != name.length) {
|
|
var ext = name.substring(last + 1);
|
|
ext = ext.toLowerCase();
|
|
if (ext == "adf" || ext == "adz" || ext == "st" || ext == "ima" || ext == "img") {
|
|
SAEF_log("disk.isrecognizedext() extention '%s' found", ext);
|
|
return true;
|
|
}
|
|
SAEF_log("disk.isrecognizedext() unknow extention '%s'", ext);
|
|
} else
|
|
SAEF_log("disk.isrecognizedext() no extention");
|
|
|
|
return false;
|
|
}
|
|
|
|
function update_disk_statusline(num) {
|
|
/*
|
|
drive *drv = &floppy[num];
|
|
if (drv->diskfile === null)
|
|
return;
|
|
const TCHAR *fname = SAEF_ZFile_getoriginalname(drv->diskfile);
|
|
if (!fname)
|
|
fname = SAEF_ZFile_getname(drv->diskfile);
|
|
if (!fname)
|
|
fname = _T("?");
|
|
if (disk_info_data.diskname[0])
|
|
statusline_add_message(_T("DF%d: [%s] %s"), num, disk_info_data.diskname, my_getfilepart(fname));
|
|
else
|
|
statusline_add_message(_T("DF%d: %s"), num, my_getfilepart(fname));*/
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
//function drive_insert(drv, p, dnum, fname, fake, forcedwriteprotect) {
|
|
function drive_insert(drv, p, dnum, file, fake) {
|
|
var buffer = new Uint8Array(2 + 2 + 4 + 4);
|
|
var tid = null;
|
|
|
|
drive_image_free(drv);
|
|
//if (!fake) examine_image(p, dnum, disk_info_data);
|
|
//DISK_validate_filename(p, fname, 1, &drv.wrprot, &drv.crc32, &drv.diskfile);
|
|
//var result = DISK_validate_filename(p, fname, fdata, true, true, true, true);
|
|
var result = DISK_validate_filename(p, file, true, true, true, true);
|
|
drv.wrprot = result[1];
|
|
drv.crc32 = result[2];
|
|
drv.diskfile = result[3];
|
|
|
|
drv.forcedwrprot = file.prot; //forcedwriteprotect;
|
|
if (drv.forcedwrprot)
|
|
drv.wrprot = true;
|
|
drv.ddhd = 1;
|
|
drv.num_heads = 2;
|
|
drv.num_secs = 0;
|
|
drv.hard_num_cyls = p.floppy.drive[dnum].type == SAEC_Config_Floppy_Type_525_SD ? 40 : 80;
|
|
drv.tracktiming[0] = 0;
|
|
drv.useturbo = 0;
|
|
drv.indexoffset = 0;
|
|
if (!fake) {
|
|
drv.dskeject = false;
|
|
//gui_disk_image_change(dnum, fname, drv.wrprot);
|
|
}
|
|
|
|
if (!drv.motoroff) {
|
|
drv.dskready_up_time = DSKREADY_UP_TIME * 312 + (Math.decimalRandom() & 511);
|
|
drv.dskready_down_time = 0;
|
|
}
|
|
|
|
if (drv.diskfile === null) {
|
|
track_reset(drv);
|
|
return 0;
|
|
}
|
|
|
|
if (!fake) {
|
|
//inprec_recorddiskchange(dnum, fname, drv.wrprot);
|
|
|
|
//if (SAEV_config.floppy.drive[dnum].name !== fname) SAEV_config.floppy.drive[dnum].name = fname;
|
|
//SAEV_config.floppy.drive[dnum].forcedWriteProtect = forcedwriteprotect;
|
|
//changed_prefs.floppyslots[dnum].name = fname;
|
|
//changed_prefs.floppyslots[dnum].forcedWriteProtect = forcedwriteprotect;
|
|
|
|
//drv.newname = fname;
|
|
//drv.newnamewriteprotected = forcedwriteprotect;
|
|
drv.newfile = file.clone(); //ATT
|
|
//SAER.gui.filename(dnum, file.name); //fname);
|
|
}
|
|
|
|
//memset(buffer, 0, sizeof buffer);
|
|
SAEF_memset(buffer,0, 0, buffer.length);
|
|
|
|
var size = 0;
|
|
if (drv.diskfile !== null) {
|
|
SAEF_ZFile_fread(buffer,0, 1, 8, drv.diskfile);
|
|
SAEF_ZFile_fseek(drv.diskfile, 0, SEEK_END);
|
|
size = SAEF_ZFile_ftell(drv.diskfile);
|
|
SAEF_ZFile_fseek(drv.diskfile, 0, SEEK_SET);
|
|
}
|
|
|
|
var canauto = 0;
|
|
if (isrecognizedext(file.name))
|
|
canauto = 1;
|
|
if (!canauto && drv.diskfile && isrecognizedext(SAEF_ZFile_getname(drv.diskfile)))
|
|
canauto = 1;
|
|
// if PC-only drive, make sure PC-like floppies are alwayss detected
|
|
if (!canauto && SAEV_config.floppy.drive[dnum].type >= SAEC_Config_Floppy_Type_35_DD_PC)
|
|
canauto = 1;
|
|
|
|
if (SAEF_CompareArray(buffer, SAEF_String2Array("SCP"), 3) == 0) {
|
|
//var num_tracks;
|
|
drv.wrprot = true;
|
|
//if (!scp_open(drv.diskfile, drv.num, num_tracks)) {
|
|
if (!scp_open(drv.diskfile, drv.num)) {
|
|
SAEF_ZFile_fclose(drv.diskfile);
|
|
drv.diskfile = null;
|
|
return 0;
|
|
}
|
|
//drv.num_tracks = num_tracks;
|
|
drv.filetype = ADF_SCP;
|
|
}
|
|
/*else if ((drv.fdi = fdi2raw_header(drv.diskfile))) {
|
|
drv.wrprot = true;
|
|
drv.num_tracks = fdi2raw_get_last_track(drv.fdi);
|
|
drv.num_secs = fdi2raw_get_num_sector(drv.fdi);
|
|
drv.filetype = ADF_FDI;
|
|
}*/
|
|
else if (SAEF_CompareArray(buffer, SAEF_String2Array("UAE-1ADF"), 8) == 0) {
|
|
//read_header_ext2(drv.diskfile, drv.trackdata, &drv.num_tracks, &drv.ddhd);
|
|
read_header_ext2(drv, drv.ddhd);
|
|
drv.filetype = ADF_EXT2;
|
|
drv.num_secs = 11;
|
|
if (drv.ddhd > 1)
|
|
drv.num_secs = 22;
|
|
}
|
|
else if (SAEF_CompareArray(buffer, SAEF_String2Array("UAE--ADF"), 8) == 0) {
|
|
var offs = 160 * 4 + 8;
|
|
|
|
drv.wrprot = true;
|
|
drv.filetype = ADF_EXT1;
|
|
drv.num_tracks = 160;
|
|
drv.num_secs = 11;
|
|
|
|
SAEF_ZFile_fseek(drv.diskfile, 8, SEEK_SET);
|
|
for (var i = 0; i < 160; i++) {
|
|
tid = drv.trackdata[i];
|
|
SAEF_ZFile_fread(buffer,0, 4, 1, drv.diskfile);
|
|
tid.sync = buffer[0] * 256 + buffer[1];
|
|
tid.len = buffer[2] * 256 + buffer[3];
|
|
tid.offs = offs;
|
|
tid.revolutions = 1;
|
|
if (tid.sync == 0) {
|
|
tid.type = TRACK_AMIGADOS;
|
|
tid.bitlen = 0;
|
|
} else {
|
|
tid.type = TRACK_RAW1;
|
|
tid.bitlen = tid.len * 8;
|
|
}
|
|
offs += tid.len;
|
|
}
|
|
}
|
|
/*else if (SAEF_CompareArray(buffer, exeheader, 8) == 0) {
|
|
var z = SAEF_ZFile_fopen_empty(null, "", 512 * 1760);
|
|
if (createimagefromexe(drv.diskfile, z)) {
|
|
SAEF_log("disk.drive_insert() converted '%s' to ADF", SAEF_ZFile_getname(drv.diskfile));
|
|
drv.filetype = ADF_NORMAL;
|
|
SAEF_ZFile_fclose(drv.diskfile);
|
|
drv.diskfile = z;
|
|
drv.num_tracks = 160;
|
|
drv.num_secs = 11;
|
|
for (var i = 0; i < drv.num_tracks; i++) {
|
|
tid = drv.trackdata[i];
|
|
tid.type = TRACK_AMIGADOS;
|
|
tid.len = 512 * drv.num_secs;
|
|
tid.bitlen = 0;
|
|
tid.offs = i * 512 * drv.num_secs;
|
|
tid.revolutions = 1;
|
|
}
|
|
drv.useturbo = 1;
|
|
} else
|
|
//SAEF_warn("disk.drive_insert() can't convert '%s' to ADF, because the file is too big", SAEF_ZFile_getname(drv.diskfile));
|
|
alert(sprintf("Can't convert '%s' to ADF. (too big)", SAEF_ZFile_getname(drv.diskfile)));
|
|
}*/
|
|
else if (canauto && (
|
|
// 320k double sided
|
|
size == 8 * 40 * 2 * 512 ||
|
|
// 320k single sided
|
|
size == 8 * 40 * 1 * 512 ||
|
|
|
|
// 360k double sided
|
|
size == 9 * 40 * 2 * 512 ||
|
|
// 360k single sided
|
|
size == 9 * 40 * 1 * 512 ||
|
|
|
|
// 1.2M double sided
|
|
size == 15 * 80 * 2 * 512 ||
|
|
|
|
// 720k/1440k double sided
|
|
size == 9 * 80 * 2 * 512 || size == 18 * 80 * 2 * 512 || size == 10 * 80 * 2 * 512 || size == 20 * 80 * 2 * 512 || size == 21 * 80 * 2 * 512 ||
|
|
size == 9 * 81 * 2 * 512 || size == 18 * 81 * 2 * 512 || size == 10 * 81 * 2 * 512 || size == 20 * 81 * 2 * 512 || size == 21 * 81 * 2 * 512 ||
|
|
size == 9 * 82 * 2 * 512 || size == 18 * 82 * 2 * 512 || size == 10 * 82 * 2 * 512 || size == 20 * 82 * 2 * 512 || size == 21 * 82 * 2 * 512 ||
|
|
// 720k/1440k single sided
|
|
size == 9 * 80 * 1 * 512 || size == 18 * 80 * 1 * 512 || size == 10 * 80 * 1 * 512 || size == 20 * 80 * 1 * 512 ||
|
|
size == 9 * 81 * 1 * 512 || size == 18 * 81 * 1 * 512 || size == 10 * 81 * 1 * 512 || size == 20 * 81 * 1 * 512 ||
|
|
size == 9 * 82 * 1 * 512 || size == 18 * 82 * 1 * 512 || size == 10 * 82 * 1 * 512 || size == 20 * 82 * 1 * 512)
|
|
) {
|
|
/* PC formatted image */
|
|
var side;
|
|
|
|
drv.num_secs = 9;
|
|
drv.ddhd = 1;
|
|
|
|
for (side = 2; side > 0; side--) {
|
|
if ( size == 9 * 80 * side * 512 || size == 9 * 81 * side * 512 || size == 9 * 82 * side * 512) {
|
|
drv.num_secs = 9;
|
|
drv.ddhd = 1;
|
|
break;
|
|
} else if (size == 18 * 80 * side * 512 || size == 18 * 81 * side * 512 || size == 18 * 82 * side * 512) {
|
|
drv.num_secs = 18;
|
|
drv.ddhd = 2;
|
|
break;
|
|
} else if (size == 10 * 80 * side * 512 || size == 10 * 81 * side * 512 || size == 10 * 82 * side * 512) {
|
|
drv.num_secs = 10;
|
|
drv.ddhd = 1;
|
|
break;
|
|
} else if (size == 20 * 80 * side * 512 || size == 20 * 81 * side * 512 || size == 20 * 82 * side * 512) {
|
|
drv.num_secs = 20;
|
|
drv.ddhd = 2;
|
|
break;
|
|
} else if (size == 21 * 80 * side * 512 || size == 21 * 81 * side * 512 || size == 21 * 82 * side * 512) {
|
|
drv.num_secs = 21;
|
|
drv.ddhd = 2;
|
|
break;
|
|
} else if (size == 9 * 40 * side * 512) {
|
|
drv.num_secs = 9;
|
|
drv.ddhd = 1;
|
|
break;
|
|
} else if (size == 8 * 40 * side * 512) {
|
|
drv.num_secs = 8;
|
|
drv.ddhd = 1;
|
|
break;
|
|
} else if (size == 15 * 80 * side * 512) {
|
|
drv.num_secs = 15;
|
|
drv.ddhd = 1;
|
|
break;
|
|
}
|
|
}
|
|
drv.num_tracks = Math.floor(size / (drv.num_secs * 512));
|
|
drv.filetype = ADF_PCDOS;
|
|
tid = drv.trackdata[0];
|
|
for (var i = 0; i < drv.num_tracks; i++) {
|
|
tid.type = TRACK_PCDOS;
|
|
tid.len = 512 * drv.num_secs;
|
|
tid.bitlen = 0;
|
|
tid.offs = i * 512 * drv.num_secs;
|
|
if (side == 1) {
|
|
tid++;
|
|
tid.type = TRACK_NONE;
|
|
tid.len = 512 * drv.num_secs;
|
|
}
|
|
tid.revolutions = 1;
|
|
tid++;
|
|
|
|
}
|
|
drv.num_heads = side;
|
|
if (side == 1)
|
|
drv.num_tracks *= 2;
|
|
} else if ((size == 262144 || size == 524288) && buffer[0] == 0x11 && (buffer[1] == 0x11 || buffer[1] == 0x14)) {
|
|
//256k == Kickstart disk, 512k == SuperKickstart disk
|
|
drv.filetype = size == 262144 ? ADF_KICK : ADF_SKICK;
|
|
drv.num_tracks = 1760 / (drv.num_secs = 11);
|
|
for (var i = 0; i < drv.num_tracks; i++) {
|
|
tid = drv.trackdata[i];
|
|
tid.type = TRACK_AMIGADOS;
|
|
tid.len = 512 * drv.num_secs;
|
|
tid.bitlen = 0;
|
|
tid.offs = i * 512 * drv.num_secs - (drv.filetype == ADF_KICK ? 512 : 262144 + 1024);
|
|
tid.track = i;
|
|
tid.revolutions = 1;
|
|
}
|
|
} else {
|
|
var i;
|
|
|
|
var ds = 0;
|
|
drv.filetype = ADF_NORMAL;
|
|
|
|
/* High-density or diskspare disk? */
|
|
drv.num_tracks = 0;
|
|
if (size > 160 * 11 * 512 + 511) { // larger than standard adf?
|
|
for (i = 80; i <= 83; i++) {
|
|
if (size == i * 22 * 512 * 2) { // HD
|
|
drv.num_secs = 22;
|
|
drv.num_tracks = size / (22 * 512);
|
|
drv.ddhd = 2;
|
|
break;
|
|
}
|
|
if (size == i * 11 * 512 * 2) { // >80 cyl DD
|
|
drv.num_secs = 11;
|
|
drv.num_tracks = size / (11 * 512);
|
|
break;
|
|
}
|
|
if (size == i * 12 * 512 * 2) { // ds 12 sectors
|
|
drv.num_secs = 12;
|
|
drv.num_tracks = size / (12 * 512);
|
|
ds = 1;
|
|
break;
|
|
}
|
|
if (size == i * 24 * 512 * 2) { // ds 24 sectors
|
|
drv.num_secs = 24;
|
|
drv.num_tracks = size / (24 * 512);
|
|
drv.ddhd = 2;
|
|
ds = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (drv.num_tracks == 0) {
|
|
drv.num_secs = 22;
|
|
drv.num_tracks = Math.floor(size / (22 * 512));
|
|
drv.ddhd = 2;
|
|
}
|
|
} else {
|
|
drv.num_secs = 11;
|
|
drv.num_tracks = Math.floor(size / (11 * 512));
|
|
}
|
|
if (!ds && drv.num_tracks > MAX_TRACKS) {
|
|
SAEF_warn("disk.drive_insert() Your diskfile is too big, %d bytes!", size);
|
|
//OWN
|
|
SAEF_ZFile_fclose(drv.diskfile);
|
|
drv.diskfile = null;
|
|
return 0;
|
|
}
|
|
for (i = 0; i < drv.num_tracks; i++) {
|
|
tid = drv.trackdata[i];
|
|
tid.type = ds ? TRACK_DISKSPARE : TRACK_AMIGADOS;
|
|
tid.len = 512 * drv.num_secs;
|
|
tid.bitlen = 0;
|
|
tid.offs = i * 512 * drv.num_secs;
|
|
tid.revolutions = 1;
|
|
}
|
|
}
|
|
//openwritefile(p, drv, 0);
|
|
drive_settype_id(drv); /* Set DD or HD drive */
|
|
drive_fill_bigbuf(drv, true);
|
|
drv.mfmpos = (((Math.decimalRandom() & 0xffff) << 16) | (Math.decimalRandom() & 0xffff)) >>> 0;
|
|
drv.mfmpos %= drv.tracklen;
|
|
drv.prevtracklen = 0;
|
|
if (!fake) {
|
|
update_drive_gui(drv.num, false);
|
|
update_disk_statusline(drv.num);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
function drive_eject(drv) {
|
|
//if (drv.diskfile || drv.filetype >= 0) statusline_add_message("DF%d: -", drv.num);
|
|
//gui_disk_image_change(drv.num, null, drv.wrprot);
|
|
drive_image_free(drv);
|
|
drv.dskeject = false;
|
|
drv.dskchange = true;
|
|
drv.ddhd = 1;
|
|
drv.dskchange_time = 0;
|
|
drv.dskready = 0;
|
|
drv.dskready_up_time = 0;
|
|
drv.dskready_down_time = 0;
|
|
drv.crc32 = 0;
|
|
drive_settype_id(drv); /* Back to 35 DD */
|
|
if (disk_debug_logging > 0) SAEF_log("disk.drive_eject() %d", drv.num);
|
|
//inprec_recorddiskchange(drv.num, null, false);
|
|
}
|
|
|
|
function drive_writeprotected(drv) {
|
|
//SAEF_log("disk.drive_writeprotected() df%d: ro %d wp %d fwp %d %s", drv.num, SAEV_config.floppy.readOnly?1:0, drv.wrprot?1:0, drv.forcedwrprot?1:0, drv.diskfile ? SAEF_ZFile_getname(drv.diskfile) : "none");
|
|
return SAEV_config.floppy.readOnly || drv.wrprot || drv.forcedwrprot || drv.diskfile === null;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* step / motor */
|
|
|
|
function rand_shifter(drv) {
|
|
var r = ((Math.decimalRandom() >>> 4) & 7) + 1;
|
|
while (r-- > 0) {
|
|
word <<= 1;
|
|
word |= (Math.decimalRandom() & 0x1000) ? 1 : 0;
|
|
word &= 0xffff; //OWN
|
|
bitoffset++;
|
|
bitoffset &= 15;
|
|
}
|
|
}
|
|
|
|
function drive_empty(drv) {
|
|
return drv.diskfile === null && drv.dskchange_time >= 0;
|
|
}
|
|
|
|
function set_steplimit(drv) {
|
|
// emulate step limit only if cycle-exact or approximate CPU speed
|
|
if (SAEV_config.cpu.speed == SAEC_Config_CPU_Speed_Original) {
|
|
drv.steplimit = 4;
|
|
drv.steplimitcycle = SAEV_Events_currcycle;
|
|
}
|
|
}
|
|
|
|
function drive_step(drv, step_direction) {
|
|
if (!drive_empty(drv))
|
|
drv.dskchange = false;
|
|
if (drv.steplimit && SAEV_Events_currcycle - drv.steplimitcycle < MIN_STEPLIMIT_CYCLE) {
|
|
SAEF_log("disk.drive_step() ignored df%d, cycle %d", drv.num, Math.floor((SAEV_Events_currcycle - drv.steplimitcycle) * SAEC_Events_CYCLE_UNIT_INV));
|
|
return;
|
|
}
|
|
/* A1200's floppy drive needs at least 30 raster lines between steps
|
|
* but we'll use very small value for better compatibility with faster CPU emulation
|
|
* (stupid trackloaders with CPU delay loops)
|
|
*/
|
|
set_steplimit(drv);
|
|
if (step_direction) {
|
|
if (drv.cyl) {
|
|
drv.cyl--;
|
|
}
|
|
/* else
|
|
SAEF_log("disk.drive_step() program tried to step beyond track zero");
|
|
"no-click" programs does that
|
|
*/
|
|
} else {
|
|
var maxtrack = drv.hard_num_cyls;
|
|
if (drv.cyl < maxtrack + 3) {
|
|
drv.cyl++;
|
|
}
|
|
if (drv.cyl >= maxtrack)
|
|
SAEF_warn("disk.drive_step() program tried to step over track %d", maxtrack);
|
|
}
|
|
rand_shifter(drv);
|
|
if (disk_debug_logging > 2) SAEF_log("disk.drive_step() %d", drv.cyl);
|
|
}
|
|
|
|
function drive_track0(drv) {
|
|
return drv.cyl == 0;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function drive_running(drv) {
|
|
return !drv.motoroff;
|
|
}
|
|
|
|
/*function motordelay_func(v) {
|
|
floppy[v].motordelay = 0;
|
|
}*/
|
|
function drive_motor(drv, off) {
|
|
if (drv.motoroff && !off) {
|
|
drv.dskready_up_time = DSKREADY_UP_TIME * 312 + (Math.decimalRandom() & 511);
|
|
rand_shifter(drv);
|
|
if (disk_debug_logging > 2) SAEF_log("disk.drive_motor() on");
|
|
}
|
|
if (!drv.motoroff && off) {
|
|
drv.drive_id_scnt = 0; /* Reset id shift reg counter */
|
|
drv.dskready_down_time = DSKREADY_DOWN_TIME * 312 + (Math.decimalRandom() & 511);
|
|
if (DEBUG_DRIVE_ID) SAEF_log("disk.drive_motor() Selected DF%d: reset id shift reg.", drv.num);
|
|
if (disk_debug_logging > 2) SAEF_log("disk.drive_motor() off");
|
|
|
|
if (SAEV_config.cpu.model <= SAEC_Config_CPU_Model_68010 && SAEV_config.cpu.speed == SAEC_Config_CPU_Speed_Original) {
|
|
drv.motordelay = 1;
|
|
//SAER.events.event2_newevent2(30, drv.num, motordelay_func);
|
|
SAER.events.event2_newevent_xx(-1, 30 * SAEC_Events_CYCLE_UNIT, drv.num, function(v) {
|
|
floppy[v].motordelay = 0;
|
|
});
|
|
}
|
|
}
|
|
drv.motoroff = off;
|
|
if (drv.motoroff) {
|
|
drv.dskready = 0;
|
|
drv.dskready_up_time = 0;
|
|
} else
|
|
drv.dskready_down_time = 0;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* read */
|
|
|
|
function read_floppy_data(diskfile, type, tid, offset, dst,dsto, len) {
|
|
if (len == 0)
|
|
return;
|
|
if (tid.track == 0) {
|
|
if (type == ADF_KICK) {
|
|
//memset(dst, 0, len > 512 ? 512 : len);
|
|
SAEF_memset(dst,dsto, 0, len > 512 ? 512 : len);
|
|
if (offset == 0) {
|
|
dst.set(SAEF_String2Array("KICK"), dsto);
|
|
len -= 512;
|
|
}
|
|
} else if (type == ADF_SKICK) {
|
|
//memset(dst, 0, len > 512 ? 512 : len);
|
|
SAEF_memset(dst,dsto, 0, len > 512 ? 512 : len);
|
|
if (offset == 0) {
|
|
dst.set(SAEF_String2Array("KICKSUP0"), dsto);
|
|
len -= 1024;
|
|
} else if (offset == 512)
|
|
len -= 512;
|
|
}
|
|
}
|
|
var off = tid.offs + offset;
|
|
if (off >= 0 && len > 0) {
|
|
SAEF_ZFile_fseek(diskfile, off, SEEK_SET);
|
|
SAEF_ZFile_fread(dst,dsto, 1, len, diskfile);
|
|
}
|
|
}
|
|
|
|
/* Megalomania does not like zero MFM words... */
|
|
function mfmcode(mfm,mfmo, words) {
|
|
var lastword = 0;
|
|
while (words--) {
|
|
var v = mfm[mfmo] & 0x5555;//5555;
|
|
var lv = ((lastword << 16) | v) >>> 0;
|
|
var nlv = ~lv & 0x55555555;
|
|
var mfmbits = (((nlv << 1) & (nlv >>> 1)) >>> 0) & 0xffff;
|
|
mfm[mfmo++] = v | mfmbits;
|
|
lastword = v;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* read amigados */
|
|
|
|
function decode_amigados(drv) {
|
|
var tr = drv.cyl * 2 + side;
|
|
var dstmfmoffset = FLOPPY_GAP_LEN();
|
|
//var dstmfmbuf = drv.bigmfmbuf; //u16 *
|
|
var len = drv.num_secs * 544 + FLOPPY_GAP_LEN();
|
|
var ti = drv.trackdata[tr];
|
|
|
|
//memset(dstmfmbuf, 0xaa, len * 2);
|
|
SAEF_memset(drv.bigmfmbuf,0, 0xaaaa, len);
|
|
//dstmfmoffset += FLOPPY_GAP_LEN();
|
|
drv.skipoffset = Math.floor((FLOPPY_GAP_LEN() * 8) / 3) * 2; //ATT
|
|
drv.tracklen = len * 2 * 8;
|
|
|
|
var prevbit = 0;
|
|
for (var sec = 0; sec < drv.num_secs; sec++) {
|
|
var secbuf = new Uint8Array(544);
|
|
var mfmbuf = new Uint16Array(544 + 1);
|
|
var hck = 0, dck = 0;
|
|
|
|
secbuf[0] = secbuf[1] = 0x00;
|
|
secbuf[2] = secbuf[3] = 0xa1;
|
|
secbuf[4] = 0xff;
|
|
secbuf[5] = tr;
|
|
secbuf[6] = sec;
|
|
secbuf[7] = drv.num_secs - sec;
|
|
|
|
for (var i = 8; i < 24; i++)
|
|
secbuf[i] = 0;
|
|
|
|
read_floppy_data(drv.diskfile, drv.filetype, ti, sec * 512, secbuf,32, 512);
|
|
|
|
mfmbuf[0] = prevbit ? 0x2aaa : 0xaaaa;
|
|
mfmbuf[1] = 0xaaaa;
|
|
mfmbuf[2] = mfmbuf[3] = 0x4489;
|
|
|
|
var deven = ((secbuf[4] << 24) | (secbuf[5] << 16) | (secbuf[6] << 8) | (secbuf[7])) >>> 0;
|
|
var dodd = deven >>> 1;
|
|
deven &= 0x55555555;
|
|
dodd &= 0x55555555;
|
|
mfmbuf[4] = dodd >>> 16;
|
|
mfmbuf[5] = dodd & 0xffff;
|
|
mfmbuf[6] = deven >>> 16;
|
|
mfmbuf[7] = deven & 0xffff;
|
|
|
|
for (i = 8; i < 48; i++)
|
|
mfmbuf[i] = 0xaaaa;
|
|
for (i = 0; i < 512; i += 4) {
|
|
deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16) | (secbuf[i + 34] << 8) | (secbuf[i + 35])) >>> 0;
|
|
dodd = deven >>> 1;
|
|
deven &= 0x55555555;
|
|
dodd &= 0x55555555;
|
|
mfmbuf[(i >> 1) + 32] = dodd >>> 16;
|
|
mfmbuf[(i >> 1) + 33] = dodd & 0xffff;
|
|
mfmbuf[(i >> 1) + 256 + 32] = deven >>> 16;
|
|
mfmbuf[(i >> 1) + 256 + 33] = deven & 0xffff;
|
|
}
|
|
|
|
for (i = 4; i < 24; i += 2)
|
|
hck = (hck ^ ((mfmbuf[i] << 16) | mfmbuf[i + 1]) >>> 0) >>> 0;
|
|
|
|
deven = dodd = hck;
|
|
dodd >>>= 1;
|
|
mfmbuf[24] = dodd >>> 16;
|
|
mfmbuf[25] = dodd & 0xffff;
|
|
mfmbuf[26] = deven >>> 16;
|
|
mfmbuf[27] = deven & 0xffff;
|
|
|
|
for (i = 32; i < 544; i += 2)
|
|
dck = (dck ^ ((mfmbuf[i] << 16) | mfmbuf[i + 1]) >>> 0) >>> 0;
|
|
|
|
deven = dodd = dck;
|
|
dodd >>>= 1;
|
|
mfmbuf[28] = dodd >>> 16;
|
|
mfmbuf[29] = dodd & 0xffff;
|
|
mfmbuf[30] = deven >>> 16;
|
|
mfmbuf[31] = deven & 0xffff;
|
|
|
|
mfmbuf[544] = 0;
|
|
|
|
mfmcode(mfmbuf,4, 544 - 4 + 1);
|
|
|
|
for (i = 0; i < 544; i++) {
|
|
drv.bigmfmbuf[dstmfmoffset % len] = mfmbuf[i];
|
|
dstmfmoffset++;
|
|
}
|
|
prevbit = mfmbuf[i - 1] & 1;
|
|
// so that final word has correct MFM encoding
|
|
drv.bigmfmbuf[dstmfmoffset % len] = mfmbuf[i];
|
|
}
|
|
|
|
if (disk_debug_logging > 0) SAEF_log("disk.decode_amigados() read track %d", tr);
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* read pcdos */
|
|
|
|
const mfmencodetable = [
|
|
0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
|
|
0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
|
|
];
|
|
function dos_encode_byte(byte) {
|
|
var word = (mfmencodetable[byte >> 4] << 8) | mfmencodetable[byte & 15];
|
|
return (word | ((word & (256 | 64)) ? 0 : 128));
|
|
}
|
|
function mfmcoder(src, dest,desto, len) {
|
|
var i, srco = 0;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
dest[desto] = dos_encode_byte(src[srco++]);
|
|
dest[desto] |= ((dest[desto - 1] & 1) || (dest[desto] & 0x4000)) ? 0: 0x8000;
|
|
desto++;
|
|
}
|
|
return desto;
|
|
}
|
|
function decode_pcdos(drv) {
|
|
var i, len;
|
|
var tr = drv.cyl * 2 + side;
|
|
//uae_u16 *dstmfmbuf, *mfm2;
|
|
var secbuf = new Uint8Array(1000);
|
|
var crc16;
|
|
var ti = drv.trackdata[tr];
|
|
const tracklen = 12500;
|
|
|
|
//SAEF_log("disk.decode_pcdos() num_secs %d, hd %d", drv.num_secs, drv.ddhd);
|
|
|
|
var mfm2 = drv.bigmfmbuf;
|
|
var mfm2o = 0; //OWN
|
|
var dstmfmbufo = 0; //OWN
|
|
|
|
mfm2[mfm2o++] = 0x9254; // *mfm2++ = 0x9254;
|
|
SAEF_memset(secbuf,0, 0x4e, 40);
|
|
SAEF_memset(secbuf,40, 0x00, 12);
|
|
secbuf[52] = 0xc2;
|
|
secbuf[53] = 0xc2;
|
|
secbuf[54] = 0xc2;
|
|
secbuf[55] = 0xfc;
|
|
SAEF_memset(secbuf,56, 0x4e, 40);
|
|
dstmfmbufo = mfmcoder(secbuf, mfm2,mfm2o, 96);
|
|
mfm2[mfm2o + 52] = 0x5224;
|
|
mfm2[mfm2o + 53] = 0x5224;
|
|
mfm2[mfm2o + 54] = 0x5224;
|
|
for (i = 0; i < drv.num_secs; i++) {
|
|
mfm2o = dstmfmbufo;
|
|
SAEF_memset(secbuf,0, 0x00, 12);
|
|
secbuf[12] = 0xa1;
|
|
secbuf[13] = 0xa1;
|
|
secbuf[14] = 0xa1;
|
|
secbuf[15] = 0xfe;
|
|
secbuf[16] = drv.cyl;
|
|
secbuf[17] = side;
|
|
secbuf[18] = 1 + i;
|
|
secbuf[19] = 2; // 128 << 2 = 512
|
|
crc16 = SAEF_crc16(secbuf,12, 3 + 1 + 4);
|
|
secbuf[20] = crc16 >> 8;
|
|
secbuf[21] = crc16 & 0xff;
|
|
SAEF_memset(secbuf,22, 0x4e, 22);
|
|
SAEF_memset(secbuf,44, 0x00, 12);
|
|
secbuf[56] = 0xa1;
|
|
secbuf[57] = 0xa1;
|
|
secbuf[58] = 0xa1;
|
|
secbuf[59] = 0xfb;
|
|
read_floppy_data(drv.diskfile, drv.filetype, ti, i * 512, secbuf,60, 512);
|
|
crc16 = SAEF_crc16(secbuf,56, 3 + 1 + 512);
|
|
secbuf[60 + 512] = crc16 >> 8;
|
|
secbuf[61 + 512] = crc16 & 0xff;
|
|
len = Math.floor((tracklen / 2 - 96) / drv.num_secs) - 574 / drv.ddhd;
|
|
if (len > 0) SAEF_memset(secbuf,512 + 62, 0x4e, len);
|
|
dstmfmbufo = mfmcoder(secbuf, mfm2,mfm2o, 62 + 512 + 76 / drv.ddhd);
|
|
mfm2[mfm2o + 12] = 0x4489;
|
|
mfm2[mfm2o + 13] = 0x4489;
|
|
mfm2[mfm2o + 14] = 0x4489;
|
|
mfm2[mfm2o + 56] = 0x4489;
|
|
mfm2[mfm2o + 57] = 0x4489;
|
|
mfm2[mfm2o + 58] = 0x4489;
|
|
}
|
|
//while (dstmfmbuf - drv.bigmfmbuf < tracklen / 2) *dstmfmbuf++ = 0x9254;
|
|
while (dstmfmbufo < tracklen / 2) drv.bigmfmbuf[dstmfmbufo++] = 0x9254;
|
|
drv.skipoffset = 0;
|
|
//drv.tracklen = (dstmfmbuf - drv.bigmfmbuf) * 16;
|
|
drv.tracklen = dstmfmbufo * 16;
|
|
if (disk_debug_logging > 0) SAEF_log("disk.decode_pcdos() read track %d, len %d bytes", tr, drv.tracklen / 8);
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* read diskspare
|
|
*
|
|
* 0 <4489> <4489> 0 track sector crchi, crclo, data[512] (520 bytes per sector)
|
|
*
|
|
* 0xAAAA 0x4489 0x4489 0x2AAA oddhi, oddlo, evenhi, evenlo, ...
|
|
*
|
|
* NOTE: data is MFM encoded using same method as ADOS header, not like ADOS data! */
|
|
|
|
function decode_diskspare(drv) {
|
|
var tr = drv.cyl * 2 + side;
|
|
var dstmfmoffset = FLOPPY_GAP_LEN();
|
|
//var dstmfmbuf = drv.bigmfmbuf; //u16 *
|
|
var len = drv.num_secs * (512 + 8) + FLOPPY_GAP_LEN(); //12 * 520 + 350 = 6590
|
|
var ti = drv.trackdata[tr];
|
|
|
|
//memset(dstmfmbuf, 0xaa, len * 2);
|
|
SAEF_memset(drv.bigmfmbuf,0, 0xaaaa, len);
|
|
//dstmfmoffset += FLOPPY_GAP_LEN();
|
|
drv.skipoffset = Math.floor((FLOPPY_GAP_LEN() * 8) / 3) * 2; //ATT
|
|
drv.tracklen = len * 2 * 8;
|
|
|
|
for (var sec = 0; sec < drv.num_secs; sec++) {
|
|
var secbuf = new Uint8Array(512 + 8);
|
|
var mfmbuf = new Uint16Array(512 + 8);
|
|
var i, deven, dodd;
|
|
|
|
secbuf[0] = tr;
|
|
secbuf[1] = sec;
|
|
secbuf[2] = 0;
|
|
secbuf[3] = 0;
|
|
|
|
read_floppy_data(drv.diskfile, drv.filetype, ti, sec * 512, secbuf,4, 512);
|
|
|
|
mfmbuf[0] = 0xaaaa;
|
|
mfmbuf[1] = 0x4489;
|
|
mfmbuf[2] = 0x4489;
|
|
mfmbuf[3] = 0x2aaa;
|
|
|
|
for (i = 0; i < 512; i += 4) {
|
|
deven = ((secbuf[i + 4] << 24) | (secbuf[i + 5] << 16) | (secbuf[i + 6] << 8) | (secbuf[i + 7])) >>> 0;
|
|
dodd = deven >>> 1;
|
|
deven &= 0x55555555;
|
|
dodd &= 0x55555555;
|
|
|
|
mfmbuf[i + 8 + 0] = dodd >>> 16;
|
|
mfmbuf[i + 8 + 1] = dodd & 0xffff;
|
|
mfmbuf[i + 8 + 2] = deven >>> 16;
|
|
mfmbuf[i + 8 + 3] = deven & 0xffff;
|
|
}
|
|
mfmcode(mfmbuf,8, 512);
|
|
|
|
i = 8;
|
|
var chk = mfmbuf[i++] & 0x7fff;
|
|
while (i < 512 + 8) chk ^= mfmbuf[i++];
|
|
secbuf[2] = chk >> 8;
|
|
secbuf[3] = chk;
|
|
|
|
deven = ((secbuf[0] << 24) | (secbuf[1] << 16) | (secbuf[2] << 8) | (secbuf[3])) >>> 0;
|
|
dodd = deven >>> 1;
|
|
deven &= 0x55555555;
|
|
dodd &= 0x55555555;
|
|
|
|
mfmbuf[4] = dodd >>> 16;
|
|
mfmbuf[5] = dodd & 0xffff;
|
|
mfmbuf[6] = deven >>> 16;
|
|
mfmbuf[7] = deven & 0xffff;
|
|
mfmcode(mfmbuf,4, 4);
|
|
|
|
for (i = 0; i < 512 + 8; i++) {
|
|
drv.bigmfmbuf[dstmfmoffset % len] = mfmbuf[i];
|
|
dstmfmoffset++;
|
|
}
|
|
}
|
|
if (disk_debug_logging > 0) SAEF_log("disk.decode_diskspare() read track %d", tr);
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function drive_fill_bigbuf(drv, force) {
|
|
var tr = drv.cyl * 2 + side;
|
|
var ti = drv.trackdata[tr];
|
|
|
|
if (drv.diskfile === null || tr >= drv.num_tracks) {
|
|
track_reset(drv);
|
|
return;
|
|
}
|
|
if (!force && drv.buffered_cyl == drv.cyl && drv.buffered_side == side)
|
|
return;
|
|
|
|
drv.indexoffset = 0;
|
|
drv.multi_revolution = 0;
|
|
drv.tracktiming[0] = 0;
|
|
drv.skipoffset = -1;
|
|
drv.revolutions = 1;
|
|
var retrytrack = drv.lastdataacesstrack == drv.cyl * 2 + side;
|
|
if (!dskdmaen && !retrytrack)
|
|
drv.track_access_done = false;
|
|
|
|
if (drv.writediskfile && drv.writetrackdata[tr].bitlen > 0) {
|
|
var wti = drv.writetrackdata[tr];
|
|
drv.tracklen = wti.bitlen;
|
|
drv.revolutions = wti.revolutions;
|
|
/*read_floppy_data(drv.writediskfile, drv.filetype, wti, 0, (uae_u8 *)drv.bigmfmbuf, (wti.bitlen + 7) / 8);
|
|
for (int i = 0; i < (drv.tracklen + 15) / 16; i++) {
|
|
uae_u16 *mfm = drv.bigmfmbuf + i;
|
|
uae_u8 *data = (uae_u8 *) mfm;
|
|
*mfm = 256 * *data + *(data + 1);
|
|
}*/
|
|
var size = (wti.bitlen + 7) >>> 3;
|
|
var tmp = new Uint8Array(size);
|
|
read_floppy_data(drv.writediskfile, drv.filetype, wti, 0, tmp,0, size);
|
|
size = (drv.tracklen + 15) >> 4;
|
|
for (var i = 0, j = 0; i < size; i++, j += 2)
|
|
drv.bigmfmbuf[i] = (tmp[j] << 8) | tmp[j + 1];
|
|
|
|
if (disk_debug_logging > 0) SAEF_log("disk.drive_fill_bigbuf() track %d, length %d read from \"saveimage\"", tr, drv.tracklen);
|
|
}
|
|
else if (drv.filetype == ADF_SCP) {
|
|
//scp_loadtrack(drv.bigmfmbuf, drv.tracktiming, drv - floppy, tr, &drv.tracklen, &drv.multi_revolution, &drv.skipoffset, &drv.lastrev, retrytrack);
|
|
scp_loadtrack(drv.bigmfmbuf, drv.tracktiming, drv.num, tr, retrytrack);
|
|
}
|
|
/*else if (drv.filetype == ADF_FDI) {
|
|
fdi2raw_loadtrack (drv.fdi, drv.bigmfmbuf, drv.tracktiming, tr, &drv.tracklen, &drv.indexoffset, &drv.multi_revolution, 1);
|
|
}*/
|
|
else if (ti.type == TRACK_PCDOS) {
|
|
decode_pcdos(drv);
|
|
}
|
|
else if (ti.type == TRACK_AMIGADOS) {
|
|
decode_amigados(drv);
|
|
}
|
|
else if (ti.type == TRACK_DISKSPARE) {
|
|
decode_diskspare(drv);
|
|
}
|
|
else if (ti.type == TRACK_NONE) {
|
|
;
|
|
} else {
|
|
var wti = drv.writetrackdata[tr];
|
|
var base_offset = ti.type == TRACK_RAW ? 0 : 1;
|
|
drv.tracklen = ti.bitlen + 16 * base_offset;
|
|
drv.bigmfmbuf[0] = ti.sync;
|
|
/*read_floppy_data(drv.diskfile, drv.filetype, ti, 0, (uae_u8*)(drv.bigmfmbuf + base_offset), (ti.bitlen + 7) / 8);
|
|
for (int i = base_offset; i < (drv.tracklen + 15) / 16; i++) {
|
|
uae_u16 *mfm = drv.bigmfmbuf + i;
|
|
uae_u8 *data = (uae_u8 *) mfm;
|
|
*mfm = 256 * *data + *(data + 1);
|
|
}*/
|
|
var size = (wti.bitlen + 7) >>> 3;
|
|
var tmp = new Uint8Array(size);
|
|
read_floppy_data(drv.diskfile, drv.filetype, ti, 0, tmp,0, size);
|
|
size = (drv.tracklen + 15) >> 4;
|
|
for (var i = base_offset, j = 0; i < size; i++, j += 2)
|
|
drv.bigmfmbuf[i] = (tmp[j] << 8) | tmp[j + 1];
|
|
|
|
if (disk_debug_logging > 2) SAEF_log("disk.drive_fill_bigbuf() rawtrack %d image offset $%x", tr, ti.offs);
|
|
}
|
|
drv.buffered_side = side;
|
|
drv.buffered_cyl = drv.cyl;
|
|
if (drv.tracklen == 0) {
|
|
drv.tracklen = FLOPPY_WRITE_LEN() * 2 * drv.ddhd * 8;
|
|
//memset(drv.bigmfmbuf, 0, FLOPPY_WRITE_LEN() * 2 * drv.ddhd);
|
|
SAEF_memset(drv.bigmfmbuf,0, 0, FLOPPY_WRITE_LEN() * 2 * drv.ddhd >> 1);
|
|
}
|
|
drv.trackspeed = get_floppy_speed2(drv);
|
|
updatemfmpos(drv);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* write */
|
|
|
|
const MFMMASK = 0x55555555;
|
|
function getmfmword(mbuf,mbufo, shift) {
|
|
return ((mbuf[mbufo] << shift) | (mbuf[mbufo + 1] >> (16 - shift))) & 0xffff;
|
|
}
|
|
function getmfmlong(mbuf,mbufo, shift) {
|
|
return (((getmfmword(mbuf,mbufo, shift) << 16) | getmfmword(mbuf,mbufo + 1, shift)) & MFMMASK) >>> 0;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* write amigados */
|
|
|
|
function check_valid_mfm(mbuf,mbufo, words, sector) {
|
|
var prevbit = 0;
|
|
for (var i = 0; i < words * 8; i++) {
|
|
var wordoffset = i / 8 >>> 0;
|
|
var w = mbuf[mbufo + wordoffset];
|
|
var wp = mbuf[mbufo + wordoffset - 1];
|
|
var bitoffset = (7 - (i & 7)) * 2;
|
|
var clockbit = w & (1 << (bitoffset + 1));
|
|
var databit = w & (1 << (bitoffset + 0));
|
|
|
|
if ((clockbit && databit) || (clockbit && !databit && prevbit) || (!clockbit && !databit && !prevbit))
|
|
SAEF_warn("disk.check_valid_mfm() illegal mfm sector %d data %04x %04x, bit %d:%d", sector, wp, w, wordoffset, bitoffset);
|
|
|
|
prevbit = databit;
|
|
}
|
|
}
|
|
function decode_buffer(mbuf, cyl, drvsec, ddhd, filetype, drvsecp, sectable, checkmode) {
|
|
var i = 0, secwritten = 0;
|
|
var fwlen = FLOPPY_WRITE_LEN() * ddhd;
|
|
var odd = 0, even = 0, chksum = 0, id = 0, dlong = 0; //u32
|
|
var secbuf = new Uint8Array(544);
|
|
var secbufo = 0; //OWN
|
|
var mbufo = 0; //OWN
|
|
var mend = fwlen * 2 - (4 + 16 + 8 + 512);
|
|
var sechead = new Uint32Array(4);
|
|
var shift = 0;
|
|
var issechead = false;
|
|
|
|
//memset(sectable, 0, MAX_SECTORS * sizeof (int));
|
|
SAEF_memset(sectable,0, 0, MAX_SECTORS);
|
|
//memcpy(mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16));
|
|
SAEF_memcpy(mbuf,fwlen, mbuf,0, fwlen);
|
|
//mbuf.copyWithin(fwlen, 0, fwlen);
|
|
|
|
while (secwritten < drvsec) {
|
|
while (getmfmword(mbuf,mbufo, shift) != 0x4489) {
|
|
if (mbufo >= mend) {
|
|
SAEF_log("disk.decode_buffer() sync not found (1)");
|
|
return 1;
|
|
}
|
|
shift++;
|
|
if (shift == 16) {
|
|
shift = 0;
|
|
mbufo++;
|
|
}
|
|
}
|
|
while (getmfmword(mbuf,mbufo, shift) == 0x4489) {
|
|
if (mbufo >= mend) {
|
|
SAEF_log("disk.decode_buffer() sync not found (2)");
|
|
return 1;
|
|
}
|
|
mbufo++;
|
|
}
|
|
|
|
odd = getmfmlong(mbuf,mbufo, shift);
|
|
even = getmfmlong(mbuf,mbufo + 2, shift);
|
|
mbufo += 4;
|
|
id = ((odd << 1) | even) >>> 0;
|
|
|
|
var trackoffs = (id & 0xff00) >> 8;
|
|
if (trackoffs + 1 > drvsec) {
|
|
SAEF_log("disk.decode_buffer() weird sector number %d (id $%08x, offset %d)", trackoffs, id, mbufo);
|
|
if (filetype == ADF_EXT2) return 2;
|
|
continue;
|
|
}
|
|
|
|
//check_valid_mfm(mbuf,mbufo - 4, 544 - 4 + 1, trackoffs);
|
|
|
|
issechead = false;
|
|
chksum = (odd ^ even) >>> 0;
|
|
for (i = 0; i < 4; i++) {
|
|
odd = getmfmlong(mbuf,mbufo, shift);
|
|
even = getmfmlong(mbuf,mbufo + 8, shift);
|
|
mbufo += 2;
|
|
|
|
dlong = ((odd << 1) | even) >>> 0;
|
|
if (dlong && !checkmode)
|
|
issechead = true;
|
|
|
|
sechead[i] = dlong;
|
|
chksum = (chksum ^ ((odd ^ even) >>> 0)) >>> 0;
|
|
}
|
|
if (issechead) {
|
|
SAEF_log("disk.decode_buffer() sector %d header: %08X %08X %08X %08X", trackoffs, sechead[0], sechead[1], sechead[2], sechead[3]);
|
|
if (filetype == ADF_EXT2) return 6;
|
|
}
|
|
mbufo += 8;
|
|
odd = getmfmlong(mbuf,mbufo, shift);
|
|
even = getmfmlong(mbuf,mbufo + 2, shift);
|
|
mbufo += 4;
|
|
if ((((odd << 1) | even) >>> 0) != chksum) {
|
|
SAEF_log("disk.decode_buffer() sector %d, header checksum error (%08X != %08X) ", trackoffs, ((odd << 1) | even) >>> 0, chksum);
|
|
if (filetype == ADF_EXT2) return 3;
|
|
continue;
|
|
}
|
|
if (((id & 0x00ff0000) >>> 16) != cyl * 2 + side) {
|
|
SAEF_log("disk.decode_buffer() mismatched track (%d <> %d) on sector %d header (%08X)", (id & 0x00ff0000) >>> 16, cyl * 2 + side, trackoffs, id);
|
|
if (filetype == ADF_EXT2) return 3;
|
|
continue;
|
|
}
|
|
odd = getmfmlong(mbuf,mbufo, shift);
|
|
even = getmfmlong(mbuf,mbufo + 2, shift);
|
|
mbufo += 4;
|
|
chksum = ((odd << 1) | even) >>> 0;
|
|
secbufo = 32;
|
|
for (i = 0; i < 128; i++) {
|
|
odd = getmfmlong(mbuf,mbufo, shift);
|
|
even = getmfmlong(mbuf,mbufo + 256, shift);
|
|
mbufo += 2;
|
|
dlong = ((odd << 1) | even) >>> 0;
|
|
secbuf[secbufo++] = dlong >>> 24;
|
|
secbuf[secbufo++] = (dlong >>> 16) & 0xff;
|
|
secbuf[secbufo++] = (dlong >>> 8) & 0xff;
|
|
secbuf[secbufo++] = dlong & 0xff;
|
|
chksum = (chksum ^ ((odd ^ even) >>> 0)) >>> 0;
|
|
}
|
|
if (chksum) {
|
|
SAEF_log("disk.decode_buffer() sector %d, data checksum error", trackoffs);
|
|
if (filetype == ADF_EXT2) return 4;
|
|
continue;
|
|
}
|
|
mbufo += 256;
|
|
//SAEF_log("disk.decode_buffer() sector %d ok", trackoffs);
|
|
sectable[trackoffs] = 1;
|
|
secwritten++;
|
|
writebuffer.set(secbuf.subarray(32, 32 + 512), trackoffs * 512); //memcpy(writebuffer + trackoffs * 512, secbuf + 32, 512);
|
|
}
|
|
if (filetype == ADF_EXT2 && (secwritten == 0 || secwritten < 0))
|
|
return 5;
|
|
if (secwritten == 0)
|
|
SAEF_log("disk.decode_buffer() unsupported format");
|
|
else if (secwritten < 0)
|
|
SAEF_log("disk.decode_buffer() sector labels ignored");
|
|
|
|
drvsecp.value = drvsec;
|
|
return 0;
|
|
}
|
|
|
|
/* Update EXT2 track header */
|
|
function diskfile_update(diskfile, ti, len, type) {
|
|
var buf = new Uint8Array(2 + 2 + 4 + 4);
|
|
|
|
ti.revolutions = 1;
|
|
ti.bitlen = len;
|
|
ti.type = type;
|
|
|
|
buf[0] = 0;
|
|
buf[1] = 0;
|
|
buf[2] = 0;
|
|
buf[3] = ti.type;
|
|
//do_put_mem_long((uae_u32 *)(buf + 4), ti.len);
|
|
buf[4] = ti.len >>> 24;
|
|
buf[5] = (ti.len >>> 16) & 0xff;
|
|
buf[6] = (ti.len >>> 8) & 0xff;
|
|
buf[7] = ti.len & 0xff;
|
|
//do_put_mem_long((uae_u32 *)(buf + 8), ti.bitlen);
|
|
buf[8] = ti.bitlen >>> 24;
|
|
buf[9] = (ti.bitlen >>> 16) & 0xff;
|
|
buf[10] = (ti.bitlen >>> 8) & 0xff;
|
|
buf[11] = ti.bitlen & 0xff;
|
|
|
|
SAEF_ZFile_fseek(diskfile, 8 + 4 + (2 + 2 + 4 + 4) * ti.track, SEEK_SET);
|
|
SAEF_ZFile_fwrite(buf,0, buf.length, 1, diskfile);
|
|
if (ti.len > Math.floor((len + 7) / 8)) {
|
|
var zerobuf = new Uint8Array(ti.len);
|
|
//memset(zerobuf, 0, ti.len);
|
|
SAEF_memset(zerobuf,0, 0, ti.len);
|
|
SAEF_ZFile_fseek(diskfile, ti.offs, SEEK_SET);
|
|
SAEF_ZFile_fwrite(zerobuf,0, 1, ti.len, diskfile);
|
|
}
|
|
if (disk_debug_logging > 0) SAEF_log("disk.diskfile_update() track %d, raw track length %d written (total size %d)", ti.track, Math.floor((ti.bitlen + 7) / 8), ti.len);
|
|
}
|
|
|
|
function drive_write_adf_amigados(drv) {
|
|
var drvsec = { value:0 };
|
|
var sectable = new Uint8Array(MAX_SECTORS);
|
|
|
|
if (decode_buffer(drv.bigmfmbuf, drv.cyl, drv.num_secs, drv.ddhd, drv.filetype, drvsec, sectable, false))
|
|
return 2;
|
|
if (!drvsec.value)
|
|
return 2;
|
|
|
|
if (drv.filetype == ADF_EXT2)
|
|
diskfile_update(drv.diskfile, drv.trackdata[drv.cyl * 2 + side], drvsec.value * 512 * 8, TRACK_AMIGADOS);
|
|
|
|
for (var i = 0; i < drvsec.value; i++) {
|
|
SAEF_ZFile_fseek(drv.diskfile, drv.trackdata[drv.cyl * 2 + side].offs + i * 512, SEEK_SET);
|
|
SAEF_ZFile_fwrite(writebuffer,i * 512, 1, 512, drv.diskfile);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* write EXT2 */
|
|
|
|
/* UAE-1ADF (ADF_EXT2)
|
|
* W reserved
|
|
* W number of tracks (default 2*80=160)
|
|
*
|
|
* W reserved
|
|
* W type, 0=normal AmigaDOS track, 1 = raw MFM (upper byte = disk revolutions - 1)
|
|
* L available space for track in bytes (must be even)
|
|
* L track length in bits
|
|
*/
|
|
|
|
/* write raw track to disk file */
|
|
function drive_write_ext2(bigmfmbuf, diskfile, ti, tracklen) {
|
|
var len = Math.floor((tracklen + 7) / 8);
|
|
if (len > ti.len) {
|
|
SAEF_warn("disk.drive_write_ext2() image file's track %d is too small (%d < %d)", ti.track, ti.len, len);
|
|
len = ti.len;
|
|
}
|
|
diskfile_update(diskfile, ti, tracklen, TRACK_RAW);
|
|
/*for (var i = 0; i < ti.len / 2; i++) {
|
|
uae_u16 *mfm = bigmfmbuf + i;
|
|
uae_u16 *mfmw = bigmfmbufw + i;
|
|
uae_u8 *data = (uae_u8 *) mfm;
|
|
*mfmw = 256 * *data + *(data + 1);
|
|
}*/
|
|
for (var i = 0; i < ti.len >> 1; i++)
|
|
bigmfmbufw[i] = bigmfmbuf[i]; //ATT
|
|
|
|
SAEF_ZFile_fseek(diskfile, ti.offs, SEEK_SET);
|
|
SAEF_ZFile_fwrite(bigmfmbufw,0, 1, len, diskfile);
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* write pcdos */
|
|
|
|
function mfmdecode(mfmp,mfmo, shift) {
|
|
var mfm = getmfmword(mfmp,mfmo, shift);
|
|
var out = 0;
|
|
|
|
mfm &= 0x5555; //ATT
|
|
for (var i = 0; i < 8; i++) {
|
|
out >>= 1;
|
|
if (mfm & 1)
|
|
out |= 0x80;
|
|
mfm >>= 2;
|
|
}
|
|
return out;
|
|
}
|
|
function drive_write_pcdos(drv, zf, count) {
|
|
var drvsec = drv.num_secs;
|
|
var fwlen = FLOPPY_WRITE_LEN() * drv.ddhd;
|
|
var mbuf = drv.bigmfmbuf;
|
|
var mbufo = 0; //OWN
|
|
var mend = fwlen * 2 - 518;
|
|
var secwritten = 0, seccnt = 0;
|
|
var shift = 0, sector = -1;
|
|
var sectable = new Uint8Array(24);
|
|
var secbuf = new Uint8Array(3 + 1 + 512);
|
|
var mark = 0; //u8
|
|
var crc = 0; //u16
|
|
var i = 0;
|
|
|
|
//memset(sectable, 0, sizeof sectable);
|
|
SAEF_memset(sectable,0, 0, 24);
|
|
//memcpy(mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16));
|
|
SAEF_memcpy(mbuf,fwlen, mbuf,0, fwlen);
|
|
//mbuf.copyWithin(fwlen, 0, fwlen);
|
|
secbuf[0] = secbuf[1] = secbuf[2] = 0xa1;
|
|
secbuf[3] = 0xfb;
|
|
|
|
while (seccnt < drvsec) {
|
|
var mfmcount = 0;
|
|
while (getmfmword(mbuf,mbufo, shift) != 0x4489) {
|
|
mfmcount++;
|
|
if (mbufo >= mend)
|
|
return -1;
|
|
shift++;
|
|
if (shift == 16) {
|
|
shift = 0;
|
|
mbufo++;
|
|
}
|
|
if (sector >= 0 && mfmcount / 16 >= 43)
|
|
sector = -1;
|
|
}
|
|
|
|
mfmcount = 0;
|
|
while (getmfmword(mbuf,mbufo, shift) == 0x4489) {
|
|
mfmcount++;
|
|
if (mbufo >= mend)
|
|
return -1;
|
|
mbufo++;
|
|
}
|
|
if (mfmcount < 3) // ignore if less than 3 sync markers
|
|
continue;
|
|
|
|
mark = mfmdecode(mbuf,mbufo++, shift);
|
|
if (mark == 0xfe) {
|
|
var tmp = new Uint8Array(8);
|
|
var cyl, head, size; //u8
|
|
|
|
cyl = mfmdecode(mbuf,mbufo++, shift);
|
|
head = mfmdecode(mbuf,mbufo++, shift);
|
|
sector = mfmdecode(mbuf,mbufo++, shift);
|
|
size = mfmdecode(mbuf,mbufo++, shift);
|
|
crc = (mfmdecode(mbuf,mbufo++, shift) << 8) | mfmdecode(mbuf,mbufo++, shift);
|
|
|
|
tmp[0] = tmp[1] = tmp[2] = 0xa1; tmp[3] = mark;
|
|
tmp[4] = cyl; tmp[5] = head; tmp[6] = sector; tmp[7] = size;
|
|
|
|
// skip 28 bytes
|
|
for (i = 0; i < 28; i++)
|
|
mfmdecode(mbuf,mbufo++, shift);
|
|
|
|
if (SAEF_crc16(tmp,0, 8) != crc || cyl != drv.cyl || head != side || size != 2 || sector < 1 || sector > drv.num_secs || sector >= sectable.length) {
|
|
SAEF_warn("disk.drive_write_pcdos() track %d, corrupted sector header", drv.cyl * 2 + side);
|
|
return -1;
|
|
}
|
|
sector--;
|
|
continue;
|
|
}
|
|
if (mark != 0xfb && mark != 0xfa) {
|
|
SAEF_warn("disk.drive_write_pcdos() track %d: unknown address mark %02X", drv.cyl * 2 + side, mark);
|
|
continue;
|
|
}
|
|
if (sector < 0)
|
|
continue;
|
|
for (i = 0; i < 512; i++)
|
|
secbuf[i + 4] = mfmdecode(mbuf,mbufo++, shift);
|
|
|
|
crc = (mfmdecode(mbuf,mbufo++, shift) << 8) | mfmdecode(mbuf,mbufo++, shift);
|
|
if (SAEF_crc16(secbuf,0, 3 + 1 + 512) != crc) {
|
|
SAEF_warn("disk.drive_write_pcdos() track %d, sector %d data checksum error", drv.cyl * 2 + side, sector + 1);
|
|
continue;
|
|
}
|
|
seccnt++;
|
|
if (count && sectable[sector])
|
|
break;
|
|
if (!sectable[sector]) {
|
|
secwritten++;
|
|
sectable[sector] = 1;
|
|
SAEF_ZFile_fseek(zf, drv.trackdata[drv.cyl * 2 + side].offs + sector * 512, SEEK_SET);
|
|
SAEF_ZFile_fwrite(secbuf,4, 1, 512, zf);
|
|
//SAEF_log("disk.drive_write_pcdos() track %d sector %d written", drv.cyl * 2 + side, sector + 1);
|
|
}
|
|
sector = -1;
|
|
}
|
|
if (!count && secwritten != drv.num_secs)
|
|
SAEF_warn("disk.drive_write_pcdos() track %d, %d corrupted sectors ignored", drv.cyl * 2 + side, drv.num_secs - secwritten);
|
|
|
|
return secwritten;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function drive_write_data(drv) {
|
|
var ret = -1;
|
|
var tr = drv.cyl * 2 + side;
|
|
|
|
if (drive_writeprotected(drv) || drv.trackdata[tr].type == TRACK_NONE) {
|
|
/* read original track back because we didn't really write anything */
|
|
drv.buffered_side = 2;
|
|
return;
|
|
}
|
|
if (drv.writediskfile)
|
|
drive_write_ext2(drv.bigmfmbuf, drv.writediskfile, drv.writetrackdata[tr], longwritemode ? dsklength2 * 8 : drv.tracklen);
|
|
|
|
switch (drv.filetype) {
|
|
case ADF_NORMAL: {
|
|
if (drive_write_adf_amigados(drv)) {
|
|
if (SAEV_config.floppy.autoEXT2)
|
|
convert_adf_to_ext2(drv, SAEV_config.floppy.autoEXT2);
|
|
else {
|
|
if (!warned_ext2) {
|
|
warned_ext2 = true;
|
|
//notify_user(NUMSG_NEEDEXT2);
|
|
alert("Disk in DF"+drv.num+" does use a non-standard floppy disk format.\n"+
|
|
"You may need to use a custom floppy disk image file instead of a standard one\n"+
|
|
"or enable 'Auto convert to EXT2' in the floppy-page.\n\n"+
|
|
"This message will not appear again."
|
|
);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
case ADF_EXT1:
|
|
break;
|
|
case ADF_EXT2: {
|
|
if (!longwritemode)
|
|
ret = drive_write_adf_amigados(drv);
|
|
if (ret) {
|
|
SAEF_warn("disk.drive_write_data() not an amigados track %d (error %d), writing as raw track", drv.cyl * 2 + side, ret);
|
|
drive_write_ext2(drv.bigmfmbuf, drv.diskfile, drv.trackdata[drv.cyl * 2 + side], longwritemode ? dsklength2 * 8 : drv.tracklen);
|
|
}
|
|
return;
|
|
}
|
|
case ADF_SCP:
|
|
break;
|
|
case ADF_PCDOS: {
|
|
ret = drive_write_pcdos(drv, drv.diskfile, 0);
|
|
if (ret < 0) SAEF_log("disk.drive_write_data() not a PC formatted track %d (error %d)", drv.cyl * 2 + side, ret);
|
|
break;
|
|
}
|
|
}
|
|
drv.tracktiming[0] = 0;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* SECT disk */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
function setdskchangetime(drv, dsktime) {
|
|
/* prevent multiple disk insertions at the same time */
|
|
if (drv.dskchange_time > 0)
|
|
return;
|
|
for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) {
|
|
if (floppy[i].num != drv.num && floppy[i].dskchange_time > 0 && floppy[i].dskchange_time + 1 >= dsktime)
|
|
dsktime = floppy[i].dskchange_time + 1;
|
|
}
|
|
drv.dskchange_time = dsktime;
|
|
if (disk_debug_logging > 0) SAEF_log("disk.setdskchangetime() delayed insert enable %d", dsktime);
|
|
}
|
|
|
|
/*function DISK_reinsert(num) {
|
|
drive_eject(floppy[num]);
|
|
setdskchangetime(floppy[num], 2 * 50 * 312);
|
|
}*/
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
//function disk_insert_2(num, name, forced, forcedwriteprotect) {
|
|
function disk_insert_2(num, file, forced) {
|
|
var drv = floppy[num];
|
|
|
|
if (forced) {
|
|
//drive_insert(drv, SAEV_config, num, name, data, false, forcedwriteprotect);
|
|
drive_insert(drv, SAEV_config, num, file, false);
|
|
return;
|
|
}
|
|
/*if (SAEV_config.floppy.drive[num].name === name) {
|
|
SAEF_warn("disk_insert_2() already inserted");
|
|
return;
|
|
}
|
|
SAEV_config.floppy.drive[num].name = name;
|
|
SAEV_config.floppy.drive[num].forcedWriteProtect = forcedwriteprotect;*/
|
|
|
|
drv.dskeject = false;
|
|
//drv.newname = name;
|
|
//drv.newnamewriteprotected = forcedwriteprotect;
|
|
drv.newfile = file.clone(); //ATT
|
|
|
|
if (file.size == 0)
|
|
SAER.disk.eject(num);
|
|
else if (!drive_empty(drv) || drv.dskchange_time > 0)
|
|
//delay eject so that it is always called when emulation is active
|
|
drv.dskeject = true;
|
|
else
|
|
setdskchangetime(drv, 1 * 312);
|
|
}
|
|
//this.insert = function(num, name, forcedwriteprotect) { //disk_insert()
|
|
this.insert = function(num, file) { //disk_insert()
|
|
//set_config_changed();
|
|
//target_addtorecent(name, 0);
|
|
disk_insert_2(num, file, false);
|
|
}
|
|
this.insert_force = function(num, file) { //disk_insert_force()
|
|
disk_insert_2(num, file, true);
|
|
}
|
|
|
|
this.eject = function(num) { //disk_eject()
|
|
//set_config_changed();
|
|
//SAER.gui.filename(num, "");
|
|
drive_eject(floppy[num]);
|
|
SAEV_config.floppy.drive[num].file.clr();
|
|
//floppy[num].newname = "";
|
|
floppy[num].newfile = null;
|
|
driveNames[num] = ""; //OWN
|
|
update_drive_gui(num, true);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
function disk_check_change() {
|
|
/*if (SAEV_config.floppy.speed != changed_prefs.floppy_speed)
|
|
SAEV_config.floppy.speed = changed_prefs.floppy_speed;
|
|
if (SAEV_config.floppy.readOnly != changed_prefs.floppy_read_only)
|
|
SAEV_config.floppy.readOnly = changed_prefs.floppy_read_only;*/
|
|
for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) {
|
|
var drv = floppy[i];
|
|
if (drv.dskeject) {
|
|
drive_eject(drv);
|
|
/* set dskchange_time, disk_insert() will be
|
|
* called from disk_check_change() after 2 second delay
|
|
* this makes sure that all programs detect disk change correctly */
|
|
setdskchangetime(drv, 2 * 50 * 312);
|
|
}
|
|
/*if (SAEV_config.floppy.drive[i].type != changed_prefs.floppyslots[i].type) {
|
|
SAEV_config.floppy.drive[i].type = changed_prefs.floppyslots[i].type;
|
|
reset_drive(i);
|
|
#ifdef RETROPLATFORM
|
|
rp_floppy_device_enable (i, SAEV_config.floppy.drive[i].type >= SAEC_Config_Floppy_Type_35_DD);
|
|
#endif
|
|
}*/
|
|
}
|
|
}
|
|
|
|
this.vsync = function() { //DISK_vsync()
|
|
disk_check_change();
|
|
|
|
for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) {
|
|
if (SAEV_config.floppy.drive[i].type > SAEC_Config_Floppy_Type_None) { //OWN
|
|
var drv = floppy[i];
|
|
var file = SAEV_config.floppy.drive[i].file;
|
|
if (drv.dskchange_time == 0 && file.name !== driveNames[i]) {
|
|
//SAEF_log("disk.vsync() dskchange unit %d ('%s')", i, file.name);
|
|
this.insert_force(i, file);
|
|
driveNames[i] = file.name;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
/*this.disk_empty = function(num) {
|
|
return drive_empty(floppy[num]);
|
|
}*/
|
|
|
|
/*static TCHAR *tobin (uae_u8 v) {
|
|
static TCHAR buf[9];
|
|
for (int i = 7; i >= 0; i--)
|
|
buf[7 - i] = v & (1 << i) ? '1' : '0';
|
|
return buf;
|
|
}*/
|
|
|
|
function fetch_DISK_select(data) {
|
|
if (SAEV_config.chipset.compatible == SAEC_Config_Chipset_Compatible_A1000V)
|
|
selected = (data >> 3) & 3;
|
|
else
|
|
selected = (data >> 3) & 15;
|
|
|
|
side = 1 - ((data >> 2) & 1);
|
|
direction = (data >> 1) & 1;
|
|
}
|
|
|
|
this.select_set = function(data) { //DISK_select_set()
|
|
prev_data = data;
|
|
prev_step = data & 1;
|
|
|
|
fetch_DISK_select(data);
|
|
}
|
|
|
|
this.select = function(data) { //DISK_select()
|
|
var velvet = SAEV_config.chipset.compatible == SAEC_Config_Chipset_Compatible_A1000V;
|
|
var dr;
|
|
|
|
var prev_selected = selected;
|
|
|
|
fetch_DISK_select(data);
|
|
var step_pulse = data & 1;
|
|
|
|
/*if (disk_debug_logging > 2) {
|
|
if (velvet)
|
|
write_log (_T("%08X %02X.%02X %s drvmask=%x"), SAER_CPU_getPC(), prev_data, data, tobin(data), selected ^ 3);
|
|
else
|
|
write_log (_T("%08X %02X.%02X %s drvmask=%x"), SAER_CPU_getPC(), prev_data, data, tobin(data), selected ^ 15);
|
|
}*/
|
|
|
|
if (amax_enabled) {
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
if (drv.amax)
|
|
amax_disk_select(data, prev_data, dr);
|
|
}
|
|
}
|
|
|
|
if (!velvet) {
|
|
if ((prev_data & 0x80) != (data & 0x80)) {
|
|
for (dr = 0; dr < 4; dr++) {
|
|
if (floppy[dr].indexhackmode > 1 && !((selected | disabled) & (1 << dr))) {
|
|
floppy[dr].indexhack = true;
|
|
//if (disk_debug_logging > 2) SAEF_log("indexhack! ");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*if (disk_debug_logging > 2) {
|
|
if (velvet) {
|
|
write_log (_T(" %d%d "), (selected & 1) ? 0 : 1, (selected & 2) ? 0 : 1);
|
|
if ((prev_data & 0x08) != (data & 0x08)) write_log (_T(" dsksel0 %d "), (data & 0x08) ? 0 : 1);
|
|
if ((prev_data & 0x10) != (data & 0x10)) write_log (_T(" dsksel1 %d "), (data & 0x10) ? 0 : 1);
|
|
if ((prev_data & 0x20) != (data & 0x20)) write_log (_T(" dskmotor0 %d "), (data & 0x20) ? 0 : 1);
|
|
if ((prev_data & 0x40) != (data & 0x40)) write_log (_T(" dskmotor1 %d "), (data & 0x40) ? 0 : 1);
|
|
if ((prev_data & 0x02) != (data & 0x02)) write_log (_T(" direct %d "), (data & 0x02) ? 1 : 0);
|
|
if ((prev_data & 0x04) != (data & 0x04)) write_log (_T(" side %d "), (data & 0x04) ? 1 : 0);
|
|
} else {
|
|
write_log (_T(" %d%d%d%d "), (selected & 1) ? 0 : 1, (selected & 2) ? 0 : 1, (selected & 4) ? 0 : 1, (selected & 8) ? 0 : 1);
|
|
if ((prev_data & 0x80) != (data & 0x80)) write_log (_T(" dskmotor %d "), (data & 0x80) ? 1 : 0);
|
|
if ((prev_data & 0x02) != (data & 0x02)) write_log (_T(" direct %d "), (data & 0x02) ? 1 : 0);
|
|
if ((prev_data & 0x04) != (data & 0x04)) write_log (_T(" side %d "), (data & 0x04) ? 1 : 0);
|
|
}
|
|
}*/
|
|
|
|
// step goes high and drive was selected when step pulse changes: step
|
|
if (prev_step != step_pulse) {
|
|
//if (disk_debug_logging > 2) SAEF_log("step %d ", step_pulse);
|
|
prev_step = step_pulse;
|
|
if (prev_step) { // && !savestate_state) {
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
if (!((prev_selected | disabled) & (1 << dr))) {
|
|
drive_step(floppy[dr], direction);
|
|
if (floppy[dr].indexhackmode > 1 && (data & 0x80))
|
|
floppy[dr].indexhack = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//if (!savestate_state)
|
|
{
|
|
if (velvet) {
|
|
for (dr = 0; dr < 2; dr++) {
|
|
var drv = floppy[dr];
|
|
var motormask = 0x20 << dr;
|
|
var selectmask = 0x08 << dr;
|
|
if (!(selected & (1 << dr)) && !(disabled & (1 << dr))) {
|
|
if (!(prev_data & motormask) && (data & motormask)) {
|
|
drive_motor(drv, 1);
|
|
} else if ((prev_data & motormask) && !(data & motormask)) {
|
|
drive_motor(drv, 0);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
/* motor on/off workings tested with small assembler code on real Amiga 1200. */
|
|
/* motor/id flipflop is set only when drive select goes from high to low */
|
|
if (!((selected | disabled) & (1 << dr)) && (prev_selected & (1 << dr)) ) {
|
|
drv.drive_id_scnt++;
|
|
drv.drive_id_scnt &= 31;
|
|
drv.idbit = (drv.drive_id & (1 << (31 - drv.drive_id_scnt))) ? 1 : 0;
|
|
if (!(disabled & (1 << dr))) {
|
|
if ((prev_data & 0x80) == 0 || (data & 0x80) == 0) {
|
|
/* motor off: if motor bit = 0 in prevdata or data . turn motor on */
|
|
drive_motor(drv, 0);
|
|
} else if (prev_data & 0x80) {
|
|
/* motor on: if motor bit = 1 in prevdata only (motor flag state in data has no effect). turn motor off */
|
|
drive_motor(drv, 1);
|
|
}
|
|
}
|
|
if (!SAEV_config.chipset.df0idhw && dr == 0)
|
|
drv.idbit = 0;
|
|
|
|
if (DEBUG_DRIVE_ID) SAEF_log("disk.select() sel %d id %s ($%08X) [$%08x, bit #%02d: %d]", dr, drive_id_name(drv), drv.drive_id, drv.drive_id << drv.drive_id_scnt >>> 0, 31 - drv.drive_id_scnt, drv.idbit);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
floppy[dr].state = (!(selected & (1 << dr))) | !floppy[dr].motoroff;
|
|
update_drive_gui(dr, false);
|
|
}
|
|
prev_data = data;
|
|
//if (disk_debug_logging > 2) SAEF_log("\n");
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
this.status_ciaa = function() { //DISK_status_ciaa()
|
|
var st = 0x3c;
|
|
|
|
if (SAEV_config.chipset.compatible == SAEC_Config_Chipset_Compatible_A1000V) {
|
|
for (var dr = 0; dr < 2; dr++) {
|
|
var drv = floppy[dr];
|
|
if (!(((selected >> 3) | disabled) & (1 << dr))) {
|
|
if (drv.dskchange)
|
|
st &= ~0x20;
|
|
if (drive_track0(drv))
|
|
st &= ~0x10;
|
|
}
|
|
}
|
|
if (disk_debug_logging > 2) SAEF_log("disk.status_ciaa() pc $%08x, status $%02x", SAER_CPU_getPC(), st);
|
|
return st;
|
|
}
|
|
|
|
for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
if (drv.amax) {
|
|
if (amax_active())
|
|
st = amax_disk_status(st);
|
|
} else if (!((selected | disabled) & (1 << dr))) {
|
|
if (drive_running(drv)) {
|
|
if (drv.dskready && !drv.indexhack && SAEV_config.floppy.drive[dr].type != SAEC_Config_Floppy_Type_35_DD_ESCOM)
|
|
st &= ~0x20;
|
|
} else {
|
|
if (SAEV_config.chipset.df0idhw || dr > 0) {
|
|
/* report drive ID */
|
|
if (drv.idbit && SAEV_config.floppy.drive[dr].type != SAEC_Config_Floppy_Type_35_DD_ESCOM)
|
|
st &= ~0x20;
|
|
} else {
|
|
/* non-ID internal drive: mirror real dskready */
|
|
if (drv.dskready)
|
|
st &= ~0x20;
|
|
}
|
|
/* dskrdy needs some cycles after switching the motor off.. (Pro Tennis Tour) */
|
|
if (!SAEV_config.chipset.df0idhw && dr == 0 && drv.motordelay)
|
|
st &= ~0x20;
|
|
}
|
|
if (drive_track0(drv))
|
|
st &= ~0x10;
|
|
if (drive_writeprotected(drv))
|
|
st &= ~8;
|
|
if (drv.dskchange && SAEV_config.floppy.drive[dr].type != SAEC_Config_Floppy_Type_525_SD)
|
|
st &= ~4;
|
|
} else if (!((selected | disabled) & (1 << dr))) {
|
|
if (drv.idbit)
|
|
st &= ~0x20;
|
|
}
|
|
}
|
|
return st;
|
|
}
|
|
|
|
this.status_ciab = function(st) { //DISK_status_ciab()
|
|
if (SAEV_config.chipset.compatible == SAEC_Config_Chipset_Compatible_A1000V) {
|
|
st |= 0x80;
|
|
for (var dr = 0; dr < 2; dr++) {
|
|
var drv = floppy[dr];
|
|
if (!(((selected >> 3) | disabled) & (1 << dr))) {
|
|
if (drive_writeprotected(drv))
|
|
st &= ~0x80;
|
|
}
|
|
}
|
|
if (disk_debug_logging > 2) SAEF_log("disk.status_ciab() pc $%08x, status $%02x", SAER_CPU_getPC(), st);
|
|
}
|
|
return st;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
function unformatted(drv) {
|
|
var tr = drv.cyl * 2 + side;
|
|
if (tr >= drv.num_tracks)
|
|
return true;
|
|
if (drv.filetype == ADF_EXT2 && drv.trackdata[tr].bitlen == 0 && drv.trackdata[tr].type != TRACK_AMIGADOS)
|
|
return true;
|
|
if (drv.trackdata[tr].type == TRACK_NONE)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/* get one bit from MFM bit stream */
|
|
/*STATIC_INLINE uae_u32 getonebit (uae_u16 * mfmbuf, int mfmpos) {
|
|
uae_u16 *buf = &mfmbuf[mfmpos >> 4];
|
|
return (buf[0] & (1 << (15 - (mfmpos & 15)))) ? 1 : 0;
|
|
}*/
|
|
function getonebit(mfmbuf, mfmpos) {
|
|
return (mfmbuf[mfmpos >> 4] & (1 << (15 - (mfmpos & 15)))) ? 1 : 0;
|
|
}
|
|
|
|
function dumpdisk(name) {
|
|
/*var i, j, k, w;
|
|
|
|
for (i = 0; i < MAX_FLOPPY_DRIVES; i++) {
|
|
drive *drv = &floppy[i];
|
|
if (!(disabled & (1 << i))) {
|
|
console_out_f (_T("%s: drive %d motor %s cylinder %2d sel %s %s mfmpos %d/%d\n"),
|
|
name, i, drv->motoroff ? _T("off") : _T(" on"), drv->cyl, (selected & (1 << i)) ? _T("no") : _T("yes"),
|
|
drive_writeprotected(drv) ? _T("ro") : _T("rw"), drv->mfmpos, drv->tracklen);
|
|
if (drv->motoroff == 0) {
|
|
w = 0;
|
|
for (j = -4; j < 13; j++) {
|
|
for (k = 0; k < 16; k++) {
|
|
int pos = drv->mfmpos + j * 16 + k;
|
|
if (pos < 0)
|
|
pos += drv->tracklen;
|
|
w <<= 1;
|
|
w |= getonebit(drv->bigmfmbuf, pos);
|
|
}
|
|
console_out_f(_T("%04X%c"), w, j == -1 ? '|' : ' ');
|
|
}
|
|
console_out (_T("\n"));
|
|
}
|
|
}
|
|
}
|
|
console_out_f (_T("side %d dma %d off %d word %04X pt %08X len %04X bytr %04X adk %04X sync %04X\n"),
|
|
side, dskdmaen, bitoffset, word, dskpt, dsklen, dskbytr_val, SAEV_Custom_adkcon, dsksync);*/
|
|
SAEF_log("disk.dumpdisk() %s", name);
|
|
}
|
|
|
|
function disk_dmafinished() {
|
|
SAER.custom.INTREQ(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_DSKBLK);
|
|
longwritemode = 0;
|
|
dskdmaen = DSKDMA_OFF;
|
|
dsklength = 0;
|
|
dsklen = 0;
|
|
/*if (disk_debug_logging > 0) {
|
|
write_log (_T("disk dma finished %08X MFMpos="), dskpt);
|
|
for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++)
|
|
write_log (_T("%d%s"), floppy[dr].mfmpos, dr < MAX_FLOPPY_DRIVES - 1 ? _T(",") : _T(""));
|
|
write_log (_T("\n"));
|
|
}*/
|
|
}
|
|
|
|
function fetchnextrevolution(drv) {
|
|
if (drv.revolution_check)
|
|
return;
|
|
drv.trackspeed = get_floppy_speed2(drv);
|
|
if (REVOLUTION_DEBUG && (1 || drv.mfmpos != 0)) SAEF_log("disk.fetchnextrevolution() DMA=%d %d %d/%d %d %d %d", dskdmaen, drv.trackspeed, drv.mfmpos, drv.tracklen, drv.indexoffset, drv.floppybitcounter);
|
|
drv.revolution_check = 2;
|
|
if (!drv.multi_revolution)
|
|
return;
|
|
switch (drv.filetype) {
|
|
case ADF_SCP:
|
|
scp_loadrevolution(drv.bigmfmbuf, drv.num, drv.tracktiming); //, &drv.tracklen);
|
|
break;
|
|
/*case ADF_FDI:
|
|
fdi2raw_loadrevolution(drv.fdi, drv.bigmfmbuf, drv.tracktiming, drv.cyl * 2 + side, &drv.tracklen, 1);
|
|
break;*/
|
|
}
|
|
}
|
|
|
|
function do_disk_index() {
|
|
if (REVOLUTION_DEBUG) SAEF_log("disk.do_disk_index() %d", indexdecay);
|
|
if (!indexdecay) {
|
|
indexdecay = 2;
|
|
SAER.cia.diskindex();
|
|
}
|
|
}
|
|
|
|
this.handler = function(data) { //DISK_handler()
|
|
var flag = data & 255;
|
|
var disk_sync_cycle = data >>> 8;
|
|
var hpos = SAER.events.current_hpos();
|
|
|
|
SAER.events.event2_remevent(SAEC_Events_EV2_DISK);
|
|
this.update(disk_sync_cycle);
|
|
if (!dskdmaen) {
|
|
if (flag & (DISK_REVOLUTION << 0)) fetchnextrevolution(floppy[0]);
|
|
if (flag & (DISK_REVOLUTION << 1)) fetchnextrevolution(floppy[1]);
|
|
if (flag & (DISK_REVOLUTION << 2)) fetchnextrevolution(floppy[2]);
|
|
if (flag & (DISK_REVOLUTION << 3)) fetchnextrevolution(floppy[3]);
|
|
}
|
|
if (flag & DISK_WORDSYNC)
|
|
SAER.custom.INTREQ(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_DSKSYN);
|
|
if (flag & DISK_INDEXSYNC)
|
|
do_disk_index();
|
|
}
|
|
|
|
function disk_doupdate_write(drv, floppybits) {
|
|
var dr, drives = [0,0,0,0];
|
|
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv2 = floppy[dr];
|
|
drives[dr] = 0;
|
|
if (drv2.motoroff)
|
|
continue;
|
|
if ((selected | disabled) & (1 << dr))
|
|
continue;
|
|
drives[dr] = 1;
|
|
}
|
|
|
|
while (floppybits >= drv.trackspeed) {
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
if (drives[dr]) {
|
|
floppy[dr].mfmpos++;
|
|
floppy[dr].mfmpos %= drv.tracklen;
|
|
}
|
|
}
|
|
if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_DSKEN) && dskdmaen == DSKDMA_WRITE && dsklength > 0 && fifo_filled) {
|
|
bitoffset++;
|
|
bitoffset &= 15;
|
|
if (!bitoffset) {
|
|
// fast disk modes, fill the fifo instantly
|
|
if (SAEV_config.floppy.speed > 100 && !fifo_inuse[0] && !fifo_inuse[1] && !fifo_inuse[2]) {
|
|
while (!fifo_inuse[2]) {
|
|
var w = SAER_Memory_chipGet16_indirect(dskpt);
|
|
SAER.disk.DSKDAT(w);
|
|
dskpt += 2;
|
|
}
|
|
}
|
|
if (SAER.disk.fifostatus() >= 0) {
|
|
var w = SAER.disk.DSKDATR();
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES ; dr++) {
|
|
var drv2 = floppy[dr];
|
|
if (drives[dr]) {
|
|
drv2.bigmfmbuf[drv2.mfmpos >> 4] = w;
|
|
drv2.bigmfmbuf[(drv2.mfmpos >> 4) + 1] = 0x5555;
|
|
drv2.writtento = 1;
|
|
}
|
|
if (amax_enabled)
|
|
amax_diskwrite(w);
|
|
}
|
|
dsklength--;
|
|
if (dsklength <= 0) {
|
|
disk_dmafinished();
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES ; dr++) {
|
|
var drv = floppy[dr];
|
|
drv.writtento = 0;
|
|
if (drv.motoroff)
|
|
continue;
|
|
if ((selected | disabled) & (1 << dr))
|
|
continue;
|
|
drive_write_data(drv);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
floppybits -= drv.trackspeed;
|
|
}
|
|
}
|
|
|
|
function update_jitter() {
|
|
if (SAEV_config.floppy.randomBitsMax > 0)
|
|
disk_jitter = ((Math.decimalRandom() >>> 4) % (SAEV_config.floppy.randomBitsMax - SAEV_config.floppy.randomBitsMin + 1)) + SAEV_config.floppy.randomBitsMin;
|
|
else
|
|
disk_jitter = 0;
|
|
}
|
|
|
|
function updatetrackspeed(drv, mfmpos) {
|
|
if (dskdmaen < DSKDMA_WRITE) {
|
|
var t = drv.tracktiming[mfmpos >> 3]; //ORG mfmpos / 8
|
|
var ts = Math.floor(get_floppy_speed2(drv) * t / 1000);
|
|
if (ts < 700 || ts > 3000) {
|
|
if (++warned_trackspeed < 50)
|
|
SAEF_warn("disk.updatetrackspeed() corrupted trackspeed value %d %d (%d/%d)", t, ts, mfmpos, drv.tracklen);
|
|
} else
|
|
drv.trackspeed = ts;
|
|
}
|
|
}
|
|
|
|
function disk_doupdate_predict(startcycle) {
|
|
var finaleventcycle = SAER.playfield.get_maxhpos() << 8;
|
|
var finaleventflag = 0;
|
|
var noselected = true;
|
|
|
|
for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
if (drv.motoroff)
|
|
continue;
|
|
if (!drv.trackspeed)
|
|
continue;
|
|
if ((selected | disabled) & (1 << dr))
|
|
continue;
|
|
var mfmpos = drv.mfmpos;
|
|
if (drv.tracktiming[0])
|
|
updatetrackspeed(drv, mfmpos);
|
|
var diskevent_flag = 0;
|
|
var tword = word; //u32
|
|
noselected = false;
|
|
//int diff = drv.floppybitcounter % drv.trackspeed; ORG
|
|
var countcycle = startcycle; // + (diff ? drv.trackspeed - diff : 0); ORG
|
|
while (countcycle < (SAER.playfield.get_maxhpos() << 8)) {
|
|
if (drv.tracktiming[0])
|
|
updatetrackspeed(drv, mfmpos);
|
|
countcycle += drv.trackspeed;
|
|
if (dskdmaen != DSKDMA_WRITE || (dskdmaen == DSKDMA_WRITE && !dma_enable)) {
|
|
tword = (tword << 1) >>> 0;
|
|
if (!drive_empty(drv)) {
|
|
if (unformatted(drv))
|
|
tword = (tword | ((Math.decimalRandom() & 0x1000) ? 1 : 0)) >>> 0;
|
|
else
|
|
tword = (tword | getonebit(drv.bigmfmbuf, mfmpos)) >>> 0;
|
|
}
|
|
if (dskdmaen != DSKDMA_READ && (tword & 0xffff) == dsksync && dsksync != 0)
|
|
diskevent_flag |= DISK_WORDSYNC;
|
|
}
|
|
mfmpos++;
|
|
mfmpos %= drv.tracklen;
|
|
if (!dskdmaen) {
|
|
if (mfmpos == 0)
|
|
diskevent_flag |= DISK_REVOLUTION << drv.num;
|
|
if (mfmpos == drv.indexoffset)
|
|
diskevent_flag |= DISK_INDEXSYNC;
|
|
}
|
|
if (dskdmaen != DSKDMA_WRITE && mfmpos == drv.skipoffset) {
|
|
update_jitter();
|
|
var skipcnt = disk_jitter;
|
|
while (skipcnt-- > 0) {
|
|
mfmpos++;
|
|
mfmpos %= drv.tracklen;
|
|
if (!dskdmaen) {
|
|
if (mfmpos == 0)
|
|
diskevent_flag |= DISK_REVOLUTION << drv.num;
|
|
if (mfmpos == drv.indexoffset)
|
|
diskevent_flag |= DISK_INDEXSYNC;
|
|
}
|
|
}
|
|
}
|
|
if (diskevent_flag)
|
|
break;
|
|
}
|
|
if (drv.tracktiming[0])
|
|
updatetrackspeed(drv, drv.mfmpos);
|
|
if (diskevent_flag && countcycle < finaleventcycle) {
|
|
finaleventcycle = countcycle;
|
|
finaleventflag = diskevent_flag;
|
|
}
|
|
}
|
|
if (finaleventflag && (finaleventcycle >> 8) < SAER.playfield.get_maxhpos())
|
|
SAER.events.event2_newevent(SAEC_Events_EV2_DISK, (finaleventcycle - startcycle) >> 8, ((finaleventcycle >> 8) << 8) | finaleventflag);
|
|
}
|
|
|
|
this.fifostatus = function() { //disk_fifostatus()
|
|
if (fifo_inuse[0] && fifo_inuse[1] && fifo_inuse[2])
|
|
return 1;
|
|
if (!fifo_inuse[0] && !fifo_inuse[1] && !fifo_inuse[2])
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
function doreaddma() {
|
|
if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_DSKEN) && bitoffset == 15 && dma_enable && dskdmaen == DSKDMA_READ && dsklength >= 0) {
|
|
if (dsklength > 0) {
|
|
// DSKLEN == 1: finish without DMA transfer.
|
|
if (dsklength == 1 && dsklength2 == 1) {
|
|
disk_dmafinished();
|
|
return 0;
|
|
}
|
|
// fast disk modes, just flush the fifo
|
|
if (SAEV_config.floppy.speed > 100 && fifo_inuse[0] && fifo_inuse[1] && fifo_inuse[2]) {
|
|
while (fifo_inuse[0]) {
|
|
var w = SAER.disk.DSKDATR();
|
|
SAER_Memory_chipPut16_indirect(dskpt, w);
|
|
dskpt += 2;
|
|
}
|
|
}
|
|
if (SAER.disk.fifostatus() > 0) {
|
|
SAEF_warn("disk.doreaddma() fifo overflow detected, retrying...");
|
|
return -1;
|
|
} else {
|
|
SAER.disk.DSKDAT(word);
|
|
dsklength--;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
function disk_doupdate_read_nothing(floppybits) {
|
|
while (floppybits >= get_floppy_speed()) {
|
|
word <<= 1;
|
|
word &= 0xffff; //OWN
|
|
doreaddma();
|
|
if ((bitoffset & 7) == 7) {
|
|
dskbytr_val = word & 0xff;
|
|
dskbytr_val |= 0x8000;
|
|
}
|
|
bitoffset++;
|
|
bitoffset &= 15;
|
|
floppybits -= get_floppy_speed();
|
|
}
|
|
}
|
|
|
|
function wordsync_detected(startup) {
|
|
dsksync_cycles = SAEV_Events_currcycle + WORDSYNC_TIME * SAEC_Events_CYCLE_UNIT;
|
|
if (dskdmaen != DSKDMA_OFF) {
|
|
/*if (disk_debug_logging && dma_enable == 0) {
|
|
int pos = -1;
|
|
for (int i = 0; i < MAX_FLOPPY_DRIVES; i++) {
|
|
drive *drv = &floppy[i];
|
|
if (!(disabled & (1 << i)) && !drv->motoroff) {
|
|
pos = drv->mfmpos;
|
|
break;
|
|
}
|
|
}
|
|
write_log(_T("Sync match %04x mfmpos %d enable %d wordsync %d\n"), dsksync, pos, dma_enable, (SAEV_Custom_adkcon & 0x0400) != 0);
|
|
if (disk_debug_logging > 1)
|
|
dumpdisk(_T("SYNC"));
|
|
}*/
|
|
if (!startup)
|
|
dma_enable = 1;
|
|
|
|
SAER.custom.INTREQ(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_DSKSYN);
|
|
}
|
|
if (SAEV_Custom_adkcon & 0x0400)
|
|
bitoffset = 15;
|
|
}
|
|
function disk_doupdate_read(drv, floppybits) {
|
|
/* ORG
|
|
uae_u16 *mfmbuf = drv.bigmfmbuf;
|
|
dsksync = 0x4444;
|
|
SAEV_Custom_adkcon |= 0x400;
|
|
drv.mfmpos = 0;
|
|
memset (mfmbuf, 0, 1000);
|
|
cycles = 0x1000000;
|
|
// 4444 4444 4444 aaaa aaaaa 4444 4444 4444
|
|
// 4444 aaaa aaaa 4444
|
|
mfmbuf[0] = 0x4444;
|
|
mfmbuf[1] = 0x4444;
|
|
mfmbuf[2] = 0x4444;
|
|
mfmbuf[3] = 0xaaaa;
|
|
mfmbuf[4] = 0xaaaa;
|
|
mfmbuf[5] = 0x4444;
|
|
mfmbuf[6] = 0x4444;
|
|
mfmbuf[7] = 0x4444;
|
|
*/
|
|
while (floppybits >= drv.trackspeed) {
|
|
if (drv.tracktiming[0])
|
|
updatetrackspeed(drv, drv.mfmpos);
|
|
word <<= 1;
|
|
word &= 0xffff; //OWN
|
|
|
|
if (!drive_empty(drv)) {
|
|
if (unformatted(drv))
|
|
word |= (Math.decimalRandom() & 0x1000) ? 1 : 0;
|
|
else
|
|
word |= getonebit(drv.bigmfmbuf, drv.mfmpos);
|
|
}
|
|
if (doreaddma() < 0) {
|
|
word >>= 1;
|
|
return;
|
|
}
|
|
drv.mfmpos++;
|
|
drv.mfmpos %= drv.tracklen;
|
|
if (drv.mfmpos == drv.indexoffset) {
|
|
if (disk_debug_logging > 2 && drv.indexhack) SAEF_log("disk.disk_doupdate_read() indexhack cleared");
|
|
drv.indexhack = false;
|
|
do_disk_index();
|
|
}
|
|
if (drv.mfmpos == 0) {
|
|
fetchnextrevolution(drv);
|
|
if (drv.tracktiming[0])
|
|
updatetrackspeed(drv, drv.mfmpos);
|
|
}
|
|
if (drv.mfmpos == drv.skipoffset) {
|
|
update_jitter();
|
|
var skipcnt = disk_jitter;
|
|
while (skipcnt-- > 0) {
|
|
drv.mfmpos++;
|
|
drv.mfmpos %= drv.tracklen;
|
|
if (drv.mfmpos == drv.indexoffset) {
|
|
if (disk_debug_logging > 2 && drv.indexhack) SAEF_log("disk.disk_doupdate_read() indexhack cleared");
|
|
drv.indexhack = false;
|
|
do_disk_index();
|
|
}
|
|
if (drv.mfmpos == 0) {
|
|
fetchnextrevolution(drv);
|
|
if (drv.tracktiming[0])
|
|
updatetrackspeed(drv, drv.mfmpos);
|
|
}
|
|
}
|
|
}
|
|
if ((bitoffset & 7) == 7) {
|
|
dskbytr_val = word & 0xff;
|
|
dskbytr_val |= 0x8000;
|
|
}
|
|
if (word == dsksync)
|
|
wordsync_detected(false);
|
|
bitoffset++;
|
|
bitoffset &= 15;
|
|
floppybits -= drv.trackspeed;
|
|
}
|
|
}
|
|
|
|
/*function disk_dma_debugmsg() {
|
|
SAEF_log("LEN=%04X (%d) SYNC=%04X PT=%08X ADKCON=%04X INTREQ=%04X PC=%08X", dsklength, dsklength, (SAEV_Custom_adkcon & 0x400) ? dsksync : 0xffff, dskpt, SAEV_Custom_adkcon, SAEV_Custom_intreq, SAER_CPU_getPC());
|
|
}*/
|
|
/* this is very unoptimized. DSKBYTR is used very rarely, so it should not matter. */
|
|
this.DSKBYTR = function(hpos) {
|
|
this.update(hpos);
|
|
var v = dskbytr_val;
|
|
dskbytr_val &= 0x7fff; //ATT ORG ~0x8000;
|
|
//if (word == dsksync && cycles_in_range(dsksync_cycles)) {
|
|
if (word == dsksync && dsksync_cycles - SAEV_Events_currcycle > 0) {
|
|
v |= 0x1000;
|
|
if (disk_debug_logging > 1) dumpdisk("disk.DSKBYTR() SYNC");
|
|
}
|
|
if (dskdmaen != DSKDMA_OFF && SAEF_Custom_dmaen(SAEC_Custom_DMAF_DSKEN))
|
|
v |= 0x4000;
|
|
if (dsklen & 0x4000)
|
|
v |= 0x2000;
|
|
if (disk_debug_logging > 2) SAEF_log("disk.DSKBYTR() $%04X, hpos %d", v, hpos);
|
|
|
|
for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
if (drv.motoroff)
|
|
continue;
|
|
if (!((selected | disabled) & (1 << dr))) {
|
|
drv.lastdataacesstrack = drv.cyl * 2 + side;
|
|
if (REVOLUTION_DEBUG && !drv.track_access_done) SAEF_log("disk.DSKBYTR()");
|
|
drv.track_access_done = true;
|
|
/*if (disk_debug_mode & DISK_DEBUG_PIO) {
|
|
if (disk_debug_track < 0 || disk_debug_track == 2 * drv.cyl + side) {
|
|
//disk_dma_debugmsg();
|
|
SAEF_log("disk.DSKBYTR () $%04X", v);
|
|
//activate_debugger();
|
|
break;
|
|
}
|
|
}*/
|
|
}
|
|
}
|
|
return v;
|
|
}
|
|
|
|
function DISK_start() {
|
|
if (disk_debug_logging > 1) dumpdisk("DSKLEN");
|
|
|
|
for (var i = 0; i < 3; i++) fifo_inuse[i] = false;
|
|
fifo_filled = 0;
|
|
|
|
for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
if (!((selected | disabled) & (1 << dr))) {
|
|
var tr = drv.cyl * 2 + side;
|
|
var ti = drv.trackdata[tr];
|
|
|
|
if (dskdmaen == DSKDMA_WRITE) {
|
|
word = 0;
|
|
drv.tracklen = longwritemode ? FLOPPY_WRITE_MAXLEN : FLOPPY_WRITE_LEN() * drv.ddhd * 8 * 2;
|
|
drv.trackspeed = get_floppy_speed();
|
|
drv.skipoffset = -1;
|
|
updatemfmpos(drv);
|
|
}
|
|
/* Ugh. A nasty hack. Assume ADF_EXT1 tracks are always read from the start. */
|
|
if (ti.type == TRACK_RAW1) {
|
|
drv.mfmpos = 0;
|
|
bitoffset = 0;
|
|
word = 0;
|
|
}
|
|
}
|
|
drv.floppybitcounter = 0;
|
|
}
|
|
|
|
dma_enable = (SAEV_Custom_adkcon & 0x400) ? 0 : 1;
|
|
if (word == dsksync)
|
|
wordsync_detected(true);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
this.hsync = function() { //DISK_hsync()
|
|
for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
if (drv.steplimit)
|
|
drv.steplimit--;
|
|
if (drv.revolution_check)
|
|
drv.revolution_check--;
|
|
|
|
if (drv.dskready_down_time > 0)
|
|
drv.dskready_down_time--;
|
|
/* emulate drive motor turn on time */
|
|
if (drv.dskready_up_time > 0 && !drive_empty(drv)) {
|
|
drv.dskready_up_time--;
|
|
if (drv.dskready_up_time == 0 && !drv.motoroff)
|
|
drv.dskready = true;
|
|
}
|
|
/* delay until new disk image is inserted */
|
|
if (drv.dskchange_time > 0) {
|
|
drv.dskchange_time--;
|
|
if (drv.dskchange_time == 0) {
|
|
drive_insert(drv, SAEV_config, dr, drv.newfile, false);
|
|
if (disk_debug_logging > 0) SAEF_log("disk.hsync() delayed insert, drive %d, image '%s', size %d", dr, drv.newfile.name, drv.newfile.size);
|
|
update_drive_gui(dr, false);
|
|
}
|
|
}
|
|
}
|
|
if (indexdecay)
|
|
indexdecay--;
|
|
if (linecounter) {
|
|
linecounter--;
|
|
if (!linecounter)
|
|
disk_dmafinished();
|
|
return;
|
|
}
|
|
this.update(SAER.playfield.get_maxhpos());
|
|
|
|
// show insert disk in df0: when booting
|
|
if (initial_disk_statusline) {
|
|
initial_disk_statusline = false;
|
|
update_disk_statusline(0);
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
this.update = function(tohpos) { //DISK_update()
|
|
var dr, cycles;
|
|
|
|
if (disk_hpos < 0) {
|
|
disk_hpos = -disk_hpos;
|
|
return;
|
|
}
|
|
|
|
cycles = (tohpos << 8) - disk_hpos;
|
|
/*#if 0
|
|
if (tohpos == 228) write_log (_T("x"));
|
|
if (tohpos != SAER.playfield.get_maxhpos() || cycles / 256 != SAER.playfield.get_maxhpos()) write_log (_T("%d %d %d\n"), tohpos, cycles / 256, disk_hpos / 256);
|
|
#endif*/
|
|
if (cycles <= 0)
|
|
return;
|
|
disk_hpos += cycles;
|
|
if (disk_hpos >= (SAER.playfield.get_maxhpos() << 8))
|
|
disk_hpos %= 1 << 8;
|
|
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
|
|
if (drv.motoroff || !drv.tracklen || !drv.trackspeed)
|
|
continue;
|
|
drv.floppybitcounter += cycles;
|
|
if ((selected | disabled) & (1 << dr)) {
|
|
drv.mfmpos += Math.floor(drv.floppybitcounter / drv.trackspeed);
|
|
drv.mfmpos %= drv.tracklen;
|
|
drv.floppybitcounter %= drv.trackspeed;
|
|
continue;
|
|
}
|
|
if (drv.diskfile)
|
|
drive_fill_bigbuf(drv, false);
|
|
drv.mfmpos %= drv.tracklen;
|
|
}
|
|
var didaccess = false;
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
if (drv.motoroff || !drv.trackspeed)
|
|
continue;
|
|
if ((selected | disabled) & (1 << dr))
|
|
continue;
|
|
/* write dma and wordsync enabled: read until wordsync match found */
|
|
if (dskdmaen == DSKDMA_WRITE && dma_enable)
|
|
disk_doupdate_write(drv, drv.floppybitcounter);
|
|
else
|
|
disk_doupdate_read(drv, drv.floppybitcounter);
|
|
|
|
drv.floppybitcounter %= drv.trackspeed;
|
|
didaccess = true;
|
|
}
|
|
/* no floppy selected but read dma */
|
|
if (!didaccess && dskdmaen == DSKDMA_READ)
|
|
disk_doupdate_read_nothing (cycles);
|
|
|
|
/* instantly finish dma if dsklen==0 and wordsync detected */
|
|
if (dskdmaen != DSKDMA_OFF && dma_enable && dsklength2 == 0 && dsklength == 0)
|
|
disk_dmafinished();
|
|
|
|
disk_doupdate_predict(disk_hpos);
|
|
}
|
|
|
|
this.update_adkcon = function(hpos, v) { //DISK_update_adkcon()
|
|
var vold = SAEV_Custom_adkcon;
|
|
var vnew = SAEV_Custom_adkcon;
|
|
if (v & 0x8000)
|
|
vnew |= v & 0x7FFF;
|
|
else
|
|
vnew &= ~v;
|
|
if ((vnew & 0x400) && !(vold & 0x400))
|
|
bitoffset = 0;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
this.DSKLEN = function(v, hpos) {
|
|
var dr, prev = dsklen;
|
|
var noselected = 0;
|
|
var motormask;
|
|
|
|
this.update(hpos);
|
|
|
|
dsklen = v;
|
|
dsklength2 = dsklength = dsklen & 0x3fff;
|
|
|
|
if ((v & 0x8000) && (prev & 0x8000)) {
|
|
if (dskdmaen == DSKDMA_READ) {
|
|
// update only currently active DMA length, don't change DMA state
|
|
SAEF_warn("disk.DSKLEN() read DMA length rewrite %d -> %d ($%04x), PC=$%x", prev & 0x3fff, v & 0x3fff, v, SAER_CPU_getPC());
|
|
return;
|
|
}
|
|
dskdmaen = DSKDMA_READ;
|
|
DISK_start();
|
|
}
|
|
if (!(v & 0x8000)) {
|
|
if (dskdmaen != DSKDMA_OFF) {
|
|
/* Megalomania and Knightmare does this */
|
|
if (disk_debug_logging > 0 && dskdmaen == DSKDMA_READ)
|
|
SAEF_warn("disk.DSKLEN() read DMA aborted, %d words left, PC=$%x", dsklength, SAER_CPU_getPC());
|
|
if (dskdmaen == DSKDMA_WRITE) {
|
|
SAEF_warn("disk.DSKLEN() write DMA aborted, %d words left, PC=$%x", dsklength, SAER_CPU_getPC());
|
|
// did program write something that needs to be stored to file?
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv2 = floppy[dr];
|
|
if (!drv2.writtento)
|
|
continue;
|
|
drive_write_data(drv2);
|
|
}
|
|
}
|
|
dskdmaen = DSKDMA_OFF;
|
|
}
|
|
}
|
|
|
|
if (dskdmaen == DSKDMA_OFF)
|
|
return;
|
|
|
|
if (dsklength == 0 && dma_enable) {
|
|
disk_dmafinished();
|
|
return;
|
|
}
|
|
|
|
if ((v & 0x4000) && (prev & 0x4000)) {
|
|
if (dsklength == 0)
|
|
return;
|
|
if (dsklength == 1) {
|
|
disk_dmafinished();
|
|
return;
|
|
}
|
|
if (dskdmaen == DSKDMA_WRITE) {
|
|
SAEF_warn("disk.DSKLEN() write DMA length rewrite %d -> %d, PC=$%x", prev & 0x3fff, v & 0x3fff, SAER_CPU_getPC());
|
|
return;
|
|
}
|
|
dskdmaen = DSKDMA_WRITE;
|
|
DISK_start();
|
|
}
|
|
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
if (drv.motoroff)
|
|
continue;
|
|
if (selected & (1 << dr))
|
|
continue;
|
|
if (dskdmaen == DSKDMA_READ) {
|
|
drv.lastdataacesstrack = drv.cyl * 2 + side;
|
|
drv.track_access_done = true;
|
|
if (REVOLUTION_DEBUG) SAEF_log("disk.DSKLEN() DMA");
|
|
}
|
|
}
|
|
|
|
/*if (((disk_debug_mode & DISK_DEBUG_DMA_READ) && dskdmaen == DSKDMA_READ) ||
|
|
((disk_debug_mode & DISK_DEBUG_DMA_WRITE) && dskdmaen == DSKDMA_WRITE))
|
|
{
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
if (drv.motoroff)
|
|
continue;
|
|
if (!(selected & (1 << dr))) {
|
|
if (disk_debug_track < 0 || disk_debug_track == 2 * drv.cyl + side) {
|
|
//disk_dma_debugmsg();
|
|
//activate_debugger ();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}*/
|
|
|
|
motormask = 0;
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
drv.writtento = 0;
|
|
if (drv.motoroff)
|
|
continue;
|
|
motormask |= 1 << dr;
|
|
if ((selected & (1 << dr)) == 0)
|
|
break;
|
|
}
|
|
if (dr == 4) {
|
|
if (!amax_enabled)
|
|
SAEF_log("disk.DSKLEN() %s DMA started, drvmask=$%x motormask=$%x PC=$%08x", dskdmaen == DSKDMA_WRITE ? "write" : "read", selected ^ 15, motormask, SAER_CPU_getPC());
|
|
noselected = 1;
|
|
} else {
|
|
if (disk_debug_logging > 0) {
|
|
SAEF_log("disk.DSKLEN() %s DMA started, drvmask=%x track %d mfmpos %d dmaen=%d PC=$%08X", dskdmaen == DSKDMA_WRITE ? "write" : "read", selected ^ 15, floppy[dr].cyl * 2 + side, floppy[dr].mfmpos, dma_enable, SAER_CPU_getPC());
|
|
//disk_dma_debugmsg();
|
|
}
|
|
}
|
|
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++)
|
|
update_drive_gui(dr, false);
|
|
|
|
/* Try to make floppy access from Kickstart faster. */
|
|
if (dskdmaen != DSKDMA_READ && dskdmaen != DSKDMA_WRITE)
|
|
return;
|
|
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
if (selected & (1 << dr))
|
|
continue;
|
|
if (drv.filetype != ADF_NORMAL && drv.filetype != ADF_KICK && drv.filetype != ADF_SKICK)
|
|
break;
|
|
}
|
|
if (dr < MAX_FLOPPY_DRIVES) /* no turbo mode if any selected drive has non-standard ADF */
|
|
return;
|
|
{
|
|
var done = 0;
|
|
for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var i, drv = floppy[dr];
|
|
|
|
if (drv.motoroff)
|
|
continue;
|
|
if (!drv.useturbo && SAEV_config.floppy.speed > 0)
|
|
continue;
|
|
if (selected & (1 << dr))
|
|
continue;
|
|
|
|
var pos = drv.mfmpos & ~15;
|
|
drive_fill_bigbuf(drv, false);
|
|
|
|
if (dskdmaen == DSKDMA_READ) { /* TURBO read */
|
|
if (SAEV_Custom_adkcon & 0x400) {
|
|
for (i = 0; i < drv.tracklen; i += 16) {
|
|
pos += 16;
|
|
pos %= drv.tracklen;
|
|
if (drv.bigmfmbuf[pos >> 4] == dsksync) {
|
|
/* must skip first disk sync marker */
|
|
pos += 16;
|
|
pos %= drv.tracklen;
|
|
break;
|
|
}
|
|
}
|
|
if (i >= drv.tracklen)
|
|
return;
|
|
}
|
|
while (dsklength-- > 0) {
|
|
SAER_Memory_chipPut16_indirect(dskpt, drv.bigmfmbuf[pos >> 4]);
|
|
dskpt += 2;
|
|
pos += 16;
|
|
pos %= drv.tracklen;
|
|
}
|
|
drv.mfmpos = pos;
|
|
SAER.custom.INTREQ(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_DSKSYN);
|
|
done = 2;
|
|
} else if (dskdmaen == DSKDMA_WRITE) { /* TURBO write */
|
|
for (i = 0; i < dsklength; i++) {
|
|
var w = SAER_Memory_chipGet16_indirect(dskpt + i * 2);
|
|
drv.bigmfmbuf[pos >> 4] = w;
|
|
if (amax_enabled)
|
|
amax_diskwrite(w);
|
|
|
|
pos += 16;
|
|
pos %= drv.tracklen;
|
|
}
|
|
drv.mfmpos = pos;
|
|
drive_write_data(drv);
|
|
done = 2;
|
|
}
|
|
}
|
|
if (!done && noselected) {
|
|
var bits = -1;
|
|
while (dsklength-- > 0) {
|
|
if (dskdmaen == DSKDMA_WRITE) {
|
|
var w = SAER_Memory_chipGet16_indirect(dskpt);
|
|
if (amax_enabled) {
|
|
amax_diskwrite(w);
|
|
if (w) {
|
|
for (var i = 0; i < 16; i++) {
|
|
if (w & (1 << i))
|
|
bits++;
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
SAER_Memory_chipPut16_indirect(dskpt, 0);
|
|
|
|
dskpt += 2;
|
|
}
|
|
if (bits == 0) {
|
|
//AMAX speedup hack
|
|
done = 1;
|
|
} else {
|
|
SAER.custom.INTREQ(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_DSKSYN);
|
|
done = 2;
|
|
}
|
|
}
|
|
|
|
if (done) {
|
|
linecounter = done;
|
|
dskdmaen = DSKDMA_OFF;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
this.DSKSYNC = function(hpos, v) {
|
|
if (v == dsksync)
|
|
return;
|
|
this.update(hpos);
|
|
dsksync = v;
|
|
}
|
|
|
|
/*function iswrite() {
|
|
return dskdmaen == DSKDMA_WRITE;
|
|
}*/
|
|
this.DSKDAT = function(v) {
|
|
if (fifo_inuse[2]) {
|
|
SAEF_warn("disk.DSKDAT() FIFO overflow!");
|
|
return;
|
|
}
|
|
fifo_inuse[2] = fifo_inuse[1];
|
|
fifo[2] = fifo[1];
|
|
fifo_inuse[1] = fifo_inuse[0];
|
|
fifo[1] = fifo[0];
|
|
//fifo_inuse[0] = iswrite() ? 2 : 1;
|
|
fifo_inuse[0] = dskdmaen == DSKDMA_WRITE ? 2 : 1;
|
|
fifo[0] = v;
|
|
fifo_filled = 1;
|
|
}
|
|
this.DSKDATR = function() {
|
|
var i, v = 0;
|
|
|
|
for (i = 2; i >= 0; i--) {
|
|
if (fifo_inuse[i]) {
|
|
fifo_inuse[i] = 0;
|
|
v = fifo[i];
|
|
break;
|
|
}
|
|
}
|
|
if (i < 0)
|
|
SAEF_warn("disk.DSKDATR() FIFO underflow!");
|
|
else if (dskdmaen > 0 && dskdmaen < 3 && dsklength <= 0 && this.fifostatus() < 0)
|
|
disk_dmafinished();
|
|
|
|
return v;
|
|
}
|
|
|
|
this.DSKPTH = function(v) {
|
|
v = v & (SAEV_config.chipset.mask == SAEC_Config_Chipset_Mask_OCS ? 7 : 31); //OWN
|
|
dskpt = ((v << 16) | (dskpt & 0xffff)) >>> 0;
|
|
}
|
|
this.DSKPTL = function(v) {
|
|
dskpt = ((dskpt & 0xffff0000) | v) >>> 0;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
this.dmal = function() { //disk_dmal()
|
|
var dmal = 0;
|
|
if (dskdmaen) {
|
|
if (dskdmaen == 3) {
|
|
dmal = (1 + 2) * (fifo_inuse[0] ? 1 : 0) + (4 + 8) * (fifo_inuse[1] ? 1 : 0) + (16 + 32) * (fifo_inuse[2] ? 1 : 0);
|
|
dmal ^= 63;
|
|
if (dsklength == 2)
|
|
dmal &= ~(16 + 32);
|
|
if (dsklength == 1)
|
|
dmal &= ~(16 + 32 + 4 + 8);
|
|
} else
|
|
dmal = 16 * (fifo_inuse[0] ? 1 : 0) + 4 * (fifo_inuse[1] ? 1 : 0) + 1 * (fifo_inuse[2] ? 1 : 0);
|
|
}
|
|
return dmal;
|
|
}
|
|
this.getpt = function() { //disk_getpt()
|
|
var pt = dskpt;
|
|
dskpt += 2;
|
|
return pt;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
this.setup = function() { //DISK_init()
|
|
for (var dr = MAX_FLOPPY_DRIVES - 1; dr >= 0; dr--) {
|
|
var drv = floppy[dr];
|
|
/* reset all drive types to 3.5 DD */
|
|
drive_settype_id(drv);
|
|
if (!drive_insert(drv, SAEV_config, dr, SAEV_config.floppy.drive[dr].file, false))
|
|
this.eject(dr);
|
|
}
|
|
if (drive_empty(floppy[0])) //if (disk_empty(0))
|
|
SAEF_log("disk.setup() No disk in drive DF0.");
|
|
|
|
amax_init();
|
|
}
|
|
this.cleanup = function() { //DISK_free()
|
|
for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) {
|
|
var drv = floppy[dr];
|
|
drive_image_free(drv);
|
|
}
|
|
}
|
|
|
|
this.reset = function() { //DISK_reset()
|
|
disk_hpos = 0;
|
|
dskdmaen = 0;
|
|
disabled = 0;
|
|
//disk_info_data.clr(); //memset(&disk_info_data, 0, sizeof disk_info_data);
|
|
for (var dr = MAX_FLOPPY_DRIVES - 1; dr >= 0; dr--)
|
|
reset_drive(dr);
|
|
|
|
initial_disk_statusline = true;
|
|
setamax();
|
|
|
|
//OWN
|
|
linecounter = 0;
|
|
warned_ext2 = false;
|
|
warned_trackspeed = 0;
|
|
driveNames = ["","","",""];
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* SECT disk tools */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
const FS_FLOPPY_BLOCKSIZE = 512;
|
|
const FS_OFS_DATABLOCKSIZE = 488;
|
|
const FS_EXTENSION_BLOCKS = 72;
|
|
const FS_FLOPPY_TOTALBLOCKS = 1760;
|
|
//const FS_FLOPPY_RESERVED = 2;
|
|
|
|
const bootblock_ofs = [
|
|
0x44,0x4f,0x53,0x00,0xc0,0x20,0x0f,0x19,0x00,0x00,0x03,0x70,0x43,0xfa,0x00,0x18,
|
|
0x4e,0xae,0xff,0xa0,0x4a,0x80,0x67,0x0a,0x20,0x40,0x20,0x68,0x00,0x16,0x70,0x00,
|
|
0x4e,0x75,0x70,0xff,0x60,0xfa,0x64,0x6f,0x73,0x2e,0x6c,0x69,0x62,0x72,0x61,0x72,
|
|
0x79
|
|
];
|
|
const bootblock_ffs = [
|
|
0x44, 0x4F, 0x53, 0x01, 0xE3, 0x3D, 0x0E, 0x72, 0x00, 0x00, 0x03, 0x70, 0x43, 0xFA, 0x00, 0x3E,
|
|
0x70, 0x25, 0x4E, 0xAE, 0xFD, 0xD8, 0x4A, 0x80, 0x67, 0x0C, 0x22, 0x40, 0x08, 0xE9, 0x00, 0x06,
|
|
0x00, 0x22, 0x4E, 0xAE, 0xFE, 0x62, 0x43, 0xFA, 0x00, 0x18, 0x4E, 0xAE, 0xFF, 0xA0, 0x4A, 0x80,
|
|
0x67, 0x0A, 0x20, 0x40, 0x20, 0x68, 0x00, 0x16, 0x70, 0x00, 0x4E, 0x75, 0x70, 0xFF, 0x4E, 0x75,
|
|
0x64, 0x6F, 0x73, 0x2E, 0x6C, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x00, 0x65, 0x78, 0x70, 0x61,
|
|
0x6E, 0x73, 0x69, 0x6F, 0x6E, 0x2E, 0x6C, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x00, 0x00, 0x00
|
|
];
|
|
|
|
/*---------------------------------*/
|
|
|
|
function disk_checksum(p,po, c,co) {
|
|
var cs = 0;
|
|
for (var i = 0; i < FS_FLOPPY_BLOCKSIZE; i += 4) {
|
|
cs += ((p[po + i] << 24) | (p[po + i + 1] << 16) | (p[po + i + 2] << 8) | p[po + i + 3]) >>> 0;
|
|
if (cs > 0xffffffff) cs -= 0x100000000; //OWN
|
|
}
|
|
cs = -cs;
|
|
if (cs < 0) cs += 0x100000000; //OWN
|
|
|
|
if (c !== null) {
|
|
c[co ] = cs >>> 24;
|
|
c[co + 1] = (cs >>> 16) & 0xff;
|
|
c[co + 2] = (cs >>> 8) & 0xff;
|
|
c[co + 3] = cs & 0xff;
|
|
}
|
|
//SAEF_log('disk.disk_checksum() 0x%08X', cs);
|
|
return cs;
|
|
}
|
|
|
|
function disk_date(p,po) {
|
|
var tv = {};
|
|
SAEF_gettimeofday(tv, null);
|
|
//tv.tv_sec -= _timezone;
|
|
var amiga = { days:0, mins:0, ticks:0 };
|
|
SAEF_timeval_to_amiga(tv, amiga, 50);
|
|
if (amiga.days == prev_days && amiga.mins == prev_mins && amiga.ticks == prev_ticks) {
|
|
amiga.ticks++;
|
|
if (amiga.ticks >= 50 * 60) {
|
|
amiga.ticks = 0;
|
|
amiga.mins++;
|
|
if (amiga.mins >= 24 * 60)
|
|
amiga.days++;
|
|
}
|
|
}
|
|
prev_days = amiga.days;
|
|
prev_mins = amiga.mins;
|
|
prev_ticks = amiga.ticks;
|
|
p[po + 0] = amiga.days >>> 24;
|
|
p[po + 1] = (amiga.days >>> 16) & 0xff;
|
|
p[po + 2] = (amiga.days >>> 8) & 0xff;
|
|
p[po + 3] = amiga.days & 0xff;
|
|
p[po + 4] = amiga.mins >>> 24;
|
|
p[po + 5] = (amiga.mins >>> 16) & 0xff;
|
|
p[po + 6] = (amiga.mins >>> 8) & 0xff;
|
|
p[po + 7] = amiga.mins & 0xff;
|
|
p[po + 8] = amiga.ticks >>> 24;
|
|
p[po + 9] = (amiga.ticks >>> 16) & 0xff;
|
|
p[po + 10] = (amiga.ticks >>> 8) & 0xff;
|
|
p[po + 11] = amiga.ticks & 0xff;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* DiskInfo */
|
|
|
|
function load_track(num, cyl, side, sectable) {
|
|
var drv = floppy[num];
|
|
var oldcyl = drv.cyl;
|
|
var oldside = side;
|
|
var drvsec = { value:0 };
|
|
drv.cyl = cyl;
|
|
side = 0;
|
|
drv.buffered_cyl = -1;
|
|
drive_fill_bigbuf(drv, true);
|
|
decode_buffer(drv.bigmfmbuf, drv.cyl, 11, drv.ddhd, drv.filetype, drvsec, sectable, true);
|
|
drv.cyl = oldcyl;
|
|
side = oldside;
|
|
drv.buffered_cyl = -1;
|
|
}
|
|
function examine_image(p, num, di) { //DISK_examine_image()
|
|
var drv = floppy[num];
|
|
var dos, crc, tmpcrc, crc2; //u32
|
|
var wasdelayed = drv.dskchange_time;
|
|
var drvsec = { value:0 };
|
|
var sectable = new Uint8Array(MAX_SECTORS);
|
|
var i, v = 0; //u32
|
|
|
|
var ret = 0;
|
|
di.clr(); //memset(di, 0, sizeof (struct diskinfo));
|
|
di.unreadable = true;
|
|
var oldcyl = drv.cyl;
|
|
var oldside = side;
|
|
drv.cyl = 0;
|
|
side = 0;
|
|
if (!drive_insert(drv, p, num, p.floppy.drive[num].file, true) || drv.diskfile === null) {
|
|
drv.cyl = oldcyl;
|
|
side = oldside;
|
|
return 1;
|
|
}
|
|
//di.crc32 = SAEF_ZFile_crc32(drv.diskfile);
|
|
di.crc32 = drv.crc32;
|
|
di.unreadable = false;
|
|
decode_buffer(drv.bigmfmbuf, drv.cyl, 11, drv.ddhd, drv.filetype, drvsec, sectable, true);
|
|
di.hd = drv.ddhd == 2;
|
|
drv.cyl = oldcyl;
|
|
side = oldside;
|
|
if (sectable[0] == 0 || sectable[1] == 0) {
|
|
ret = 2;
|
|
//goto end2;
|
|
}
|
|
if (ret != 2) {
|
|
crc = crc2 = 0;
|
|
for (i = 0; i < 1024; i += 4) {
|
|
di.bootblock[i ] = writebuffer[i ];
|
|
di.bootblock[i + 1] = writebuffer[i + 1];
|
|
di.bootblock[i + 2] = writebuffer[i + 2];
|
|
di.bootblock[i + 3] = writebuffer[i + 3];
|
|
var v = ((writebuffer[i] << 24) | (writebuffer[i + 1] << 16) | (writebuffer[i + 2] << 8) | writebuffer[i + 3]) >>> 0;
|
|
if (i == 0)
|
|
dos = v;
|
|
else if (i == 4) {
|
|
crc2 = v;
|
|
v = 0;
|
|
}
|
|
//if (crc + v < crc) crc++;
|
|
tmpcrc = crc + v; if (tmpcrc > 0xffffffff) tmpcrc -= 0x100000000;
|
|
if (tmpcrc < crc) {
|
|
crc++; if (crc > 0xffffffff) crc -= 0x100000000;
|
|
}
|
|
crc += v; if (crc > 0xffffffff) crc -= 0x100000000;
|
|
}
|
|
if (dos == 0x4b49434b) { /* KICK */
|
|
ret = 10;
|
|
//goto end;
|
|
}
|
|
if (ret != 10) {
|
|
di.bootblockChecksum = crc2;
|
|
crc = (crc ^ 0xffffffff) >>> 0;
|
|
if (crc != crc2) {
|
|
ret = 3;
|
|
//goto end;
|
|
}
|
|
if (ret != 3) {
|
|
di.bootblockChecksumValid = true;
|
|
writebuffer[4] = writebuffer[5] = writebuffer[6] = writebuffer[7] = 0;
|
|
if (SAEF_crc32(writebuffer,0, 0x31) == 0xae5e282c)
|
|
di.bootblockType = 1;
|
|
|
|
if (dos == 0x444f5300)
|
|
ret = 10;
|
|
else if (dos == 0x444f5301 || dos == 0x444f5302 || dos == 0x444f5303)
|
|
ret = 11;
|
|
else if (dos == 0x444f5304 || dos == 0x444f5305 || dos == 0x444f5306 || dos == 0x444f5307)
|
|
ret = 12;
|
|
else
|
|
ret = 4;
|
|
|
|
v = SAEF_crc32(writebuffer,8, 0x5c - 8);
|
|
if (ret >= 10 && v == 0xe158ca4b)
|
|
di.bootblockType = 2;
|
|
}
|
|
}
|
|
//end:
|
|
load_track(num, 40, 0, sectable);
|
|
if (sectable[0]) {
|
|
if (!disk_checksum(writebuffer,0, null,0) &&
|
|
writebuffer[0] == 0 && writebuffer[1] == 0 && writebuffer[2] == 0 && writebuffer[3] == 2 &&
|
|
writebuffer[508] == 0 && writebuffer[509] == 0 && writebuffer[510] == 0 && writebuffer[511] == 1
|
|
) {
|
|
|
|
/*writebuffer[512 - 20 * 4 + 1 + writebuffer[512 - 20 * 4]] = 0;
|
|
TCHAR *n = au((const char*)(writebuffer + 512 - 20 * 4 + 1));
|
|
if (_tcslen (n) >= sizeof (di.diskname)) n[sizeof (di.diskname) - 1] = 0;
|
|
di.diskname = n;
|
|
xfree(n);*/
|
|
var len = writebuffer[512 - 20 * 4]; //BSTR
|
|
var off = 512 - 20 * 4 + 1;
|
|
var n = "";
|
|
while (--len >= 0) n += String.fromCharCode(writebuffer[off++]);
|
|
di.diskname = n;
|
|
}
|
|
}
|
|
}
|
|
//end2:
|
|
drive_image_free(drv);
|
|
if (wasdelayed > 1) {
|
|
drive_eject(drv);
|
|
SAEV_config.floppy.drive[num].file.clr();
|
|
drv.dskchange_time = wasdelayed;
|
|
SAER.disk.insert(num, drv.newfile);
|
|
}
|
|
return ret;
|
|
}
|
|
this.examine = function(di, num) {
|
|
var ret = examine_image(SAEV_config, num, di);
|
|
if (ret != 1)
|
|
return SAEE_None;
|
|
|
|
return SAEE_Internal; //FIX better error
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* EXE -> ADF */
|
|
|
|
function writeimageblock(dst, sector, offset) {
|
|
SAEF_ZFile_fseek(dst, offset, SEEK_SET);
|
|
SAEF_ZFile_fwrite(sector,0, FS_FLOPPY_BLOCKSIZE, 1, dst);
|
|
}
|
|
function dirhash(name) {
|
|
name = name.toUpperCase();
|
|
var hash = name.length; //u32
|
|
for (var i = 0; i < name.length; i++) {
|
|
hash = hash * 13;
|
|
hash = hash + name.charCodeAt(i);
|
|
hash = hash & 0x7ff;
|
|
}
|
|
hash = hash % ((FS_FLOPPY_BLOCKSIZE >> 2) - 56);
|
|
//SAEF_log("disk.dirhash() %X", hash);
|
|
return hash;
|
|
}
|
|
function createbootblock(sector, bootable) {
|
|
//memset(sector, 0, FS_FLOPPY_BLOCKSIZE);
|
|
SAEF_memset(sector,0, 0, FS_FLOPPY_BLOCKSIZE);
|
|
if (bootable) {
|
|
//memcpy(sector, bootblock_ofs, sizeof bootblock_ofs);
|
|
sector.set(bootblock_ofs);
|
|
} else {
|
|
//memcpy(sector, "DOS", 3);
|
|
sector.set(SAEF_String2Array("DOS"));
|
|
}
|
|
}
|
|
function createrootblock(sector, disk_name) {
|
|
var dn = disk_name;
|
|
if (dn.length > 30)
|
|
dn = dn.substr(0, 30);
|
|
dn2 = dn;
|
|
if (dn2.length == 0)
|
|
dn2 = "empty";
|
|
//memset(sector, 0, FS_FLOPPY_BLOCKSIZE);
|
|
SAEF_memset(sector,0, 0, FS_FLOPPY_BLOCKSIZE);
|
|
sector[0+3] = 2;
|
|
sector[12+3] = 0x48;
|
|
sector[312] = sector[313] = sector[314] = sector[315] = 0xff;
|
|
sector[316+2] = 881 >> 8;
|
|
sector[316+3] = 881 & 255;
|
|
sector[432] = dn2.length; sector.set(SAEF_String2Array(dn2), 433); //BSTR
|
|
sector[508 + 3] = 1;
|
|
disk_date(sector,420);
|
|
//memcpy(sector + 472, sector + 420, 3 * 4);
|
|
//memcpy(sector + 484, sector + 420, 3 * 4);
|
|
SAEF_memcpy(sector,472, sector,420, 3 * 4);
|
|
SAEF_memcpy(sector,484, sector,420, 3 * 4);
|
|
//sector.copyWithin(472, 420, 420 + 3 * 4);
|
|
//sector.copyWithin(484, 420, 420 + 3 * 4);
|
|
}
|
|
function getblock(bitmap, prev) {
|
|
var i = prev.block;
|
|
while (bitmap[i] != 0xff) {
|
|
if (bitmap[i] == 0) {
|
|
bitmap[i] = 1;
|
|
prev.block = i;
|
|
return i;
|
|
}
|
|
i++;
|
|
}
|
|
i = 0;
|
|
while (bitmap[i] != 0xff) {
|
|
if (bitmap[i] == 0) {
|
|
bitmap[i] = 1;
|
|
prev.block = i;
|
|
return i;
|
|
}
|
|
i++;
|
|
}
|
|
return -1;
|
|
}
|
|
function pl(sector, offset, v) {
|
|
sector[offset + 0] = v >>> 24;
|
|
sector[offset + 1] = (v >>> 16) & 0xff;
|
|
sector[offset + 2] = (v >>> 8) & 0xff;
|
|
sector[offset + 3] = v & 0xff;
|
|
}
|
|
function createdirheaderblock(sector, parent, filename, bitmap, prevblock) {
|
|
var block = getblock(bitmap, prevblock);
|
|
|
|
//memset(sector, 0, FS_FLOPPY_BLOCKSIZE);
|
|
SAEF_memset(sector,0, 0, FS_FLOPPY_BLOCKSIZE);
|
|
pl(sector, 0, 2);
|
|
pl(sector, 4, block);
|
|
disk_date(sector, 512 - 92);
|
|
sector[512 - 80] = filename.length; sector.set(SAEF_String2Array(filename), 512 - 79); //BSTR
|
|
pl(sector, 512 - 12, parent);
|
|
pl(sector, 512 - 4, 2);
|
|
return block;
|
|
}
|
|
function createfileheaderblock(z, sector, parent, filename, src, bitmap, prevblock) {
|
|
var sector2 = new Uint8Array(FS_FLOPPY_BLOCKSIZE);
|
|
var sector3 = new Uint8Array(FS_FLOPPY_BLOCKSIZE);
|
|
var block = getblock(bitmap, prevblock);
|
|
var datablock = getblock(bitmap, prevblock);
|
|
var datasec = 1;
|
|
var headerextension = 1;
|
|
|
|
SAEF_ZFile_fseek(src, 0, SEEK_END);
|
|
var size = SAEF_ZFile_ftell(src);
|
|
SAEF_ZFile_fseek(src, 0, SEEK_SET);
|
|
var extensions = Math.floor((size + FS_OFS_DATABLOCKSIZE - 1) / FS_OFS_DATABLOCKSIZE);
|
|
|
|
//memset(sector, 0, FS_FLOPPY_BLOCKSIZE);
|
|
SAEF_memset(sector,0, 0, FS_FLOPPY_BLOCKSIZE);
|
|
pl(sector, 0, 2);
|
|
pl(sector, 4, block);
|
|
pl(sector, 8, extensions > FS_EXTENSION_BLOCKS ? FS_EXTENSION_BLOCKS : extensions);
|
|
pl(sector, 16, datablock);
|
|
pl(sector, FS_FLOPPY_BLOCKSIZE - 188, size);
|
|
disk_date(sector,FS_FLOPPY_BLOCKSIZE - 92);
|
|
sector[FS_FLOPPY_BLOCKSIZE - 80] = filename.length; sector.set(SAEF_String2Array(filename), FS_FLOPPY_BLOCKSIZE - 79); //BSTR
|
|
pl(sector, FS_FLOPPY_BLOCKSIZE - 12, parent);
|
|
pl(sector, FS_FLOPPY_BLOCKSIZE - 4, -3 >>> 0);
|
|
var extensioncounter = 0;
|
|
var extensionblock = 0;
|
|
|
|
while (size > 0) {
|
|
var datablock2 = datablock;
|
|
var extensionblock2 = extensionblock;
|
|
if (extensioncounter == FS_EXTENSION_BLOCKS) {
|
|
extensioncounter = 0;
|
|
extensionblock = getblock(bitmap, prevblock);
|
|
if (datasec > FS_EXTENSION_BLOCKS + 1) {
|
|
pl(sector3, 8, FS_EXTENSION_BLOCKS);
|
|
pl(sector3, FS_FLOPPY_BLOCKSIZE - 8, extensionblock);
|
|
pl(sector3, 4, extensionblock2);
|
|
disk_checksum(sector3,0, sector3,20);
|
|
writeimageblock(z, sector3, extensionblock2 * FS_FLOPPY_BLOCKSIZE);
|
|
} else
|
|
pl(sector, 512 - 8, extensionblock);
|
|
|
|
//memset(sector3, 0, FS_FLOPPY_BLOCKSIZE);
|
|
SAEF_memset(sector3,0, 0, FS_FLOPPY_BLOCKSIZE);
|
|
pl(sector3, 0, 16);
|
|
pl(sector3, FS_FLOPPY_BLOCKSIZE - 12, block);
|
|
pl(sector3, FS_FLOPPY_BLOCKSIZE - 4, -3 >>> 0);
|
|
}
|
|
//memset(sector2, 0, FS_FLOPPY_BLOCKSIZE);
|
|
SAEF_memset(sector2,0, 0, FS_FLOPPY_BLOCKSIZE);
|
|
pl(sector2, 0, 8);
|
|
pl(sector2, 4, block);
|
|
pl(sector2, 8, datasec++);
|
|
pl(sector2, 12, size > FS_OFS_DATABLOCKSIZE ? FS_OFS_DATABLOCKSIZE : size);
|
|
SAEF_ZFile_fread(sector2,24, size > FS_OFS_DATABLOCKSIZE ? FS_OFS_DATABLOCKSIZE : size, 1, src);
|
|
size -= FS_OFS_DATABLOCKSIZE;
|
|
datablock = 0;
|
|
if (size > 0) datablock = getblock(bitmap, prevblock);
|
|
pl(sector2, 16, datablock);
|
|
disk_checksum(sector2,0, sector2,20);
|
|
writeimageblock(z, sector2, datablock2 * FS_FLOPPY_BLOCKSIZE);
|
|
if (datasec <= FS_EXTENSION_BLOCKS + 1)
|
|
pl(sector, 512 - 204 - extensioncounter * 4, datablock2);
|
|
else
|
|
pl(sector3, 512 - 204 - extensioncounter * 4, datablock2);
|
|
extensioncounter++;
|
|
}
|
|
if (datasec > FS_EXTENSION_BLOCKS) {
|
|
pl(sector3, 8, extensioncounter);
|
|
disk_checksum(sector3,0, sector3,20);
|
|
writeimageblock(z, sector3, extensionblock * FS_FLOPPY_BLOCKSIZE);
|
|
}
|
|
disk_checksum(sector,0, sector,20);
|
|
writeimageblock(z, sector, block * FS_FLOPPY_BLOCKSIZE);
|
|
return block;
|
|
}
|
|
function createbitmapblock(sector, bitmap) {
|
|
//memset(sector, 0, FS_FLOPPY_BLOCKSIZE);
|
|
SAEF_memset(sector,0, 0, FS_FLOPPY_BLOCKSIZE);
|
|
var i = 0;
|
|
for (;;) {
|
|
var mask = 0;
|
|
for (var j = 0; j < 32; j++) {
|
|
if (bitmap[2 + i * 32 + j] == 0xff)
|
|
break;
|
|
if (!bitmap[2 + i * 32 + j])
|
|
mask |= 1 << j;
|
|
}
|
|
mask >>>= 0;
|
|
sector[4 + i * 4 + 0] = mask >>> 24;
|
|
sector[4 + i * 4 + 1] = (mask >>> 16) & 0xff;
|
|
sector[4 + i * 4 + 2] = (mask >>> 8) & 0xff;
|
|
sector[4 + i * 4 + 3] = mask & 0xff;
|
|
if (bitmap[2 + i * 32 + j] == 0xff)
|
|
break;
|
|
i++;
|
|
}
|
|
disk_checksum(sector,0, sector,0);
|
|
}
|
|
function createimagefromexe(src, dst) {
|
|
var sector1 = new Uint8Array(FS_FLOPPY_BLOCKSIZE)
|
|
var sector2 = new Uint8Array(FS_FLOPPY_BLOCKSIZE)
|
|
var bitmap = new Uint8Array(FS_FLOPPY_TOTALBLOCKS + 8);
|
|
var blocksize = FS_OFS_DATABLOCKSIZE;
|
|
const fname1 = "runme.exe";
|
|
const fname1b = "runme.adf";
|
|
const fname2 = "startup-sequence";
|
|
const dirname1 = "s";
|
|
var prevblock = {
|
|
block:880
|
|
};
|
|
|
|
//memset(bitmap, 0, sizeof bitmap);
|
|
SAEF_ZFile_fseek(src, 0, SEEK_END);
|
|
var exesize = SAEF_ZFile_ftell(src);
|
|
var blocks = Math.floor((exesize + blocksize - 1) / blocksize);
|
|
var extensionblocks = Math.floor((blocks + FS_EXTENSION_BLOCKS - 1) / FS_EXTENSION_BLOCKS);
|
|
//bootblock=2, root=1, bitmap=1, startup-sequence=1+1, exefileheader=1
|
|
var totalblocks = 2 + 1 + 1 + 2 + 1 + blocks + extensionblocks;
|
|
if (totalblocks > FS_FLOPPY_TOTALBLOCKS)
|
|
return 0;
|
|
|
|
bitmap[880] = 1;
|
|
bitmap[881] = 1;
|
|
bitmap[0] = 1;
|
|
bitmap[1] = 1;
|
|
bitmap[1760] = -1;
|
|
//prevblock = 880;
|
|
|
|
var dblock1 = createdirheaderblock(sector2, 880, dirname1, bitmap, prevblock);
|
|
var ss = SAEF_ZFile_fopen_empty(src, fname1b, fname1.length);
|
|
SAEF_ZFile_fwrite(SAEF_String2Array(fname1),0, fname1.length, 1, ss);
|
|
var fblock1 = createfileheaderblock(dst, sector1, dblock1, fname2, ss, bitmap, prevblock);
|
|
SAEF_ZFile_fclose(ss);
|
|
pl(sector2, 24 + dirhash(fname2) * 4, fblock1);
|
|
disk_checksum(sector2,0, sector2,20);
|
|
writeimageblock(dst, sector2, dblock1 * FS_FLOPPY_BLOCKSIZE);
|
|
|
|
fblock1 = createfileheaderblock(dst, sector1, 880, fname1, src, bitmap, prevblock);
|
|
|
|
createrootblock(sector1, SAEF_ZFile_getfilename(src));
|
|
pl(sector1, 24 + dirhash(fname1) * 4, fblock1);
|
|
pl(sector1, 24 + dirhash(dirname1) * 4, dblock1);
|
|
disk_checksum(sector1,0, sector1,20);
|
|
writeimageblock(dst, sector1, 880 * FS_FLOPPY_BLOCKSIZE);
|
|
|
|
createbitmapblock(sector1, bitmap);
|
|
writeimageblock(dst, sector1, 881 * FS_FLOPPY_BLOCKSIZE);
|
|
|
|
createbootblock(sector1, 1);
|
|
writeimageblock(dst, sector1, 0 * FS_FLOPPY_BLOCKSIZE);
|
|
return 1;
|
|
}
|
|
|
|
this.EXE2ADF = function(z) {
|
|
var orgname = SAEF_ZFile_getname(z);
|
|
var newname = "";
|
|
|
|
var ext = orgname.lastIndexOf('.');
|
|
if (ext != -1) {
|
|
newname = orgname.substr(0, ext);
|
|
newname += ".ADF";
|
|
} else
|
|
newname = orgname + ".ADF";
|
|
|
|
var zo = SAEF_ZFile_fopen_empty(z, newname, 1760 * 512);
|
|
if (zo === null)
|
|
return null;
|
|
|
|
var ret = createimagefromexe(z, zo);
|
|
if (ret) {
|
|
SAEF_ZFile_fseek(zo, 0, SEEK_SET);
|
|
|
|
SAEF_ZFile_fclose(z);
|
|
z = null;
|
|
|
|
SAEF_log("disk.EXE2ADF() converted '%s' to '%s'", orgname, newname);
|
|
} else {
|
|
SAEF_ZFile_fclose(zo);
|
|
zo = null;
|
|
|
|
//SAEF_warn("disk.EXE2ADF() error converting '%s' (too big)"), orgname);
|
|
alert(sprintf("Can't convert '%s' to ADF. (too big)", orgname));
|
|
}
|
|
return zo;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
/* create ADF */
|
|
|
|
function floppy_get_bootblock(dst, ffs, bootable) {
|
|
if (bootable)
|
|
dst.set(ffs ? bootblock_ffs : bootblock_ofs);
|
|
else {
|
|
dst[0] = 68; //D
|
|
dst[1] = 79; //O
|
|
dst[2] = 83; //S
|
|
dst[3] = ffs ? 1 : 0;
|
|
}
|
|
}
|
|
function floppy_get_rootblock(dst, block, label, type) {
|
|
var ls = label.length > 0 ? label : "empty";
|
|
dst[0+3] = 2;
|
|
dst[12+3] = 0x48;
|
|
dst[312] = dst[313] = dst[314] = dst[315] = 0xff;
|
|
dst[316+2] = ((block + 1) >> 8) & 255;
|
|
dst[316+3] = (block + 1) & 255;
|
|
dst[432] = ls.length; dst.set(SAEF_String2Array(ls), 433); //BSTR
|
|
dst[508 + 3] = 1;
|
|
disk_date(dst,420);
|
|
//memcpy(dst + 472, dst + 420, 3 * 4);
|
|
//memcpy(dst + 484, dst + 420, 3 * 4);
|
|
SAEF_memcpy(dst,472, dst,420, 3 * 4);
|
|
SAEF_memcpy(dst,484, dst,420, 3 * 4);
|
|
//dst.copyWithin(472, 420, 420 + 3 * 4);
|
|
//dst.copyWithin(484, 420, 420 + 3 * 4);
|
|
disk_checksum(dst,0, dst,20);
|
|
//bitmap block
|
|
//memset(dst + 512 + 4, 0xff, 2 * block / 8);
|
|
SAEF_memset(dst,512 + 4, 0xff, 2 * block >> 3);
|
|
if (type == SAEC_Disk_Create_Type_35_DD)
|
|
dst[512 + 0x72] = 0x3f;
|
|
else
|
|
dst[512 + 0xdc] = 0x3f;
|
|
disk_checksum(dst,512, dst,512);
|
|
}
|
|
|
|
//function creatediskfile(name, mode, type, label, ffs, bootable, copyfrom) {
|
|
function creatediskfile(name, mode, type, label, ffs, bootable, copyfrom) { //disk_creatediskfile()
|
|
const size = 32768;
|
|
var chunk = null; //u8 *
|
|
var ddhd = 1;
|
|
var pos; //u64
|
|
var i;
|
|
var ok = false;
|
|
|
|
var tracks = 2 * (mode == SAEC_Disk_Create_Mode_Custom ? 83 : 80);
|
|
var file_size = 880 * 1024;
|
|
var sectors = 11;
|
|
if (type == SAEC_Disk_Create_Type_35_DD_PC || type == SAEC_Disk_Create_Type_35_HD_PC) {
|
|
file_size = 720 * 1024;
|
|
sectors = 9;
|
|
}
|
|
var track_len = FLOPPY_WRITE_LEN() * 2;
|
|
if (type == SAEC_Disk_Create_Type_35_HD || type == SAEC_Disk_Create_Type_35_HD_PC) {
|
|
file_size <<= 1;
|
|
track_len <<= 1;
|
|
ddhd = 2;
|
|
} else if (type == SAEC_Disk_Create_Type_525_SD) {
|
|
file_size >>= 1;
|
|
tracks >>= 1;
|
|
}
|
|
|
|
if (copyfrom !== null) {
|
|
pos = SAEF_ZFile_ftell(copyfrom);
|
|
SAEF_ZFile_fseek(copyfrom, 0, SEEK_SET);
|
|
}
|
|
|
|
//var f = SAEF_ZFile_fopen(name, "wb", 0);
|
|
var f = SAEF_ZFile_fopen_empty(null, name, file_size);
|
|
chunk = new Uint8Array(size);
|
|
if (f !== null) {
|
|
var cylsize = sectors * 2 * 512;
|
|
//memset(chunk, 0, size);
|
|
SAEF_memset(chunk,0, 0, size);
|
|
if (mode == SAEC_Disk_Create_Mode_Normal) {
|
|
for (i = 0; i < file_size; i += cylsize) {
|
|
//memset(chunk, 0, cylsize);
|
|
SAEF_memset(chunk,0, 0, cylsize);
|
|
if (type <= SAEC_Disk_Create_Type_35_HD) {
|
|
if (i == 0) {
|
|
//boot block
|
|
floppy_get_bootblock(chunk, ffs, bootable);
|
|
} else if (i == file_size >> 1) {
|
|
//root block
|
|
floppy_get_rootblock(chunk, file_size / (2 * 512), label, type);
|
|
}
|
|
}
|
|
SAEF_ZFile_fwrite(chunk,0, cylsize, 1, f);
|
|
}
|
|
ok = true;
|
|
} else {
|
|
var root = new Uint8Array(4);
|
|
var rawtrack = new Uint8Array(3 * 4);
|
|
var dostrack = new Uint8Array(3 * 4);
|
|
var l = track_len;
|
|
SAEF_ZFile_fwrite(SAEF_String2Array("UAE-1ADF"),0, 8, 1, f);
|
|
root[0] = 0; root[1] = 0; //flags (reserved)
|
|
root[2] = 0; root[3] = tracks; //number of tracks
|
|
SAEF_ZFile_fwrite(root,0, 4, 1, f);
|
|
rawtrack[0] = 0; rawtrack[1] = 0; //flags (reserved)
|
|
rawtrack[2] = 0; rawtrack[3] = 1; //track type
|
|
rawtrack[4] = 0; rawtrack[5] = 0; rawtrack[6] = l >> 8; rawtrack[7] = l & 0xff;
|
|
rawtrack[8] = 0; rawtrack[9] = 0; rawtrack[10] = 0; rawtrack[11] = 0;
|
|
dostrack.set(rawtrack);
|
|
dostrack[3] = 0;
|
|
dostrack[9] = ((l * 8) >> 16) & 0xff;
|
|
dostrack[10] = ((l * 8) >> 8) & 0xff;
|
|
dostrack[11] = (l * 8) & 0xff;
|
|
var dodos = ffs || bootable || label.length > 0;
|
|
for (i = 0; i < tracks; i++) {
|
|
var tmp = new Uint8Array(3 * 4);
|
|
if (dodos || copyfrom !== null)
|
|
tmp.set(dostrack);
|
|
else
|
|
tmp.set(rawtrack);
|
|
SAEF_ZFile_fwrite(tmp,0, tmp.length, 1, f);
|
|
}
|
|
for (i = 0; i < tracks; i++) {
|
|
//memset(chunk, 0, size);
|
|
SAEF_memset(chunk,0, 0, size);
|
|
if (copyfrom !== null)
|
|
SAEF_ZFile_fread(chunk,0, 11 * ddhd, 512, copyfrom);
|
|
else {
|
|
if (dodos) {
|
|
if (i == 0)
|
|
floppy_get_bootblock(chunk, ffs, bootable);
|
|
else if (i == 80)
|
|
floppy_get_rootblock(chunk, 80 * 11 * ddhd, label, type);
|
|
}
|
|
}
|
|
SAEF_ZFile_fwrite(chunk,0, l, 1, f);
|
|
}
|
|
ok = true;
|
|
}
|
|
}
|
|
|
|
//SAEF_ZFile_fclose(f);
|
|
|
|
if (copyfrom !== null)
|
|
SAEF_ZFile_fseek(copyfrom, pos, SEEK_SET);
|
|
|
|
//return ok;
|
|
return ok ? f : null;
|
|
}
|
|
this.create = function(unit, name, mode, type, label, ffs, bootable) {
|
|
var f = creatediskfile(name, mode, type, label, ffs, bootable, null);
|
|
if (f !== null) {
|
|
switch (type) {
|
|
case SAEC_Disk_Create_Type_35_DD: SAEV_config.floppy.drive[unit].type = SAEC_Config_Floppy_Type_35_DD; break;
|
|
case SAEC_Disk_Create_Type_35_HD: SAEV_config.floppy.drive[unit].type = SAEC_Config_Floppy_Type_35_HD; break;
|
|
case SAEC_Disk_Create_Type_35_DD_PC: SAEV_config.floppy.drive[unit].type = SAEC_Config_Floppy_Type_35_DD_PC; break;
|
|
case SAEC_Disk_Create_Type_35_HD_PC: SAEV_config.floppy.drive[unit].type = SAEC_Config_Floppy_Type_35_HD_PC; break;
|
|
case SAEC_Disk_Create_Type_525_SD: SAEV_config.floppy.drive[unit].type = SAEC_Config_Floppy_Type_525_SD; break;
|
|
}
|
|
var data = SAEF_ZFile_getdata(f, 0, -1);
|
|
var file = SAEV_config.floppy.drive[unit].file;
|
|
file.name = SAEF_ZFile_getname(f);
|
|
file.data = SAEF_Array2String(data);
|
|
file.size = SAEF_ZFile_size(f);
|
|
file.prot = false;
|
|
|
|
SAEF_ZFile_fclose(f);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*---------------------------------*/
|
|
|
|
function convert_adf_to_ext2(drv, mode) {
|
|
if (drv.filetype != ADF_NORMAL)
|
|
return false;
|
|
|
|
var file = SAEV_config.floppy.drive[drv.num].file;
|
|
var hd = drv.ddhd == 2;
|
|
var name = file.name;
|
|
if (name.length == 0)
|
|
return false;
|
|
|
|
var f = null;
|
|
if (mode == 1) {
|
|
/*var p = name.lastIndexOf('.');
|
|
if (p != -1)
|
|
name = name.substr(0, p) + ".extended.adf";
|
|
else
|
|
name += ".extended.adf";*/
|
|
|
|
f = creatediskfile(name, SAEC_Disk_Create_Mode_Custom, hd ? SAEC_Disk_Create_Type_35_HD : SAEC_Disk_Create_Type_35_DD, "", false, false, drv.diskfile);
|
|
if (f === null)
|
|
return false;
|
|
} else if (mode == 2) {
|
|
var tmp = SAEF_ZFile_fopen_load_zfile(drv.diskfile);
|
|
if (tmp === null)
|
|
return false;
|
|
|
|
SAEF_ZFile_fclose(drv.diskfile);
|
|
drv.diskfile = null;
|
|
|
|
f = creatediskfile(name, SAEC_Disk_Create_Mode_Custom, hd ? SAEC_Disk_Create_Type_35_HD : SAEC_Disk_Create_Type_35_DD, "", false, false, tmp);
|
|
if (f === null) {
|
|
SAEF_ZFile_fclose(tmp);
|
|
return false;
|
|
}
|
|
} else
|
|
return false;
|
|
|
|
/*var f = SAEF_ZFile_fopen(name, "r+b");
|
|
if (f === null)
|
|
return false;*/
|
|
|
|
//file.name = name;
|
|
//changed_prefs.floppyslots[drv.num].file.name = name;
|
|
SAEF_ZFile_fclose(drv.diskfile);
|
|
|
|
drv.diskfile = f;
|
|
drv.filetype = ADF_EXT2;
|
|
//read_header_ext2(drv.diskfile, drv.trackdata, &drv.num_tracks, &drv.ddhd);
|
|
read_header_ext2(drv, drv.ddhd);
|
|
|
|
drive_write_data(drv);
|
|
/*#ifdef RETROPLATFORM
|
|
rp_disk_image_change(drv - &floppy[0], name, false);
|
|
#endif*/
|
|
drive_fill_bigbuf(drv, true);
|
|
|
|
SAEF_log("disk.convert_adf_to_ext2() converted '%s' to ADF-EXT2", file.name);
|
|
return true;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
/*#define FLOPPY_RATE_500K 0
|
|
#define FLOPPY_RATE_300K 1
|
|
#define FLOPPY_RATE_250K 2
|
|
#define FLOPPY_RATE_1M 3
|
|
struct floppy_reserved {
|
|
int num;
|
|
struct zfile *img;
|
|
bool wrprot;
|
|
int cyl;
|
|
int cyls;
|
|
int heads;
|
|
int secs;
|
|
int drive_cyls;
|
|
bool disk_changed;
|
|
int rate;
|
|
};
|
|
static int get_reserved_id(int num) {
|
|
for (int i = 0; i < MAX_FLOPPY_DRIVES; i++) {
|
|
if (reserved & (1 << i)) {
|
|
if (num > 0) {
|
|
num--;
|
|
continue;
|
|
}
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
void disk_reserved_setinfo(int num, int cyl, int head, int motor) {
|
|
int i = get_reserved_id(num);
|
|
if (i >= 0) {
|
|
drive *drv = &floppy[i];
|
|
reserved_side = head;
|
|
drv->cyl = cyl;
|
|
drv->state = motor != 0;
|
|
update_drive_gui(i, false);
|
|
}
|
|
}
|
|
bool disk_reserved_getinfo(int num, struct floppy_reserved *fr) {
|
|
int idx = get_reserved_id(num);
|
|
if (idx >= 0) {
|
|
drive *drv = &floppy[idx];
|
|
fr->num = idx;
|
|
fr->img = drv->diskfile;
|
|
fr->wrprot = drv->wrprot;
|
|
if (drv->diskfile && !drv->pcdecodedfile && (drv->filetype == ADF_EXT2 || drv->filetype == ADF_FDI || drv->filetype == ADF_SCP)) {
|
|
int cyl = drv->cyl;
|
|
int side2 = side;
|
|
struct zfile *z = SAEF_ZFile_fopen_empty(null, SAEF_ZFile_getfilename(drv->diskfile));
|
|
if (z) {
|
|
bool ok = false;
|
|
drv->num_secs = 21; // max possible
|
|
drive_fill_bigbuf(drv, true);
|
|
int secs = drive_write_pcdos(drv, z, 1);
|
|
if (secs >= 8) {
|
|
ok = true;
|
|
drv->num_secs = secs;
|
|
for (int i = 0; i < drv->num_tracks; i++) {
|
|
drv->cyl = i / 2;
|
|
side = i & 1;
|
|
drive_fill_bigbuf(drv, true);
|
|
drive_write_pcdos(drv, z, 0);
|
|
}
|
|
}
|
|
drv->cyl = cyl;
|
|
side = side2;
|
|
if (ok) {
|
|
write_log(_T("Created internal PC disk image cyl=%d secs=%d size=%d\n"), drv->num_tracks / 2, drv->num_secs, SAEF_ZFile_size(z));
|
|
drv->pcdecodedfile = z;
|
|
} else {
|
|
write_log(_T("Failed to create internal PC disk image\n"));
|
|
SAEF_ZFile_fclose(z);
|
|
}
|
|
}
|
|
}
|
|
if (drv->pcdecodedfile) {
|
|
fr->img = drv->pcdecodedfile;
|
|
}
|
|
fr->cyl = drv->cyl;
|
|
fr->cyls = drv->num_tracks / 2;
|
|
fr->drive_cyls = SAEV_config.floppy.drive[idx].type == SAEC_Config_Floppy_Type_35_DD_PC ? 40 : 80;
|
|
fr->secs = drv->num_secs;
|
|
fr->heads = drv->num_heads;
|
|
fr->disk_changed = drv->dskchange || fr->img == null;
|
|
if (SAEV_config.floppy.drive[idx].type == SAEC_Config_Floppy_Type_35_HD_PC) {
|
|
if (fr->cyls < 80) {
|
|
if (drv->num_secs < 9)
|
|
fr->rate = FLOPPY_RATE_250K; // 320k in 80 track drive
|
|
else
|
|
fr->rate = FLOPPY_RATE_300K; // 360k in 80 track drive
|
|
} else {
|
|
if (drv->num_secs > 14)
|
|
fr->rate = FLOPPY_RATE_500K; // 1.2M/1.4M
|
|
else
|
|
fr->rate = FLOPPY_RATE_250K; // 720K
|
|
}
|
|
} else {
|
|
if (drv->num_secs < 9)
|
|
fr->rate = FLOPPY_RATE_300K;// 320k in 40 track drive
|
|
else
|
|
fr->rate = FLOPPY_RATE_250K;// 360k in 40 track drive
|
|
// yes, above values are swapped compared to 1.2M drive case
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
void disk_reserved_reset_disk_change(int num) {
|
|
int i = get_reserved_id(num);
|
|
if (i >= 0) {
|
|
drive *drv = &floppy[i];
|
|
drv->dskchange = false;
|
|
}
|
|
}*/
|
|
}
|