From 32c9735dffc3f2329bc663df580971062e7a9699 Mon Sep 17 00:00:00 2001 From: Jason Robson Date: Sun, 29 May 2022 23:14:09 +0100 Subject: [PATCH] Support for ADFS 640K (.adl) disk image files (#357) * initial pass * Reworked interval timing Reworked interval timing to resolve an occasional hang after a BREAK. * Correcting utils to prev version Correcting utils to prev version * Add or update the Azure App Service build and deployment workflow config * Music 5000 support * Add or update the Azure App Service build and deployment workflow config * CD fix * added M5000 master SSD * updated README * tidy-up #1 * tidyup #2 * tidyup #3 * Amendments from inital PR review Removed .DS_Store Put back discs/.gitignore Image files renamed to lower case Removed my intro text in README.md * Improved audio worklet design pattern Taken inspiration from another pending branch (which uses audio worklets for the main sound recorder). * alignment of the 'fix' for the left/right channel swap I had previously chosen to address this by swapping over the speaker channels at output, but now will align with what the Beebem devs did and re-map the stereo generator array instead * Typo in stereo array ... oops * Updates as part of Matt code review * conversion of music 5000 / teletext functions to classes + replacement of tabs with 4 x spaces (yuk!) :) :) * Support for ADFS (640K) disk images (.adl) * Avoid repetition of the 16 : 10 logic with the addition of sectorsPerTrack * Added ability to download the current drive 0 image This allows any local changes made to disks to be persisted * Largely cosmetic changes following a run by prettier --- fdc.js | 34 ++++++++++++++++++---------------- index.html | 12 ++++++++---- main.js | 13 +++++++++++++ models.js | 4 ++-- utils.js | 11 ++++++++++- 5 files changed, 51 insertions(+), 23 deletions(-) diff --git a/fdc.js b/fdc.js index e4617556..367fbdbe 100644 --- a/fdc.js +++ b/fdc.js @@ -78,6 +78,7 @@ export function BaseDisc(fdc, name, data, flusher) { if (data === null || data === undefined) throw new Error("Bad disc data"); let nameDetails = utils.discImageSize(name); let isDsd = nameDetails.isDsd; + let sectorsPerTrack = nameDetails.isDoubleDensity ? 16 : 10; let byteSize = nameDetails.byteSize; if (data.length > byteSize && !isDsd) { // For safety, if SSD is too big, assume it's a mis-named DSD. @@ -90,6 +91,7 @@ export function BaseDisc(fdc, name, data, flusher) { this.fdc = fdc; this.name = name; this.isDsd = isDsd; + this.sectorsPerTrack = sectorsPerTrack; this.flusher = flusher; this.data = data; this.byteWithinSector = 0; @@ -146,7 +148,7 @@ export function BaseDisc(fdc, name, data, flusher) { case 6: this.fdc.discFinishRead(); this.rsector++; - if (this.rsector === 10) this.rsector = 0; + if (this.rsector === this.sectorsPerTrack) this.rsector = 0; return; } this.byteWithinSector++; @@ -161,7 +163,7 @@ export function BaseDisc(fdc, name, data, flusher) { if (++this.byteWithinSector === 256) { this.byteWithinSector = 0; this.sectorOffset += 256; - if (++this.formatSector === 10) { + if (++this.formatSector === this.sectorsPerTrack) { this.fdc.discFinishRead(); this.flush(); return; @@ -174,49 +176,49 @@ export function BaseDisc(fdc, name, data, flusher) { if (this.flusher) this.flusher(); }; BaseDisc.prototype.seek = (track) => { - this.seekOffset = track * 10 * 256; + this.seekOffset = track * this.sectorsPerTrack * 256; if (this.isDsd) this.seekOffset <<= 1; const oldTrack = this.track; this.track = track; return this.track - oldTrack; }; - BaseDisc.prototype.check = (track, side, density) => { - if (this.track !== track || density || (side && !this.isDsd)) { + BaseDisc.prototype.check = (track, side) => { + if (this.track !== track || (side && !this.isDsd)) { this.notFoundTask.reschedule(500 * DiscTimeSlice); return false; } return true; }; - BaseDisc.prototype.read = (sector, track, side, density) => { - if (!this.check(track, side, density)) return; + BaseDisc.prototype.read = (sector, track, side) => { + if (!this.check(track, side)) return; this.side = side; this.readTask.reschedule(DiscTimeSlice); - this.sectorOffset = sector * 256 + (side ? 10 * 256 : 0); + this.sectorOffset = sector * 256 + (side ? this.sectorsPerTrack * 256 : 0); this.byteWithinSector = 0; }; - BaseDisc.prototype.write = (sector, track, side, density) => { - if (!this.check(track, side, density)) return; + BaseDisc.prototype.write = (sector, track, side) => { + if (!this.check(track, side)) return; this.side = side; // NB in old code this used to override "time" to be -1000, which immediately forced a write. // I'm not sure why that was required. So I'm ignoring it here. Any funny disc write bugs might be // traceable to this change. this.writeTask.reschedule(DiscTimeSlice); - this.sectorOffset = sector * 256 + (side ? 10 * 256 : 0); + this.sectorOffset = sector * 256 + (side ? this.sectorsPerTrack * 256 : 0); this.byteWithinSector = 0; }; - BaseDisc.prototype.address = (track, side, density) => { - if (!this.check(track, side, density)) return; + BaseDisc.prototype.address = (track, side) => { + if (!this.check(track, side)) return; this.side = side; this.readAddrTask.reschedule(DiscTimeSlice); this.byteWithinSector = 0; this.rsector = 0; }; - BaseDisc.prototype.format = (track, side, density) => { - if (!this.check(track, side, density)) return; + BaseDisc.prototype.format = (track, side) => { + if (!this.check(track, side)) return; this.side = side; this.formatTask.reschedule(DiscTimeSlice); this.formatSector = 0; - this.sectorOffset = side ? 10 * 256 : 0; + this.sectorOffset = side ? this.sectorsPerTrack * 256 : 0; this.byteWithinSector = 0; }; } diff --git a/index.html b/index.html index 85613e89..2cd532b7 100644 --- a/index.html +++ b/index.html @@ -78,6 +78,10 @@
  • From Google Drive
  • +
    +
  • + Download drive 0 image +
  • - To load a custom disc image, get an SSD or DSD file and load it below. Search the web, or check somewhere - like + To load a custom disc image, get an SSD, DSD or ADL file and load it below. Search the web, or check + somewhere like here for these. Be aware the images are usually stored in a ZIP file, and you'll need to unzip first.
    diff --git a/main.js b/main.js index c25def29..f99f6385 100644 --- a/main.js +++ b/main.js @@ -1103,6 +1103,19 @@ $("#google-drive form").on("submit", function (e) { ); }); +$("#download-drive-link").on("click", function () { + var a = document.createElement("a"); + document.body.appendChild(a); + a.style = "display: none"; + + var blob = new Blob([processor.fdc.drives[0].data], { type: "application/octet-stream" }), + url = window.URL.createObjectURL(blob); + a.href = url; + a.download = processor.fdc.drives[0].name; + a.click(); + window.URL.revokeObjectURL(url); +}); + $("#hard-reset").click(function (event) { processor.reset(true); event.preventDefault(); diff --git a/models.js b/models.js index c95fbe87..e7bc502a 100644 --- a/models.js +++ b/models.js @@ -70,7 +70,7 @@ export const allModels = [ false ), new Model( - "BBC B with Teletext", + "BBC B (with Teletext)", ["BTeletext"], ["os.rom", "BASIC.ROM", "b/DFS-0.9.rom", "ats-3.0.rom"], true, @@ -81,7 +81,7 @@ export const allModels = [ true ), new Model( - "BBC B with Music 5000", + "BBC B (with Music 5000)", ["BMusic5000"], ["os.rom", "BASIC.ROM", "b/DFS-0.9.rom", "ample.rom"], true, diff --git a/utils.js b/utils.js index 2a18a4f7..541e7332 100644 --- a/utils.js +++ b/utils.js @@ -1025,6 +1025,7 @@ var knownDiscExtensions = { uef: true, ssd: true, dsd: true, + adl: true, }; var knownRomExtensions = { @@ -1078,13 +1079,21 @@ export function discImageSize(name) { // - 10 sectors per track. // - 256 bytes per sector. var isDsd = false; + var isDoubleDensity = false; var byteSize = 80 * 10 * 256; // DSD, aka. double-sided disc is twice the size. if (name.toLowerCase().endsWith(".dsd")) { byteSize *= 2; isDsd = true; } - return { isDsd: isDsd, byteSize: byteSize }; + if (name.toLowerCase().endsWith(".adl")) { + // ADFS (Large) disks are: + // double density, double sided, 80 track, 16 sectors per track, 256 bytes per sector (640K) + byteSize = 2 * 80 * 16 * 256; + isDsd = true; + isDoubleDensity = true; + } + return { isDsd: isDsd, isDoubleDensity: isDoubleDensity, byteSize: byteSize }; } export function setDiscName(data, name) {