/*------------------------------------------------------------------------- | 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; } }*/ }