mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Merge branch 'master' of https://github.com/wybren1971/fluxengine into wybren1971-master
This commit is contained in:
25
doc/using.md
25
doc/using.md
@@ -1,4 +1,4 @@
|
||||
Using a FluxEngine
|
||||
Using a FluxEngine
|
||||
==================
|
||||
|
||||
So you've [built the hardware](building.md), programmed and tested it! What
|
||||
@@ -140,6 +140,29 @@ exact format varies according to the extension:
|
||||
read, but not yet written. You only get the data; the density and DAM bits
|
||||
are ignored.
|
||||
|
||||
- `.imd`: a disk image format created by [David Dunfield](http://dunfield.classiccmp.org/img/index.htm).
|
||||
These images can be used as input image for writing a disk. If you don’t know the diskformat, Fluxengine will show the stored comment and display the geometry to use. Just give a command like:
|
||||
|
||||
```
|
||||
$ ./fluxengine write ibm -i filenaam.imd
|
||||
Comment in IMD image:
|
||||
*** DOUBLE SIDED FORMAT ***
|
||||
HP-IB,RS-232C & RS-449 PREPROCESSOR
|
||||
For HP1650A, HP1651A & HP16500A
|
||||
10342-13017
|
||||
Rev 2749 Ver 1.1
|
||||
Copyright (c) 1987, Hewlett-Packard
|
||||
|
||||
|
||||
reading IMD image
|
||||
77 tracks, 2 heads; MFM; 250 kbps; 5 sectoren; sectorsize 1024; sectormap 12345; 770 kB total
|
||||
Writing to: :d=0:s=0-1:t=0-79
|
||||
0.0: Error: track data overrun
|
||||
```
|
||||
|
||||
For input files you normally have to specify it yourself. So in this case append `:c=76:h=2:s=5:b=1024` to set the geometry.
|
||||
|
||||
|
||||
### High density disks
|
||||
|
||||
High density disks use a different magnetic medium to low and double density
|
||||
|
||||
@@ -19,6 +19,8 @@ std::map<std::string, ImageReader::Constructor> ImageReader::formats =
|
||||
{".jv1", ImageReader::createImgImageReader},
|
||||
{".jv3", ImageReader::createJv3ImageReader},
|
||||
{".st", ImageReader::createImgImageReader},
|
||||
{".imd", ImageReader::createIMDImageReader},
|
||||
{".IMD", ImageReader::createIMDImageReader},
|
||||
};
|
||||
|
||||
ImageReader::Constructor ImageReader::findConstructor(const ImageSpec& spec)
|
||||
|
||||
@@ -26,6 +26,7 @@ private:
|
||||
static std::unique_ptr<ImageReader> createDiskCopyImageReader(const ImageSpec& spec);
|
||||
static std::unique_ptr<ImageReader> createImgImageReader(const ImageSpec& spec);
|
||||
static std::unique_ptr<ImageReader> createJv3ImageReader(const ImageSpec& spec);
|
||||
static std::unique_ptr<ImageReader> createIMDImageReader(const ImageSpec& spec);
|
||||
|
||||
static Constructor findConstructor(const ImageSpec& spec);
|
||||
|
||||
|
||||
281
lib/imagereader/imdimagereader.cc
Normal file
281
lib/imagereader/imdimagereader.cc
Normal file
@@ -0,0 +1,281 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "dataspec.h"
|
||||
#include "sector.h"
|
||||
#include "sectorset.h"
|
||||
#include "imagereader/imagereader.h"
|
||||
#include "fmt/format.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
static unsigned getModulationandSpeed(uint8_t flags, bool *mfm)
|
||||
{
|
||||
switch (flags)
|
||||
{
|
||||
case 0: /* 500 kbps FM */
|
||||
//clockRateKhz.setDefaultValue(250);
|
||||
*mfm = false;
|
||||
return 500;
|
||||
break;
|
||||
|
||||
case 1: /* 300 kbps FM */
|
||||
*mfm = false;
|
||||
return 300;
|
||||
|
||||
break;
|
||||
|
||||
case 2: /* 250 kbps FM */
|
||||
*mfm = false;
|
||||
return 250;
|
||||
break;
|
||||
|
||||
case 3: /* 500 kbps MFM */
|
||||
*mfm = true;
|
||||
return 500;
|
||||
break;
|
||||
|
||||
case 4: /* 300 kbps MFM */
|
||||
*mfm = true;
|
||||
return 300;
|
||||
break;
|
||||
|
||||
case 5: /* 250 kbps MFM */
|
||||
*mfm = true;
|
||||
return 250;
|
||||
break;
|
||||
|
||||
default:
|
||||
Error() << fmt::format("don't understand IMD disks with this modulation and speed {}", flags);
|
||||
}
|
||||
}
|
||||
|
||||
struct TrackHeader
|
||||
{
|
||||
uint8_t ModeValue;
|
||||
uint8_t track;
|
||||
uint8_t Head;
|
||||
uint8_t numSectors;
|
||||
uint8_t SectorSize;
|
||||
};
|
||||
|
||||
static unsigned getSectorSize(uint8_t flags)
|
||||
{
|
||||
switch (flags)
|
||||
{
|
||||
case 0: return 128;
|
||||
case 1: return 256;
|
||||
case 2: return 512;
|
||||
case 3: return 1024;
|
||||
case 4: return 2048;
|
||||
case 5: return 4096;
|
||||
case 6: return 8192;
|
||||
}
|
||||
Error() << "not reachable";
|
||||
}
|
||||
|
||||
|
||||
#define SEC_CYL_MAP_FLAG 0x80
|
||||
#define SEC_HEAD_MAP_FLAG 0x40
|
||||
#define HEAD_MASK 0x3F
|
||||
#define END_OF_FILE 0x1A
|
||||
|
||||
|
||||
class IMDImageReader : public ImageReader
|
||||
{
|
||||
public:
|
||||
IMDImageReader(const ImageSpec& spec):
|
||||
ImageReader(spec)
|
||||
{}
|
||||
|
||||
SectorSet readImage()
|
||||
/*
|
||||
IMAGE FILE FORMAT
|
||||
The overall layout of an ImageDisk .IMD image file is:
|
||||
IMD v.vv: dd/mm/yyyy hh:mm:ss
|
||||
Comment (ASCII only - unlimited size)
|
||||
1A byte - ASCII EOF character
|
||||
- For each track on the disk:
|
||||
1 byte Mode value see getModulationspeed for definition
|
||||
1 byte Cylinder
|
||||
1 byte Head
|
||||
1 byte number of sectors in track
|
||||
1 byte sector size see getsectorsize for definition
|
||||
sector numbering map
|
||||
sector cylinder map (optional) definied in high byte of head (since head is 0 or 1)
|
||||
sector head map (optional) definied in high byte of head (since head is 0 or 1)
|
||||
sector data records
|
||||
<End of file>
|
||||
*/
|
||||
{
|
||||
//Read File
|
||||
std::ifstream inputFile(spec.filename, std::ios::in | std::ios::binary);
|
||||
if (!inputFile.is_open())
|
||||
Error() << "cannot open input file";
|
||||
//define some variables
|
||||
bool mfm = false; //define coding just to show in comment for setting the right write parameters
|
||||
inputFile.seekg(0, inputFile.end);
|
||||
int inputFileSize = inputFile.tellg(); // determine filesize
|
||||
inputFile.seekg(0, inputFile.beg);
|
||||
Bytes data;
|
||||
data.writer() += inputFile;
|
||||
ByteReader br(data);
|
||||
SectorSet sectors;
|
||||
TrackHeader header = {0, 0, 0, 0, 0};
|
||||
|
||||
unsigned n = 0;
|
||||
unsigned headerPtr = 0;
|
||||
unsigned Modulation_Speed = 0;
|
||||
unsigned sectorSize = 0;
|
||||
std::string sector_skew;
|
||||
int b;
|
||||
unsigned char comment[8192]; //i choose a fixed value. dont know how to make dynamic arrays in C++. This should be enough
|
||||
// Read comment
|
||||
while ((b = br.read_8()) != EOF && b != 0x1A)
|
||||
{
|
||||
comment[n++] = (unsigned char)b;
|
||||
}
|
||||
headerPtr = n; //set pointer to after comment
|
||||
comment[n] = '\0'; // null-terminate the string
|
||||
//write comment to screen
|
||||
std::cout << "Comment in IMD image:\n"
|
||||
<< fmt::format("{}\n",
|
||||
comment);
|
||||
|
||||
//first read header
|
||||
for (;;)
|
||||
{
|
||||
if (headerPtr >= inputFileSize-1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
header.ModeValue = br.read_8();
|
||||
headerPtr++;
|
||||
Modulation_Speed = getModulationandSpeed(header.ModeValue, &mfm);
|
||||
header.track = br.read_8();
|
||||
headerPtr++;
|
||||
header.Head = br.read_8();
|
||||
headerPtr++;
|
||||
header.numSectors = br.read_8();
|
||||
headerPtr++;
|
||||
header.SectorSize = br.read_8();
|
||||
headerPtr++;
|
||||
sectorSize = getSectorSize(header.SectorSize);
|
||||
|
||||
//Read optional cylinder map To Do
|
||||
|
||||
//Read optional sector head map To Do
|
||||
|
||||
//read sector numbering map
|
||||
unsigned int sector_map[header.numSectors]= {};
|
||||
bool blnBaseOne = false;
|
||||
sector_skew.clear();
|
||||
for (b = 0; b < header.numSectors; b++)
|
||||
{
|
||||
sector_map[b] = br.read_8();
|
||||
sector_skew.push_back(sector_map[b] + '0');
|
||||
if (b == 0) //first sector see if base is 0 or 1 Fluxengine wants 0
|
||||
{
|
||||
if (sector_map[b]==1)
|
||||
{
|
||||
blnBaseOne = true;
|
||||
}
|
||||
}
|
||||
if (blnBaseOne==true)
|
||||
{
|
||||
sector_map[b] = (sector_map[b]-1);
|
||||
}
|
||||
headerPtr++;
|
||||
}
|
||||
//read the sectors
|
||||
for (int s = 0; s < header.numSectors; s++)
|
||||
{
|
||||
Bytes sectordata;
|
||||
std::unique_ptr<Sector>& sector = sectors.get(header.track, header.Head, sector_map[s]);
|
||||
sector.reset(new Sector);
|
||||
//read the status of the sector
|
||||
unsigned int Status_Sector = br.read_8();
|
||||
headerPtr++;
|
||||
|
||||
switch (Status_Sector)
|
||||
{
|
||||
case 0: /* Sector data unavailable - could not be read */
|
||||
|
||||
break;
|
||||
|
||||
case 1: /* Normal data: (Sector Size) bytes follow */
|
||||
sectordata = br.read(sectorSize);
|
||||
headerPtr += sectorSize;
|
||||
sector->data.writer().append(sectordata);
|
||||
|
||||
break;
|
||||
|
||||
case 2: /* Compressed: All bytes in sector have same value (xx) */
|
||||
sectordata = br.read(1);
|
||||
headerPtr++;
|
||||
sector->data.writer().append(sectordata);
|
||||
|
||||
for (int k = 1; k < sectorSize; k++)
|
||||
{
|
||||
//fill data till sector is full
|
||||
sector->data.writer().append(sectordata);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3: /* Normal data with "Deleted-Data address mark" */
|
||||
|
||||
break;
|
||||
|
||||
case 4: /* Compressed with "Deleted-Data address mark"*/
|
||||
|
||||
break;
|
||||
|
||||
case 5: /* Normal data read with data error */
|
||||
|
||||
break;
|
||||
|
||||
case 6: /* Compressed read with data error" */
|
||||
|
||||
break;
|
||||
|
||||
case 7: /* Deleted data read with data error" */
|
||||
|
||||
break;
|
||||
|
||||
case 8: /* Compressed, Deleted read with data error" */
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
Error() << fmt::format("don't understand IMD disks with sector status {}", Status_Sector);
|
||||
}
|
||||
sector->status = Sector::OK;
|
||||
sector->logicalTrack = sector->physicalTrack = header.track;
|
||||
sector->logicalSide = sector->physicalSide = header.Head;
|
||||
sector->logicalSector = (sector_map[s]);
|
||||
}
|
||||
|
||||
}
|
||||
//Write format detected in IMD image to screen to help user set the right write parameters
|
||||
|
||||
size_t headSize = header.numSectors * sectorSize;
|
||||
size_t trackSize = headSize * (header.Head + 1);
|
||||
|
||||
std::cout << "reading IMD image\n"
|
||||
<< fmt::format("{} tracks, {} heads; {}; {} kbps; {} sectoren; sectorsize {}; sectormap {}; {} kB total \n",
|
||||
header.track, header.Head + 1,
|
||||
mfm ? "MFM" : "FM",
|
||||
Modulation_Speed, header.numSectors, sectorSize, sector_skew, (header.track+1) * trackSize / 1024);
|
||||
|
||||
return sectors;
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<ImageReader> ImageReader::createIMDImageReader(
|
||||
const ImageSpec& spec)
|
||||
{
|
||||
return std::unique_ptr<ImageReader>(new IMDImageReader(spec));
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@ buildlibrary libbackend.a \
|
||||
lib/imagereader/imagereader.cc \
|
||||
lib/imagereader/imgimagereader.cc \
|
||||
lib/imagereader/jv3imagereader.cc \
|
||||
lib/imagereader/imdimagereader.cc \
|
||||
lib/imagewriter/d64imagewriter.cc \
|
||||
lib/imagewriter/diskcopyimagewriter.cc \
|
||||
lib/imagewriter/imagewriter.cc \
|
||||
|
||||
@@ -113,6 +113,7 @@ static ActionFlag preset720(
|
||||
trackLengthMs.setDefaultValue(200);
|
||||
clockRateKhz.setDefaultValue(250);
|
||||
sectorSkew.setDefaultValue("012345678");
|
||||
set_ibm_defaults();
|
||||
});
|
||||
|
||||
/* --- Commodore disks ----------------------------------------------------- */
|
||||
|
||||
Reference in New Issue
Block a user