summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/img_dsk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/formats/img_dsk.cpp')
-rw-r--r--src/lib/formats/img_dsk.cpp250
1 files changed, 154 insertions, 96 deletions
diff --git a/src/lib/formats/img_dsk.cpp b/src/lib/formats/img_dsk.cpp
index 5921130003f..66e097c281e 100644
--- a/src/lib/formats/img_dsk.cpp
+++ b/src/lib/formats/img_dsk.cpp
@@ -6,24 +6,29 @@
"IMG" disk format
- This format is just a raw image of every sector on SSDD 8" floppy
- disks as used in Intel MDS-II systems.
+ This format is just a raw image of every sector on SSDD & SSSD 8"
+ floppy disks as used in Intel MDS-II systems.
Files with this format have no header/trailer and are exactly
512512 bytes in size (52 sectors, 1 head, 77 tracks,
- 128 bytes per sector).
+ 128 bytes per sector) for SSDD format or 256256 bytes (26 sectors,
+ 1 head, 77 tracks, 128 bytes per sector) for SSSD format
*********************************************************************/
#include "img_dsk.h"
#include "coretmpl.h" // BIT
+#include "ioprocs.h"
+
+#include "osdcore.h" // osd_printf_*
// Debugging
#define VERBOSE 0
#define LOG(...) do { if (VERBOSE) osd_printf_info(__VA_ARGS__); } while (false)
-constexpr unsigned CELL_SIZE = 1200; // Bit cell size (1 µs)
+constexpr unsigned CELL_SIZE = 1200; // Bit cell size of MMFM format (1 µs)
+constexpr unsigned CELL_SIZE_FM = 2400; // Bit cell size of FM format (2 µs)
constexpr uint8_t INDEX_AM = 0x0c; // Index address mark
constexpr uint8_t ID_AM = 0x0e; // ID address mark
constexpr uint8_t DATA_AM = 0x0b; // Data address mark
@@ -32,146 +37,197 @@ constexpr unsigned PREIDX_GAP = 45; // Size of pre-index gap
constexpr unsigned SYNC_00_LEN = 18; // 00's in sync (gaps 1, 2, 3)
constexpr unsigned SYNC_FF_LEN = 10; // FF's in sync (gaps 1, 2, 3)
constexpr int ID_DATA_OFFSET = 35 * 16; // Nominal distance (in cells) between ID & DATA AM
-// Size of image file
+// Size of image file (SSDD)
constexpr unsigned IMG_IMAGE_SIZE = img_format::TRACKS * img_format::HEADS * img_format::SECTORS * img_format::SECTOR_SIZE;
+// Size of image file (SSSD)
+constexpr unsigned IMG_IMAGE_SIZE_FM = img_format::TRACKS * img_format::HEADS * img_format::SECTORS_FM * img_format::SECTOR_SIZE;
constexpr uint16_t CRC_POLY = 0x1021; // CRC-CCITT
img_format::img_format()
{
}
-int img_format::identify(io_generic *io, uint32_t form_factor)
+int img_format::identify(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants) const
{
- uint64_t size = io_generic_size(io);
+ uint64_t size;
+ if (io.length(size)) {
+ return 0;
+ }
if (((form_factor == floppy_image::FF_8) || (form_factor == floppy_image::FF_UNKNOWN)) &&
- size == IMG_IMAGE_SIZE) {
- return 50;
+ (size == IMG_IMAGE_SIZE || size == IMG_IMAGE_SIZE_FM)) {
+ return FIFID_SIZE;
} else {
return 0;
}
}
-bool img_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
+bool img_format::load(util::random_read &io, uint32_t form_factor, const std::vector<uint32_t> &variants, floppy_image &image) const
{
- uint64_t size = io_generic_size(io);
- if (size != IMG_IMAGE_SIZE) {
+ uint64_t size;
+ if (io.length(size) || (size != IMG_IMAGE_SIZE && size != IMG_IMAGE_SIZE_FM)) {
return false;
}
- image->set_variant(floppy_image::SSDD);
+ bool is_dd = size == IMG_IMAGE_SIZE;
+ image.set_variant(is_dd ? floppy_image::SSDD : floppy_image::SSSD);
// Suck in the whole image
- std::vector<uint8_t> image_data(size);
- io_generic_read(io, (void *)image_data.data(), 0, size);
+ auto const [err, image_data, actual] = read_at(io, 0, size);
+ if (err || (actual != size)) {
+ return false;
+ }
for (unsigned cyl = 0; cyl < TRACKS; cyl++) {
- std::vector<uint32_t> track_data;
-
- write_gap(track_data, 0 , PREIDX_GAP);
- write_mmfm_byte(track_data , INDEX_AM , AM_CLOCK);
-
- // Compute interleave factor and skew for current track
- unsigned il_factor;
- unsigned skew;
- if (cyl == 0) {
- il_factor = 1;
- skew = 51;
- } else if (cyl == 1) {
- il_factor = 4;
- skew = 48;
- } else {
- il_factor = 5;
- skew = (47 + 45 * (cyl - 2)) % 52;
- }
- std::vector<uint8_t> sector_list = interleaved_sectors(il_factor);
+ if (is_dd) {
+ // SSDD (MMFM)
+ std::vector<uint32_t> track_data;
+
+ write_gap(track_data, 0 , PREIDX_GAP);
+ uint16_t crc = 0;
+ write_mmfm_byte(track_data , INDEX_AM , crc, AM_CLOCK);
+
+ // Compute interleave factor and skew for current track
+ unsigned il_factor;
+ unsigned skew;
+ if (cyl == 0) {
+ il_factor = 1;
+ skew = 51;
+ } else if (cyl == 1) {
+ il_factor = 4;
+ skew = 48;
+ } else {
+ il_factor = 5;
+ skew = (47 + 45 * (cyl - 2)) % 52;
+ }
+ std::vector<uint8_t> sector_list = interleaved_sectors(SECTORS, il_factor);
- for (unsigned sector = 0; sector < SECTORS; sector++) {
- unsigned real_sector = sector_list[ (sector + skew) % SECTORS ];
- unsigned offset_in_image = (real_sector - 1 + cyl * SECTORS) * SECTOR_SIZE;
- write_sector(track_data , cyl , real_sector , &image_data[ offset_in_image ]);
+ for (unsigned sector = 0; sector < SECTORS; sector++) {
+ unsigned real_sector = sector_list[ (sector + skew) % SECTORS ];
+ unsigned offset_in_image = (real_sector - 1 + cyl * SECTORS) * SECTOR_SIZE;
+ write_sector(track_data , cyl , real_sector , &image_data[ offset_in_image ]);
+ }
+ fill_with_gap4(track_data);
+ generate_track_from_levels(cyl , 0 , track_data , 0 , image);
+ } else {
+ // SSSD (FM)
+ // Compute interleave factor and skew for current track
+ unsigned il_factor;
+ unsigned skew;
+ if (cyl == 0) {
+ il_factor = 1;
+ skew = 25;
+ } else if (cyl == 1) {
+ il_factor = 12;
+ skew = 14;
+ } else {
+ il_factor = 6;
+ skew = (20 + 21 * (cyl - 2)) % 26;
+ }
+ std::vector<uint8_t> sector_list = interleaved_sectors(SECTORS_FM, il_factor);
+ desc_pc_sector sects[ SECTORS_FM ];
+ for (unsigned sector = 0; sector < SECTORS_FM; sector++) {
+ unsigned real_sector = sector_list[ (sector + skew) % SECTORS_FM ];
+ unsigned offset_in_image = (real_sector - 1 + cyl * SECTORS_FM) * SECTOR_SIZE;
+ sects[ sector ].actual_size = SECTOR_SIZE;
+ sects[ sector ].track = cyl;
+ sects[ sector ].head = 0;
+ sects[ sector ].size = 0;
+ sects[ sector ].sector = real_sector;
+ sects[ sector ].bad_crc = false;
+ sects[ sector ].deleted = false;
+ sects[ sector ].data = &image_data[offset_in_image];
+ }
+ build_pc_track_fm(cyl, 0, image, 83333, SECTORS_FM, sects, 33, 46, 32, 11);
}
- fill_with_gap4(track_data);
- generate_track_from_levels(cyl , 0 , track_data , 0 , image);
}
return true;
}
-bool img_format::save(io_generic *io, floppy_image *image)
+bool img_format::save(util::random_read_write &io, const std::vector<uint32_t> &variants, const floppy_image &image) const
{
+ bool is_dd = image.get_variant() == floppy_image::SSDD;
+
for (int cyl = 0; cyl < TRACKS; cyl++) {
- uint8_t bitstream[ 21000 ];
- int bitstream_size;
- generate_bitstream_from_track(cyl , 0 , CELL_SIZE , bitstream , bitstream_size , image , 0);
- int pos = 0;
- unsigned track_no , sector_no;
- uint8_t sector_data[ SECTOR_SIZE ];
- while (get_next_sector(bitstream , bitstream_size , pos , track_no , sector_no , sector_data)) {
- if (track_no == cyl && sector_no >= 1 && sector_no <= SECTORS) {
- unsigned offset_in_image = (cyl * SECTORS + sector_no - 1) * SECTOR_SIZE;
- io_generic_write(io, sector_data, offset_in_image, SECTOR_SIZE);
+ if (is_dd) {
+ auto bitstream = generate_bitstream_from_track(cyl , 0 , CELL_SIZE , image , 0);
+ int pos = 0;
+ unsigned track_no , sector_no;
+ uint8_t sector_data[ SECTOR_SIZE ];
+ while (get_next_sector(bitstream , pos , track_no , sector_no , sector_data)) {
+ if (track_no == cyl && sector_no >= 1 && sector_no <= SECTORS) {
+ unsigned offset_in_image = (cyl * SECTORS + sector_no - 1) * SECTOR_SIZE;
+ /*auto const [err, actual] =*/ write_at(io, offset_in_image, sector_data, SECTOR_SIZE); // FIXME: check for errors
+ }
+ }
+ } else {
+ auto bitstream = generate_bitstream_from_track(cyl , 0 , CELL_SIZE_FM , image , 0);
+ auto sects = extract_sectors_from_bitstream_fm_pc(bitstream);
+ for (unsigned s = 1; s <= SECTORS_FM; s++) {
+ unsigned offset_in_image = (cyl * SECTORS_FM + s - 1) * SECTOR_SIZE;
+ /*auto const [err, actual] =*/ write_at(io, offset_in_image, sects[ s ].data(), SECTOR_SIZE); // FIXME: check for errors and premature EOF
}
}
}
return true;
}
-const char *img_format::name() const
+const char *img_format::name() const noexcept
{
- return "img";
+ return "mds2";
}
-const char *img_format::description() const
+const char *img_format::description() const noexcept
{
return "MDS-II floppy disk image";
}
-const char *img_format::extensions() const
+const char *img_format::extensions() const noexcept
{
return "img";
}
-bool img_format::supports_save() const
+bool img_format::supports_save() const noexcept
{
return true;
}
-std::vector<uint8_t> img_format::interleaved_sectors(unsigned il_factor)
+std::vector<uint8_t> img_format::interleaved_sectors(unsigned sects, unsigned il_factor)
{
- std::vector<uint8_t> out(SECTORS);
+ std::vector<uint8_t> out(sects);
unsigned idx = 0;
- for (unsigned s = 0; s < SECTORS; s++) {
+ for (unsigned s = 0; s < sects; s++) {
while (out[ idx ] != 0) {
- if (++idx >= SECTORS) {
+ if (++idx >= sects) {
idx = 0;
}
}
out[ idx ] = s + 1;
idx += il_factor;
- if (idx >= SECTORS) {
- idx -= SECTORS;
+ if (idx >= sects) {
+ idx -= sects;
}
}
return out;
}
-void img_format::write_mmfm_bit(std::vector<uint32_t> &buffer , bool data_bit , bool clock_bit)
+void img_format::write_mmfm_bit(std::vector<uint32_t> &buffer , bool data_bit , bool clock_bit , uint16_t &crc)
{
bool had_transition = buffer.size() < 2 ? false : bit_r(buffer, buffer.size() - 1) || bit_r(buffer , buffer.size() - 2);
clock_bit = !data_bit && (clock_bit || !had_transition);
bit_w(buffer , clock_bit , CELL_SIZE);
bit_w(buffer , data_bit , CELL_SIZE);
- if (util::BIT(m_crc , 15) ^ data_bit) {
- m_crc = (m_crc << 1) ^ CRC_POLY;
+ if (util::BIT(crc , 15) ^ data_bit) {
+ crc = (crc << 1) ^ CRC_POLY;
} else {
- m_crc <<= 1;
+ crc <<= 1;
}
}
-void img_format::write_mmfm_byte(std::vector<uint32_t> &buffer , uint8_t data , uint8_t clock)
+void img_format::write_mmfm_byte(std::vector<uint32_t> &buffer , uint8_t data , uint16_t &crc , uint8_t clock)
{
for (int i = 7; i >= 0; i--) {
- write_mmfm_bit(buffer , util::BIT(data , i) , util::BIT(clock , i));
+ write_mmfm_bit(buffer , util::BIT(data , i) , util::BIT(clock , i) , crc);
}
}
@@ -182,19 +238,21 @@ void img_format::write_sync(std::vector<uint32_t> &buffer)
void img_format::write_crc(std::vector<uint32_t> &buffer , uint16_t crc)
{
+ uint16_t xcrc = crc;
// Note that CRC is stored with MSB (x^15) first
for (unsigned i = 0; i < 16; i++) {
- write_mmfm_bit(buffer , util::BIT(crc , 15 - i) , 0);
+ write_mmfm_bit(buffer , util::BIT(crc , 15 - i) , 0 , xcrc);
}
}
void img_format::write_gap(std::vector<uint32_t> &buffer , unsigned size_00 , unsigned size_ff)
{
+ uint16_t crc = 0;
for (unsigned i = 0; i < size_00; ++i) {
- write_mmfm_byte(buffer, 0);
+ write_mmfm_byte(buffer, 0 , crc);
}
for (unsigned i = 0; i < size_ff; ++i) {
- write_mmfm_byte(buffer, 0xff);
+ write_mmfm_byte(buffer, 0xff , crc);
}
}
@@ -222,27 +280,27 @@ void img_format::write_sector(std::vector<uint32_t> &buffer , uint8_t track_no ,
// Gap1
write_sync(buffer);
// ID AM
- m_crc = 0;
- write_mmfm_byte(buffer , ID_AM , AM_CLOCK);
+ uint16_t crc = 0;
+ write_mmfm_byte(buffer , ID_AM , crc , AM_CLOCK);
// Track #
- write_mmfm_byte(buffer , track_no);
- write_mmfm_byte(buffer , 0);
+ write_mmfm_byte(buffer , track_no , crc);
+ write_mmfm_byte(buffer , 0 , crc);
// Sector #
- write_mmfm_byte(buffer , sect_no);
- write_mmfm_byte(buffer , 0);
+ write_mmfm_byte(buffer , sect_no , crc);
+ write_mmfm_byte(buffer , 0 , crc);
// ID CRC
- write_crc(buffer , m_crc);
+ write_crc(buffer , crc);
// Gap 2
write_sync(buffer);
// Data AM
- m_crc = 0;
- write_mmfm_byte(buffer , DATA_AM , AM_CLOCK);
+ crc = 0;
+ write_mmfm_byte(buffer , DATA_AM , crc, AM_CLOCK);
for (unsigned i = 0; i < SECTOR_SIZE; i++) {
// Data
- write_mmfm_byte(buffer , sect_data[ i ]);
+ write_mmfm_byte(buffer , sect_data[ i ] , crc);
}
// Data CRC
- write_crc(buffer , m_crc);
+ write_crc(buffer , crc);
}
void img_format::fill_with_gap4(std::vector<uint32_t> &buffer)
@@ -260,7 +318,7 @@ void img_format::fill_with_gap4(std::vector<uint32_t> &buffer)
}
}
-std::vector<uint8_t> img_format::get_next_id_n_block(const uint8_t *bitstream , int bitstream_size , int& pos , int& start_pos)
+std::vector<uint8_t> img_format::get_next_id_n_block(const std::vector<bool> &bitstream , int& pos , int& start_pos)
{
std::vector<uint8_t> res;
uint8_t data_sr;
@@ -269,8 +327,8 @@ std::vector<uint8_t> img_format::get_next_id_n_block(const uint8_t *bitstream ,
// Look for either sync + ID AM or sync + DATA AM
do {
unsigned cnt_trans = 0;
- while (pos < bitstream_size && cnt_trans < 34) {
- bool bit = util::BIT(bitstream[ pos >> 3 ] , ~pos & 7);
+ while (pos < bitstream.size() && cnt_trans < 34) {
+ bool bit = bitstream[pos];
pos++;
if (cnt_trans < 32) {
if (!(util::BIT(cnt_trans , 0) ^ bit)) {
@@ -292,7 +350,7 @@ std::vector<uint8_t> img_format::get_next_id_n_block(const uint8_t *bitstream ,
}
}
- if (pos == bitstream_size) {
+ if (pos == bitstream.size()) {
// End of track reached
return res;
}
@@ -300,14 +358,14 @@ std::vector<uint8_t> img_format::get_next_id_n_block(const uint8_t *bitstream ,
// Get AM
data_sr = clock_sr = 0;
for (unsigned i = 0; i < 7; ++i) {
- bool bit = util::BIT(bitstream[ pos >> 3 ] , ~pos & 7);
+ bool bit = bitstream[pos];
pos++;
clock_sr = (clock_sr << 1) | bit;
- bit = util::BIT(bitstream[ pos >> 3 ] , ~pos & 7);
+ bit = bitstream[pos];
pos++;
data_sr = (data_sr << 1) | bit;
}
- if (pos >= bitstream_size) {
+ if (pos >= bitstream.size()) {
return res;
}
} while (clock_sr != AM_CLOCK);
@@ -325,11 +383,11 @@ std::vector<uint8_t> img_format::get_next_id_n_block(const uint8_t *bitstream ,
}
pos++;
- for (unsigned i = 0; i < to_dump && pos < bitstream_size; i++) {
+ for (unsigned i = 0; i < to_dump && pos < bitstream.size(); i++) {
data_sr = 0;
unsigned j;
- for (j = 0; j < 8 && pos < bitstream_size; j++) {
- bool bit = util::BIT(bitstream[ pos >> 3 ] , ~pos & 7);
+ for (j = 0; j < 8 && pos < bitstream.size(); j++) {
+ bool bit = bitstream[pos];
pos += 2;
data_sr = (data_sr << 1) | bit;
}
@@ -340,7 +398,7 @@ std::vector<uint8_t> img_format::get_next_id_n_block(const uint8_t *bitstream ,
return res;
}
-bool img_format::get_next_sector(const uint8_t *bitstream , int bitstream_size , int& pos , unsigned& track , unsigned& sector , uint8_t *sector_data)
+bool img_format::get_next_sector(const std::vector<bool> &bitstream , int& pos , unsigned& track , unsigned& sector , uint8_t *sector_data)
{
std::vector<uint8_t> block;
while (true) {
@@ -348,7 +406,7 @@ bool img_format::get_next_sector(const uint8_t *bitstream , int bitstream_size ,
int id_pos = 0;
while (true) {
if (block.size() == 0) {
- block = get_next_id_n_block(bitstream , bitstream_size , pos , id_pos);
+ block = get_next_id_n_block(bitstream , pos , id_pos);
if (block.size() == 0) {
return false;
}
@@ -363,7 +421,7 @@ bool img_format::get_next_sector(const uint8_t *bitstream , int bitstream_size ,
}
// Then for DATA block
int data_pos = 0;
- block = get_next_id_n_block(bitstream , bitstream_size , pos , data_pos);
+ block = get_next_id_n_block(bitstream , pos , data_pos);
if (block.size() == 0) {
return false;
}
@@ -377,4 +435,4 @@ bool img_format::get_next_sector(const uint8_t *bitstream , int bitstream_size ,
return true;
}
-const floppy_format_type FLOPPY_IMG_FORMAT = &floppy_image_format_creator<img_format>;
+const img_format FLOPPY_IMG_FORMAT;