Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for DVK MX format and --scale option #1

Merged
merged 1 commit into from
Feb 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/BitstreamDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ void scan_flux_mfm_fm (TrackData &trackdata, DataRate last_datarate);
void scan_flux_amiga (TrackData &trackdata);
void scan_flux_gcr (TrackData &trackdata);
void scan_flux_ace (TrackData &trackdata);
void scan_flux_mx (TrackData &trackdata);

void scan_bitstream (TrackData &trackdata);
void scan_bitstream_mfm_fm (TrackData &trackdata);
void scan_bitstream_amiga (TrackData &trackdata);
void scan_bitstream_ace (TrackData &trackdata);
void scan_bitstream_gcr (TrackData &trackdata);
void scan_bitstream_mx (TrackData &trackdata);

#endif // BITSTREAM_DECODER_H
2 changes: 1 addition & 1 deletion include/Header.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define HEADER_H

enum class DataRate : int { Unknown = 0, _250K = 250'000, _300K = 300'000, _500K = 500'000, _1M = 1'000'000 };
enum class Encoding { Unknown, MFM, FM, Amiga, GCR, Ace };
enum class Encoding { Unknown, MFM, FM, Amiga, GCR, Ace, MX };

std::string to_string (const DataRate &datarate);
std::string to_string (const Encoding &encoding);
Expand Down
4 changes: 2 additions & 2 deletions include/SAMdisk.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,8 @@ typedef struct
int offsets = -1, absoffsets = 0, nowrite = 0, nodiff = 0, noformat = 0, nodups = 0, rpm = 0, flip = 0;
int base = -1, size = -1, gap3 = -1, interleave = -1, skew = -1, fill = -1, fm = -1, head0 = -1, head1 = -1;
int maxcopies = 3, fmoverlap = 0, multiformat = 0, cylsfirst = -1;
int bdos = 0, atom = 0, hdf = 0, cpm = 0, resize = 0, nocfa = 0, noidentify = 0, ace = 0;
int force = 0, nosig = 0, check8k = -1, tty = 0, nodata = 0, noflux = 0, nowobble = 0;
int bdos = 0, atom = 0, hdf = 0, cpm = 0, resize = 0, nocfa = 0, noidentify = 0, ace = 0, mx = 0;
int force = 0, nosig = 0, check8k = -1, tty = 0, nodata = 0, noflux = 0, nowobble = 0, scale = 100;
int time = 0, rate = -1, mt = -1;
long sectors = -1;
std::string label {}, boot {};
Expand Down
112 changes: 112 additions & 0 deletions src/BitstreamDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ void scan_flux (TrackData &trackdata)
return;
}

if (opt.mx)
{
scan_flux_mx(trackdata);
return;
}

// Set the encoding scanning order, with the last successful encoding first (and its duplicate removed)
std::vector<Encoding> encodings = { last_encoding, Encoding::MFM, Encoding::Amiga/*, Encoding::GCR*/ };
encodings.erase(std::next(std::find(encodings.rbegin(), encodings.rend(), last_encoding)).base());
Expand Down Expand Up @@ -107,6 +113,12 @@ void scan_bitstream (TrackData &trackdata)
return;
}

if (opt.mx)
{
scan_bitstream_mx(trackdata);
return;
}

// Set the encoding scanning order, with the last successful encoding first (and its duplicate removed)
std::vector<Encoding> encodings = { last_encoding, Encoding::MFM, Encoding::Amiga/*, Encoding::GCR*/ };
encodings.erase(std::next(std::find(encodings.rbegin(), encodings.rend(), last_encoding)).base());
Expand Down Expand Up @@ -374,6 +386,106 @@ void scan_flux_ace (TrackData &trackdata)
}


/*
* DVK MX format. DVK was a family of DEC LSI-11 compatible computers
* produced by Soviet Union in 1980's, MX.SYS is the RT-11 driver name
* for the controller.
*
* FM encoding. Track format is driver-dependent (except the sync word).
* Hardware always reads or writes entire track, hence no sector headers.
*
* 1. gap1 (8 words)
* 2. sync (1 word, 000363 octal, regular FM encoding)
* 3. zero-based track number (1 word)
* 4. 11 sectors:
* data (128 words)
* checksum (1 word)
* 5. extra (1..4 words)
* 6. gap4 (or unformatted)
*
* See also http://torlus.com/floppy/forum/viewtopic.php?f=19&t=1384
*/

void scan_bitstream_mx (TrackData &trackdata)
{
Track track;
Data block;
uint64_t dword = 0;
uint16_t stored_cksum = 0, cksum = 0;

auto &bitbuf = trackdata.bitstream();
bitbuf.seek(0);
bitbuf.encoding = Encoding::FM;
track.tracklen = bitbuf.track_bitsize();
bool sync = false;

while (!bitbuf.wrapped())
{
// Give up if no headers were found in the first revolution
if (!track.size() && bitbuf.tell() > track.tracklen)
break;

// ignore sync sequences after first one
if (sync)
break;

dword = (dword << 1) | bitbuf.read1();
if (opt.debug)
util::cout << util::fmt (" s_b_mx %016lx c:h %d:%d\n", dword, trackdata.cylhead.cyl, trackdata.cylhead.head);

switch (dword)
{
case 0x88888888aaaa88aa: // FM-encoded 0x00f3 (000363 octal)
sync = true;
if (opt.debug) util::cout << " s_b_mx found sync at " << bitbuf.tell() << "\n";
break;

default:
continue;
}

// skip track number
bitbuf.read_byte();
bitbuf.read_byte();

// read sectors
for (auto s = 0; s < 11; s++) {
Sector sector(DataRate::_250K, Encoding::MX, Header(trackdata.cylhead, s, SizeToCode(256)));

block.clear();
cksum = 0;

for (auto i = 0; i < 128; i++) {
auto msb = bitbuf.read_byte();
auto lsb = bitbuf.read_byte();
cksum += (lsb | (msb << 8));
block.push_back(lsb);
block.push_back(msb);
}

stored_cksum = bitbuf.read_byte() << 8;
stored_cksum |= bitbuf.read_byte();

if (opt.debug) util::cout << util::fmt ("cksum s %d disk:calc %06o:%06o (%04x:%04x)\n",
s, stored_cksum, cksum, stored_cksum, cksum);

sector.add(std::move(block), cksum != stored_cksum, 0);
track.add(std::move(sector));
}
}

trackdata.add(std::move(track));
}

void scan_flux_mx (TrackData &trackdata)
{
FluxDecoder decoder(trackdata.flux(), ::bitcell_ns(DataRate::_250K), opt.scale);
BitBuffer bitbuf(DataRate::_250K, decoder);

trackdata.add(std::move(bitbuf));
}


#define MFM_MASK 0x55555555UL

static bool amiga_read_dwords (BitBuffer &bitbuf, uint32_t *pdw, size_t dwords, uint32_t &checksum)
Expand Down
2 changes: 2 additions & 0 deletions src/Header.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ std::string to_string (const Encoding &encoding)
case Encoding::GCR: return "GCR"; break;
case Encoding::Amiga: return "Amiga"; break;
case Encoding::Ace: return "Ace"; break;
case Encoding::MX: return "MX"; break;
case Encoding::Unknown: break;
}
return "Unknown";
Expand All @@ -37,6 +38,7 @@ std::string short_name (const Encoding &encoding)
case Encoding::GCR: return "gcr"; break;
case Encoding::Amiga: return "ami"; break;
case Encoding::Ace: return "ace"; break;
case Encoding::MX: return "mx"; break;
case Encoding::Unknown: break;
}
return "unk";
Expand Down
5 changes: 4 additions & 1 deletion src/SAMdisk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ extern "C" {
#include "getopt_long.h"
}

enum { OPT_RPM = 256, OPT_RATE, OPT_LOG, OPT_VERSION, OPT_HEAD0, OPT_HEAD1, OPT_GAPMASK, OPT_MAXCOPIES, OPT_MAXSPLICE, OPT_CHECK8K, OPT_BYTES, OPT_HDF, OPT_ORDER };
enum { OPT_RPM = 256, OPT_RATE, OPT_LOG, OPT_VERSION, OPT_HEAD0, OPT_HEAD1, OPT_GAPMASK, OPT_MAXCOPIES, OPT_MAXSPLICE, OPT_CHECK8K, OPT_BYTES, OPT_HDF, OPT_ORDER, OPT_SCALE };

struct option long_options[] =
{
Expand Down Expand Up @@ -151,6 +151,7 @@ struct option long_options[] =
{ "byte-swap", no_argument, &opt.byteswap, 1 },
{ "atom", no_argument, &opt.byteswap, 1 },
{ "ace", no_argument, &opt.ace, 1 },
{ "mx", no_argument, &opt.mx, 1 },
{ "quick", no_argument, &opt.quick, 1 },
{ "repair", no_argument, &opt.repair, 1},
{ "fix", no_argument, &opt.fix, 1 },
Expand Down Expand Up @@ -181,6 +182,7 @@ struct option long_options[] =
{ "hdf", required_argument, nullptr, OPT_HDF },
{ "order", required_argument, nullptr, OPT_ORDER },
{ "version", no_argument, nullptr, OPT_VERSION },
{ "scale", required_argument, nullptr, OPT_SCALE },

{ 0, 0, 0, 0 }
};
Expand Down Expand Up @@ -303,6 +305,7 @@ bool ParseCommandLine (int argc_, char *argv_[])
case OPT_RPM: if (!GetInt(optarg, opt.rpm) || (opt.rpm != 300 && opt.rpm != 360)) return BadValue("rpm"); break;
case OPT_BYTES: if (!GetInt(optarg, opt.bytes) || !opt.bytes) return BadValue("bytes"); break;
case OPT_HDF: if (!GetInt(optarg, opt.hdf) || (opt.hdf != 10 && opt.hdf != 11)) return BadValue("hdf"); break;
case OPT_SCALE: if (!GetInt(optarg, opt.scale)) return BadValue("scale"); break;

case OPT_VERSION:
Version();
Expand Down