mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Merge from trunk.
This commit is contained in:
@@ -871,6 +871,7 @@
|
|||||||
<Data key="c5367cde-21d5-4866-9a32-d16abfea0c61" value="WPT" />
|
<Data key="c5367cde-21d5-4866-9a32-d16abfea0c61" value="WPT" />
|
||||||
<Data key="d19368c5-6855-41bb-a9ff-808938abef00" value="INDEX" />
|
<Data key="d19368c5-6855-41bb-a9ff-808938abef00" value="INDEX" />
|
||||||
<Data key="e9f14b5a-b2bf-49b8-98f3-d7b5a43ace8d" value="DRVSB" />
|
<Data key="e9f14b5a-b2bf-49b8-98f3-d7b5a43ace8d" value="DRVSB" />
|
||||||
|
<Data key="e16b5ef8-00d3-40a4-bc1c-194983c8eb3d" value="LOW_CURRENT" />
|
||||||
<Data key="e851a3b9-efb8-48be-bbb8-b303b216c393" value="INDEX300" />
|
<Data key="e851a3b9-efb8-48be-bbb8-b303b216c393" value="INDEX300" />
|
||||||
<Data key="e51063a9-4fad-40c7-a06b-7cc4b137dc18" value="DSKCHG" />
|
<Data key="e51063a9-4fad-40c7-a06b-7cc4b137dc18" value="DSKCHG" />
|
||||||
<Data key="ea7ee228-8b3f-426c-8bb8-cd7a81937769" value="DIR" />
|
<Data key="ea7ee228-8b3f-426c-8bb8-cd7a81937769" value="DIR" />
|
||||||
@@ -4161,6 +4162,11 @@
|
|||||||
<Data key="Port Format" value="12,3" />
|
<Data key="Port Format" value="12,3" />
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
|
<Group key="e16b5ef8-00d3-40a4-bc1c-194983c8eb3d">
|
||||||
|
<Group key="0">
|
||||||
|
<Data key="Port Format" value="3,2" />
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
<Group key="e851a3b9-efb8-48be-bbb8-b303b216c393">
|
<Group key="e851a3b9-efb8-48be-bbb8-b303b216c393">
|
||||||
<Group key="0">
|
<Group key="0">
|
||||||
<Data key="Port Format" value="3,0" />
|
<Data key="Port Format" value="3,0" />
|
||||||
|
|||||||
@@ -2847,6 +2847,72 @@
|
|||||||
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
||||||
<filters />
|
<filters />
|
||||||
</CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0>
|
</CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0>
|
||||||
|
<CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3">
|
||||||
|
<CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="TK43_REG" persistent="">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2">
|
||||||
|
<dependencies>
|
||||||
|
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="TK43_REG.h" persistent="Generated_Source\PSoC5\TK43_REG.h">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<build_action v="HEADER;;;;" />
|
||||||
|
<PropertyDeltas />
|
||||||
|
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||||
|
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="TK43_REG.c" persistent="Generated_Source\PSoC5\TK43_REG.c">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<build_action v="SOURCE_C;CortexM3;;;" />
|
||||||
|
<PropertyDeltas />
|
||||||
|
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||||
|
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="TK43_REG_PM.c" persistent="Generated_Source\PSoC5\TK43_REG_PM.c">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<build_action v="SOURCE_C;CortexM3;;;" />
|
||||||
|
<PropertyDeltas />
|
||||||
|
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||||
|
</dependencies>
|
||||||
|
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
|
||||||
|
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
||||||
|
<filters />
|
||||||
|
</CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0>
|
||||||
|
<CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3">
|
||||||
|
<CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="TK43" persistent="">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2">
|
||||||
|
<dependencies>
|
||||||
|
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="TK43_aliases.h" persistent="Generated_Source\PSoC5\TK43_aliases.h">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<build_action v="HEADER;;;;" />
|
||||||
|
<PropertyDeltas />
|
||||||
|
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||||
|
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="TK43.c" persistent="Generated_Source\PSoC5\TK43.c">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<build_action v="SOURCE_C;CortexM3;;;" />
|
||||||
|
<PropertyDeltas />
|
||||||
|
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||||
|
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="TK43.h" persistent="Generated_Source\PSoC5\TK43.h">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<build_action v="HEADER;;;;" />
|
||||||
|
<PropertyDeltas />
|
||||||
|
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||||
|
</dependencies>
|
||||||
|
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
|
||||||
|
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
||||||
|
<filters />
|
||||||
|
</CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
|
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
|
||||||
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
||||||
|
|||||||
Binary file not shown.
@@ -13,8 +13,8 @@
|
|||||||
#define DISKSTATUS_WPT 1
|
#define DISKSTATUS_WPT 1
|
||||||
#define DISKSTATUS_DSKCHG 2
|
#define DISKSTATUS_DSKCHG 2
|
||||||
|
|
||||||
#define STEP_TOWARDS0 1
|
#define STEP_TOWARDS0 0
|
||||||
#define STEP_AWAYFROM0 0
|
#define STEP_AWAYFROM0 1
|
||||||
|
|
||||||
static bool drive0_present;
|
static bool drive0_present;
|
||||||
static bool drive1_present;
|
static bool drive1_present;
|
||||||
@@ -249,6 +249,8 @@ static void seek_to(int track)
|
|||||||
CyWdtClear();
|
CyWdtClear();
|
||||||
}
|
}
|
||||||
CyDelay(STEP_SETTLING_TIME);
|
CyDelay(STEP_SETTLING_TIME);
|
||||||
|
|
||||||
|
TK43_REG_Write(track < 43); /* high if 0..42, low if 43 or up */
|
||||||
print("finished seek");
|
print("finished seek");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,8 +383,9 @@ static void init_capture_dma(void)
|
|||||||
|
|
||||||
static void cmd_read(struct read_frame* f)
|
static void cmd_read(struct read_frame* f)
|
||||||
{
|
{
|
||||||
SIDE_REG_Write(f->side);
|
|
||||||
seek_to(current_track);
|
seek_to(current_track);
|
||||||
|
SIDE_REG_Write(f->side);
|
||||||
|
STEP_REG_Write(f->side); /* for drives which multiplex SIDE and DIR */
|
||||||
|
|
||||||
/* Do slow setup *before* we go into the real-time bit. */
|
/* Do slow setup *before* we go into the real-time bit. */
|
||||||
|
|
||||||
@@ -478,6 +481,7 @@ abort:;
|
|||||||
wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM);
|
wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM);
|
||||||
deinit_dma();
|
deinit_dma();
|
||||||
|
|
||||||
|
STEP_REG_Write(0);
|
||||||
if (saved_dma_underrun)
|
if (saved_dma_underrun)
|
||||||
{
|
{
|
||||||
print("underrun after %d packets");
|
print("underrun after %d packets");
|
||||||
@@ -523,9 +527,11 @@ static void cmd_write(struct write_frame* f)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SEQUENCER_CONTROL_Write(1); /* put the sequencer into reset */
|
seek_to(current_track);
|
||||||
|
|
||||||
SIDE_REG_Write(f->side);
|
SIDE_REG_Write(f->side);
|
||||||
|
STEP_REG_Write(f->side); /* for drives which multiplex SIDE and DIR */
|
||||||
|
|
||||||
|
SEQUENCER_CONTROL_Write(1); /* put the sequencer into reset */
|
||||||
{
|
{
|
||||||
uint8_t i = CyEnterCriticalSection();
|
uint8_t i = CyEnterCriticalSection();
|
||||||
REPLAY_FIFO_SET_LEVEL_MID;
|
REPLAY_FIFO_SET_LEVEL_MID;
|
||||||
@@ -533,7 +539,6 @@ static void cmd_write(struct write_frame* f)
|
|||||||
REPLAY_FIFO_SINGLE_BUFFER_UNSET;
|
REPLAY_FIFO_SINGLE_BUFFER_UNSET;
|
||||||
CyExitCriticalSection(i);
|
CyExitCriticalSection(i);
|
||||||
}
|
}
|
||||||
seek_to(current_track);
|
|
||||||
|
|
||||||
init_replay_dma();
|
init_replay_dma();
|
||||||
bool writing = false; /* to the disk */
|
bool writing = false; /* to the disk */
|
||||||
@@ -638,6 +643,7 @@ abort:
|
|||||||
|
|
||||||
deinit_dma();
|
deinit_dma();
|
||||||
|
|
||||||
|
STEP_REG_Write(0);
|
||||||
if (dma_underrun)
|
if (dma_underrun)
|
||||||
{
|
{
|
||||||
print("underrun!");
|
print("underrun!");
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ INDEX300 ---+ 3.0| | GND+--------------------------+
|
|||||||
+----+ +----+ +--+--+ |
|
+----+ +----+ +--+--+ |
|
||||||
INDEX360 ---+ 3.1| | 1.7+------ DISKCHG --+34+33+--+
|
INDEX360 ---+ 3.1| | 1.7+------ DISKCHG --+34+33+--+
|
||||||
+----+ +----+ +--+--+
|
+----+ +----+ +--+--+
|
||||||
+ 3.2| | 1.6+------- SIDE1 ---+32+31+
|
TK43 ---+ 3.2| | 1.6+------- SIDE1 ---+32+31+
|
||||||
+----+ +----+ +--+--+
|
+----+ +----+ +--+--+
|
||||||
+ 3.3| | 1.5+------- RDATA ---+30+29+
|
+ 3.3| | 1.5+------- RDATA ---+30+29+
|
||||||
+----+ +----+ +--+--+
|
+----+ +----+ +--+--+
|
||||||
@@ -306,7 +306,7 @@ INDEX360 ---+ 3.1| | 1.7+------ DISKCHG --+34+33+--+
|
|||||||
+----+ +----+ +--+--+
|
+----+ +----+ +--+--+
|
||||||
+15.0| | 1.0+------- STEP ----+20+19+
|
+15.0| | 1.0+------- STEP ----+20+19+
|
||||||
+----+ +----+ +--+--+
|
+----+ +----+ +--+--+
|
||||||
+15.1| |12.0+-------- DIR ----+18+17+
|
+15.1| |12.0+--- DIR/SIDE1 ---+18+17+
|
||||||
+----+ +----+ +--+--+
|
+----+ +----+ +--+--+
|
||||||
+15.2| |12.1+------- MOTEB ---+16+15+
|
+15.2| |12.1+------- MOTEB ---+16+15+
|
||||||
+----+ +----+ +--+--+
|
+----+ +----+ +--+--+
|
||||||
@@ -343,6 +343,10 @@ INDEX360 ---+ 3.1| | 1.7+------ DISKCHG --+34+33+--+
|
|||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
|
- `DIR/SIDE1` is the step direction pin. During reads or writes, `SIDE1` is
|
||||||
|
also multiplexed onto it, because some drives expect this. This is harmless
|
||||||
|
on other drives because the `DIR` pin is ignored during reads or writes.
|
||||||
|
|
||||||
- `TX` is the debug UART port. It's on pin 12.7 because the board routes it
|
- `TX` is the debug UART port. It's on pin 12.7 because the board routes it
|
||||||
to the USB serial port on the programmer, so you can get debug information
|
to the USB serial port on the programmer, so you can get debug information
|
||||||
from the FluxEngine by just plugging the programming end into a USB port
|
from the FluxEngine by just plugging the programming end into a USB port
|
||||||
@@ -365,6 +369,10 @@ Notes:
|
|||||||
rather exotic things. See the section on flippy disks [in the FAQ](faq.md)
|
rather exotic things. See the section on flippy disks [in the FAQ](faq.md)
|
||||||
for more details; you can normally ignore these.
|
for more details; you can normally ignore these.
|
||||||
|
|
||||||
|
- `TK43` is an optional output pin which goes low when the drive is seeking
|
||||||
|
to track 43 or above. This is useful when using 8" floppy drives, which
|
||||||
|
require reduced write current when writing to these tracks.
|
||||||
|
|
||||||
## Next steps
|
## Next steps
|
||||||
|
|
||||||
You should now be ready to go. You'll want to read [the client
|
You should now be ready to go. You'll want to read [the client
|
||||||
|
|||||||
@@ -32,3 +32,11 @@ If you've got a 40-track disk, use `-s :t=0-79x2`.
|
|||||||
|
|
||||||
If you've got a single density disk, use `--read-fm=true`. (Double density is
|
If you've got a single density disk, use `--read-fm=true`. (Double density is
|
||||||
the default.)
|
the default.)
|
||||||
|
|
||||||
|
|
||||||
|
Useful references
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
- [The JV3 file format](https://www.tim-mann.org/trs80/dskspec.html):
|
||||||
|
documents the most popular emulator disk image.
|
||||||
|
|
||||||
|
|||||||
19
doc/using.md
19
doc/using.md
@@ -136,6 +136,10 @@ exact format varies according to the extension:
|
|||||||
format due to the weird layout of Mac GCR disks, but it can also support
|
format due to the weird layout of Mac GCR disks, but it can also support
|
||||||
720kB and 1440kB IBM disks (although there's no real benefit).
|
720kB and 1440kB IBM disks (although there's no real benefit).
|
||||||
|
|
||||||
|
- `.jv3`: a disk image format mainly used by the TRS-80. These images can be
|
||||||
|
read, but not yet written. You only get the data; the density and DAM bits
|
||||||
|
are ignored.
|
||||||
|
|
||||||
### High density disks
|
### High density disks
|
||||||
|
|
||||||
High density disks use a different magnetic medium to low and double density
|
High density disks use a different magnetic medium to low and double density
|
||||||
@@ -228,21 +232,16 @@ directory.
|
|||||||
format in a non-backwards-compatible way; this tool will upgrade flux files
|
format in a non-backwards-compatible way; this tool will upgrade flux files
|
||||||
to the new format.
|
to the new format.
|
||||||
|
|
||||||
- `fluxengine convert`: converts flux files from various formats to various
|
- `fluxengine convert`: converts files from various formats to various other
|
||||||
other formats. You can use this to convert Catweasel flux files to
|
formats. The main use of this is probably `fluxengine convert image`, which
|
||||||
|
will convert a disk image from one format to another.
|
||||||
|
|
||||||
|
There are also subcommands for converting Catweasel flux files to
|
||||||
FluxEngine's native format, FluxEngine flux files to various other formats
|
FluxEngine's native format, FluxEngine flux files to various other formats
|
||||||
useful for debugging (including VCD which can be loaded into
|
useful for debugging (including VCD which can be loaded into
|
||||||
[sigrok](http://sigrok.org)), and bidirectional conversion to and from
|
[sigrok](http://sigrok.org)), and bidirectional conversion to and from
|
||||||
Supercard Pro `.scp` format.
|
Supercard Pro `.scp` format.
|
||||||
|
|
||||||
**Important SCP note:** import (`fluxengine convert scptoflux`) should be
|
|
||||||
fairly robust, but export (`fluxengine convert fluxtoscp`) should only be
|
|
||||||
done with great caution as FluxEngine files contain features which can't be
|
|
||||||
represented very well in `.scp` format and they're probably pretty dubious.
|
|
||||||
As ever, please [get in
|
|
||||||
touch](https://github.com/davidgiven/fluxengine/issues/new) with any
|
|
||||||
reports.
|
|
||||||
|
|
||||||
Commands which normally take `--source` or `--dest` get a sensible default if
|
Commands which normally take `--source` or `--dest` get a sensible default if
|
||||||
left unspecified. `fluxengine read ibm` on its own will read drive 0 and
|
left unspecified. `fluxengine read ibm` on its own will read drive 0 and
|
||||||
write an `ibm.img` file.
|
write an `ibm.img` file.
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ std::map<std::string, ImageReader::Constructor> ImageReader::formats =
|
|||||||
{".diskcopy", ImageReader::createDiskCopyImageReader},
|
{".diskcopy", ImageReader::createDiskCopyImageReader},
|
||||||
{".img", ImageReader::createImgImageReader},
|
{".img", ImageReader::createImgImageReader},
|
||||||
{".ima", ImageReader::createImgImageReader},
|
{".ima", ImageReader::createImgImageReader},
|
||||||
|
{".jv1", ImageReader::createImgImageReader},
|
||||||
|
{".jv3", ImageReader::createJv3ImageReader},
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool ends_with(const std::string& value, const std::string& ending)
|
static bool ends_with(const std::string& value, const std::string& ending)
|
||||||
@@ -46,7 +48,7 @@ std::unique_ptr<ImageReader> ImageReader::create(const ImageSpec& spec)
|
|||||||
void ImageReader::verifyImageSpec(const ImageSpec& spec)
|
void ImageReader::verifyImageSpec(const ImageSpec& spec)
|
||||||
{
|
{
|
||||||
if (!findConstructor(spec))
|
if (!findConstructor(spec))
|
||||||
Error() << "unrecognised image filename extension";
|
Error() << "unrecognised input image filename extension";
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageReader::ImageReader(const ImageSpec& spec):
|
ImageReader::ImageReader(const ImageSpec& spec):
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ private:
|
|||||||
|
|
||||||
static std::unique_ptr<ImageReader> createDiskCopyImageReader(const ImageSpec& spec);
|
static std::unique_ptr<ImageReader> createDiskCopyImageReader(const ImageSpec& spec);
|
||||||
static std::unique_ptr<ImageReader> createImgImageReader(const ImageSpec& spec);
|
static std::unique_ptr<ImageReader> createImgImageReader(const ImageSpec& spec);
|
||||||
|
static std::unique_ptr<ImageReader> createJv3ImageReader(const ImageSpec& spec);
|
||||||
|
|
||||||
static Constructor findConstructor(const ImageSpec& spec);
|
static Constructor findConstructor(const ImageSpec& spec);
|
||||||
|
|
||||||
|
|||||||
141
lib/imagereader/jv3imagereader.cc
Normal file
141
lib/imagereader/jv3imagereader.cc
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
#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>
|
||||||
|
|
||||||
|
/* JV3 files are kinda weird. There's a fixed layout for up to 2901 sectors, which may appear
|
||||||
|
* in any order, followed by the same again for more sectors. To find the second data block
|
||||||
|
* you need to know the size of the first data block, which requires parsing it.
|
||||||
|
*
|
||||||
|
* https://www.tim-mann.org/trs80/dskspec.html
|
||||||
|
*
|
||||||
|
* typedef struct {
|
||||||
|
* SectorHeader headers1[2901];
|
||||||
|
* unsigned char writeprot;
|
||||||
|
* unsigned char data1[];
|
||||||
|
* SectorHeader headers2[2901];
|
||||||
|
* unsigned char padding;
|
||||||
|
* unsigned char data2[];
|
||||||
|
* } JV3;
|
||||||
|
*
|
||||||
|
* typedef struct {
|
||||||
|
* unsigned char track;
|
||||||
|
* unsigned char sector;
|
||||||
|
* unsigned char flags;
|
||||||
|
* } SectorHeader;
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct SectorHeader
|
||||||
|
{
|
||||||
|
uint8_t track;
|
||||||
|
uint8_t sector;
|
||||||
|
uint8_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define JV3_DENSITY 0x80 /* 1=dden, 0=sden */
|
||||||
|
#define JV3_DAM 0x60 /* data address mark code; see below */
|
||||||
|
#define JV3_SIDE 0x10 /* 0=side 0, 1=side 1 */
|
||||||
|
#define JV3_ERROR 0x08 /* 0=ok, 1=CRC error */
|
||||||
|
#define JV3_NONIBM 0x04 /* 0=normal, 1=short */
|
||||||
|
#define JV3_SIZE 0x03 /* in used sectors: 0=256,1=128,2=1024,3=512
|
||||||
|
in free sectors: 0=512,1=1024,2=128,3=256 */
|
||||||
|
|
||||||
|
#define JV3_FREE 0xFF /* in track and sector fields of free sectors */
|
||||||
|
#define JV3_FREEF 0xFC /* in flags field, or'd with size code */
|
||||||
|
|
||||||
|
static unsigned getSectorSize(uint8_t flags)
|
||||||
|
{
|
||||||
|
if ((flags & JV3_FREEF) == JV3_FREEF)
|
||||||
|
{
|
||||||
|
switch (flags & JV3_SIZE)
|
||||||
|
{
|
||||||
|
case 0: return 512;
|
||||||
|
case 1: return 1024;
|
||||||
|
case 2: return 128;
|
||||||
|
case 3: return 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (flags & JV3_SIZE)
|
||||||
|
{
|
||||||
|
case 0: return 256;
|
||||||
|
case 1: return 128;
|
||||||
|
case 2: return 1024;
|
||||||
|
case 3: return 512;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Error() << "not reachable";
|
||||||
|
}
|
||||||
|
|
||||||
|
class Jv3ImageReader : public ImageReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Jv3ImageReader(const ImageSpec& spec):
|
||||||
|
ImageReader(spec)
|
||||||
|
{}
|
||||||
|
|
||||||
|
SectorSet readImage()
|
||||||
|
{
|
||||||
|
std::ifstream inputFile(spec.filename, std::ios::in | std::ios::binary);
|
||||||
|
if (!inputFile.is_open())
|
||||||
|
Error() << "cannot open input file";
|
||||||
|
|
||||||
|
inputFile.seekg( 0, std::ios::end);
|
||||||
|
unsigned inputFileSize = inputFile.tellg();
|
||||||
|
unsigned headerPtr = 0;
|
||||||
|
SectorSet sectors;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
unsigned dataPtr = headerPtr + 2901*3 + 1;
|
||||||
|
if (dataPtr >= inputFileSize)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (unsigned i=0; i<2901; i++)
|
||||||
|
{
|
||||||
|
SectorHeader header = {0, 0, 0xff};
|
||||||
|
inputFile.seekg(headerPtr);
|
||||||
|
inputFile.read((char*) &header, 3);
|
||||||
|
unsigned sectorSize = getSectorSize(header.flags);
|
||||||
|
if ((header.flags & JV3_FREEF) != JV3_FREEF)
|
||||||
|
{
|
||||||
|
Bytes data(sectorSize);
|
||||||
|
inputFile.seekg(dataPtr);
|
||||||
|
inputFile.read((char*) data.begin(), sectorSize);
|
||||||
|
|
||||||
|
unsigned head = !!(header.flags & JV3_SIDE);
|
||||||
|
std::unique_ptr<Sector>& sector = sectors.get(header.track, head, header.sector);
|
||||||
|
sector.reset(new Sector);
|
||||||
|
sector->status = Sector::OK;
|
||||||
|
sector->logicalTrack = sector->physicalTrack = header.track;
|
||||||
|
sector->logicalSide = sector->physicalSide = head;
|
||||||
|
sector->logicalSector = header.sector;
|
||||||
|
sector->data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
headerPtr += 3;
|
||||||
|
dataPtr += sectorSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dataPtr is now pointing at the beginning of the next chunk. */
|
||||||
|
|
||||||
|
headerPtr = dataPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sectors;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<ImageReader> ImageReader::createJv3ImageReader(
|
||||||
|
const ImageSpec& spec)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<ImageReader>(new Jv3ImageReader(spec));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ std::unique_ptr<ImageWriter> ImageWriter::create(const SectorSet& sectors, const
|
|||||||
void ImageWriter::verifyImageSpec(const ImageSpec& spec)
|
void ImageWriter::verifyImageSpec(const ImageSpec& spec)
|
||||||
{
|
{
|
||||||
if (!findConstructor(spec))
|
if (!findConstructor(spec))
|
||||||
Error() << "unrecognised image filename extension";
|
Error() << "unrecognised output image filename extension";
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageWriter::ImageWriter(const SectorSet& sectors, const ImageSpec& spec):
|
ImageWriter::ImageWriter(const SectorSet& sectors, const ImageSpec& spec):
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ buildlibrary libbackend.a \
|
|||||||
lib/imagereader/diskcopyimagereader.cc \
|
lib/imagereader/diskcopyimagereader.cc \
|
||||||
lib/imagereader/imagereader.cc \
|
lib/imagereader/imagereader.cc \
|
||||||
lib/imagereader/imgimagereader.cc \
|
lib/imagereader/imgimagereader.cc \
|
||||||
|
lib/imagereader/jv3imagereader.cc \
|
||||||
lib/imagewriter/d64imagewriter.cc \
|
lib/imagewriter/d64imagewriter.cc \
|
||||||
lib/imagewriter/diskcopyimagewriter.cc \
|
lib/imagewriter/diskcopyimagewriter.cc \
|
||||||
lib/imagewriter/imagewriter.cc \
|
lib/imagewriter/imagewriter.cc \
|
||||||
@@ -214,6 +215,7 @@ buildlibrary libfrontend.a \
|
|||||||
src/fe-fluxtoau.cc \
|
src/fe-fluxtoau.cc \
|
||||||
src/fe-fluxtoscp.cc \
|
src/fe-fluxtoscp.cc \
|
||||||
src/fe-fluxtovcd.cc \
|
src/fe-fluxtovcd.cc \
|
||||||
|
src/fe-image.cc \
|
||||||
src/fe-inspect.cc \
|
src/fe-inspect.cc \
|
||||||
src/fe-readadfs.cc \
|
src/fe-readadfs.cc \
|
||||||
src/fe-readaeslanier.cc \
|
src/fe-readaeslanier.cc \
|
||||||
|
|||||||
38
src/fe-image.cc
Normal file
38
src/fe-image.cc
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include "globals.h"
|
||||||
|
#include "flags.h"
|
||||||
|
#include "dataspec.h"
|
||||||
|
#include "sector.h"
|
||||||
|
#include "sectorset.h"
|
||||||
|
#include "imagereader/imagereader.h"
|
||||||
|
#include "imagewriter/imagewriter.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
static FlagGroup flags { };
|
||||||
|
|
||||||
|
static void syntax()
|
||||||
|
{
|
||||||
|
std::cout << "Syntax: fluxengine convert image <srcspec> <destspec>\n";
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mainConvertImage(int argc, const char* argv[])
|
||||||
|
{
|
||||||
|
auto filenames = flags.parseFlagsWithFilenames(argc, argv);
|
||||||
|
if (filenames.size() != 2)
|
||||||
|
syntax();
|
||||||
|
|
||||||
|
DataSpec ids(filenames[0]);
|
||||||
|
ImageSpec iis(ids);
|
||||||
|
SectorSet sectors = ImageReader::create(iis)->readImage();
|
||||||
|
|
||||||
|
DataSpec ods(filenames[1]);
|
||||||
|
ImageSpec ois(ods);
|
||||||
|
auto writer = ImageWriter::create(sectors, ois);
|
||||||
|
writer->adjustGeometry();
|
||||||
|
writer->printMap();
|
||||||
|
writer->writeImage();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -7,6 +7,7 @@ extern command_cb mainConvertCwfToFlux;
|
|||||||
extern command_cb mainConvertFluxToAu;
|
extern command_cb mainConvertFluxToAu;
|
||||||
extern command_cb mainConvertFluxToScp;
|
extern command_cb mainConvertFluxToScp;
|
||||||
extern command_cb mainConvertFluxToVcd;
|
extern command_cb mainConvertFluxToVcd;
|
||||||
|
extern command_cb mainConvertImage;
|
||||||
extern command_cb mainConvertScpToFlux;
|
extern command_cb mainConvertScpToFlux;
|
||||||
extern command_cb mainInspect;
|
extern command_cb mainInspect;
|
||||||
extern command_cb mainReadADFS;
|
extern command_cb mainReadADFS;
|
||||||
@@ -103,6 +104,7 @@ static std::vector<Command> convertables =
|
|||||||
{ "fluxtoau", mainConvertFluxToAu, "Converts (one track of a) flux file to an .au audio file.", },
|
{ "fluxtoau", mainConvertFluxToAu, "Converts (one track of a) flux file to an .au audio file.", },
|
||||||
{ "fluxtoscp", mainConvertFluxToScp, "Converrt a flux file to a Supercard Pro file.", },
|
{ "fluxtoscp", mainConvertFluxToScp, "Converrt a flux file to a Supercard Pro file.", },
|
||||||
{ "fluxtovcd", mainConvertFluxToVcd, "Converts (one track of a) flux file to a VCD file.", },
|
{ "fluxtovcd", mainConvertFluxToVcd, "Converts (one track of a) flux file to a VCD file.", },
|
||||||
|
{ "image", mainConvertImage, "Converts one disk image to another.", },
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<Command> testables =
|
static std::vector<Command> testables =
|
||||||
|
|||||||
Reference in New Issue
Block a user