From 26bf6638a994a9fd5d4c980575d1a7e0c018a51f Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Mon, 15 Feb 2021 23:43:32 +0100 Subject: woz: Add write some formats: Correct setting up of form factor and variant --- src/lib/formats/ap2_dsk.cpp | 146 ++++++++++++++++++++++++++++++++++++++++- src/lib/formats/ap2_dsk.h | 3 + src/lib/formats/flopimg.cpp | 15 +++++ src/lib/formats/flopimg.h | 5 ++ src/lib/formats/mfi_dsk.cpp | 2 +- src/lib/formats/upd765_dsk.cpp | 2 +- src/lib/formats/wd177x_dsk.cpp | 2 +- 7 files changed, 170 insertions(+), 5 deletions(-) diff --git a/src/lib/formats/ap2_dsk.cpp b/src/lib/formats/ap2_dsk.cpp index 3af006fcfc7..082c263c569 100644 --- a/src/lib/formats/ap2_dsk.cpp +++ b/src/lib/formats/ap2_dsk.cpp @@ -578,6 +578,8 @@ bool a2_16sect_format::load(io_generic *io, uint32_t form_factor, const std::vec { uint64_t size = io_generic_size(io); + image->set_form_variant(floppy_image::FF_525, floppy_image::SSSD); + m_prodos_order = false; m_tracks = (size == (40 * 16 * 256)) ? 40 : 35; @@ -768,6 +770,9 @@ bool a2_16sect_format::save(io_generic *io, const std::vector &variant } image->get_actual_geometry(g_tracks, g_heads); + if(!m_tracks) + m_tracks = g_tracks; + int head = 0; int pos_data = 0; @@ -1586,6 +1591,9 @@ bool a2_edd_format::load(io_generic *io, uint32_t form_factor, const std::vector image->set_write_splice_position(i >> 2, 0, uint32_t(uint64_t(200'000'000)*splice/len), i & 3); } free(img); + + image->set_form_variant(floppy_image::FF_525, floppy_image::SSSD); + return true; } @@ -1613,7 +1621,7 @@ const char *a2_woz_format::extensions() const bool a2_woz_format::supports_save() const { - return false; + return true; } const uint8_t a2_woz_format::signature[8] = { 0x57, 0x4f, 0x5a, 0x31, 0xff, 0x0a, 0x0d, 0x0a }; @@ -1664,7 +1672,13 @@ bool a2_woz_format::load(io_generic *io, uint32_t form_factor, const std::vector unsigned int limit = is_35 ? 160 : 141; + if(is_35) + image->set_form_variant(floppy_image::FF_35, floppy_image::SSDD); + else + image->set_form_variant(floppy_image::FF_525, floppy_image::SSSD); + if (woz_vers == 1) { + for (unsigned int trkid = 0; trkid != limit; trkid++) { int head = is_35 && trkid >= 80 ? 1 : 0; int track = is_35 ? trkid % 80 : trkid / 4; @@ -1676,6 +1690,8 @@ bool a2_woz_format::load(io_generic *io, uint32_t form_factor, const std::vector if (r16(img, boff + 6648) == 0) return false; generate_track_from_bitstream(track, head, &img[boff], r16(img, boff + 6648), image, subtrack, r16(img, boff + 6650)); + if(is_35 && !track && head) + image->set_variant(floppy_image::DSDD); } } } else if (woz_vers == 2) { @@ -1693,8 +1709,10 @@ bool a2_woz_format::load(io_generic *io, uint32_t form_factor, const std::vector if (r32(img, trks_off + 4) == 0) return false; - // TODO: when write capability is added, use the WRIT chunk data if it's present generate_track_from_bitstream(track, head, &img[boff], r32(img, trks_off + 4), image, subtrack, 0xffff); + + if(is_35 && !track && head) + image->set_variant(r32(img, trks_off + 4) >= 90000 ? floppy_image::DSHD : floppy_image::DSDD); } } } @@ -1703,6 +1721,113 @@ bool a2_woz_format::load(io_generic *io, uint32_t form_factor, const std::vector return true; } +bool a2_woz_format::save(io_generic *io, const std::vector &variants, floppy_image *image) +{ + std::vector> tracks(160); + bool twosided = false; + + if(image->get_form_factor() == floppy_image::FF_525) { + for(unsigned int i=0; i != 160; i++) + if(image->track_is_formatted(i >> 2, 0, i & 3)) + tracks[i] = generate_bitstream_from_track(i >> 2, 0, 3915, image, i & 3); + + } else if(image->get_variant() == floppy_image::DSHD) { + for(unsigned int i=0; i != 160; i++) + if(image->track_is_formatted(i >> 1, i & 1)) { + tracks[i] = generate_bitstream_from_track(i >> 1, i & 1, 1000, image); + if(i & 1) + twosided = true; + } + + } else { + // 200000000 / 60.0 * 1.979e-6 ~= 6.5967 + static const int cell_size_per_speed_zone[5] = { + 394 * 65967 / 10000, + 429 * 65967 / 10000, + 472 * 65967 / 10000, + 525 * 65967 / 10000, + 590 * 65967 / 10000 + }; + + for(unsigned int i=0; i != 160; i++) + if(image->track_is_formatted(i >> 1, i & 1)) { + tracks[i] = generate_bitstream_from_track(i >> 1, i & 1, cell_size_per_speed_zone[i / (2*16)], image); + if(i & 1) + twosided = true; + } + } + + int max_blocks = 0; + int total_blocks = 0; + for(const auto &t : tracks) { + int blocks = (t.size() + 4095) / 4096; + total_blocks += blocks; + if(max_blocks < blocks) + max_blocks = blocks; + } + + std::vector data(1536 + total_blocks*512, 0); + + memcpy(&data[0], signature2, 8); + + w32(data, 12, 0x4F464E49); // INFO + w32(data, 16, 60); // size + data[20] = 2; // chunk version + data[21] = image->get_form_factor() == floppy_image::FF_525 ? 1 : 2; + data[22] = 0; // not write protected + data[23] = 1; // synchronized, since our internal format is + data[24] = 1; // weak bits are generated, not stored + data[25] = 'M'; + data[26] = 'A'; + data[27] = 'M'; + data[28] = 'E'; + memset(&data[29], ' ', 32-4); + data[57] = twosided ? 2 : 1; + data[58] = 0; // boot sector unknown + data[59] = image->get_form_factor() == floppy_image::FF_525 ? 32 : image->get_variant() == floppy_image::DSHD ? 8 : 16; + w16(data, 60, 0); // compatibility unknown + w16(data, 62, 0); // needed ram unknown + w16(data, 64, max_blocks); + w32(data, 80, 0x50414D54); // TMAP + w32(data, 84, 160); // size + + uint8_t tcount = 0; + for(int i=0; i != 160 ; i++) + data[88 + i] = tracks[i].empty() ? 0xff : tcount++; + + w32(data, 248, 0x534B5254); // TRKS + w32(data, 252, 8*tcount); // size + + uint8_t tid = 0; + uint16_t tb = 3; + for(int i=0; i != 160 ; i++) + if(!tracks[i].empty()) { + int blocks = (tracks[i].size() + 4095) / 4096; + w16(data, 256 + tid*8, tb); + w16(data, 256 + tid*8 + 2, blocks); + w32(data, 256 + tid*8 + 4, tracks[i].size()); + tb += blocks; + tid ++; + } + + tb = 3; + for(int i=0; i != 160 ; i++) + if(!tracks[i].empty()) { + int off = tb * 512; + int size = tracks[i].size(); + for(int j=0; j != size; j++) + if(tracks[i][j]) + data[off + (j >> 3)] |= 0x80 >> (j & 7); + tb += (size + 4095) / 4096; + } + + w32(data, 8, crc32r(&data[12], data.size() - 12)); + + io_generic_write(io, data.data(), 0, data.size()); + return true; +} + + uint32_t a2_woz_format::find_tag(const std::vector &data, uint32_t tag) { uint32_t offset = 12; @@ -1729,6 +1854,20 @@ uint8_t a2_woz_format::r8(const std::vector &data, uint32_t offset) return data[offset]; } +void a2_woz_format::w32(std::vector &data, int offset, uint32_t value) +{ + data[offset] = value; + data[offset+1] = value >> 8; + data[offset+2] = value >> 16; + data[offset+3] = value >> 24; +} + +void a2_woz_format::w16(std::vector &data, int offset, uint16_t value) +{ + data[offset] = value; + data[offset+1] = value >> 8; +} + uint32_t a2_woz_format::crc32r(const uint8_t *data, uint32_t size) { // Reversed crc32 @@ -1909,6 +2048,9 @@ bool a2_nib_format::load(io_generic *io, uint32_t form_factor, const std::vector levels, 0, image); } + + image->set_form_variant(floppy_image::FF_525, floppy_image::SSSD); + return true; } diff --git a/src/lib/formats/ap2_dsk.h b/src/lib/formats/ap2_dsk.h index 15b41503ce9..7420d72d818 100644 --- a/src/lib/formats/ap2_dsk.h +++ b/src/lib/formats/ap2_dsk.h @@ -113,6 +113,7 @@ public: virtual int identify(io_generic *io, uint32_t form_factor, const std::vector &variants) override; virtual bool load(io_generic *io, uint32_t form_factor, const std::vector &variants, floppy_image *image) override; + virtual bool save(io_generic *io, const std::vector &variants, floppy_image *image) override; virtual bool supports_save() const override; virtual const char *name() const override; @@ -126,6 +127,8 @@ private: static uint32_t r32(const std::vector &data, uint32_t offset); static uint16_t r16(const std::vector &data, uint32_t offset); static uint8_t r8(const std::vector &data, uint32_t offset); + static void w32(std::vector &data, int offset, uint32_t value); + static void w16(std::vector &data, int offset, uint16_t value); static uint32_t crc32r(const uint8_t *data, uint32_t size); static uint32_t find_tag(const std::vector &data, uint32_t tag); }; diff --git a/src/lib/formats/flopimg.cpp b/src/lib/formats/flopimg.cpp index cb8d6ca1300..595332571ec 100644 --- a/src/lib/formats/flopimg.cpp +++ b/src/lib/formats/flopimg.cpp @@ -955,6 +955,21 @@ int floppy_image::get_resolution() const return 0; } +bool floppy_image::track_is_formatted(int track, int head, int subtrack) +{ + int idx = track*4 + subtrack; + if(int(track_array.size()) <= idx) + return false; + if(int(track_array[idx].size()) <= head) + return false; + const auto &data = track_array[idx][head].cell_data; + if(data.empty()) + return false; + if(data.size() == 1 && (data[0] & MG_MASK) == MG_N) + return false; + return true; +} + const char *floppy_image::get_variant_name(uint32_t form_factor, uint32_t variant) { switch(variant) { diff --git a/src/lib/formats/flopimg.h b/src/lib/formats/flopimg.h index a471167dbfe..661ce4b2ac5 100644 --- a/src/lib/formats/flopimg.h +++ b/src/lib/formats/flopimg.h @@ -750,6 +750,8 @@ public: uint32_t get_variant() const { return variant; } //! @param v the variant. void set_variant(uint32_t v) { variant = v; } + //! @param v the variant. + void set_form_variant(uint32_t f, uint32_t v) { if(form_factor == FF_UNKNOWN) form_factor = f, variant = v; } /*! @param track @@ -783,6 +785,9 @@ public: //! @return the track resolution (0=full track, 1 = half-track, 2 = quarter track) int get_resolution() const; + //! @return whether a given track is formatted + bool track_is_formatted(int track, int head, int subtrack = 0); + //! Returns the variant name for the particular disk form factor/variant //! @param form_factor //! @param variant diff --git a/src/lib/formats/mfi_dsk.cpp b/src/lib/formats/mfi_dsk.cpp index dc6c320042f..df60e5aeec0 100644 --- a/src/lib/formats/mfi_dsk.cpp +++ b/src/lib/formats/mfi_dsk.cpp @@ -117,7 +117,7 @@ bool mfi_format::load(io_generic *io, uint32_t form_factor, const std::vectorset_variant(h.variant); + image->set_form_variant(h.form_factor, h.variant); std::vector compressed; diff --git a/src/lib/formats/upd765_dsk.cpp b/src/lib/formats/upd765_dsk.cpp index ce17bd1c4f2..0538dc58010 100644 --- a/src/lib/formats/upd765_dsk.cpp +++ b/src/lib/formats/upd765_dsk.cpp @@ -224,7 +224,7 @@ bool upd765_format::load(io_generic *io, uint32_t form_factor, const std::vector generate_track(desc, track, head, sectors, f.sector_count, total_size, image); } - image->set_variant(f.variant); + image->set_form_variant(f.form_factor, f.variant); return true; } diff --git a/src/lib/formats/wd177x_dsk.cpp b/src/lib/formats/wd177x_dsk.cpp index 5a83da6a473..e89fe9b3f6e 100644 --- a/src/lib/formats/wd177x_dsk.cpp +++ b/src/lib/formats/wd177x_dsk.cpp @@ -247,7 +247,7 @@ bool wd177x_format::load(io_generic *io, uint32_t form_factor, const std::vector generate_track(desc, track, head, sectors, tf.sector_count, total_size, image); } - image->set_variant(f.variant); + image->set_form_variant(f.form_factor, f.variant); return true; } -- cgit v1.2.3