mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
2
.github/workflows/ccpp.yml
vendored
2
.github/workflows/ccpp.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
run: |
|
||||
brew install sqlite pkg-config libusb protobuf wxwidgets fmt make coreutils dylibbundler libjpeg
|
||||
- name: make
|
||||
run: gmake -C fluxengine -j $(nprocs)
|
||||
run: gmake -C fluxengine -j2
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -97,7 +97,7 @@ jobs:
|
||||
|
||||
- name: make
|
||||
run: |
|
||||
gmake -j $(nprocs)
|
||||
gmake -j2
|
||||
mv FluxEngine.pkg FluxEngine-${{ runner.arch }}.pkg
|
||||
|
||||
- name: tag
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/core/utils.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "agat.h"
|
||||
#include "lib/core/crc.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "lib/data/layout.h"
|
||||
#include "arch/agat/agat.pb.h"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/core/utils.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "amiga.h"
|
||||
#include "lib/core/crc.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "arch/amiga/amiga.pb.h"
|
||||
#include "lib/encoders/encoders.pb.h"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/core/utils.h"
|
||||
#include "arch/apple2/apple2.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "fmt/format.h"
|
||||
#include "lib/encoders/encoders.pb.h"
|
||||
|
||||
97
arch/arch.cc
Normal file
97
arch/arch.cc
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/config/config.h"
|
||||
#include "arch/agat/agat.h"
|
||||
#include "arch/aeslanier/aeslanier.h"
|
||||
#include "arch/amiga/amiga.h"
|
||||
#include "arch/apple2/apple2.h"
|
||||
#include "arch/brother/brother.h"
|
||||
#include "arch/c64/c64.h"
|
||||
#include "arch/f85/f85.h"
|
||||
#include "arch/fb100/fb100.h"
|
||||
#include "arch/ibm/ibm.h"
|
||||
#include "arch/macintosh/macintosh.h"
|
||||
#include "arch/micropolis/micropolis.h"
|
||||
#include "arch/mx/mx.h"
|
||||
#include "arch/northstar/northstar.h"
|
||||
#include "arch/rolandd20/rolandd20.h"
|
||||
#include "arch/smaky6/smaky6.h"
|
||||
#include "arch/tartu/tartu.h"
|
||||
#include "arch/tids990/tids990.h"
|
||||
#include "arch/victor9k/victor9k.h"
|
||||
#include "arch/zilogmcz/zilogmcz.h"
|
||||
#include "arch/arch.h"
|
||||
|
||||
std::unique_ptr<Encoder> Arch::createEncoder(Config& config)
|
||||
{
|
||||
if (!config.hasEncoder())
|
||||
error("no encoder configured");
|
||||
return createEncoder(config->encoder());
|
||||
}
|
||||
|
||||
std::unique_ptr<Encoder> Arch::createEncoder(const EncoderProto& config)
|
||||
{
|
||||
static const std::map<int,
|
||||
std::function<std::unique_ptr<Encoder>(const EncoderProto&)>>
|
||||
encoders = {
|
||||
{EncoderProto::kAgat, createAgatEncoder },
|
||||
{EncoderProto::kAmiga, createAmigaEncoder },
|
||||
{EncoderProto::kApple2, createApple2Encoder },
|
||||
{EncoderProto::kBrother, createBrotherEncoder },
|
||||
{EncoderProto::kC64, createCommodore64Encoder},
|
||||
{EncoderProto::kIbm, createIbmEncoder },
|
||||
{EncoderProto::kMacintosh, createMacintoshEncoder },
|
||||
{EncoderProto::kMicropolis, createMicropolisEncoder },
|
||||
{EncoderProto::kNorthstar, createNorthstarEncoder },
|
||||
{EncoderProto::kTartu, createTartuEncoder },
|
||||
{EncoderProto::kTids990, createTids990Encoder },
|
||||
{EncoderProto::kVictor9K, createVictor9kEncoder },
|
||||
};
|
||||
|
||||
auto encoder = encoders.find(config.format_case());
|
||||
if (encoder == encoders.end())
|
||||
error("no encoder specified");
|
||||
|
||||
return (encoder->second)(config);
|
||||
}
|
||||
|
||||
std::unique_ptr<Decoder> Arch::createDecoder(Config& config)
|
||||
{
|
||||
if (!config.hasDecoder())
|
||||
error("no decoder configured");
|
||||
return createDecoder(config->decoder());
|
||||
}
|
||||
|
||||
std::unique_ptr<Decoder> Arch::createDecoder(const DecoderProto& config)
|
||||
{
|
||||
static const std::map<int,
|
||||
std::function<std::unique_ptr<Decoder>(const DecoderProto&)>>
|
||||
decoders = {
|
||||
{DecoderProto::kAgat, createAgatDecoder },
|
||||
{DecoderProto::kAeslanier, createAesLanierDecoder },
|
||||
{DecoderProto::kAmiga, createAmigaDecoder },
|
||||
{DecoderProto::kApple2, createApple2Decoder },
|
||||
{DecoderProto::kBrother, createBrotherDecoder },
|
||||
{DecoderProto::kC64, createCommodore64Decoder},
|
||||
{DecoderProto::kF85, createDurangoF85Decoder },
|
||||
{DecoderProto::kFb100, createFb100Decoder },
|
||||
{DecoderProto::kIbm, createIbmDecoder },
|
||||
{DecoderProto::kMacintosh, createMacintoshDecoder },
|
||||
{DecoderProto::kMicropolis, createMicropolisDecoder },
|
||||
{DecoderProto::kMx, createMxDecoder },
|
||||
{DecoderProto::kNorthstar, createNorthstarDecoder },
|
||||
{DecoderProto::kRolandd20, createRolandD20Decoder },
|
||||
{DecoderProto::kSmaky6, createSmaky6Decoder },
|
||||
{DecoderProto::kTartu, createTartuDecoder },
|
||||
{DecoderProto::kTids990, createTids990Decoder },
|
||||
{DecoderProto::kVictor9K, createVictor9kDecoder },
|
||||
{DecoderProto::kZilogmcz, createZilogMczDecoder },
|
||||
};
|
||||
|
||||
auto decoder = decoders.find(config.format_case());
|
||||
if (decoder == decoders.end())
|
||||
error("no decoder specified");
|
||||
|
||||
return (decoder->second)(config);
|
||||
}
|
||||
16
arch/arch.h
Normal file
16
arch/arch.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
class Encoder;
|
||||
class Decoder;
|
||||
class DecoderProto;
|
||||
class EncoderProto;
|
||||
class Config;
|
||||
|
||||
namespace Arch
|
||||
{
|
||||
std::unique_ptr<Decoder> createDecoder(Config& config);
|
||||
std::unique_ptr<Decoder> createDecoder(const DecoderProto& config);
|
||||
|
||||
std::unique_ptr<Encoder> createEncoder(Config& config);
|
||||
std::unique_ptr<Encoder> createEncoder(const EncoderProto& config);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/core/utils.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "brother.h"
|
||||
#include "lib/core/crc.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "arch/brother/brother.pb.h"
|
||||
#include "lib/encoders/encoders.pb.h"
|
||||
|
||||
@@ -28,3 +28,75 @@ proto(
|
||||
)
|
||||
|
||||
protocc(name="proto_lib", srcs=[".+proto"], deps=["lib+common_proto_lib"])
|
||||
|
||||
cxxlibrary(
|
||||
name="arch",
|
||||
srcs=[
|
||||
"./arch.cc",
|
||||
"./aeslanier/decoder.cc",
|
||||
"./agat/agat.cc",
|
||||
"./agat/decoder.cc",
|
||||
"./agat/encoder.cc",
|
||||
"./amiga/amiga.cc",
|
||||
"./amiga/decoder.cc",
|
||||
"./amiga/encoder.cc",
|
||||
"./apple2/decoder.cc",
|
||||
"./apple2/encoder.cc",
|
||||
"./brother/decoder.cc",
|
||||
"./brother/encoder.cc",
|
||||
"./c64/c64.cc",
|
||||
"./c64/decoder.cc",
|
||||
"./c64/encoder.cc",
|
||||
"./f85/decoder.cc",
|
||||
"./fb100/decoder.cc",
|
||||
"./ibm/decoder.cc",
|
||||
"./ibm/encoder.cc",
|
||||
"./macintosh/decoder.cc",
|
||||
"./macintosh/encoder.cc",
|
||||
"./micropolis/decoder.cc",
|
||||
"./micropolis/encoder.cc",
|
||||
"./mx/decoder.cc",
|
||||
"./northstar/decoder.cc",
|
||||
"./northstar/encoder.cc",
|
||||
"./rolandd20/decoder.cc",
|
||||
"./smaky6/decoder.cc",
|
||||
"./tartu/decoder.cc",
|
||||
"./tartu/encoder.cc",
|
||||
"./tids990/decoder.cc",
|
||||
"./tids990/encoder.cc",
|
||||
"./victor9k/decoder.cc",
|
||||
"./victor9k/encoder.cc",
|
||||
"./zilogmcz/decoder.cc",
|
||||
],
|
||||
hdrs={
|
||||
"arch/ibm/ibm.h": "./ibm/ibm.h",
|
||||
"arch/apple2/data_gcr.h": "./apple2/data_gcr.h",
|
||||
"arch/apple2/apple2.h": "./apple2/apple2.h",
|
||||
"arch/amiga/amiga.h": "./amiga/amiga.h",
|
||||
"arch/smaky6/smaky6.h": "./smaky6/smaky6.h",
|
||||
"arch/tids990/tids990.h": "./tids990/tids990.h",
|
||||
"arch/zilogmcz/zilogmcz.h": "./zilogmcz/zilogmcz.h",
|
||||
"arch/amiga/amiga.h": "./amiga/amiga.h",
|
||||
"arch/f85/data_gcr.h": "./f85/data_gcr.h",
|
||||
"arch/f85/f85.h": "./f85/f85.h",
|
||||
"arch/mx/mx.h": "./mx/mx.h",
|
||||
"arch/aeslanier/aeslanier.h": "./aeslanier/aeslanier.h",
|
||||
"arch/northstar/northstar.h": "./northstar/northstar.h",
|
||||
"arch/brother/data_gcr.h": "./brother/data_gcr.h",
|
||||
"arch/brother/brother.h": "./brother/brother.h",
|
||||
"arch/brother/header_gcr.h": "./brother/header_gcr.h",
|
||||
"arch/macintosh/data_gcr.h": "./macintosh/data_gcr.h",
|
||||
"arch/macintosh/macintosh.h": "./macintosh/macintosh.h",
|
||||
"arch/agat/agat.h": "./agat/agat.h",
|
||||
"arch/fb100/fb100.h": "./fb100/fb100.h",
|
||||
"arch/victor9k/data_gcr.h": "./victor9k/data_gcr.h",
|
||||
"arch/victor9k/victor9k.h": "./victor9k/victor9k.h",
|
||||
"arch/rolandd20/rolandd20.h": "./rolandd20/rolandd20.h",
|
||||
"arch/micropolis/micropolis.h": "./micropolis/micropolis.h",
|
||||
"arch/c64/data_gcr.h": "./c64/data_gcr.h",
|
||||
"arch/c64/c64.h": "./c64/c64.h",
|
||||
"arch/tartu/tartu.h": "./tartu/tartu.h",
|
||||
"arch/arch.h": "./arch.h",
|
||||
},
|
||||
deps=["lib/core", "lib/data", "lib/config", "lib/encoders", "lib/decoders"],
|
||||
)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/core/utils.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "c64.h"
|
||||
#include "lib/core/crc.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "fmt/format.h"
|
||||
#include "arch/c64/c64.pb.h"
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "ibm.h"
|
||||
#include "lib/core/crc.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "arch/ibm/ibm.pb.h"
|
||||
#include "lib/encoders/encoders.pb.h"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/core/utils.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "macintosh.h"
|
||||
#include "lib/core/crc.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "fmt/format.h"
|
||||
#include "lib/encoders/encoders.pb.h"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "tids990.h"
|
||||
#include "lib/core/crc.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "arch/tids990/tids990.pb.h"
|
||||
#include "lib/encoders/encoders.pb.h"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/core/utils.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "victor9k.h"
|
||||
#include "lib/core/crc.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "fmt/format.h"
|
||||
#include "arch/victor9k/victor9k.pb.h"
|
||||
|
||||
132
build.py
132
build.py
@@ -22,135 +22,10 @@ clibrary(name="protocol", hdrs={"protocol.h": "./protocol.h"})
|
||||
cxxlibrary(
|
||||
name="lib",
|
||||
srcs=[
|
||||
"./lib/decoders/decoders.cc",
|
||||
"./lib/decoders/fluxdecoder.cc",
|
||||
"./lib/decoders/fmmfm.cc",
|
||||
"./lib/encoders/encoders.cc",
|
||||
"./lib/fluxsink/a2rfluxsink.cc",
|
||||
"./lib/fluxsink/aufluxsink.cc",
|
||||
"./lib/fluxsink/fl2fluxsink.cc",
|
||||
"./lib/fluxsink/fluxsink.cc",
|
||||
"./lib/fluxsink/hardwarefluxsink.cc",
|
||||
"./lib/fluxsink/scpfluxsink.cc",
|
||||
"./lib/fluxsink/vcdfluxsink.cc",
|
||||
"./lib/fluxsource/a2rfluxsource.cc",
|
||||
"./lib/fluxsource/cwffluxsource.cc",
|
||||
"./lib/fluxsource/dmkfluxsource.cc",
|
||||
"./lib/fluxsource/erasefluxsource.cc",
|
||||
"./lib/fluxsource/fl2fluxsource.cc",
|
||||
"./lib/fluxsource/fluxsource.cc",
|
||||
"./lib/fluxsource/flx.cc",
|
||||
"./lib/fluxsource/flxfluxsource.cc",
|
||||
"./lib/fluxsource/hardwarefluxsource.cc",
|
||||
"./lib/fluxsource/kryofluxfluxsource.cc",
|
||||
"./lib/fluxsource/memoryfluxsource.cc",
|
||||
"./lib/fluxsource/scpfluxsource.cc",
|
||||
"./lib/fluxsource/testpatternfluxsource.cc",
|
||||
"./lib/imagereader/d64imagereader.cc",
|
||||
"./lib/imagereader/d88imagereader.cc",
|
||||
"./lib/imagereader/dimimagereader.cc",
|
||||
"./lib/imagereader/diskcopyimagereader.cc",
|
||||
"./lib/imagereader/fdiimagereader.cc",
|
||||
"./lib/imagereader/imagereader.cc",
|
||||
"./lib/imagereader/imdimagereader.cc",
|
||||
"./lib/imagereader/imgimagereader.cc",
|
||||
"./lib/imagereader/jv3imagereader.cc",
|
||||
"./lib/imagereader/nfdimagereader.cc",
|
||||
"./lib/imagereader/nsiimagereader.cc",
|
||||
"./lib/imagereader/td0imagereader.cc",
|
||||
"./lib/imagewriter/d64imagewriter.cc",
|
||||
"./lib/imagewriter/d88imagewriter.cc",
|
||||
"./lib/imagewriter/diskcopyimagewriter.cc",
|
||||
"./lib/imagewriter/imagewriter.cc",
|
||||
"./lib/imagewriter/imdimagewriter.cc",
|
||||
"./lib/imagewriter/imgimagewriter.cc",
|
||||
"./lib/imagewriter/ldbsimagewriter.cc",
|
||||
"./lib/imagewriter/nsiimagewriter.cc",
|
||||
"./lib/imagewriter/rawimagewriter.cc",
|
||||
"./lib/readerwriter.cc",
|
||||
"./lib/usb/applesauceusb.cc",
|
||||
"./lib/usb/fluxengineusb.cc",
|
||||
"./lib/usb/greaseweazle.cc",
|
||||
"./lib/usb/greaseweazleusb.cc",
|
||||
"./lib/usb/serial.cc",
|
||||
"./lib/usb/usb.cc",
|
||||
"./lib/usb/usbfinder.cc",
|
||||
"./arch/aeslanier/decoder.cc",
|
||||
"./arch/agat/agat.cc",
|
||||
"./arch/agat/decoder.cc",
|
||||
"./arch/agat/encoder.cc",
|
||||
"./arch/amiga/amiga.cc",
|
||||
"./arch/amiga/decoder.cc",
|
||||
"./arch/amiga/encoder.cc",
|
||||
"./arch/apple2/decoder.cc",
|
||||
"./arch/apple2/encoder.cc",
|
||||
"./arch/brother/decoder.cc",
|
||||
"./arch/brother/encoder.cc",
|
||||
"./arch/c64/c64.cc",
|
||||
"./arch/c64/decoder.cc",
|
||||
"./arch/c64/encoder.cc",
|
||||
"./arch/f85/decoder.cc",
|
||||
"./arch/fb100/decoder.cc",
|
||||
"./arch/ibm/decoder.cc",
|
||||
"./arch/ibm/encoder.cc",
|
||||
"./arch/macintosh/decoder.cc",
|
||||
"./arch/macintosh/encoder.cc",
|
||||
"./arch/micropolis/decoder.cc",
|
||||
"./arch/micropolis/encoder.cc",
|
||||
"./arch/mx/decoder.cc",
|
||||
"./arch/northstar/decoder.cc",
|
||||
"./arch/northstar/encoder.cc",
|
||||
"./arch/rolandd20/decoder.cc",
|
||||
"./arch/smaky6/decoder.cc",
|
||||
"./arch/tartu/decoder.cc",
|
||||
"./arch/tartu/encoder.cc",
|
||||
"./arch/tids990/decoder.cc",
|
||||
"./arch/tids990/encoder.cc",
|
||||
"./arch/victor9k/decoder.cc",
|
||||
"./arch/victor9k/encoder.cc",
|
||||
"./arch/zilogmcz/decoder.cc",
|
||||
],
|
||||
hdrs={
|
||||
"arch/ibm/ibm.h": "./arch/ibm/ibm.h",
|
||||
"arch/apple2/data_gcr.h": "./arch/apple2/data_gcr.h",
|
||||
"arch/apple2/apple2.h": "./arch/apple2/apple2.h",
|
||||
"arch/smaky6/smaky6.h": "./arch/smaky6/smaky6.h",
|
||||
"arch/tids990/tids990.h": "./arch/tids990/tids990.h",
|
||||
"arch/zilogmcz/zilogmcz.h": "./arch/zilogmcz/zilogmcz.h",
|
||||
"arch/amiga/amiga.h": "./arch/amiga/amiga.h",
|
||||
"arch/f85/data_gcr.h": "./arch/f85/data_gcr.h",
|
||||
"arch/f85/f85.h": "./arch/f85/f85.h",
|
||||
"arch/mx/mx.h": "./arch/mx/mx.h",
|
||||
"arch/aeslanier/aeslanier.h": "./arch/aeslanier/aeslanier.h",
|
||||
"arch/northstar/northstar.h": "./arch/northstar/northstar.h",
|
||||
"arch/brother/data_gcr.h": "./arch/brother/data_gcr.h",
|
||||
"arch/brother/brother.h": "./arch/brother/brother.h",
|
||||
"arch/brother/header_gcr.h": "./arch/brother/header_gcr.h",
|
||||
"arch/macintosh/data_gcr.h": "./arch/macintosh/data_gcr.h",
|
||||
"arch/macintosh/macintosh.h": "./arch/macintosh/macintosh.h",
|
||||
"arch/agat/agat.h": "./arch/agat/agat.h",
|
||||
"arch/fb100/fb100.h": "./arch/fb100/fb100.h",
|
||||
"arch/victor9k/data_gcr.h": "./arch/victor9k/data_gcr.h",
|
||||
"arch/victor9k/victor9k.h": "./arch/victor9k/victor9k.h",
|
||||
"arch/rolandd20/rolandd20.h": "./arch/rolandd20/rolandd20.h",
|
||||
"arch/micropolis/micropolis.h": "./arch/micropolis/micropolis.h",
|
||||
"arch/c64/data_gcr.h": "./arch/c64/data_gcr.h",
|
||||
"arch/c64/c64.h": "./arch/c64/c64.h",
|
||||
"arch/tartu/tartu.h": "./arch/tartu/tartu.h",
|
||||
"lib/decoders/decoders.h": "./lib/decoders/decoders.h",
|
||||
"lib/decoders/fluxdecoder.h": "./lib/decoders/fluxdecoder.h",
|
||||
"lib/decoders/rawbits.h": "./lib/decoders/rawbits.h",
|
||||
"lib/encoders/encoders.h": "./lib/encoders/encoders.h",
|
||||
"lib/fluxsink/fluxsink.h": "./lib/fluxsink/fluxsink.h",
|
||||
"lib/fluxsource/fluxsource.h": "lib/fluxsource/fluxsource.h",
|
||||
"lib/fluxsource/flx.h": "lib/fluxsource/flx.h",
|
||||
"lib/imagereader/imagereader.h": "./lib/imagereader/imagereader.h",
|
||||
"lib/imagewriter/imagewriter.h": "./lib/imagewriter/imagewriter.h",
|
||||
"lib/readerwriter.h": "./lib/readerwriter.h",
|
||||
"lib/usb/applesauce.h": "./lib/usb/applesauce.h",
|
||||
"lib/usb/greaseweazle.h": "./lib/usb/greaseweazle.h",
|
||||
"lib/usb/usb.h": "./lib/usb/usb.h",
|
||||
"lib/usb/usbfinder.h": "./lib/usb/usbfinder.h",
|
||||
},
|
||||
deps=[
|
||||
"+fmt_lib",
|
||||
@@ -165,7 +40,12 @@ cxxlibrary(
|
||||
"lib/config",
|
||||
"lib/data",
|
||||
"lib/external",
|
||||
"lib/fluxsource+proto_lib",
|
||||
"lib/fluxsink",
|
||||
"lib/fluxsource",
|
||||
"lib/imagereader",
|
||||
"lib/imagewriter",
|
||||
"lib/decoders",
|
||||
"lib/encoders",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ endif
|
||||
EXT ?=
|
||||
|
||||
ifeq ($(PROGRESSINFO),)
|
||||
rulecount := $(shell $(MAKE) --no-print-directory -q $(OBJ)/build.mk PROGRESSINFO=1 && $(MAKE) -n $(MAKECMDGOALS) PROGRESSINFO=XXXPROGRESSINFOXXX | grep XXXPROGRESSINFOXXX | wc -l)
|
||||
rulecount := $(strip $(shell $(MAKE) --no-print-directory -q $(OBJ)/build.mk PROGRESSINFO=1 && $(MAKE) --no-print-directory -n $(MAKECMDGOALS) PROGRESSINFO=XXXPROGRESSINFOXXX | grep XXXPROGRESSINFOXXX | wc -l))
|
||||
ruleindex := 1
|
||||
PROGRESSINFO = "[$(ruleindex)/$(rulecount)]$(eval ruleindex := $(shell expr $(ruleindex) + 1))"
|
||||
endif
|
||||
|
||||
@@ -27,8 +27,8 @@ class Toolchain:
|
||||
label = ""
|
||||
cfile = ["$(CC) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"]
|
||||
cxxfile = ["$(CXX) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"]
|
||||
clibrary = ["$(AR) cqs {outs[0]} {ins}"]
|
||||
cxxlibrary = ["$(AR) cqs {outs[0]} {ins}"]
|
||||
clibrary = ["rm -f {outs[0]} && $(AR) cqs {outs[0]} {ins}"]
|
||||
cxxlibrary = ["rm -f {outs[0]} && $(AR) cqs {outs[0]} {ins}"]
|
||||
cprogram = [
|
||||
"$(CC) -o {outs[0]} $(STARTGROUP) {ins} {ldflags} $(LDFLAGS) $(ENDGROUP)"
|
||||
]
|
||||
@@ -41,8 +41,8 @@ class HostToolchain:
|
||||
label = "HOST "
|
||||
cfile = ["$(HOSTCC) -c -o {outs[0]} {ins[0]} $(HOSTCFLAGS) {cflags}"]
|
||||
cxxfile = ["$(HOSTCXX) -c -o {outs[0]} {ins[0]} $(HOSTCFLAGS) {cflags}"]
|
||||
clibrary = ["$(HOSTAR) cqs {outs[0]} {ins}"]
|
||||
cxxlibrary = ["$(HOSTAR) cqs {outs[0]} {ins}"]
|
||||
clibrary = ["rm -f {outs[0]} && $(HOSTAR) cqs {outs[0]} {ins}"]
|
||||
cxxlibrary = ["rm -f {outs[0]} && $(HOSTAR) cqs {outs[0]} {ins}"]
|
||||
cprogram = [
|
||||
"$(HOSTCC) -o {outs[0]} $(HOSTSTARTGROUP) {ins} {ldflags} $(HOSTLDFLAGS) $(HOSTENDGROUP)"
|
||||
]
|
||||
|
||||
@@ -1,2 +1,15 @@
|
||||
-d
|
||||
\r
|
||||
40track_drive
|
||||
====
|
||||
## Adjust configuration for a 40-track drive
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
This is an extension profile; adding this to the command line will configure
|
||||
FluxEngine to read from 40-track, 48tpi 5.25" drives. You have to tell it because there is
|
||||
no way to detect this automatically.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
fluxengine read ibm --180 40track_drive
|
||||
```
|
||||
|
||||
|
||||
@@ -1,2 +1,39 @@
|
||||
-d
|
||||
\r
|
||||
acornadfs
|
||||
====
|
||||
## BBC Micro, Archimedes
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
Acorn ADFS disks are used by the 6502-based BBC Micro and ARM-based Archimedes
|
||||
series of computers. They are yet another variation on MFM encoded IBM scheme
|
||||
disks, although with different sector sizes and with the 0-based sector
|
||||
identifiers rather than 1-based sector identifiers. The index hole is ignored
|
||||
and sectors are written whereever, requiring FluxEngine to do two revolutions
|
||||
to read a disk.
|
||||
|
||||
There are various different kinds, which should all work out of the box.
|
||||
|
||||
Be aware that Acorn logical block numbering goes all the way up side 0 and
|
||||
then all the way up side 1. However, FluxEngine uses traditional disk images
|
||||
with alternating sides, with the blocks from track 0 side 0 then track 0 side
|
||||
1 then track 1 side 0 etc. Most Acorn emulators will use both formats, but
|
||||
they might require nudging as the side order can't be reliably autodetected.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `160`: 160kB 3.5" or 5.25" 40-track SSDD; S format
|
||||
- `320`: 320kB 3.5" or 5.25" 80-track SSDD; M format
|
||||
- `640`: 640kB 3.5" or 5.25" 80-track DSDD; L format
|
||||
- `800`: 800kB 3.5" 80-track DSDD; D and E formats
|
||||
- `1600`: 1600kB 3.5" 80-track DSHD; F formats
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read acornadfs --160 -s drive:0 -o acornadfs.img`
|
||||
- `fluxengine read acornadfs --320 -s drive:0 -o acornadfs.img`
|
||||
- `fluxengine read acornadfs --640 -s drive:0 -o acornadfs.img`
|
||||
- `fluxengine read acornadfs --800 -s drive:0 -o acornadfs.img`
|
||||
- `fluxengine read acornadfs --1600 -s drive:0 -o acornadfs.img`
|
||||
|
||||
|
||||
@@ -1,2 +1,38 @@
|
||||
-d
|
||||
\r
|
||||
acorndfs
|
||||
====
|
||||
## Acorn Atom, BBC Micro series
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
Acorn DFS disks are used by the Acorn Atom and BBC Micro series of computers.
|
||||
They are pretty standard FM encoded IBM scheme disks, with 256-sectors and
|
||||
0-based sector identifiers. There's nothing particularly special here.
|
||||
|
||||
DFS disks are all single-sided, but allow the other side of the disk to be
|
||||
used as another volume.
|
||||
|
||||
They come in two varieties, 40 track and 80 track. These should both work.
|
||||
Some rare disks are both at the same time. FluxEngine can read these but it
|
||||
requires a bit of fiddling as they have the same tracks on twice.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `100`: 100kB 40-track SSSD
|
||||
- `200`: 200kB 80-track SSSD
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read acorndfs --100 -s drive:0 -o acorndfs.img`
|
||||
- `fluxengine read acorndfs --200 -s drive:0 -o acorndfs.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write acorndfs --100 -d drive:0 -i acorndfs.img`
|
||||
- `fluxengine write acorndfs --200 -d drive:0 -i acorndfs.img`
|
||||
|
||||
## References
|
||||
|
||||
- [The Acorn DFS disc format](https://beebwiki.mdfs.net/Acorn_DFS_disc_format)
|
||||
|
||||
|
||||
@@ -1,2 +1,48 @@
|
||||
-d
|
||||
\r
|
||||
aeslanier
|
||||
====
|
||||
## 616kB 5.25" 77-track SSDD hard sectored
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
Back in 1980 Lanier released a series of very early integrated word processor
|
||||
appliances, the No Problem. These were actually [rebranded AES Data Superplus
|
||||
machines](http://vintagecomputers.site90.net/aes/). They were gigantic,
|
||||
weighed 40kg, and one example I've found cost ꆲ5bb4
|
||||
of nearly ㇢1a6e
|
||||
|
||||
8080 machines with 32kB of RAM, they ran their own proprietary word
|
||||
processing software off twin 5.25" drive units, but apparently other software
|
||||
was available.
|
||||
|
||||
The disk format is exceptionally weird. They used 77 track, 32 sector, single-sided
|
||||
_hard_ sectored disks, where there were multiple index holes,
|
||||
indicating to the hardware where the sectors start. The encoding scheme
|
||||
itself is [MMFM (aka
|
||||
M2FM)](http://www.retrotechnology.com/herbs_stuff/m2fm.html), an early
|
||||
attempt at double-density disk encoding which rapidly got obsoleted by the
|
||||
simpler MFM --- and the bytes are stored on disk _backwards_. Even aside from
|
||||
the encoding, the format on disk was strange; unified sector header/data
|
||||
records, so that the sector header (containing the sector and track number)
|
||||
is actually inside the user data.
|
||||
|
||||
FluxEngine can read these, but I only have a single, fairly poor example of a
|
||||
disk image, and I've had to make a lot of guesses as to the sector format
|
||||
based on what looks right. If anyone knows _anything_ about these disks,
|
||||
[please get in touch](https://github.com/davidgiven/fluxengine/issues/new).
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read aeslanier -s drive:0 -o aeslanier.img`
|
||||
|
||||
## References
|
||||
|
||||
* [SA800 Diskette Storage Drive - Theory Of
|
||||
Operations](http://www.hartetechnologies.com/manuals/Shugart/50664-1_SA800_TheorOp_May78.pdf):
|
||||
talks about MMFM a lot, but the Lanier machines didn't use this disk
|
||||
format.
|
||||
|
||||
|
||||
@@ -1,2 +1,36 @@
|
||||
-d
|
||||
\r
|
||||
agat
|
||||
====
|
||||
## 840kB 5.25" 80-track DS
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Agat (Russian: ↊fd74
|
||||
1983. These were based around a 6502 and were nominally Apple II-compatible
|
||||
although with enough differences to be problematic.
|
||||
|
||||
They could use either standard Apple II 140kB disks, or a proprietary 840kb
|
||||
MFM-based double-sided format. FluxEngine supports both of these; this profile
|
||||
is for the proprietary format. for the Apple II format, use the `apple2`
|
||||
profile.
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read agat -s drive:0 -o agat.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write agat -d drive:0 -i agat.img`
|
||||
|
||||
## References
|
||||
|
||||
- [Magazine article on the
|
||||
Agat](https://sudonull.com/post/54185-Is-AGAT-a-bad-copy-of-Apple)
|
||||
|
||||
- [Forum thread with (some) documentation on the
|
||||
format](https://torlus.com/floppy/forum/viewtopic.php?t=1385)
|
||||
|
||||
|
||||
@@ -1,2 +1,41 @@
|
||||
-d
|
||||
\r
|
||||
amiga
|
||||
====
|
||||
## 880kB 3.5" DSDD
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
Amiga disks use MFM, but don't use IBM scheme. Instead, the entire track is
|
||||
read and written as a unit, with each sector butting up against the previous
|
||||
one. This saves a lot of space which allows the Amiga to not just store 880kB
|
||||
on a DD disk, but _also_ allows an extra 16 bytes of metadata per sector.
|
||||
|
||||
This metadata is mostly unused, so the default for FluxEngine is to ignore it
|
||||
and just use the 512 bytes of main sector data. If you want it, specify a
|
||||
528-byte sector size. The metadata will come after the user data.
|
||||
|
||||
Bizarrely, the data in each sector is stored with all the odd bits first, and
|
||||
then all the even bits. This is tied into the checksum algorithm, which is
|
||||
distinctly subpar and not particularly good at detecting errors.
|
||||
|
||||
## Options
|
||||
|
||||
- Sector size:
|
||||
- `without_metadata`: 512-byte sectors
|
||||
- `with_metadata`: 528-byte sectors
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read amiga -s drive:0 -o amiga.adf`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write amiga -d drive:0 -i amiga.adf`
|
||||
|
||||
## References
|
||||
|
||||
- [The Amiga Floppy Boot Process and Physical
|
||||
Layout](https://wiki.amigaos.net/wiki/Amiga_Floppy_Boot_Process_and_Physical_Layout)
|
||||
|
||||
- [The Amiga Disk File FAQ](http://lclevy.free.fr/adflib/adf_info.html)
|
||||
|
||||
|
||||
@@ -1,2 +1,52 @@
|
||||
-d
|
||||
\r
|
||||
ampro
|
||||
====
|
||||
## CP/M
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Ampro Little Board was a very simple and cheap Z80-based computer from
|
||||
1984, which ran CP/M. It was, in fact, a single PCB which you could mount
|
||||
on the bottom of a 5.25" drive.
|
||||
|
||||
[All about the Ampro Little Board](http://oldcomputers.net/ampro-little-board.html)
|
||||
|
||||
It stored either 400kB on a double-sided 40-track drive or 800kB on a
|
||||
double-sided 80 track drive. The disk format it used was a slightly quirky
|
||||
variation of the standard MFM IBM scheme --- sector numbering starts at 17
|
||||
rather than 1 (or Acorn's 0). FluxEngine supports this.
|
||||
|
||||
FluxEngine has direct filesystem support for these disks, or you can pass the
|
||||
disk images into [cpmtools](http://www.moria.de/~michael/cpmtools/):
|
||||
|
||||
```
|
||||
$ cpmls -f ampdsdd ampro.img
|
||||
0:
|
||||
-a60014.e
|
||||
amprodsk.com
|
||||
bitchk.doc
|
||||
bitchk.mac
|
||||
cpmmac.mac
|
||||
dir.com
|
||||
himem.doc
|
||||
himem.mac
|
||||
kaydiag.lbr
|
||||
kayinfo.lbr
|
||||
...etc...
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `400`: 400kB 40-track DSDD
|
||||
- `800`: 800kB 80-track DSDD
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read ampro --400 -s drive:0 -o ampro.img`
|
||||
- `fluxengine read ampro --800 -s drive:0 -o ampro.img`
|
||||
|
||||
## References
|
||||
|
||||
- [The Ampro Little Board](http://oldcomputers.net/ampro-little-board.html)
|
||||
|
||||
|
||||
@@ -1,2 +1,74 @@
|
||||
-d
|
||||
\r
|
||||
apple2
|
||||
====
|
||||
## Prodos, Appledos, and CP/M
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
Apple II disks are nominally fairly sensible 40-track, single-sided, 256
|
||||
bytes-per-sector jobs. However, they come in two varieties: DOS 3.3/ProDOS and
|
||||
above, and pre-DOS 3.3. They use different GCR encoding systems, dubbed
|
||||
6-and-2 and 5-and-3, and are mutually incompatible (although in some rare
|
||||
cases you can mix 6-and-2 and 5-and-3 sectors on the same disk).
|
||||
|
||||
The difference is in the drive controller; the 6-and-2 controller is capable
|
||||
of a more efficient encoding, and can fit 16 sectors on a track, storing
|
||||
140kB on a disk. The 5-and-3 controller can only fit 13, with a mere 114kB.
|
||||
|
||||
Both formats use GCR (in different varieties) in a nice, simple grid of
|
||||
sectors, unlike the Macintosh. Like the Macintosh, there's a crazy encoding
|
||||
scheme applied to the data before it goes down on disk to speed up
|
||||
checksumming.
|
||||
|
||||
In addition, a lot of the behaviour of the drive was handled in software.
|
||||
This means that Apple II disks can do all kinds of weird things, including
|
||||
having spiral tracks! Copy protection for the Apple II was even madder than
|
||||
on other systems.
|
||||
|
||||
FluxEngine can only read well-behaved 6-and-2 disks. It doesn't even try to
|
||||
handle the weird stuff.
|
||||
|
||||
Apple DOS also applies logical sector remapping on top of the physical sector
|
||||
numbering on the disk, and this _varies_ depending on what the disk is for.
|
||||
FluxEngine can remap the sectors from physical to logical using modifiers. If
|
||||
you don't specify a remapping modifier, you get the sectors in the order they
|
||||
appear on the disk.
|
||||
|
||||
If you don't want an image in physical sector order, specify one of the
|
||||
filesystem ordering options. These also select the appropriate file system;
|
||||
FluxEngine has read-only support for all of these.
|
||||
|
||||
In addition, some third-party systems use 80-track double sides drives, with
|
||||
the same underlying disk format. The complication here is that the AppleDOS
|
||||
filesystem only supports up to 50 tracks, so it needs tweaking to support
|
||||
larger disks. It treats the second side of the disk as a completely different
|
||||
volume.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `140`: 140kB 5.25" 35-track SS
|
||||
- `640`: 640kB 5.25" 80-track DS
|
||||
- Filesystem and sector skew:
|
||||
- `nofs`: use physical CHS sector order and no file system
|
||||
- `appledos`: use AppleDOS soft sector skew and file system
|
||||
- `prodos`: use ProDOS soft sector skew and filesystem
|
||||
- `cpm`: use CP/M soft sector skew and filesystem
|
||||
- `side1`: for AppleDOS file system access, read the volume on side 1 of a disk
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read apple2 --140 -s drive:0 -o apple2.img`
|
||||
- `fluxengine read apple2 --640 -s drive:0 -o apple2.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write apple2 --140 -d drive:0 -i apple2.img`
|
||||
- `fluxengine write apple2 --640 -d drive:0 -i apple2.img`
|
||||
|
||||
## References
|
||||
|
||||
- [Beneath Apple DOS](https://fabiensanglard.net/fd_proxy/prince_of_persia/Beneath%20Apple%20DOS.pdf)
|
||||
|
||||
- [MAME's ap2_dsk.cpp file](https://github.com/mamedev/mame/blob/4263a71e64377db11392c458b580c5ae83556bc7/src/lib/formats/ap2_dsk.cpp)
|
||||
|
||||
|
||||
@@ -1,2 +1,16 @@
|
||||
-d
|
||||
\r
|
||||
apple2_drive
|
||||
====
|
||||
## Adjust configuration for a 40-track Apple II drive
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
This is an extension profile; adding this to the command line will configure
|
||||
FluxEngine to adjust the pinout and track spacing to work with an Apple II
|
||||
drive. This only works on Greaseweazle hardware and requires a custom
|
||||
connector.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
fluxengine read apple2 --160 apple2_drive
|
||||
```
|
||||
|
||||
|
||||
@@ -1,2 +1,61 @@
|
||||
-d
|
||||
\r
|
||||
atarist
|
||||
====
|
||||
## Almost PC compatible
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
Atari ST disks are standard MFM encoded IBM scheme disks without an IAM header.
|
||||
Disks are typically formatted 512 bytes per sector with between 9-10 (sometimes
|
||||
11!) sectors per track and 80-82 tracks per side.
|
||||
|
||||
For some reason, occasionally formatting software will put an extra IDAM record
|
||||
with a sector number of 66 on a disk, which can horribly confuse things. The
|
||||
Atari profiles below are configured to ignore these.
|
||||
|
||||
Be aware that many PC drives (including mine) won't do the 82 track formats.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `360`: 360kB 3.5" 80-track 9-sector SSDD
|
||||
- `370`: 370kB 3.5" 82-track 9-sector SSDD
|
||||
- `400`: 400kB 3.5" 80-track 10-sector SSDD
|
||||
- `410`: 410kB 3.5" 82-track 10-sector SSDD
|
||||
- `720`: 720kB 3.5" 80-track 9-sector DSDD
|
||||
- `740`: 740kB 3.5" 82-track 9-sector DSDD
|
||||
- `800`: 800kB 3.5" 80-track 10-sector DSDD
|
||||
- `820`: 820kB 3.5" 82-track 10-sector DSDD
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read atarist --360 -s drive:0 -o atarist.img`
|
||||
- `fluxengine read atarist --370 -s drive:0 -o atarist.img`
|
||||
- `fluxengine read atarist --400 -s drive:0 -o atarist.img`
|
||||
- `fluxengine read atarist --410 -s drive:0 -o atarist.img`
|
||||
- `fluxengine read atarist --720 -s drive:0 -o atarist.img`
|
||||
- `fluxengine read atarist --740 -s drive:0 -o atarist.img`
|
||||
- `fluxengine read atarist --800 -s drive:0 -o atarist.img`
|
||||
- `fluxengine read atarist --820 -s drive:0 -o atarist.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write atarist --360 -d drive:0 -i atarist.img`
|
||||
- `fluxengine write atarist --370 -d drive:0 -i atarist.img`
|
||||
- `fluxengine write atarist --400 -d drive:0 -i atarist.img`
|
||||
- `fluxengine write atarist --410 -d drive:0 -i atarist.img`
|
||||
- `fluxengine write atarist --720 -d drive:0 -i atarist.img`
|
||||
- `fluxengine write atarist --740 -d drive:0 -i atarist.img`
|
||||
- `fluxengine write atarist --800 -d drive:0 -i atarist.img`
|
||||
- `fluxengine write atarist --820 -d drive:0 -i atarist.img`
|
||||
|
||||
## References
|
||||
|
||||
- [Atari ST Floppy Drive Hardware
|
||||
Information](https://info-coach.fr/atari/hardware/FD-Hard.php) by Jean
|
||||
Louis-Guerin
|
||||
|
||||
- [Atari ST Floppy Drive Software
|
||||
Information](https://info-coach.fr/atari/software/FD-Soft.php) by Jean
|
||||
Louis-Guerin
|
||||
|
||||
|
||||
@@ -1,2 +1,30 @@
|
||||
-d
|
||||
\r
|
||||
bk
|
||||
====
|
||||
## 800kB 5.25"/3.5" 80-track 10-sector DSDD
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The BK (an abbreviation for 1ba9
|
||||
is a Soviet era personal computer from Elektronika based on a PDP-11
|
||||
single-chip processor. It was the _only_ official, government approved home
|
||||
computer in mass production at the time.
|
||||
|
||||
It got a floppy interface in 1989 when the 128kB BK-0011 was released. This
|
||||
used a relatively normal double-sided IBM scheme format with 80 sectors and ten
|
||||
sectors per track, resulting in 800kB disks. The format is, in fact, identical
|
||||
to the Atari ST 800kB format. Either 5.25" or 3.5" drives were used depending
|
||||
on what was available at the time, with the same format on both.
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read bk -s drive:0 -o bk800.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write bk -d drive:0 -i bk800.img`
|
||||
|
||||
|
||||
@@ -1,2 +1,128 @@
|
||||
-d
|
||||
\r
|
||||
brother
|
||||
====
|
||||
## GCR family
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
Brother word processor disks are weird, using custom tooling and chipsets.
|
||||
They are completely not PC compatible in every possible way other than the
|
||||
size.
|
||||
|
||||
Different word processors use different disk formats --- the only ones supported
|
||||
by FluxEngine are the 120kB and 240kB 3.5" formats. Use the `--120` and `--240`
|
||||
options to select which one.
|
||||
|
||||
Apparently about 20% of Brother word processors have alignment issues which
|
||||
means that the disks can't be read by FluxEngine (because the tracks on the disk
|
||||
don't line up with the position of the head in a PC drive). The word processors
|
||||
themselves solved this by microstepping until they found where the real track
|
||||
is, but normal PC drives aren't capable of doing this. Particularly with the
|
||||
120kB disks, you might want to fiddle with the head bias (e.g.
|
||||
`--drive.head_bias=3`) to get a clean read. Keep an eye on the bad sector map
|
||||
that's dumped at the end of a read. My word processor likes to put logical track
|
||||
0 on physical track 3, which means that logical track 77 is on physical track
|
||||
80, so I need that `head_bias` value of 3; luckily my PC drive can access track
|
||||
80.
|
||||
|
||||
Using FluxEngine to *write* disks isn't a problem, so the
|
||||
simplest solution is to use FluxEngine to create a new disk, with the tracks
|
||||
aligned properly, and then use a word processor to copy the files you want
|
||||
onto it. The new disk can then be read and you can extract the files.
|
||||
Obviously this sucks if you don't actually have a word processor, but I can't
|
||||
do anything about that.
|
||||
|
||||
If you find one of these misaligned disks then *please* [get in
|
||||
touch](https://github.com/davidgiven/fluxengine/issues/new); I want to
|
||||
investigate.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `120`: 120kB 3.5" 39-track SS GCR
|
||||
- `240`: 240kB 3.5" 78-track SS GCR
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read brother --120 -s drive:0 -o brother.img`
|
||||
- `fluxengine read brother --240 -s drive:0 -o brother.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write brother --120 -d drive:0 -i brother.img`
|
||||
- `fluxengine write brother --240 -d drive:0 -i brother.img`
|
||||
|
||||
Dealing with misaligned disks
|
||||
-----------------------------
|
||||
|
||||
While FluxEngine can't read misaligned disks directly, Brother word processors
|
||||
_can_. If you have access to a compatible word processor, there's a fairly
|
||||
simple workaround to allow you to extract the data:
|
||||
|
||||
1. Format a disk using FluxEngine (by simply writing a blank filesystem image
|
||||
to a disk). This will have the correct alignment to work on a PC drive.
|
||||
|
||||
2. Use a word processor to copy the misaligned disk to the newly formatted
|
||||
disk. The machine will happily adjust itself to both sets of alignments.
|
||||
|
||||
3. Use FluxEngine to read the data off the correctly aligned disk.
|
||||
|
||||
I realise this is rather unsatisfactory, as the Brother hardware is becoming
|
||||
rarer and they cope rather badly with damaged disks, but this is a limitation
|
||||
of the hardware of normal PC drives. (It _is_ possible to deliberately misalign
|
||||
a drive to make it match up with a bad disk, but this is for experts only --- I
|
||||
wouldn't dare.)
|
||||
|
||||
Low level format
|
||||
----------------
|
||||
|
||||
The drive is a single-sided 3.5" drive spinning at not 300 rpm (I don't know
|
||||
the precise speed yet but FluxEngine doesn't care). The 240kB disks have 78
|
||||
tracks and the 120kB disks have 39.
|
||||
|
||||
Each track has 12 256-byte sectors. The drive ignores the index hole so they're
|
||||
lined up all anyhow. As FluxEngine can only read from index to index, it
|
||||
actually reads two complete revolutions and reassembles the sectors from that.
|
||||
|
||||
The underlying encoding is exceptionally weird; they use two different kinds of
|
||||
GCR, one kind for the sector header records and a completely different one for
|
||||
the data itself. It also has a completely bizarre CRC variant which a genius on
|
||||
StackOverflow reverse engineered for me. However, odd though it may be, it does
|
||||
seem pretty robust.
|
||||
|
||||
See the source code for the GCR tables and CRC routine.
|
||||
|
||||
Sectors are about 16.2ms apart on the disk (at 300 rpm). The header and
|
||||
data records are 0.694ms apart. (All measured from the beginning of the
|
||||
record.) The sector order is 05a3816b4927, which gives a sector skew of 5.
|
||||
|
||||
High level format
|
||||
-----------------
|
||||
|
||||
Once decoded, you end up with a file system image. FluxEngine supports direct
|
||||
filesystem access for both kinds of disks.
|
||||
|
||||
### 120kB disks
|
||||
|
||||
These disks use a proprietary and very simple file system. It's FAT-like
|
||||
with an obvious directory and allocation table. It's supported by FluxEngine.
|
||||
|
||||
Any files whose names begin with an asterisk (`*`) will be marked as hidden. If
|
||||
the file is named `*boot`, then a boot sector will be created which will load
|
||||
and run the file at 0x7000 if the machine is started with CODE+Q pressed. So
|
||||
far this has only been confirmed to work on a WP-1.
|
||||
|
||||
### 240kB disks
|
||||
|
||||
Conversely, the 240kB disks turns out to be a completely normal Microsoft FAT
|
||||
file system with a media type of 0x58 --- did you know that FAT supports 256
|
||||
byte sectors? I didn't --- of the MSX-DOS variety. There's a faint
|
||||
possibility that the word processor is based on MSX-DOS, but I haven't
|
||||
reverse engineered it to find out.
|
||||
|
||||
Standard Linux mtools will access the filesystem image and allow you to move
|
||||
files in and out. However, you'll need to change the media type bytes at
|
||||
offsets 0x015 and 0x100 from 0x58 to 0xf0 before mtools will touch it. The
|
||||
supplied `brother240tool` will do this. Additionally, FluxEngine's own FAT
|
||||
file system supports this.
|
||||
|
||||
|
||||
@@ -1,2 +1,74 @@
|
||||
-d
|
||||
\r
|
||||
commodore
|
||||
====
|
||||
## 1541, 1581, 8050 and variations
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
Commodore 8-bit computer disks come in two varieties: GCR, which are the
|
||||
overwhelming majority; and MFM, only used on the 1571 and 1581. The latter were
|
||||
(as far as I can tell) standard IBM PC format disks with a slightly odd sector
|
||||
count.
|
||||
|
||||
The GCR disks are much more interesting. They could store 170kB on a
|
||||
single-sided disk (although later drives were double-sided), using a proprietary
|
||||
encoding and record scheme; like [Apple Macintosh disks](macintosh.md) they
|
||||
stored varying numbers of sectors per track to make the most of the physical
|
||||
disk area, although unlike them they did it by changing the bitrate rather than
|
||||
adjusting the motor speed.
|
||||
|
||||
The drives were also intelligent and ran DOS on a CPU inside them. The
|
||||
computer itself knew nothing about file systems. You could even upload
|
||||
programs onto the drive and run them there, allowing all sorts of custom disk
|
||||
formats, although this was mostly used to compensate for the [cripplingly
|
||||
slow connection to the
|
||||
computer](https://ilesj.wordpress.com/2014/05/14/1541-why-so-complicated/) of
|
||||
300 bytes per second (!). (The drive itself could transfer data reasonably
|
||||
quickly.)
|
||||
|
||||
- a 1541 disk has 35 tracks of 17 to 21 sectors, each 256 bytes long
|
||||
(sometimes 40 tracks), and uses GCR encoding.
|
||||
|
||||
- a standard 1581 disk has 80 tracks and two sides, each with 10 sectors, 512
|
||||
bytes long, and uses normal IBM encoding.
|
||||
|
||||
- an 8050 disk has 77 tracks and two sides, with four speed zones; the number
|
||||
of sectors varies from 23 to 29, using GCR encoding. These will store
|
||||
1042kB. These drives are peculiar because they are 100tpi and therefore the
|
||||
disks cannot be read in normal 96tpi drives.
|
||||
|
||||
- a CMD FD2000 disk (a popular third-party Commodore disk drive) has 81
|
||||
tracks and two sides, each with 10 1024-byte sectors, for a massive 1620kB
|
||||
of storage. This also uses IBM encoding.
|
||||
|
||||
A CMD FD2000 disk (a popular third-party Commodore disk drive)
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `171`: 171kB 1541, 35-track variant
|
||||
- `192`: 192kB 1541, 40-track variant
|
||||
- `800`: 800kB 3.5" 1581
|
||||
- `1042`: 1042kB 5.25" 8051
|
||||
- `1620`: 1620kB, CMD FD2000
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read commodore --171 -s drive:0 -o commodore.d64`
|
||||
- `fluxengine read commodore --192 -s drive:0 -o commodore.d64`
|
||||
- `fluxengine read commodore --800 -s drive:0 -o commodore.d64`
|
||||
- `fluxengine read commodore --1042 -s drive:0 -o commodore.d64`
|
||||
- `fluxengine read commodore --1620 -s drive:0 -o commodore.d64`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write commodore --171 -d drive:0 -i commodore.d64`
|
||||
- `fluxengine write commodore --192 -d drive:0 -i commodore.d64`
|
||||
- `fluxengine write commodore --800 -d drive:0 -i commodore.d64`
|
||||
- `fluxengine write commodore --1620 -d drive:0 -i commodore.d64`
|
||||
|
||||
## References
|
||||
|
||||
- [Ruud's Commodore Site: 1541](http://www.baltissen.org/newhtm/1541c.htm):
|
||||
documentation on the 1541 disk format.
|
||||
|
||||
|
||||
@@ -1,2 +1,42 @@
|
||||
-d
|
||||
\r
|
||||
eco1
|
||||
====
|
||||
## CP/M; 1210kB 77-track mixed format DSHD
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Eco1 is a Italian CP/M machine produced in 1982. It had 64kB of RAM, in
|
||||
later models expandable up to 384kB, and _two_ Z80 processors. One of these was
|
||||
used solely for managing the twin 8" drives, each storing 1.2MB, which was
|
||||
quite impressive for a CP/M machine in those days. Visually it is best
|
||||
described as 'very brown'.
|
||||
|
||||
<div style="text-align: center">
|
||||
<a href="vds-eco1.jpg"> <img src="vds-eco1.jpg" style="width:80%" alt="A contemporary advert for the Eco1"/></a>
|
||||
</div>
|
||||
|
||||
Its format is standard IBM scheme, but with an interesting wrinkle: there are
|
||||
_three_ different formatting zones on the disk:
|
||||
|
||||
- Track 0 side 0: 26 sectors, 128 bytes per sector (3296 bytes)
|
||||
- Track 0 side 1: 26 sectors, 256 bytes per sector (6656 bytes)
|
||||
- All others: 16 sectors, 512 bytes per sector (8192 bytes)
|
||||
|
||||
The standard `read ibm` command will autodetect and read these disks, but due
|
||||
to the format confusing the size autodetection the images need postprocessing
|
||||
to be useful, so there's a custom profile for the Eco1 which produces sensible
|
||||
images.
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read eco1 -s drive:0 -o eco1.img`
|
||||
|
||||
## References
|
||||
|
||||
- [Apulio Retrocomputing's page on the
|
||||
Eco1](https://www.apuliaretrocomputing.it/wordpress/?p=8976)
|
||||
|
||||
|
||||
@@ -1,2 +1,19 @@
|
||||
-d
|
||||
\r
|
||||
epsonpf10
|
||||
====
|
||||
## CP/M; 3.5" 40-track DSDD
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Epson PF10 is the disk unit for the Epson Z80 series of 'laptops', running
|
||||
CP/M. It uses a single-sided 40-track 3.5" format, which is unusual, but the
|
||||
format itself is yet another IBM scheme variant.
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read epsonpf10 -s drive:0 -o epsonpf10.img`
|
||||
|
||||
|
||||
@@ -1,2 +1,47 @@
|
||||
-d
|
||||
\r
|
||||
f85
|
||||
====
|
||||
## 461kB 5.25" 77-track SS
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Durango F85 was an early office computer based around a 5MHz 8085 processor,
|
||||
sold in 1977. It had an impressive 64kB of RAM, upgradable to 128kB, and ran
|
||||
its own multitasking operating system call DX-85M, as well as CP/M. It had an
|
||||
interesting electric-typewriter form factor, with a little monitor sitting on
|
||||
the side of it --- in operation you were facing the 14" printer.
|
||||
|
||||
It was touted as being portable. Which it was, if you were strong; the story
|
||||
is that they had to do an extensive search to find someone capable of lifting
|
||||
it for the following photo...
|
||||
|
||||
<div style="text-align: center">
|
||||
<img src="durangof85.jpg" style="max-width: 60%" alt="A Durango F85, held precariously">
|
||||
</div>
|
||||
|
||||
...and even then, they had to airbrush out the tendons in her neck from the
|
||||
effort!
|
||||
|
||||
It used 5.25 soft-sectored disks storing an impressive-for-those-days
|
||||
480kBish on a side, using a proprietary 4-in-5 GCR encoding. They used 77
|
||||
tracks, 12 sectors and 512 bytes per sector. Later models used double-sided
|
||||
disks; I don't have access to an image of one so don't know how they work
|
||||
(there's a suspicious looking spare byte in the sector header which could
|
||||
store the side). As always, if you have one, please [get in
|
||||
touch](https://github.com/davidgiven/fluxengine/issues/new).
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read f85 -s drive:0 -o f85.img`
|
||||
|
||||
## References
|
||||
|
||||
There's amazingly little information about these things.
|
||||
|
||||
* [Chuck Guzis' F85 page](http://www.sydex.com/durango/durango.html) with
|
||||
lots of pictures
|
||||
|
||||
|
||||
@@ -1,2 +1,48 @@
|
||||
-d
|
||||
\r
|
||||
fb100
|
||||
====
|
||||
## 100kB 3.5" 40-track SSSD
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Brother FB-100 is a serial-attached smart floppy drive used by a several
|
||||
different machines for mass storage, including the Tandy Model 100 and
|
||||
clones, the Husky Hunter 2, and (bizarrely) several knitting machines. It was
|
||||
usually rebadged, sometimes with a cheap paper label stuck over the Brother
|
||||
logo, but the most common variant appears to be the Tandy Portable Disk Drive
|
||||
or TPDD:
|
||||
|
||||
<div style="text-align: center">
|
||||
<a href="http://www.old-computers.com/museum/computer.asp?c=233&st=1"> <img src="tpdd.jpg" alt="A Tandy Portable Disk Drive"/></a>
|
||||
</div>
|
||||
|
||||
It's a bit of an oddball: the disk encoding is FM with a very custom record
|
||||
scheme: 40-track single-sided 3.5" disks storing 100kB or so each. Each track
|
||||
had only _two_ sectors, each 1280 bytes, but with an additional 12 bytes of
|
||||
ID data used for filesystem management.
|
||||
|
||||
There was also apparently a TPDD-2 which could store twice as much data, but
|
||||
I don't have access to one of those disks.
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read fb100 -s drive:0 -o fb100.img`
|
||||
|
||||
## References
|
||||
|
||||
- [Tandy Portable Disk Drive operations
|
||||
manual](http://www.classiccmp.org/cini/pdf/Tandy/Portable%20Disk%20Drive%20Operation%20Manual.pdf)
|
||||
|
||||
- [Tandy Portable Disk Drive service
|
||||
manual](https://archive.org/details/TandyPortableDiskDriveSoftwareManual26-3808s)
|
||||
|
||||
- [TPDD design notes (including a dump of the
|
||||
ROM)](http://bitchin100.com/wiki/index.php?title=TPDD_Design_Notes)
|
||||
|
||||
- [Knitting machine FB-100
|
||||
resources](http://www.k2g2.org/wiki:brother_fb-100)
|
||||
|
||||
|
||||
@@ -1,2 +1,42 @@
|
||||
-d
|
||||
\r
|
||||
hplif
|
||||
====
|
||||
## a variety of disk formats used by HP
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
LIF, a.k.a. Logical Interchange Format, is a series of formats used by
|
||||
Hewlett-Packard across their entire range of computers, from calculators to
|
||||
modern servers. It also defines a simple non-hierarchical filesystem which is
|
||||
bizarrely _still_ supported by HP-UX systems.
|
||||
|
||||
Floppy-disk wise, they're yet more variations of the standard IBM floppy
|
||||
encoding scheme.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `264`: 264kB 3.5" 66-track SSDD; HP9121 format
|
||||
- `608`: 608kB 3.5" 76-track DSDD; HP9122 format
|
||||
- `616`: 616kB 3.5" 77-track DSDD
|
||||
- `770`: 770kB 3.5" 77-track DSDD
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read hplif --264 -s drive:0 -o hplif.img`
|
||||
- `fluxengine read hplif --608 -s drive:0 -o hplif.img`
|
||||
- `fluxengine read hplif --616 -s drive:0 -o hplif.img`
|
||||
- `fluxengine read hplif --770 -s drive:0 -o hplif.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write hplif --264 -d drive:0 -i hplif.img`
|
||||
- `fluxengine write hplif --608 -d drive:0 -i hplif.img`
|
||||
- `fluxengine write hplif --616 -d drive:0 -i hplif.img`
|
||||
- `fluxengine write hplif --770 -d drive:0 -i hplif.img`
|
||||
|
||||
## References
|
||||
|
||||
* [A summary of the Hewlett Packard floppy disk
|
||||
formats](http://www.bitsavers.org/pdf/hp/disc/912x/HP_Flexible_Disk_Formats.pdf)
|
||||
|
||||
|
||||
124
doc/disk-ibm.md
124
doc/disk-ibm.md
@@ -1,2 +1,122 @@
|
||||
-d
|
||||
\r
|
||||
ibm
|
||||
====
|
||||
## Generic PC 3.5"/5.25" disks
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
IBM scheme disks are _the_ most common disk format, ever. They're used by a
|
||||
huge variety of different systems, and they come in a huge variety of different
|
||||
forms, but they're all fundamentally the same: either FM or MFM, either single-
|
||||
or double-sided, with distinct sector header and data records and no sector
|
||||
metadata. Systems which use IBM scheme disks include but are not limited to:
|
||||
|
||||
- IBM PCs (naturally)
|
||||
- Atari ST
|
||||
- late era Apple machines
|
||||
- Acorn machines
|
||||
- the TRS-80
|
||||
- late era Commodore machines (the 1571 and so on)
|
||||
- most CP/M machines
|
||||
- NEC PC-88 series
|
||||
- NEC PC-98 series
|
||||
- Sharp X68000
|
||||
- Fujitsu FM Towns
|
||||
- VAX & PDP-11
|
||||
- etc
|
||||
|
||||
FluxEngine supports reading these. However, some variants are more peculiar
|
||||
than others, and as a result there are specific decoders which set the defaults
|
||||
correctly for certain formats (for example: on PC disks the sector numbers
|
||||
start from 1, but on Acorn disks they start from 0). The IBM decoder described
|
||||
here is the generic one, and is suited for 'conventional' PC disks. While you
|
||||
can read all the variant formats with it if you use the right set of arguments,
|
||||
it's easier to use the specific decoder.
|
||||
|
||||
There is a generic decoder which should adjust automatically to whichever disk
|
||||
format you are using, but it's unreliable and not recommended. This format
|
||||
should also be used if you are writing images such as DIM which specify the
|
||||
image format. FluxEngine will use these parameters.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `auto`: try to autodetect the format (unreliable)
|
||||
- `160`: 160kB 5.25" 40-track 8-sector SSDD
|
||||
- `180`: 180kB 5.25" 40-track 9-sector SSDD
|
||||
- `320`: 320kB 5.25" 40-track 8-sector DSDD
|
||||
- `360`: 360kB 5.25" 40-track 9-sector DSDD
|
||||
- `720_96`: 720kB 5.25" 80-track 9-sector DSDD
|
||||
- `720_135`: 720kB 3.5" 80-track 9-sector DSDD
|
||||
- `1200`: 1200kB 5.25" 80-track 15-sector DSHD
|
||||
- `1232`: 1232kB 5.25" 77-track 8-sector DSHD
|
||||
- `1440`: 1440kB 3.5" 80-track 18-sector DSHD
|
||||
- `1680`: 1680kB 3.5" 80-track 21-sector DSHD; DMF
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read ibm --auto -s drive:0 -o ibm.img`
|
||||
- `fluxengine read ibm --160 -s drive:0 -o ibm.img`
|
||||
- `fluxengine read ibm --180 -s drive:0 -o ibm.img`
|
||||
- `fluxengine read ibm --320 -s drive:0 -o ibm.img`
|
||||
- `fluxengine read ibm --360 -s drive:0 -o ibm.img`
|
||||
- `fluxengine read ibm --720_96 -s drive:0 -o ibm.img`
|
||||
- `fluxengine read ibm --720_135 -s drive:0 -o ibm.img`
|
||||
- `fluxengine read ibm --1200 -s drive:0 -o ibm.img`
|
||||
- `fluxengine read ibm --1232 -s drive:0 -o ibm.img`
|
||||
- `fluxengine read ibm --1440 -s drive:0 -o ibm.img`
|
||||
- `fluxengine read ibm --1680 -s drive:0 -o ibm.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write ibm --160 -d drive:0 -i ibm.img`
|
||||
- `fluxengine write ibm --180 -d drive:0 -i ibm.img`
|
||||
- `fluxengine write ibm --320 -d drive:0 -i ibm.img`
|
||||
- `fluxengine write ibm --360 -d drive:0 -i ibm.img`
|
||||
- `fluxengine write ibm --720_96 -d drive:0 -i ibm.img`
|
||||
- `fluxengine write ibm --720_135 -d drive:0 -i ibm.img`
|
||||
- `fluxengine write ibm --1200 -d drive:0 -i ibm.img`
|
||||
- `fluxengine write ibm --1232 -d drive:0 -i ibm.img`
|
||||
- `fluxengine write ibm --1440 -d drive:0 -i ibm.img`
|
||||
- `fluxengine write ibm --1680 -d drive:0 -i ibm.img`
|
||||
|
||||
Mixed-format disks
|
||||
------------------
|
||||
|
||||
Some disks, such as those belonging to early CP/M machines, or N88-Basic disks
|
||||
(for PC-88 and PC-98), have more than one format on the disk at once. Typically,
|
||||
the first few tracks will be low-density FM encoded and will be read by the
|
||||
machine's ROM; those tracks contain new floppy drive handling code capable of
|
||||
coping with MFM data, and so the rest of the disk will use that, allowing them
|
||||
to store more data.
|
||||
|
||||
FluxEngine can read these fine, but it tends to get a bit confused when it sees
|
||||
tracks with differing numbers of sectors --- if track 0 has 32 sectors but
|
||||
track 1 has 16, it will assume that sectors 16..31 are missing on track 1 and
|
||||
size the image file accordingly. This can be worked around by specifying the
|
||||
size of each track; see the `eco1` read profile for an example.
|
||||
|
||||
N88-Basic format floppies can be written by either specifying the `n88basic`
|
||||
format, or by using D88 or NFD format images which include explicit sector
|
||||
layout information.
|
||||
|
||||
Writing other formats can be made to work too, by creating a custom format
|
||||
specifier, using the `n88basic` format as an example.
|
||||
Please [get in touch](https://github.com/davidgiven/fluxengine/issues/new) if
|
||||
you have specific requirements.
|
||||
|
||||
360rpm 3.5" disks
|
||||
-----------------
|
||||
|
||||
Japanese PCs (NEC PC-98, Sharp X68000, Fujitsu FM Towns) spin their floppy
|
||||
drives at 360rpm rather than the more typical 300rpm. This was done in order
|
||||
to be fully backwards compatible with 5.25" disks, while using the exact
|
||||
same floppy controller. Later models of the PC-9821, as well as most USB floppy
|
||||
drives, feature "tri-mode" support which in addition to normal 300rpm modes,
|
||||
can change their speed to read and write 360rpm DD and HD disks.
|
||||
|
||||
Neither the FluxEngine or Greaseweazle hardware can currently command a
|
||||
tri-mode drive to spin at 360rpm. However on both devices the FluxEngine
|
||||
software is capable of both reading and writing 300rpm disks at 360rpm and vice
|
||||
versa, so it shouldn't matter.
|
||||
|
||||
|
||||
@@ -1,2 +1,19 @@
|
||||
-d
|
||||
\r
|
||||
icl30
|
||||
====
|
||||
## CP/M; 263kB 35-track DSSD
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The ICL Model 30 is a reasonably standard CP/M machine using 35-track single
|
||||
density disks and the traditional CP/M 128-byte secotrs --- 30 of them per
|
||||
track! Other than that it's another IBM scheme variation.
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read icl30 -s drive:0 -o icl30.img`
|
||||
|
||||
|
||||
@@ -1,2 +1,73 @@
|
||||
-d
|
||||
\r
|
||||
mac
|
||||
====
|
||||
## 400kB/800kB 3.5" GCR
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
Macintosh disks come in two varieties: the newer 1440kB ones, which are
|
||||
perfectly ordinary PC disks you should use the `ibm` profile to read them, and
|
||||
the older 800kB disks (and 400kB for the single sides ones). They have 80
|
||||
tracks and up to 12 sectors per track.
|
||||
|
||||
They are also completely insane.
|
||||
|
||||
It's not just the weird, custom GCR encoding. It's not just the utterly
|
||||
bizarre additional encoding/checksum built on top of that where [every byte
|
||||
is mutated according to the previous bytes in the
|
||||
sector](https://www.bigmessowires.com/2011/10/02/crazy-disk-encoding-schemes/).
|
||||
It's not just the odd way in which disks think they have four sides, two on one
|
||||
side and two on the other, so that the track byte stores only the bottom 6 bits
|
||||
of the track number. It's not just the way that Macintosh sectors are 524 bytes
|
||||
long. No, it's the way the Macintosh drive changes speed depending on which
|
||||
track it's looking at, so that each track contains a different amount of data.
|
||||
|
||||
The reason for this is actually quite sensible: the tracks towards the centre
|
||||
of the disk are obviously moving more slowly, so you can't pack the bits in
|
||||
quite as closely (due to limitations in the magnetic media). You can use a
|
||||
higher bitrate at the edge of the disk than in the middle. Many platforms, for
|
||||
example the Commodore 64 1541 drive, changed bitrate this way.
|
||||
|
||||
But Macintosh disks used a constant bitrate and changed the speed that the disk
|
||||
spun instead to achieve the same effect...
|
||||
|
||||
_Anyway_: FluxEngine will read them fine on conventional drives. Because it's
|
||||
clever.
|
||||
|
||||
Macintosh computers never really used the twelve bytes of metadata and the
|
||||
standard for disk images is to omit it. If you want them, specify that you want
|
||||
524-byte sectors. The metadata will follow the 512 bytes of user data.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `400`: 400kB 80-track SSDD
|
||||
- `800`: 800kB 80-track DSDD
|
||||
- `metadata`: read/write 524 byte sectors
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read mac --400 -s drive:0 -o mac.dsk`
|
||||
- `fluxengine read mac --800 -s drive:0 -o mac.dsk`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write mac --400 -d drive:0 -i mac.dsk`
|
||||
- `fluxengine write mac --800 -d drive:0 -i mac.dsk`
|
||||
|
||||
## References
|
||||
|
||||
- [MAME's ap_dsk35.cpp file](https://github.com/mamedev/mame/blob/4263a71e64377db11392c458b580c5ae83556bc7/src/lib/formats/ap_dsk35.cpp),
|
||||
without which I'd never have managed to do this
|
||||
|
||||
- [Crazy Disk Encoding
|
||||
Schemes](https://www.bigmessowires.com/2011/10/02/crazy-disk-encoding-schemes/), which made
|
||||
me realise just how nuts the format is
|
||||
|
||||
- [Les Disquettes et le drive Disk II](http://www.hackzapple.com/DISKII/DISKIITECH.HTM), an
|
||||
epicly detailed writeup of the Apple II disk format (which is closely related)
|
||||
|
||||
- [The DiskCopy 4.2
|
||||
format](https://www.discferret.com/wiki/Apple_DiskCopy_4.2), described on
|
||||
the DiskFerret website.
|
||||
|
||||
|
||||
@@ -1,2 +1,87 @@
|
||||
-d
|
||||
\r
|
||||
micropolis
|
||||
====
|
||||
## 100tpi MetaFloppy disks
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
Micropolis MetaFloppy disks use MFM and hard sectors. Mod I was 48 TPI and
|
||||
stored 143k per side. Mod II was 100 TPI and stored 315k per side. Each of the
|
||||
16 sectors contains 266 bytes of "user data," allowing 10 bytes of metadata for
|
||||
use by the operating system. Micropolis DOS (MDOS) used the metadata bytes, but
|
||||
CP/M did not.
|
||||
|
||||
Some later systems were Micropolis-compatible and so were also 100 TPI, like
|
||||
the Vector Graphic Dual-Mode Disk Controller which was paired with a Tandon
|
||||
drive.
|
||||
|
||||
**Important note:** You _cannot_ read these disks with a normal PC drive, as
|
||||
these drives are 96tpi. The track spacing is determined by the physical geometry
|
||||
of the drive and can't be changed in software. You'll need to get hold of a
|
||||
100tpi Micropolis drive. Luckily these seem to use the same connector and
|
||||
pinout as a 96tpi PC 5.25" drive. In use they should be identical.
|
||||
|
||||
While most operating systems use the standard Micropolis checksum, Vector
|
||||
Graphic MZOS uses a unique checksum. The decoder will automatically detect
|
||||
the checksum type in use; however, a specific checksum type may be forced
|
||||
using the `--decoder.micropolis.checksum_type=TYPE` where TYPE is one of:
|
||||
|
||||
| Checksum | Description |
|
||||
|------------|-----------------------------------------|
|
||||
| AUTO | Automatically detect |
|
||||
| MICROPOLIS | Standard Micropolis (MDOS, CP/M, OASIS) |
|
||||
| MZOS | Vector Graphic MZOS |
|
||||
|
||||
Later versions of the Micropolis format supported ECC, especially in
|
||||
controllers with HDD support. The ECC can detect and correct errors. However,
|
||||
it is unclear what ECC algorithm was used by each vendor. ECC is disabled by
|
||||
default, but available for checking and correcting using
|
||||
`--decoder.micropolis.ecc_type=TYPE` and for writing from IMG files using
|
||||
`--encoder.micropolis.ecc_type=TYPE`, where TYPE is one of:
|
||||
|
||||
| ECC | Description |
|
||||
|--------|------------------------------------------|
|
||||
| NONE | No ECC processing enabled |
|
||||
| VECTOR | Vector Graphic Dual-Mode Disk Controller |
|
||||
|
||||
The [CP/M BIOS](https://www.seasip.info/Cpm/bios.html) defined SELDSK, SETTRK,
|
||||
and SETSEC, but no function to select the head/side. Double-sided floppies
|
||||
could be represented as having either twice the number of sectors, for CHS, or
|
||||
twice the number of tracks, HCS; the second side's tracks in opposite order
|
||||
logically followed the first side (e.g., tracks 77-153). Micropolis disks
|
||||
tended to be the latter. FluxEngine always emits CHS format disks, so you may
|
||||
need to apply extra options to change the format if desired.
|
||||
|
||||
## Options
|
||||
|
||||
- :
|
||||
- `143`: 143kB 5.25" SSDD hard-sectored; Micropolis MetaFloppy Mod I
|
||||
- `287`: 287kB 5.25" DSDD hard-sectored; Micropolis MetaFloppy Mod I
|
||||
- `315`: 315kB 5.25" SSDD hard-sectored; Micropolis MetaFloppy Mod II
|
||||
- `630`: 630kB 5.25" DSDD hard-sectored; Micropolis MetaFloppy Mod II
|
||||
- `vgi`: Read/write VGI format images with 275 bytes per sector
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read micropolis -s drive:0 -o micropolis.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write micropolis -d drive:0 -i micropolis.img`
|
||||
|
||||
## References
|
||||
|
||||
- [Micropolis 1040/1050 S-100 Floppy Disk Subsystems User's Manual][micropolis1040/1050].
|
||||
Section 6, pages 261-266. Documents pre-ECC sector format. Note that the
|
||||
entire record, starting at the sync byte, is controlled by software
|
||||
|
||||
- [Vector Graphic Dual-Mode Disk Controller Board Engineering Documentation][vectordualmode].
|
||||
Section 1.6.2. Documents ECC sector format
|
||||
|
||||
- [AltairZ80 Simulator Usage Manual][altairz80]. Section 10.6. Documents ECC
|
||||
sector format and VGI file format
|
||||
|
||||
[micropolis1040/1050]: http://www.bitsavers.org/pdf/micropolis/metafloppy/1084-01_1040_1050_Users_Manual_Apr79.pdf
|
||||
[vectordualmode]: http://bitsavers.org/pdf/vectorGraphic/hardware/7200-1200-02-1_Dual-Mode_Disk_Controller_Board_Engineering_Documentation_Feb81.pdf
|
||||
[altairz80]: http://www.bitsavers.org/simh.trailing-edge.com_201206/pdf/altairz80_doc.pdf
|
||||
|
||||
|
||||
@@ -1,2 +1,33 @@
|
||||
-d
|
||||
\r
|
||||
ms2000
|
||||
====
|
||||
## MS2000 Microdisk Development System
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The RCA MicroDisk Development System MS2000 is a highly obscure (i.e. I gather
|
||||
that single digit numbers of original machines exist) development system for the
|
||||
RCA1802 series of CPUs, as made famous by the Cosmac ELF. It was a fairly
|
||||
straightforward big bag o'RAM system with a 2kB boot ROM, 62kB of RAM, twin
|
||||
floppy drives and a serial terminal --- CP/M users will find it very familiar.
|
||||
|
||||
Read and writing disks is currently not supported by FluxEngine, but there is
|
||||
basic support for the MicroDisk operating system's file system. This should
|
||||
allow files to be read from MS2000 disk images.
|
||||
|
||||
The disks are normal DD 3.5" disks, using a 70-track, single sided variation of
|
||||
the venerable IBM floppy disk scheme, so allowing 315kB of storage per disk.
|
||||
|
||||
If you have access to flux files for MS2000 disks, please [get in
|
||||
touch](https://github.com/davidgiven/cpm65/issues/new) --- I would like to add
|
||||
better support for these.
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
## References
|
||||
|
||||
- [The EMMA-02 emulator](https://www.emma02.hobby-site.com/ms2000.html), which
|
||||
supports the MS2000 and provides information on it.
|
||||
|
||||
|
||||
@@ -1,2 +1,69 @@
|
||||
-d
|
||||
\r
|
||||
mx
|
||||
====
|
||||
## Soviet-era PDP-11 clone
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The DVK (in Russian, 沾7d65
|
||||
Computing Complex) was a late 1970s Soviet personal computer, a cut-down
|
||||
version of the professional SM EVM (ⵁ241c
|
||||
--- literally System of Mini Computers), which _itself_ was an unlicensed
|
||||
clone of the PDP-11. The MX board was an early floppy drive controller board
|
||||
for it.
|
||||
|
||||
<div style="text-align: center">
|
||||
<a href="http://www.leningrad.su/museum/show_big.php?n=1006"><img src="dvk3m.jpg" style="max-width: 60%" alt="A DVK computer"></a>
|
||||
</div>
|
||||
|
||||
The MX format is interesting in that it has to be read a track at a time. The
|
||||
format contains the usual ID prologue at the beginning of the track, then
|
||||
eleven data blocks and checksums, then the epilogue, then it stops. The
|
||||
actual encoding is normal FM. There were four different disk variants, in all
|
||||
combinations of single- and double-sided and 40- and 80-tracked; but every
|
||||
track contained eleven 256-byte sectors.
|
||||
|
||||
The format varies subtly depending on whether you're using the 'new' driver
|
||||
or the 'old' driver. FluxEngine should read both.
|
||||
|
||||
A track is:
|
||||
|
||||
* 8 x 0x0000 words (FM encoded as 01010101...)
|
||||
* 1 x 0x00F3 --- start of track
|
||||
* 1 x 0xnnnn --- track number
|
||||
* 11 of:
|
||||
* 128 words (256 bytes) of data
|
||||
* 16 bit checksum
|
||||
* **if 'new' format:**
|
||||
* 3 x 0x83nn --- `n = (track_number<<1) + side_number`
|
||||
* **if 'old' format:**
|
||||
* 3 x 0x8301
|
||||
|
||||
The checksum is just the unsigned integer sum of all the words in the sector.
|
||||
Words are all stored little-endian.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `110`: 110kB 5.25" 40-track SSSD
|
||||
- `220ds`: 220kB 5.25" 40-track DSSD
|
||||
- `220ss`: 220kB 5.25" 80-track SSSD
|
||||
- `440`: 440kB 5.25" 80-track DSSD
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read mx --110 -s drive:0 -o mx.img`
|
||||
- `fluxengine read mx --220ds -s drive:0 -o mx.img`
|
||||
- `fluxengine read mx --220ss -s drive:0 -o mx.img`
|
||||
- `fluxengine read mx --440 -s drive:0 -o mx.img`
|
||||
|
||||
## References
|
||||
|
||||
- [The Soviet Digital Electronics
|
||||
Museum](http://www.leningrad.su/museum/main.php) (source of the image
|
||||
above)
|
||||
|
||||
- [a random post on the HxC2001 support
|
||||
forum](http://torlus.com/floppy/forum/viewtopic.php?t=1384) with lots of
|
||||
information on the format
|
||||
|
||||
|
||||
@@ -1,2 +1,26 @@
|
||||
-d
|
||||
\r
|
||||
n88basic
|
||||
====
|
||||
## PC8800/PC98 5.25" 77-track 26-sector DSHD
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The N88-BASIC disk format is the one used by the operating system of the same
|
||||
name for the Japanese PC8800 and PC98 computers. It is another IBM scheme
|
||||
variant, and is very similar to some mixed-format CP/M disk formats, where
|
||||
track 0 side 0 uses 128-byte single density sectors and the rest of the disk
|
||||
uses 512-byte double density sectors. (The reason for this is that the PC8800
|
||||
boot ROM could only read single density data.)
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read n88basic -s drive:0 -o n88basic.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write n88basic -d drive:0 -i n88basic.img`
|
||||
|
||||
|
||||
@@ -1,2 +1,50 @@
|
||||
-d
|
||||
\r
|
||||
northstar
|
||||
====
|
||||
## 5.25" hard sectored
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
Northstar Floppy disks use 10-sector hard sectored disks with either FM or MFM
|
||||
encoding. They may be single- or double-sided. Each of the 10 sectors contains
|
||||
256 (FM) or 512 (MFM) bytes of data. The disk has 35 cylinders, with tracks 0-
|
||||
34 on side 0, and tracks 35-69 on side 1. Tracks on side 1 are numbered "back-
|
||||
wards" in that track 35 corresponds to cylinder 34, side 1, and track 69
|
||||
corresponds to cylinder 0, side 1.
|
||||
|
||||
The Northstar sector format does not include any head positioning information.
|
||||
As such, reads from Northstar floppies need to by synchronized with the index
|
||||
pulse, in order to properly identify the sector being read. This is handled
|
||||
automatically by FluxEngine.
|
||||
|
||||
Due to the nature of the track ordering on side 1, an .nsi image reader and
|
||||
writer are provided for double-sided disks. The .nsi image writer supports
|
||||
both single- and double-sided disks; however single-sided .nsi images are
|
||||
equivalent to .img images.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `87`: 87.5kB 5.25" 35-track SSSD hard-sectored
|
||||
- `175`: 175kB 5.25" 40-track SSDD hard-sectored
|
||||
- `350`: 350kB 5.25" 40-track DSDD hard-sectored
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read northstar --87 -s drive:0 -o northstar.nsi`
|
||||
- `fluxengine read northstar --175 -s drive:0 -o northstar.nsi`
|
||||
- `fluxengine read northstar --350 -s drive:0 -o northstar.nsi`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write northstar --87 -d drive:0 -i northstar.nsi`
|
||||
- `fluxengine write northstar --175 -d drive:0 -i northstar.nsi`
|
||||
- `fluxengine write northstar --350 -d drive:0 -i northstar.nsi`
|
||||
|
||||
## References
|
||||
|
||||
- [MICRO-DISK SYSTEM MDS-A-D DOUBLE DENSITY Manual][northstar_mds].
|
||||
Page 33 documents sector format for single- and double-density.
|
||||
|
||||
[northstar_mds]: http://bitsavers.org/pdf/northstar/boards/Northstar_MDS-A-D_1978.pdf
|
||||
|
||||
|
||||
@@ -1,2 +1,32 @@
|
||||
-d
|
||||
\r
|
||||
psos
|
||||
====
|
||||
## 800kB DSDD with PHILE
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
pSOS was an influential real-time operating system from the 1980s, used mainly
|
||||
on 68000-based machines, lasting up until about 2000 when it was bought (and
|
||||
cancelled) by Wind River. It had its own floppy disk format and file system,
|
||||
both of which are partially supported here.
|
||||
|
||||
The PHILE file system is almost completely undocumented and so many of the data
|
||||
structures have had to be reverse engineered and are not well known. Please
|
||||
[get in touch](https://github.com/davidgiven/fluxengine/issues/new) if you know
|
||||
anything about it.
|
||||
|
||||
The floppy disk format itself is an IBM scheme variation with 1024-byte sectors
|
||||
and, oddly, swapped sides.
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read psos -s drive:0 -o pme.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write psos -d drive:0 -i pme.img`
|
||||
|
||||
|
||||
@@ -1,2 +1,48 @@
|
||||
-d
|
||||
\r
|
||||
rolandd20
|
||||
====
|
||||
## 3.5" electronic synthesiser disks
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Roland D20 is a classic electronic synthesiser with a built-in floppy
|
||||
drive, used for saving MIDI sequences and samples.
|
||||
|
||||
Weirdly, it seems to use precisely the same format as the Brother word
|
||||
processors: a thoroughly non-IBM-compatible custom GCR system.
|
||||
|
||||
FluxEngine supports both reading and writing D20 disks, as well as basic support
|
||||
for the filesystem, allowing files to be read from and written to D20 disks.
|
||||
Note that the D20 was never intended to support arbitrary files on its disks and
|
||||
is very likely to crash if you put unexpected files on a disk. In addition,
|
||||
while the file format itself is currently unknown, there is a header at the top
|
||||
of the file containing what appears to be the name shown in the D20 file
|
||||
browser, so the name by which you see it is not necessarily the filename.
|
||||
|
||||
A word of warning --- just like the Brother word processors, the D20 floppy
|
||||
drive isn't very well aligned. The drive itself uses quarter-stepping to
|
||||
automatically adapt to whatever alignment the disk was formatted with. This
|
||||
means that trying to read such a disk on a PC drive, which does _not_ have
|
||||
adjustable alignment, may not work very well. In these situations it is possible
|
||||
to adjust the alignment of most modern drives, but this is a somewhat risky
|
||||
process and may result in permanently wrecking the drive alignment.
|
||||
|
||||
Please [get in touch](https://github.com/davidgiven/fluxengine/issues/new) if
|
||||
you know anything about it.
|
||||
|
||||
Many thanks to trondl [on the VCF
|
||||
forums](https://forum.vcfed.org/index.php?threads/roland-d-20-decoding-the-mysterious-floppy-format.1243226/)
|
||||
for assistance with this!
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read rolandd20 -s drive:0 -o rolandd20.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write rolandd20 -d drive:0 -i rolandd20.img`
|
||||
|
||||
|
||||
@@ -1,2 +1,23 @@
|
||||
-d
|
||||
\r
|
||||
rx50
|
||||
====
|
||||
## 400kB 5.25" 80-track 10-sector SSDD
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Digital RX50 is one of the external floppy drive units used by Digital's
|
||||
range of computers, especially the DEC Rainbow microcomputer. It is a fairly
|
||||
vanilla single-sided IBM scheme variation.
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read rx50 -s drive:0 -o rx50.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write rx50 -d drive:0 -i rx50.img`
|
||||
|
||||
|
||||
@@ -1,2 +1,15 @@
|
||||
-d
|
||||
\r
|
||||
shugart_drive
|
||||
====
|
||||
## Adjust configuration for a Shugart drive
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
This is an extension profile; adding this to the command line will configure
|
||||
FluxEngine to adjust the pinout to work with a Shugart drive. This only works
|
||||
on Greaseweazle hardware.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
fluxengine read ibm --720 shugart_drive
|
||||
```
|
||||
|
||||
|
||||
@@ -1,2 +1,34 @@
|
||||
-d
|
||||
\r
|
||||
smaky6
|
||||
====
|
||||
## 308kB 5.25" 77-track 16-sector SSDD, hard sectored
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Smaky 6 is a Swiss computer from 1978 produced by Epsitec. It's based
|
||||
around a Z80 processor and has one or two Micropolis 5.25" drives which use
|
||||
16-sector hard sectored disks. The disk format is single-sided with 77 tracks
|
||||
and 256-byte sectors, resulting in 308kB disks. It uses MFM with a custom
|
||||
sector record scheme. It was later superceded by a 68000-based Smaky which used
|
||||
different disks.
|
||||
|
||||
FluxEngine supports these, although because the Micropolis drives use a 100tpi
|
||||
track pitch, you can't read Smaky 6 disks with a normal PC 96tpi drive. You
|
||||
will have to find a 100tpi drive from somewhere (they're rare).
|
||||
|
||||
There is experimental read-only support for the Smaky 6 filesystem, allowing
|
||||
the directory to be listed and files read from disks. It's not known whether
|
||||
this is completely correct, so don't trust it!
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read smaky6 -s drive:0 -o smaky6.img`
|
||||
|
||||
## References
|
||||
|
||||
- [Smaky Info, 1978-2002 (in French)](https://www.smaky.ch/theme.php?id=sminfo)
|
||||
|
||||
|
||||
@@ -1,2 +1,48 @@
|
||||
-d
|
||||
\r
|
||||
tartu
|
||||
====
|
||||
## The Palivere and variations
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Tartu Palivere is a 1988 Z80-based computer from Estonia. It is a CP/M
|
||||
machine with 64kB of RAM, running off a 2MHz ꃣ0e30
|
||||
clone; it operated off punched tape, cassette, external hard drive or floppy, and was notable as being the first ever computer with an Estonian keyboard.
|
||||
|
||||
<div style="text-align: center">
|
||||
<img src="tartu.jpg" alt="The Tartu computer's developer Leo Humal working with one."/>
|
||||
</div>
|
||||
|
||||
From a floppy disk perspective, it is interesting because the floppy drive
|
||||
interface is almost entirely handled in software --- necessary at the time as
|
||||
the usual floppy disk interface chip at the time, the ⎲fba5
|
||||
of the WD1793), was hard to find. Instead, the floppy controller board was
|
||||
implemented entirely using TTL logic. Despite this, the encoding is fairly high
|
||||
density, using MFM and with up to 780kB on a double-sided 80 track disk.
|
||||
|
||||
<div style="text-align: center">
|
||||
<img src="tartu-fdc.jpg" alt="The Tartu FDC with Soviet TTL logic chips."/>
|
||||
</div>
|
||||
|
||||
FluxEngine supports reading and writing Tartu disks with CP/M filesystem access.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `390`: 390kB 5.25" 40-track DSDD
|
||||
- `780`: 780kB 5.25" 80-track DSDD
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read tartu --390 -s drive:0 -o tartu.img`
|
||||
- `fluxengine read tartu --780 -s drive:0 -o tartu.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write tartu --390 -d drive:0 -i tartu.img`
|
||||
- `fluxengine write tartu --780 -d drive:0 -i tartu.img`
|
||||
|
||||
## References
|
||||
|
||||
- [The Estonia Museum of Electronics](https://www.elektroonikamuuseum.ee/tartu_arvuti_lugu.html)
|
||||
|
||||
|
||||
@@ -1,2 +1,39 @@
|
||||
-d
|
||||
\r
|
||||
tids990
|
||||
====
|
||||
## 1126kB 8" DSSD
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Texas Instruments DS990 was a multiuser modular computing system from 1998,
|
||||
based around the TMS-9900 processor (as used by the TI-99). It had an 8" floppy
|
||||
drive module, the FD1000, which was a 77-track, 288-byte sector FM/MFM system
|
||||
with 26 sectors per track. The encoding scheme was very similar to a simplified
|
||||
version of the IBM scheme, but of course not compatible. A double-sided disk
|
||||
would store a very satisfactory 1126kB of data; here's one at <a
|
||||
href="https://www.old-computers.com/museum/computer.asp?st=1&c=1025">old-computers.com</a>:
|
||||
|
||||
<div style="text-align: center">
|
||||
<a href="https://www.old-computers.com/museum/computer.asp?st=1&c=1025">
|
||||
<img src="tids990.jpg" style="max-width: 60%" alt="A DS990 at old-computers.com"></a>
|
||||
</div>
|
||||
|
||||
FluxEngine will read and write these (but only the DSDD MFM variant).
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read tids990 -s drive:0 -o tids990.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write tids990 -d drive:0 -i tids990.img`
|
||||
|
||||
## References
|
||||
|
||||
- [The FD1000 Depot Maintenance
|
||||
Manual](http://www.bitsavers.org/pdf/ti/990/disk/2261885-9701_FD1000depotVo1_Jan81.pdf)
|
||||
|
||||
|
||||
@@ -1,2 +1,27 @@
|
||||
-d
|
||||
\r
|
||||
tiki
|
||||
====
|
||||
## CP/M
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Tiki 100 is a Z80-based Norwegian microcomputer from the mid 1980s intended
|
||||
for eductional use. It mostly ran an unbranded CP/M clone, and uses fairly
|
||||
normal CP/M disks --- IBM scheme and from 128 to 512 bytes per sector depending
|
||||
on the precise format.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `90`: 90kB 40-track 18-sector SSSD
|
||||
- `200`: 200kB 40-track 10-sector SSDD
|
||||
- `400`: 400kB 40-track 10-sector DSDD
|
||||
- `800`: 800kB 80-track 10-sector DSDD
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read tiki --90 -s drive:0 -o tiki.img`
|
||||
- `fluxengine read tiki --200 -s drive:0 -o tiki.img`
|
||||
- `fluxengine read tiki --400 -s drive:0 -o tiki.img`
|
||||
- `fluxengine read tiki --800 -s drive:0 -o tiki.img`
|
||||
|
||||
|
||||
@@ -1,2 +1,62 @@
|
||||
-d
|
||||
\r
|
||||
victor9k
|
||||
====
|
||||
## 1224kB 5.25" DSDD GCR
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Victor 9000 / Sirius One was a rather strange old 8086-based machine
|
||||
which used a disk format very reminiscent of the Commodore format; not a
|
||||
coincidence, as Chuck Peddle designed them both. They're 80-track, 512-byte
|
||||
sector GCR disks, with a variable-speed drive and a varying number of sectors
|
||||
per track --- from 19 to 12. Disks can be double-sided, meaning that they can
|
||||
store 1224kB per disk, which was almost unheard of back then. Because the way
|
||||
that the tracks on head 1 are offset from head 0 (this happens with all disks),
|
||||
the speed zone allocation on head 1 differs from head 0...
|
||||
|
||||
| Zone | Head 0 tracks | Head 1 tracks | Sectors | Original period (ms) |
|
||||
|:----:|:-------------:|:-------------:|:-------:|:--------------------:|
|
||||
| 0 | 0-3 | | 19 | 237.9 |
|
||||
| 1 | 4-15 | 0-7 | 18 | 224.5 |
|
||||
| 2 | 16-26 | 8-18 | 17 | 212.2 |
|
||||
| 3 | 27-37 | 19-29 | 16 | 199.9 |
|
||||
| 4 | 38-47\* | 30-39\* | 15 | 187.6 |
|
||||
| 5 | 48-59 | 40-51 | 14 | 175.3 |
|
||||
| 6 | 60-70 | 52-62 | 13 | 163.0 |
|
||||
| 7 | 71-79 | 63-74 | 12 | 149.6 |
|
||||
| 8 | | 75-79 | 11 | 144.0 |
|
||||
|
||||
(The Original Period column is the original rotation rate. When used in
|
||||
FluxEngine, the disk always spins at 360 rpm, which corresponds to a rotational
|
||||
period of 166 ms.)
|
||||
|
||||
\*The Victor 9000 Hardware Reference Manual has a bug in the documentation
|
||||
and lists Zone 4 as ending with track 48 on head 0 and track 40 on head 1.
|
||||
The above table matches observed data on various disks and the assembly
|
||||
code in the boot loader, which ends Zone 4 with track 47 on head 0
|
||||
and track 39 on Head 1.
|
||||
|
||||
FluxEngine can read and write both the single-sided and double-sided variants.
|
||||
|
||||
## Options
|
||||
|
||||
- Format variants:
|
||||
- `612`: 612kB 80-track DSHD GCR
|
||||
- `1224`: 1224kB 80-track DSHD GCR
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read victor9k --612 -s drive:0 -o victor9k.img`
|
||||
- `fluxengine read victor9k --1224 -s drive:0 -o victor9k.img`
|
||||
|
||||
To write:
|
||||
|
||||
- `fluxengine write victor9k --612 -d drive:0 -i victor9k.img`
|
||||
- `fluxengine write victor9k --1224 -d drive:0 -i victor9k.img`
|
||||
|
||||
## References
|
||||
|
||||
- [The Victor 9000 technical reference manual](http://bitsavers.org/pdf/victor/victor9000/Victor9000TechRef_Jun82.pdf)
|
||||
|
||||
- [DiskFerret's Victor 9000 format guide](https://discferret.com/wiki/Victor_9000_format)
|
||||
|
||||
|
||||
@@ -1,2 +1,42 @@
|
||||
-d
|
||||
\r
|
||||
zilogmcz
|
||||
====
|
||||
## 320kB 8" 77-track SSSD hard-sectored
|
||||
<!-- This file is automatically generated. Do not edit. -->
|
||||
|
||||
The Zilog MCZ is an extremely early Z80 development system, produced by
|
||||
Zilog, which came out in 1976. It used twin 8-inch hard sectored floppy
|
||||
drives; here's one at the <a
|
||||
href="http://www.computinghistory.org.uk/det/12157/Zilog-Z-80-Microcomputer-System/">Centre
|
||||
for Computing History</a>:
|
||||
|
||||
<div style="text-align: center">
|
||||
<a href="http://www.computinghistory.org.uk/det/12157/Zilog-Z-80-Microcomputer-System/">
|
||||
<img src="zilogmcz.jpg" style="max-width: 60%" alt="A Zilog MCZ at the Centre For Computing History"></a>
|
||||
</div>
|
||||
|
||||
The MCZ ran Zilog's own operating system, Z80-RIO, and used 77 track
|
||||
single-sided disks, with 32 sectors (each marked by an index hole), with 132
|
||||
bytes per sector --- 128 bytes of user payload plus two two-byte metadata
|
||||
words used to construct linked lists of sectors for storing files. These
|
||||
stored 320kB each.
|
||||
|
||||
FluxEngine has read support for these, including support for RIO's ZDOS file
|
||||
system.
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read zilogmcz -s drive:0 -o zilogmcz.img`
|
||||
|
||||
## References
|
||||
|
||||
* [About the Zilog MCZ](http://www.retrotechnology.com/restore/zilog.html),
|
||||
containing lots of useful links
|
||||
|
||||
* [The hardware user's manual](https://amaus.org/static/S100/zilog/ZDS/Zilog%20ZDS%201-25%20Hardware%20Users%20Manual.pdf)
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ from build.protobuf import proto, protocc
|
||||
|
||||
|
||||
proto(name="common_proto", srcs=["./common.proto"])
|
||||
protocc(name="common_proto_lib", srcs=[".+common_proto"], deps=["+protobuf_lib"])
|
||||
protocc(
|
||||
name="common_proto_lib", srcs=[".+common_proto"], deps=["+protobuf_lib"]
|
||||
)
|
||||
|
||||
proto(
|
||||
name="layout_proto",
|
||||
|
||||
@@ -250,3 +250,17 @@ void warning(const std::string msg)
|
||||
log(msg);
|
||||
}
|
||||
|
||||
void fillBitmapTo(std::vector<bool>& bitmap,
|
||||
unsigned& cursor,
|
||||
unsigned terminateAt,
|
||||
const std::vector<bool>& pattern)
|
||||
{
|
||||
while (cursor < terminateAt)
|
||||
{
|
||||
for (bool b : pattern)
|
||||
{
|
||||
if (cursor < bitmap.size())
|
||||
bitmap[cursor++] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,11 @@ extern int countSetBits(uint32_t word);
|
||||
extern uint32_t unbcd(uint32_t bcd);
|
||||
extern int findLowestSetBit(uint64_t value);
|
||||
|
||||
extern void fillBitmapTo(std::vector<bool>& bitmap,
|
||||
unsigned& cursor,
|
||||
unsigned terminateAt,
|
||||
const std::vector<bool>& pattern);
|
||||
|
||||
template <class K, class V>
|
||||
std::map<V, K> reverseMap(const std::map<K, V>& map)
|
||||
{
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
from build.protobuf import proto, protocc
|
||||
from build.c import cxxlibrary
|
||||
|
||||
proto(
|
||||
name="proto",
|
||||
srcs=["./decoders.proto"],
|
||||
deps=["lib+common_proto", "arch+proto", "lib/fluxsink+proto"],
|
||||
)
|
||||
|
||||
protocc(
|
||||
name="proto_lib",
|
||||
srcs=[".+proto"],
|
||||
deps=["lib+common_proto_lib", "arch+proto_lib", "lib/fluxsink+proto_lib"],
|
||||
)
|
||||
|
||||
cxxlibrary(
|
||||
name="decoders",
|
||||
srcs=["./decoders.cc", "./fluxdecoder.cc", "./fmmfm.cc"],
|
||||
hdrs={
|
||||
"lib/decoders/decoders.h": "./decoders.h",
|
||||
"lib/decoders/fluxdecoder.h": "./fluxdecoder.h",
|
||||
"lib/decoders/rawbits.h": "./rawbits.h",
|
||||
},
|
||||
deps=["lib/core", "lib/config", "lib/data", ".+proto_lib"],
|
||||
)
|
||||
|
||||
@@ -3,26 +3,6 @@
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/config/config.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "arch/agat/agat.h"
|
||||
#include "arch/aeslanier/aeslanier.h"
|
||||
#include "arch/amiga/amiga.h"
|
||||
#include "arch/apple2/apple2.h"
|
||||
#include "arch/brother/brother.h"
|
||||
#include "arch/c64/c64.h"
|
||||
#include "arch/f85/f85.h"
|
||||
#include "arch/fb100/fb100.h"
|
||||
#include "arch/ibm/ibm.h"
|
||||
#include "arch/macintosh/macintosh.h"
|
||||
#include "arch/micropolis/micropolis.h"
|
||||
#include "arch/mx/mx.h"
|
||||
#include "arch/northstar/northstar.h"
|
||||
#include "arch/rolandd20/rolandd20.h"
|
||||
#include "arch/smaky6/smaky6.h"
|
||||
#include "arch/tartu/tartu.h"
|
||||
#include "arch/tids990/tids990.h"
|
||||
#include "arch/victor9k/victor9k.h"
|
||||
#include "arch/zilogmcz/zilogmcz.h"
|
||||
#include "lib/data/fluxmapreader.h"
|
||||
#include "lib/data/flux.h"
|
||||
#include "protocol.h"
|
||||
@@ -33,46 +13,6 @@
|
||||
#include "lib/data/layout.h"
|
||||
#include <numeric>
|
||||
|
||||
std::unique_ptr<Decoder> Decoder::create(Config& config)
|
||||
{
|
||||
if (!config.hasDecoder())
|
||||
error("no decoder configured");
|
||||
return create(config->decoder());
|
||||
}
|
||||
|
||||
std::unique_ptr<Decoder> Decoder::create(const DecoderProto& config)
|
||||
{
|
||||
static const std::map<int,
|
||||
std::function<std::unique_ptr<Decoder>(const DecoderProto&)>>
|
||||
decoders = {
|
||||
{DecoderProto::kAgat, createAgatDecoder },
|
||||
{DecoderProto::kAeslanier, createAesLanierDecoder },
|
||||
{DecoderProto::kAmiga, createAmigaDecoder },
|
||||
{DecoderProto::kApple2, createApple2Decoder },
|
||||
{DecoderProto::kBrother, createBrotherDecoder },
|
||||
{DecoderProto::kC64, createCommodore64Decoder},
|
||||
{DecoderProto::kF85, createDurangoF85Decoder },
|
||||
{DecoderProto::kFb100, createFb100Decoder },
|
||||
{DecoderProto::kIbm, createIbmDecoder },
|
||||
{DecoderProto::kMacintosh, createMacintoshDecoder },
|
||||
{DecoderProto::kMicropolis, createMicropolisDecoder },
|
||||
{DecoderProto::kMx, createMxDecoder },
|
||||
{DecoderProto::kNorthstar, createNorthstarDecoder },
|
||||
{DecoderProto::kRolandd20, createRolandD20Decoder },
|
||||
{DecoderProto::kSmaky6, createSmaky6Decoder },
|
||||
{DecoderProto::kTartu, createTartuDecoder },
|
||||
{DecoderProto::kTids990, createTids990Decoder },
|
||||
{DecoderProto::kVictor9K, createVictor9kDecoder },
|
||||
{DecoderProto::kZilogmcz, createZilogMczDecoder },
|
||||
};
|
||||
|
||||
auto decoder = decoders.find(config.format_case());
|
||||
if (decoder == decoders.end())
|
||||
error("no decoder specified");
|
||||
|
||||
return (decoder->second)(config);
|
||||
}
|
||||
|
||||
std::shared_ptr<TrackDataFlux> Decoder::decodeToSectors(
|
||||
std::shared_ptr<const Fluxmap> fluxmap,
|
||||
std::shared_ptr<const TrackInfo>& trackInfo)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from build.protobuf import proto, protocc
|
||||
|
||||
from build.c import cxxlibrary
|
||||
|
||||
proto(
|
||||
name="proto",
|
||||
@@ -11,3 +11,10 @@ protocc(
|
||||
srcs=[".+proto"],
|
||||
deps=["lib+common_proto_lib", "arch+proto_lib"],
|
||||
)
|
||||
|
||||
cxxlibrary(
|
||||
name="encoders",
|
||||
srcs=["./encoders.cc"],
|
||||
hdrs={"lib/encoders/encoders.h": "./encoders.h"},
|
||||
deps=["lib/core", "lib/data", "lib/config", ".+proto_lib"],
|
||||
)
|
||||
|
||||
@@ -1,59 +1,13 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/config/config.h"
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "arch/agat/agat.h"
|
||||
#include "arch/amiga/amiga.h"
|
||||
#include "arch/apple2/apple2.h"
|
||||
#include "arch/brother/brother.h"
|
||||
#include "arch/c64/c64.h"
|
||||
#include "arch/ibm/ibm.h"
|
||||
#include "arch/macintosh/macintosh.h"
|
||||
#include "arch/micropolis/micropolis.h"
|
||||
#include "arch/northstar/northstar.h"
|
||||
#include "arch/tartu/tartu.h"
|
||||
#include "arch/tids990/tids990.h"
|
||||
#include "arch/victor9k/victor9k.h"
|
||||
#include "lib/encoders/encoders.pb.h"
|
||||
#include "lib/config/proto.h"
|
||||
#include "lib/data/layout.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "protocol.h"
|
||||
|
||||
std::unique_ptr<Encoder> Encoder::create(Config& config)
|
||||
{
|
||||
if (!config.hasEncoder())
|
||||
error("no encoder configured");
|
||||
return create(config->encoder());
|
||||
}
|
||||
|
||||
std::unique_ptr<Encoder> Encoder::create(const EncoderProto& config)
|
||||
{
|
||||
static const std::map<int,
|
||||
std::function<std::unique_ptr<Encoder>(const EncoderProto&)>>
|
||||
encoders = {
|
||||
{EncoderProto::kAgat, createAgatEncoder },
|
||||
{EncoderProto::kAmiga, createAmigaEncoder },
|
||||
{EncoderProto::kApple2, createApple2Encoder },
|
||||
{EncoderProto::kBrother, createBrotherEncoder },
|
||||
{EncoderProto::kC64, createCommodore64Encoder},
|
||||
{EncoderProto::kIbm, createIbmEncoder },
|
||||
{EncoderProto::kMacintosh, createMacintoshEncoder },
|
||||
{EncoderProto::kMicropolis, createMicropolisEncoder },
|
||||
{EncoderProto::kNorthstar, createNorthstarEncoder },
|
||||
{EncoderProto::kTartu, createTartuEncoder },
|
||||
{EncoderProto::kTids990, createTids990Encoder },
|
||||
{EncoderProto::kVictor9K, createVictor9kEncoder },
|
||||
};
|
||||
|
||||
auto encoder = encoders.find(config.format_case());
|
||||
if (encoder == encoders.end())
|
||||
error("no encoder specified");
|
||||
|
||||
return (encoder->second)(config);
|
||||
}
|
||||
|
||||
nanoseconds_t Encoder::calculatePhysicalClockPeriod(
|
||||
nanoseconds_t targetClockPeriod, nanoseconds_t targetRotationalPeriod)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,6 @@ public:
|
||||
virtual ~Encoder() {}
|
||||
|
||||
static std::unique_ptr<Encoder> create(Config& config);
|
||||
static std::unique_ptr<Encoder> create(const EncoderProto& config);
|
||||
|
||||
public:
|
||||
virtual std::shared_ptr<const Sector> getSector(
|
||||
|
||||
11
lib/external/build.py
vendored
11
lib/external/build.py
vendored
@@ -7,17 +7,22 @@ protocc(name="fl2_proto_lib", srcs=[".+fl2_proto"], deps=["+protobuf_lib"])
|
||||
cxxlibrary(
|
||||
name="external",
|
||||
srcs=[
|
||||
"./ldbs.cc",
|
||||
"./fl2.cc",
|
||||
"./kryoflux.cc",
|
||||
"./catweasel.cc",
|
||||
"./csvreader.cc",
|
||||
"./fl2.cc",
|
||||
"./flx.cc",
|
||||
"./greaseweazle.cc",
|
||||
"./kryoflux.cc",
|
||||
"./ldbs.cc",
|
||||
],
|
||||
hdrs={
|
||||
"lib/external/a2r.h": "./a2r.h",
|
||||
"lib/external/applesauce.h": "./applesauce.h",
|
||||
"lib/external/catweasel.h": "./catweasel.h",
|
||||
"lib/external/csvreader.h": "./csvreader.h",
|
||||
"lib/external/fl2.h": "./fl2.h",
|
||||
"lib/external/flx.h": "./flx.h",
|
||||
"lib/external/greaseweazle.h": "./greaseweazle.h",
|
||||
"lib/external/kryoflux.h": "./kryoflux.h",
|
||||
"lib/external/ldbs.h": "./ldbs.h",
|
||||
"lib/external/scp.h": "./scp.h",
|
||||
|
||||
2
lib/fluxsource/flx.cc → lib/external/flx.cc
vendored
2
lib/fluxsource/flx.cc → lib/external/flx.cc
vendored
@@ -2,7 +2,7 @@
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/external/kryoflux.h"
|
||||
#include "protocol.h"
|
||||
#include "lib/fluxsource/flx.h"
|
||||
#include "lib/external/flx.h"
|
||||
|
||||
std::unique_ptr<Fluxmap> readFlxBytes(const Bytes& bytes)
|
||||
{
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "usb.h"
|
||||
#include "protocol.h"
|
||||
#include "lib/core/bytes.h"
|
||||
#include "greaseweazle.h"
|
||||
@@ -1,5 +1,20 @@
|
||||
from build.protobuf import proto, protocc
|
||||
from build.c import cxxlibrary
|
||||
|
||||
proto(name="proto", srcs=["./fluxsink.proto"], deps=["lib+common_proto"])
|
||||
|
||||
protocc(name="proto_lib", srcs=[".+proto"], deps=["lib+common_proto_lib"])
|
||||
|
||||
cxxlibrary(
|
||||
name="fluxsink",
|
||||
srcs=[
|
||||
"./a2rfluxsink.cc",
|
||||
"./aufluxsink.cc",
|
||||
"./fl2fluxsink.cc",
|
||||
"./fluxsink.cc",
|
||||
"./hardwarefluxsink.cc",
|
||||
"./scpfluxsink.cc",
|
||||
"./vcdfluxsink.cc",
|
||||
],
|
||||
hdrs={"lib/fluxsink/fluxsink.h": "./fluxsink.h"},
|
||||
deps=["lib/core", "lib/config", "lib/data", "lib/external", "lib/usb"],
|
||||
)
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "lib/usb/usb.h"
|
||||
#include "lib/fluxsink/fluxsink.h"
|
||||
#include "lib/fluxsink/fluxsink.pb.h"
|
||||
#include "lib/readerwriter.h"
|
||||
|
||||
class HardwareFluxSink : public FluxSink
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from build.protobuf import proto, protocc
|
||||
from build.c import cxxlibrary
|
||||
|
||||
proto(name="proto", srcs=["./fluxsource.proto"], deps=["lib+common_proto"])
|
||||
|
||||
@@ -7,3 +8,23 @@ protocc(
|
||||
srcs=[".+proto"],
|
||||
deps=["lib+common_proto", "lib+common_proto_lib"],
|
||||
)
|
||||
|
||||
cxxlibrary(
|
||||
name="fluxsource",
|
||||
srcs=[
|
||||
"./a2rfluxsource.cc",
|
||||
"./cwffluxsource.cc",
|
||||
"./dmkfluxsource.cc",
|
||||
"./erasefluxsource.cc",
|
||||
"./fl2fluxsource.cc",
|
||||
"./fluxsource.cc",
|
||||
"./flxfluxsource.cc",
|
||||
"./hardwarefluxsource.cc",
|
||||
"./kryofluxfluxsource.cc",
|
||||
"./memoryfluxsource.cc",
|
||||
"./scpfluxsource.cc",
|
||||
"./testpatternfluxsource.cc",
|
||||
],
|
||||
hdrs={"lib/fluxsource/fluxsource.h": "./fluxsource.h"},
|
||||
deps=["lib/core", "lib/data", "lib/external", "lib/usb", ".+proto_lib"],
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/fluxsource/fluxsource.pb.h"
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
#include "lib/fluxsource/flx.h"
|
||||
#include "lib/external/flx.h"
|
||||
|
||||
class FlxFluxSource : public TrivialFluxSource
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "lib/usb/usb.h"
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
#include "lib/fluxsource/fluxsource.pb.h"
|
||||
#include "lib/readerwriter.h"
|
||||
|
||||
class HardwareFluxSource : public FluxSource
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from build.protobuf import proto, protocc
|
||||
from build.c import cxxlibrary
|
||||
|
||||
proto(
|
||||
name="proto",
|
||||
@@ -10,3 +11,23 @@ protocc(
|
||||
srcs=[".+proto"],
|
||||
deps=["lib+common_proto_lib"],
|
||||
)
|
||||
|
||||
cxxlibrary(
|
||||
name="imagereader",
|
||||
srcs=[
|
||||
"./d64imagereader.cc",
|
||||
"./d88imagereader.cc",
|
||||
"./dimimagereader.cc",
|
||||
"./diskcopyimagereader.cc",
|
||||
"./fdiimagereader.cc",
|
||||
"./imagereader.cc",
|
||||
"./imdimagereader.cc",
|
||||
"./imgimagereader.cc",
|
||||
"./jv3imagereader.cc",
|
||||
"./nfdimagereader.cc",
|
||||
"./nsiimagereader.cc",
|
||||
"./td0imagereader.cc",
|
||||
],
|
||||
hdrs={"lib/imagereader/imagereader.h": "./imagereader.h"},
|
||||
deps=["lib/core", "lib/config", "lib/data", ".+proto_lib"],
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from build.protobuf import proto, protocc
|
||||
from build.c import cxxlibrary
|
||||
|
||||
proto(
|
||||
name="proto",
|
||||
@@ -10,3 +11,22 @@ protocc(
|
||||
srcs=[".+proto"],
|
||||
deps=["lib+common_proto_lib", "lib/imagereader+proto_lib"],
|
||||
)
|
||||
|
||||
cxxlibrary(
|
||||
name="imagewriter",
|
||||
srcs=[
|
||||
"./d64imagewriter.cc",
|
||||
"./d88imagewriter.cc",
|
||||
"./diskcopyimagewriter.cc",
|
||||
"./imagewriter.cc",
|
||||
"./imdimagewriter.cc",
|
||||
"./imgimagewriter.cc",
|
||||
"./ldbsimagewriter.cc",
|
||||
"./nsiimagewriter.cc",
|
||||
"./rawimagewriter.cc",
|
||||
],
|
||||
hdrs={
|
||||
"lib/imagewriter/imagewriter.h": "./imagewriter.h",
|
||||
},
|
||||
deps=["lib/core", "lib/data", "lib/external", ".+proto_lib"],
|
||||
)
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
#include "lib/config/flags.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/imagewriter/imagewriter.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "lib/core/logger.h"
|
||||
#include "arch/northstar/northstar.h"
|
||||
#include "lib/imagewriter/imagewriter.pb.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
#include "lib/config/flags.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/imagewriter/imagewriter.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/data/image.h"
|
||||
#include "lib/data/flux.h"
|
||||
#include "lib/core/logger.h"
|
||||
#include "arch/northstar/northstar.h"
|
||||
#include "lib/imagewriter/imagewriter.pb.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
@@ -768,18 +768,3 @@ void rawReadDiskCommand(FluxSource& fluxsource, FluxSink& fluxsink)
|
||||
|
||||
log(EndOperationLogMessage{"Raw read complete"});
|
||||
}
|
||||
|
||||
void fillBitmapTo(std::vector<bool>& bitmap,
|
||||
unsigned& cursor,
|
||||
unsigned terminateAt,
|
||||
const std::vector<bool>& pattern)
|
||||
{
|
||||
while (cursor < terminateAt)
|
||||
{
|
||||
for (bool b : pattern)
|
||||
{
|
||||
if (cursor < bitmap.size())
|
||||
bitmap[cursor++] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +86,6 @@ extern void writeTracksAndVerify(FluxSink& fluxSink,
|
||||
const Image& image,
|
||||
std::vector<std::shared_ptr<const TrackInfo>>& locations);
|
||||
|
||||
extern void fillBitmapTo(std::vector<bool>& bitmap,
|
||||
unsigned& cursor,
|
||||
unsigned terminateAt,
|
||||
const std::vector<bool>& pattern);
|
||||
|
||||
extern void writeDiskCommand(const Image& image,
|
||||
Encoder& encoder,
|
||||
FluxSink& fluxSink,
|
||||
|
||||
@@ -1,4 +1,19 @@
|
||||
from build.protobuf import proto, protocc
|
||||
from build.c import cxxlibrary
|
||||
|
||||
proto(name="proto", srcs=["./usb.proto"], deps=["lib+common_proto"])
|
||||
protocc(name="proto_lib", srcs=[".+proto"], deps=["lib+common_proto_lib"])
|
||||
|
||||
cxxlibrary(
|
||||
name="usb",
|
||||
srcs=[
|
||||
"./applesauceusb.cc",
|
||||
"./fluxengineusb.cc",
|
||||
"./greaseweazleusb.cc",
|
||||
"./serial.cc",
|
||||
"./usb.cc",
|
||||
"./usbfinder.cc",
|
||||
],
|
||||
hdrs={"lib/usb/usb.h": "./usb.h", "lib/usb/usbfinder.h": "./usbfinder.h"},
|
||||
deps=["lib/core", "lib/config", "lib/external", "dep/libusbp", "+protocol"],
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/core/bytes.h"
|
||||
#include "lib/usb/usb.pb.h"
|
||||
#include "greaseweazle.h"
|
||||
#include "lib/external/greaseweazle.h"
|
||||
#include "serial.h"
|
||||
#include "usb.h"
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#include "lib/config/proto.h"
|
||||
#include "usbfinder.h"
|
||||
#include "lib/core/logger.h"
|
||||
#include "applesauce.h"
|
||||
#include "greaseweazle.h"
|
||||
#include "lib/external/applesauce.h"
|
||||
#include "lib/external/greaseweazle.h"
|
||||
|
||||
static USB* usb = NULL;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include "usb.h"
|
||||
#include "lib/core/bytes.h"
|
||||
#include "usbfinder.h"
|
||||
#include "applesauce.h"
|
||||
#include "greaseweazle.h"
|
||||
#include "lib/external/applesauce.h"
|
||||
#include "lib/external/greaseweazle.h"
|
||||
#include "protocol.h"
|
||||
#include "libusbp.hpp"
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ cxxlibrary(
|
||||
deps=[
|
||||
"+lib",
|
||||
"+fmt_lib",
|
||||
"arch",
|
||||
".+proto_lib",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "lib/config/config.pb.h"
|
||||
#include "lib/core/utils.h"
|
||||
#include "arch/arch.h"
|
||||
|
||||
Path::Path(const std::vector<std::string> other):
|
||||
std::vector<std::string>(other)
|
||||
@@ -244,12 +245,12 @@ std::unique_ptr<Filesystem> Filesystem::createFilesystemFromConfig()
|
||||
if (globalConfig().hasFluxSource())
|
||||
{
|
||||
fluxSource = FluxSource::create(globalConfig());
|
||||
decoder = Decoder::create(globalConfig());
|
||||
decoder = Arch::createDecoder(globalConfig());
|
||||
}
|
||||
if (globalConfig()->flux_sink().type() == FLUXTYPE_DRIVE)
|
||||
{
|
||||
fluxSink = FluxSink::create(globalConfig());
|
||||
encoder = Encoder::create(globalConfig());
|
||||
encoder = Arch::createEncoder(globalConfig());
|
||||
}
|
||||
sectorInterface = SectorInterface::createFluxSectorInterface(
|
||||
fluxSource, fluxSink, encoder, decoder);
|
||||
|
||||
@@ -33,7 +33,6 @@ cxxprogram(
|
||||
"+fmt_lib",
|
||||
"+lib",
|
||||
"+protobuf_lib",
|
||||
"+protobuf_lib",
|
||||
"+protocol",
|
||||
"+z_lib",
|
||||
"dep/adflib",
|
||||
@@ -46,8 +45,8 @@ cxxprogram(
|
||||
"lib/core",
|
||||
"lib/data",
|
||||
"lib/external",
|
||||
"lib/fluxsource+proto_lib",
|
||||
"lib/vfs",
|
||||
"arch",
|
||||
"src/formats",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "lib/core/bitmap.h"
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/data/fluxmapreader.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "protocol.h"
|
||||
#include "lib/config/proto.h"
|
||||
#include "lib/fluxsink/fluxsink.h"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/config/proto.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/imagereader/imagereader.h"
|
||||
#include "lib/imagewriter/imagewriter.h"
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/config/proto.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/imagereader/imagereader.h"
|
||||
#include "lib/imagewriter/imagewriter.h"
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/config/proto.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/imagereader/imagereader.h"
|
||||
#include "lib/imagewriter/imagewriter.h"
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/config/proto.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/imagereader/imagereader.h"
|
||||
#include "lib/imagewriter/imagewriter.h"
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/config/config.h"
|
||||
#include "lib/config/flags.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/data/fluxmapreader.h"
|
||||
#include "lib/decoders/fluxdecoder.h"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/config/proto.h"
|
||||
#include "lib/readerwriter.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
#include "lib/imagereader/imagereader.h"
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
#include "lib/fluxsink/fluxsink.h"
|
||||
#include "lib/imagewriter/imagewriter.h"
|
||||
#include "arch/arch.h"
|
||||
#include "fluxengine.h"
|
||||
#include <google/protobuf/text_format.h>
|
||||
#include <fstream>
|
||||
@@ -66,7 +67,7 @@ int mainRead(int argc, const char* argv[])
|
||||
error("you cannot copy flux to a hardware device");
|
||||
|
||||
auto fluxSource = FluxSource::create(globalConfig());
|
||||
auto decoder = Decoder::create(globalConfig());
|
||||
auto decoder = Arch::createDecoder(globalConfig());
|
||||
auto writer = ImageWriter::create(globalConfig());
|
||||
|
||||
readDiskCommand(*fluxSource, *decoder, *writer);
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
#include "lib/config/proto.h"
|
||||
#include "lib/fluxsink/fluxsink.h"
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
#include "arch/brother/brother.h"
|
||||
#include "arch/ibm/ibm.h"
|
||||
#include "arch/arch.h"
|
||||
#include "lib/imagereader/imagereader.h"
|
||||
#include "fluxengine.h"
|
||||
#include <google/protobuf/text_format.h>
|
||||
@@ -71,14 +70,14 @@ int mainWrite(int argc, const char* argv[])
|
||||
auto reader = ImageReader::create(globalConfig());
|
||||
std::shared_ptr<Image> image = reader->readMappedImage();
|
||||
|
||||
auto encoder = Encoder::create(globalConfig());
|
||||
auto encoder = Arch::createEncoder(globalConfig());
|
||||
auto fluxSink = FluxSink::create(globalConfig());
|
||||
|
||||
std::shared_ptr<Decoder> decoder;
|
||||
std::shared_ptr<FluxSource> verificationFluxSource;
|
||||
if (globalConfig().hasDecoder() && fluxSink->isHardware() && verify)
|
||||
{
|
||||
decoder = Decoder::create(globalConfig());
|
||||
decoder = Arch::createDecoder(globalConfig());
|
||||
verificationFluxSource =
|
||||
FluxSource::create(globalConfig().getVerificationFluxSourceProto());
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ cxxprogram(
|
||||
"lib/data",
|
||||
"lib/vfs",
|
||||
"lib/config",
|
||||
"lib/fluxsource+proto_lib",
|
||||
"arch",
|
||||
"src/formats",
|
||||
"src/gui/drivetypes",
|
||||
"+z_lib",
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#include <lib/core/globals.h>
|
||||
#include <lib/fluxsource/fluxsource.h>
|
||||
#include <lib/fluxsink/fluxsink.h>
|
||||
#include <lib/imagereader/imagereader.h>
|
||||
#include <lib/imagewriter/imagewriter.h>
|
||||
#include <lib/decoders/decoders.h>
|
||||
#include <lib/encoders/encoders.h>
|
||||
#include <lib/config/config.h>
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
#include "lib/fluxsink/fluxsink.h"
|
||||
#include "lib/imagereader/imagereader.h"
|
||||
#include "lib/imagewriter/imagewriter.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "lib/encoders/encoders.h"
|
||||
#include "arch/arch.h"
|
||||
#include "lib/config/config.h"
|
||||
#include "context.h"
|
||||
#include "gui.h"
|
||||
|
||||
@@ -64,7 +65,7 @@ namespace
|
||||
{
|
||||
if (!_encoder)
|
||||
{
|
||||
_encoder = Encoder::create(globalConfig());
|
||||
_encoder = Arch::createEncoder(globalConfig());
|
||||
}
|
||||
return _encoder.get();
|
||||
}
|
||||
@@ -73,7 +74,7 @@ namespace
|
||||
{
|
||||
if (!_decoder)
|
||||
{
|
||||
_decoder = Decoder::create(globalConfig());
|
||||
_decoder = Arch::createDecoder(globalConfig());
|
||||
}
|
||||
return _decoder.get();
|
||||
}
|
||||
|
||||
@@ -103,7 +103,8 @@ export(
|
||||
"src/formats",
|
||||
]
|
||||
+ ([".+test_proto_lib"] if n == "options" else [])
|
||||
+ (["lib/vfs"] if n in {"cpmfs", "applesingle", "vfs"} else []),
|
||||
+ (["lib/vfs"] if n in {"cpmfs", "applesingle", "vfs"} else [])
|
||||
+ (["arch"] if n in {"amiga"} else []),
|
||||
),
|
||||
)
|
||||
for n in tests
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/fluxsource/flx.h"
|
||||
#include "lib/external/flx.h"
|
||||
|
||||
static void test_convert(const Bytes& flxbytes, const Bytes& fluxmapbytes)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/usb/greaseweazle.h"
|
||||
#include "lib/external/greaseweazle.h"
|
||||
|
||||
#define E28(val) \
|
||||
(1 | ((val) << 1) & 0xff), (1 | ((val) >> 6) & 0xff), \
|
||||
|
||||
Reference in New Issue
Block a user