mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
61
arch/micropolis/decoder.cc
Normal file
61
arch/micropolis/decoder.cc
Normal file
@@ -0,0 +1,61 @@
|
||||
#include "globals.h"
|
||||
#include "fluxmap.h"
|
||||
#include "decoders/fluxmapreader.h"
|
||||
#include "decoders/decoders.h"
|
||||
#include "sector.h"
|
||||
#include "micropolis.h"
|
||||
#include "bytes.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
/* The sector has a preamble of MFM 0x00s and uses 0xFF as a sync pattern. */
|
||||
static const FluxPattern SECTOR_SYNC_PATTERN(32, 0xaaaa5555);
|
||||
|
||||
AbstractDecoder::RecordType MicropolisDecoder::advanceToNextRecord()
|
||||
{
|
||||
_fmr->seekToIndexMark();
|
||||
const FluxMatcher* matcher = nullptr;
|
||||
_sector->clock = _fmr->seekToPattern(SECTOR_SYNC_PATTERN, matcher);
|
||||
if (matcher == &SECTOR_SYNC_PATTERN) {
|
||||
readRawBits(16);
|
||||
return SECTOR_RECORD;
|
||||
}
|
||||
return UNKNOWN_RECORD;
|
||||
}
|
||||
|
||||
/* Adds all bytes, with carry. */
|
||||
static uint8_t checksum(const Bytes& bytes) {
|
||||
ByteReader br(bytes);
|
||||
uint16_t sum = 0;
|
||||
while (!br.eof()) {
|
||||
if (sum > 0xFF) {
|
||||
sum -= 0x100 - 1;
|
||||
}
|
||||
sum += br.read_8();
|
||||
}
|
||||
/* The last carry is ignored */
|
||||
return sum & 0xFF;
|
||||
}
|
||||
|
||||
void MicropolisDecoder::decodeSectorRecord()
|
||||
{
|
||||
auto rawbits = readRawBits(MICROPOLIS_ENCODED_SECTOR_SIZE*16);
|
||||
auto bytes = decodeFmMfm(rawbits).slice(0, MICROPOLIS_ENCODED_SECTOR_SIZE);
|
||||
ByteReader br(bytes);
|
||||
|
||||
br.read_8(); /* sync */
|
||||
_sector->logicalTrack = br.read_8();
|
||||
_sector->logicalSide = _sector->physicalSide;
|
||||
_sector->logicalSector = br.read_8();
|
||||
if (_sector->logicalSector > 15)
|
||||
return;
|
||||
if (_sector->logicalTrack > 77)
|
||||
return;
|
||||
|
||||
br.read(10); /* OS data or padding */
|
||||
_sector->data = br.read(256);
|
||||
uint8_t wantChecksum = br.read_8();
|
||||
uint8_t gotChecksum = checksum(bytes.slice(1, 2+266));
|
||||
br.read(5); /* 4 byte ECC and ECC-present flag */
|
||||
|
||||
_sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
|
||||
}
|
||||
18
arch/micropolis/micropolis.h
Normal file
18
arch/micropolis/micropolis.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef ZILOGMCZ_H
|
||||
#define ZILOGMCZ_H
|
||||
|
||||
#define MICROPOLIS_ENCODED_SECTOR_SIZE (1+2+266+6)
|
||||
|
||||
class Sector;
|
||||
class Fluxmap;
|
||||
|
||||
class MicropolisDecoder : public AbstractDecoder
|
||||
{
|
||||
public:
|
||||
virtual ~MicropolisDecoder() {}
|
||||
|
||||
RecordType advanceToNextRecord();
|
||||
void decodeSectorRecord();
|
||||
};
|
||||
|
||||
#endif
|
||||
49
doc/disk-micropolis.md
Normal file
49
doc/disk-micropolis.md
Normal file
@@ -0,0 +1,49 @@
|
||||
Disk: Micropolis
|
||||
================
|
||||
|
||||
Micropolis MetaFloppy disks use MFM and hard sectors. They were 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.
|
||||
|
||||
Reading disks
|
||||
-------------
|
||||
|
||||
Just do:
|
||||
|
||||
```
|
||||
fluxengine read micropolis
|
||||
```
|
||||
|
||||
You should end up with a `micropolis.img` which is 630784 bytes long (for a
|
||||
normal DD disk). The image is written in CHS order, but HCS is generally used
|
||||
by CP/M tools so the image needs to be post-processed. For only half-full disks
|
||||
or single-sided disks, you can use `-s :s=0` to read only one side of the disk
|
||||
which works around the problem.
|
||||
|
||||
The [CP/M BIOS](https://www.seasip.info/Cpm/bios.html) defined SELDSK, SETTRK,
|
||||
and SETSEC, but no function to select the head/side. This caused dual-sided
|
||||
floppies to be represented as twice the number of tracks with the second side's
|
||||
tracks logically following the first side (e.g., tracks 77-153). That produces
|
||||
results mostly indistinguishable from HCS.
|
||||
|
||||
Useful 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
|
||||
@@ -171,6 +171,7 @@ buildlibrary libbackend.a \
|
||||
arch/ibm/decoder.cc \
|
||||
arch/ibm/encoder.cc \
|
||||
arch/macintosh/decoder.cc \
|
||||
arch/micropolis/decoder.cc \
|
||||
arch/mx/decoder.cc \
|
||||
arch/tids990/decoder.cc \
|
||||
arch/tids990/encoder.cc \
|
||||
@@ -224,6 +225,7 @@ buildlibrary libfrontend.a \
|
||||
src/fe-readfb100.cc \
|
||||
src/fe-readibm.cc \
|
||||
src/fe-readmac.cc \
|
||||
src/fe-readmicropolis.cc \
|
||||
src/fe-readmx.cc \
|
||||
src/fe-readtids990.cc \
|
||||
src/fe-readvictor9k.cc \
|
||||
|
||||
26
src/fe-readmicropolis.cc
Normal file
26
src/fe-readmicropolis.cc
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "reader.h"
|
||||
#include "fluxmap.h"
|
||||
#include "encoders/encoders.h"
|
||||
#include "decoders/decoders.h"
|
||||
#include "sector.h"
|
||||
#include "sectorset.h"
|
||||
#include "record.h"
|
||||
#include "micropolis/micropolis.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
static FlagGroup flags { &readerFlags };
|
||||
|
||||
int mainReadMicropolis(int argc, const char* argv[])
|
||||
{
|
||||
setReaderDefaultSource(":t=0-76");
|
||||
setReaderDefaultOutput("micropolis.img");
|
||||
setReaderRevolutions(21); /* 17 index holes * 1.25 */
|
||||
flags.parseFlags(argc, argv);
|
||||
|
||||
MicropolisDecoder decoder;
|
||||
readDiskCommand(decoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ extern command_cb mainReadF85;
|
||||
extern command_cb mainReadFB100;
|
||||
extern command_cb mainReadIBM;
|
||||
extern command_cb mainReadMac;
|
||||
extern command_cb mainReadMicropolis;
|
||||
extern command_cb mainReadMx;
|
||||
extern command_cb mainReadTiDs990;
|
||||
extern command_cb mainReadVictor9K;
|
||||
@@ -78,6 +79,7 @@ static std::vector<Command> readables =
|
||||
{ "fb100", mainReadFB100, "Reads FB100 disks.", },
|
||||
{ "ibm", mainReadIBM, "Reads the ubiquitous IBM format disks.", },
|
||||
{ "mac", mainReadMac, "Reads Apple Macintosh disks.", },
|
||||
{ "micropolis", mainReadMicropolis, "Reads Micropolis disks.", },
|
||||
{ "mx", mainReadMx, "Reads MX disks.", },
|
||||
{ "tids990", mainReadTiDs990, "Reads Texas Instruments DS990 disks.", },
|
||||
{ "victor9k", mainReadVictor9K, "Reads Victor 9000 disks.", },
|
||||
|
||||
Reference in New Issue
Block a user