Compare commits

...

41 Commits

Author SHA1 Message Date
David Given
28e0ef0463 Merge pull request #84 from davidgiven/cleanup
Mechanical refactor to rearrange the source files into a more pleasing order.
2019-08-06 22:33:05 +02:00
David Given
4b07c38782 Mechanical refactor to rearrange the source files into a more pleasing order. 2019-08-06 22:25:11 +02:00
David Given
e0256adf77 Merge pull request #83 from davidgiven/write
Write code refactoring.
2019-08-06 22:24:40 +02:00
David Given
5748f017dd Refactor the write code to make it easier to add new encoders. 2019-08-06 22:17:58 +02:00
David Given
973f4c2c2d Skeleton work to factor out the encoder logic. 2019-08-03 22:30:30 +02:00
David Given
8e1774c69f Show the clock rate in kHz as well, because that's more useful. 2019-07-12 23:09:50 +02:00
David Given
56a36072f7 Sampler state machine cleanup; more debugging tools for the logic analyser. 2019-07-12 21:09:53 +02:00
David Given
8755d108ed Sanity check Mac sectors --- reject anything with an out-of-bounds sector ID. 2019-07-11 23:16:02 +02:00
David Given
ea40cd73d1 Merge pull request #78 from davidgiven/mx
Bugfixing and documentation for MX disks.
2019-07-11 22:02:24 +02:00
David Given
0e28899b72 Add the page on the MX disk format. Mac disks are now unicorns. 2019-07-11 21:34:01 +02:00
David Given
eee30db981 Honour the logical track numbering in MX disks (allows reading 40-track disks). 2019-07-11 21:03:54 +02:00
David Given
6959d18017 Merge pull request #77 from davidgiven/build
Build cleanups
2019-07-11 12:18:59 +02:00
David Given
9f92ce0ef7 Typo fix. 2019-07-11 12:10:36 +02:00
David Given
7658c1d774 Move the fluxtoau tool into the main client. 2019-07-11 12:00:25 +02:00
David Given
31dc3504e6 Move the fluxtovcd file into the main client. 2019-07-11 11:52:38 +02:00
David Given
af0c9d4261 Move cwftoflux into the main client. 2019-07-11 11:45:15 +02:00
David Given
155b9daef6 Clean build scripts a bit. 2019-07-11 11:25:29 +02:00
David Given
a2fdbc5c73 Merge pull request #76 from davidgiven/sampling
Minor fixes and debugging tooling
2019-07-11 00:10:18 +02:00
David Given
1e3581c5f3 Turns out I was using the wrong error threshold flags for Mac disks. ND disks
work fine now.
2019-07-10 23:55:16 +02:00
David Given
a1d345856e Add a tool for converting flux files directly to mono or stereo au files,
suitable for comparison in Audacity.
2019-07-10 22:56:39 +02:00
David Given
7a775afaea Make sure that CounterClock is actually 12MHz, and not 12-ish MHz. Doesn't
help.
2019-07-10 20:26:17 +02:00
David Given
c27c4fe312 Synchronise input pins and set LVTTL levels. More correct, but doesn't help the
read issues.
2019-07-10 19:48:03 +02:00
David Given
ad295c683c The sampler pulse conversion now uses BUS_CLK as the sample clock. 2019-07-09 22:43:46 +02:00
David Given
3f8fdaa27a Fix missing flag initialisation. 2019-07-09 22:38:35 +02:00
David Given
9f5d01787f Fix missing flag initialisation. 2019-07-09 22:38:35 +02:00
David Given
3c4487c42e Add the tool to export flux files as VCD, so that they can be read into
pulseview.
2019-07-09 00:48:35 +02:00
David Given
e5c2168a35 Merge. 2019-07-08 23:32:53 +02:00
David Given
a06d8ff05a Merge pull request #74 from davidgiven/tools
Build brother120tool and cwftoflux.
2019-07-08 23:32:20 +02:00
David Given
c91ca1b730 Try to stop OSX from running brew cleanup every time. 2019-07-08 23:27:54 +02:00
David Given
3b6ea24df5 Rename fnmatchemu to just emu, because I'm sure we'll want to put more stuff
there.
2019-07-08 23:21:49 +02:00
David Given
b0e905fdd0 Typo fix. 2019-07-08 23:16:46 +02:00
David Given
34a858346e Add our own copy of fnmatch(), which mingw doesn't have --- we need it for the
Brother tool and I'm sure it'll come in useful elsewhere.
2019-07-08 23:12:58 +02:00
David Given
499cb4f720 Typo fix. 2019-07-08 22:46:16 +02:00
David Given
3960b1e4d7 Build brother120tool and cwftoflux. 2019-07-08 22:44:38 +02:00
David Given
98ea5e9600 Connect up pins 2.3, 2.4 and 2.5 for debugging with a logic analyser. 2019-07-08 01:08:05 +02:00
David Given
ce6077fa22 Apply Denis Kushch's timing fixes to the schematic. No more warnings on builds! 2019-07-08 00:52:59 +02:00
David Given
adb1e9ba00 Document the precompiled releases. 2019-07-07 01:50:31 +02:00
David Given
7752fd9f2c Remember that our build artifact is now a zipfile... 2019-07-07 01:45:11 +02:00
David Given
5db81e681f Appveyor really doesn't have zip? 2019-07-07 01:44:08 +02:00
David Given
6ef969fd7e Upload zipfiles rather than uncompressed exes. 2019-07-07 01:42:05 +02:00
David Given
98dece78c6 Let's see if we can avoid the infinite build loops this time... 2019-07-07 01:37:58 +02:00
64 changed files with 1292 additions and 242 deletions

View File

@@ -1,5 +1,6 @@
version: '{branch}.{build}'
clone_depth: 1
skip_tags: true
environment:
MSYSTEM: MINGW32
@@ -10,22 +11,29 @@ init:
install:
- set PATH=c:\msys64\mingw32\bin;c:\msys64\usr\bin;c:\msys64\bin;%PATH%
- echo %PATH%
- pacman -S --noconfirm --needed make ninja mingw-w64-i686-libusb mingw-w64-i686-sqlite3 mingw-w64-i686-zlib mingw-w64-i686-gcc
- pacman -S --noconfirm --needed make ninja mingw-w64-i686-libusb mingw-w64-i686-sqlite3 mingw-w64-i686-zlib mingw-w64-i686-gcc zip
build_script:
- make
- zip -9 fluxengine.zip fluxengine.exe brother120tool.exe
artifacts:
- path: fluxengine.exe
name: fluxengine.exe
- path: fluxengine.zip
name: fluxengine.zip
deploy:
release: fluxengine-windows-client-v$(appveyor_build_version)
description: FluxEngine Windows client
release: FluxEngine Windows client version $(APPVEYOR_BUILD_NUMBER)
description: >
This is an automatically built version of the FluxEngine Windows client
which is generated whenever a significant checkin has happened. It's had
no testing whatsoever.
To use, download it, put it somewhere, and then run it from a cmd window
or other command line shell.
provider: GitHub
auth_token:
secure: dfJjj7fWCoDUz+Ni11OcNPB/U3TNJFwNA2AsL++ChFjniUsZLlC6SDWHiL/t4FZo
artifact: fluxengine.exe
artifact: fluxengine.zip
draft: false
prerelease: false
on:

View File

@@ -11,11 +11,13 @@ matrix:
compiler: gcc
env: CXX=g++-8
script:
- make
- make
-
os: osx
osx_image: xcode10.2
compiler: clang
env:
- HOMEBREW_NO_INSTALL_CLEANUP=1
addons:
apt:

View File

@@ -28,13 +28,37 @@
<Data key="sync_with_bus_clk" value="True" />
<Data key="user_set_domain" value="False" />
</Group>
<Group key="4eef02b9-8ad1-43c4-85f1-b3335faa5fc4">
<Data key="check_tolerance" value="True" />
<Data key="clock_version" value="v1" />
<Data key="derive_type" value="NAMED_DIVIDER" />
<Data key="desired_freq" value="0" />
<Data key="desired_unit" value="15" />
<Data key="divider" value="0" />
<Data key="domain" value="DIGITAL" />
<Data key="enabled" value="True" />
<Data key="minus_accuracy" value="0.25" />
<Data key="minus_tolerance" value="5" />
<Data key="name" value="Clock_3" />
<Data key="named_src_direct_connect" value="True" />
<Data key="netlist_name" value="Clock_3" />
<Data key="placement" value="AUTO" />
<Data key="plus_accuracy" value="0.25" />
<Data key="plus_tolerance" value="5" />
<Data key="scope" value="LOCAL" />
<Data key="src_clk_id" value="75C2148C-3656-4d8a-846D-0CAE99AB6FF7" />
<Data key="src_clk_name" value="BUS_CLK" />
<Data key="start_on_reset" value="True" />
<Data key="sync_with_bus_clk" value="True" />
<Data key="user_set_domain" value="False" />
</Group>
<Group key="06c4d5d4-f15f-4b29-a1d0-c24b2e38b1ec">
<Data key="check_tolerance" value="True" />
<Data key="clock_version" value="v1" />
<Data key="derive_type" value="NAMED_FREQ" />
<Data key="desired_freq" value="24" />
<Data key="desired_freq" value="12" />
<Data key="desired_unit" value="6" />
<Data key="divider" value="1" />
<Data key="divider" value="2" />
<Data key="domain" value="DIGITAL" />
<Data key="enabled" value="True" />
<Data key="minus_accuracy" value="0.25" />
@@ -50,7 +74,7 @@
<Data key="src_clk_name" value="IMO" />
<Data key="start_on_reset" value="True" />
<Data key="sync_with_bus_clk" value="True" />
<Data key="user_set_domain" value="False" />
<Data key="user_set_domain" value="True" />
</Group>
<Group key="24cd38f7-f472-4403-837f-86807c8f5333">
<Data key="check_tolerance" value="True" />
@@ -193,6 +217,54 @@
<Data key="sync_with_bus_clk" value="True" />
<Data key="user_set_domain" value="False" />
</Group>
<Group key="75187c05-9501-4450-b306-6ccdd3bb77db">
<Data key="check_tolerance" value="True" />
<Data key="clock_version" value="v1" />
<Data key="derive_type" value="NAMED_DIVIDER" />
<Data key="desired_freq" value="0" />
<Data key="desired_unit" value="15" />
<Data key="divider" value="0" />
<Data key="domain" value="DIGITAL" />
<Data key="enabled" value="True" />
<Data key="minus_accuracy" value="0.25" />
<Data key="minus_tolerance" value="5" />
<Data key="name" value="Clock_5" />
<Data key="named_src_direct_connect" value="True" />
<Data key="netlist_name" value="Clock_5" />
<Data key="placement" value="AUTO" />
<Data key="plus_accuracy" value="0.25" />
<Data key="plus_tolerance" value="5" />
<Data key="scope" value="LOCAL" />
<Data key="src_clk_id" value="75C2148C-3656-4d8a-846D-0CAE99AB6FF7" />
<Data key="src_clk_name" value="BUS_CLK" />
<Data key="start_on_reset" value="True" />
<Data key="sync_with_bus_clk" value="True" />
<Data key="user_set_domain" value="False" />
</Group>
<Group key="b762c287-7f87-4b21-982e-84be01dc5115">
<Data key="check_tolerance" value="True" />
<Data key="clock_version" value="v1" />
<Data key="derive_type" value="NAMED_DIVIDER" />
<Data key="desired_freq" value="0" />
<Data key="desired_unit" value="15" />
<Data key="divider" value="0" />
<Data key="domain" value="DIGITAL" />
<Data key="enabled" value="True" />
<Data key="minus_accuracy" value="0.25" />
<Data key="minus_tolerance" value="5" />
<Data key="name" value="Clock_2" />
<Data key="named_src_direct_connect" value="True" />
<Data key="netlist_name" value="Clock_2" />
<Data key="placement" value="AUTO" />
<Data key="plus_accuracy" value="0.25" />
<Data key="plus_tolerance" value="5" />
<Data key="scope" value="LOCAL" />
<Data key="src_clk_id" value="75C2148C-3656-4d8a-846D-0CAE99AB6FF7" />
<Data key="src_clk_name" value="BUS_CLK" />
<Data key="start_on_reset" value="True" />
<Data key="sync_with_bus_clk" value="True" />
<Data key="user_set_domain" value="False" />
</Group>
<Group key="b0162966-0060-4af5-82d1-fcb491ad7619/be0a0e37-ad17-42ca-b5a1-1a654d736358">
<Data key="check_tolerance" value="True" />
<Data key="clock_version" value="v1" />
@@ -537,6 +609,7 @@
<Group key="DWRInstGuidMapping">
<Group key="Clock">
<Data key="0b2f9bbb-00ce-4115-a788-ffb9d046a9e5" value="Clock_4" />
<Data key="4eef02b9-8ad1-43c4-85f1-b3335faa5fc4" value="Clock_3" />
<Data key="06c4d5d4-f15f-4b29-a1d0-c24b2e38b1ec" value="CounterClock" />
<Data key="24cd38f7-f472-4403-837f-86807c8f5333" value="PULSE_CLOCK" />
<Data key="63ed4137-0b09-4256-8a27-35c9a2653f1a" value="Clock_2" />
@@ -544,6 +617,8 @@
<Data key="349ffa20-8576-4ac3-9a6f-34ef606de6cf" value="Clock_1" />
<Data key="6616e828-6611-4893-a674-66c861d79d6c" value="SignalSamplingClock" />
<Data key="12664fc6-9d70-44b1-8a49-887a292e1b7f" value="Clock_3" />
<Data key="75187c05-9501-4450-b306-6ccdd3bb77db" value="Clock_5" />
<Data key="b762c287-7f87-4b21-982e-84be01dc5115" value="Clock_2" />
<Data key="b0162966-0060-4af5-82d1-fcb491ad7619/be0a0e37-ad17-42ca-b5a1-1a654d736358" value="UART_IntClock" />
<Data key="cb7e877c-9fb4-4fc1-a708-f1e48eb5a68c" value="CounterClock" />
<Data key="e4a53a4c-40e1-4747-a72a-10193ffdf31c" value="Clock_1" />
@@ -553,6 +628,7 @@
<Data key="4a398466-709f-4228-9500-96178658e13e" value="RDATA" />
<Data key="5a3407c1-b434-4438-a7b4-b9dfd2280495" value="MOTEA" />
<Data key="8d318d8b-cf7b-4b6b-b02c-ab1c5c49d0ba" value="SW1" />
<Data key="12e00eac-69b5-4717-85c8-25ef6b224d4c" value="DEBUG_PINS" />
<Data key="41e2d8ed-5494-4d8c-8ff7-f4f789cece51" value="REDWC" />
<Data key="264be2d3-9481-494b-8d9c-c1905a45e9cc" value="FDD" />
<Data key="472f8fdb-f772-44fb-8897-cc690694237b" value="WDATA" />
@@ -561,6 +637,7 @@
<Data key="1425177d-0d0e-4468-8bcc-e638e5509a9b" value="UartRx" />
<Data key="a5d987c6-e45b-45b9-ad93-656fab06d720" value="TRK00" />
<Data key="a93ef5b3-00f4-42c0-8fad-0e275a7e2537" value="MOTEB" />
<Data key="b8380fb7-fdb8-449f-bd8d-c4ca96cdf55a" value="DEBUG_PINS" />
<Data key="bc5d52a1-1b25-4aa0-9ba9-3f81d122772f" value="DEBUG_PINS" />
<Data key="beca5e2d-f70f-4900-a4db-7eca1ed3126e/8b77a6c4-10a0-4390-971c-672353e2a49c" value="USBFS_Dm" />
<Data key="beca5e2d-f70f-4900-a4db-7eca1ed3126e/618a72fc-5ddd-4df5-958f-a3d55102db42" value="USBFS_Dp" />
@@ -571,7 +648,7 @@
<Data key="e51063a9-4fad-40c7-a06b-7cc4b137dc18" value="DSKCHG" />
<Data key="ea7ee228-8b3f-426c-8bb8-cd7a81937769" value="DIR" />
<Data key="ed092b9b-d398-4703-be89-cebf998501f6" value="UartTx" />
<Data key="fbd1f839-40f9-498e-a48b-5f3048ea5c3d/52f31aa9-2f0a-497d-9a1f-1424095e13e6" value="SW_Tx_UART_1_tx" />
<Data key="fbd1f839-40f9-498e-a48b-5f3048ea5c3d/52f31aa9-2f0a-497d-9a1f-1424095e13e6" value="UART_tx" />
<Data key="fede1767-f3fd-4021-b3d7-8f9d88f36f9b" value="DRVSA" />
<Data key="fff78075-035e-43d7-8577-bc5be4d21926" value="WGATE" />
</Group>
@@ -3675,6 +3752,20 @@
<Data key="Port Format" value="2,2" />
</Group>
</Group>
<Group key="12e00eac-69b5-4717-85c8-25ef6b224d4c">
<Group key="0">
<Data key="Port Format" value="2,2" />
</Group>
<Group key="1">
<Data key="Port Format" value="2,3" />
</Group>
<Group key="2">
<Data key="Port Format" value="2,4" />
</Group>
<Group key="3">
<Data key="Port Format" value="2,0" />
</Group>
</Group>
<Group key="41e2d8ed-5494-4d8c-8ff7-f4f789cece51">
<Group key="0">
<Data key="Port Format" value="2,7" />
@@ -3757,6 +3848,17 @@
<Data key="Port Format" value="12,1" />
</Group>
</Group>
<Group key="b8380fb7-fdb8-449f-bd8d-c4ca96cdf55a">
<Group key="0">
<Data key="Port Format" value="2,5" />
</Group>
<Group key="1">
<Data key="Port Format" value="2,4" />
</Group>
<Group key="2">
<Data key="Port Format" value="2,3" />
</Group>
</Group>
<Group key="bc5d52a1-1b25-4aa0-9ba9-3f81d122772f">
<Group key="0">
<Data key="Port Format" value="0,5" />
@@ -3812,7 +3914,7 @@
</Group>
<Group key="fbd1f839-40f9-498e-a48b-5f3048ea5c3d/52f31aa9-2f0a-497d-9a1f-1424095e13e6">
<Group key="0">
<Data key="Port Format" value="2,0" />
<Data key="Port Format" value="2,5" />
</Group>
</Group>
<Group key="fede1767-f3fd-4021-b3d7-8f9d88f36f9b">
@@ -3840,7 +3942,7 @@
<Data key="CYDEV_ECC_ENABLE" value="False" />
<Data key="CYDEV_HEAP_SIZE" value="0x80" />
<Data key="CYDEV_INSTRUCT_CACHE_ENABLED" value="True" />
<Data key="CYDEV_PROTECTION_ENABLE" value="False" />
<Data key="CYDEV_PROTECTION_ENABLE" value="True" />
<Data key="CYDEV_STACK_SIZE" value="0x0800" />
<Data key="CYDEV_TEMPERATURE" value="0C - 85/125C" />
<Data key="CYDEV_TRACE_ENABLED" value="False" />

View File

@@ -2310,13 +2310,13 @@
<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="DEBUG_PINS" persistent="">
<Hidden v="True" />
<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="DEBUG_PINS_aliases.h" persistent="Generated_Source\PSoC5\DEBUG_PINS_aliases.h">
<Hidden v="True" />
<Hidden v="False" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="HEADER;;;;" />
<PropertyDeltas />
@@ -3249,6 +3249,39 @@
</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="CAPTURE_CONTROL" 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="CAPTURE_CONTROL.h" persistent="Generated_Source\PSoC5\CAPTURE_CONTROL.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="CAPTURE_CONTROL.c" persistent="Generated_Source\PSoC5\CAPTURE_CONTROL.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="CAPTURE_CONTROL_PM.c" persistent="Generated_Source\PSoC5\CAPTURE_CONTROL_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>
</dependencies>
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
@@ -3667,6 +3700,6 @@
</ignored_deps>
</CyGuid_495451fe-d201-4d01-b22d-5d3f5609ac37>
<boot_component v="" />
<current_generation v="52" />
<current_generation v="60" />
</CyGuid_fec8f9e8-2365-4bdb-96d3-a4380222e01b>
</CyXmlSerializer>

View File

Binary file not shown.

View File

Binary file not shown.

View File

@@ -306,6 +306,7 @@ static void cmd_read(struct read_frame* f)
dma_underrun = false;
int count = 0;
SAMPLER_CONTROL_Write(0); /* !reset */
CAPTURE_CONTROL_Write(1);
CyDmaChSetInitialTd(dma_channel, td[dma_writing_to_td]);
CyDmaClearPendingDrq(dma_channel);
CyDmaChEnable(dma_channel, 1);
@@ -364,7 +365,8 @@ static void cmd_read(struct read_frame* f)
}
dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td);
}
abort:
abort:;
CAPTURE_CONTROL_Write(0);
CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN);
while (CyDmaChGetRequest(dma_channel))
;

View File

@@ -1,24 +1,28 @@
PACKAGES = zlib sqlite3 libusb-1.0
export CFLAGS = -O3 -g --std=c++14 \
-ffunction-sections -fdata-sections
export LDFLAGS = -O3
ifeq ($(OS), Windows_NT)
export CXX = /mingw32/bin/g++
export AR = /mingw32/bin/ar rcs
export STRIP = /mingw32/bin/strip
export CFLAGS = -O3 -g --std=c++14 -I/mingw32/include/libusb-1.0
export LDFLAGS = -O3
export CFLAGS += -I/mingw32/include/libusb-1.0
export LDFLAGS +=
export LIBS = -static -lz -lsqlite3 -lusb-1.0
export EXTENSION = .exe
else
export CXX = g++
export AR = ar rcs
export STRIP = strip
export CFLAGS = -Og -g --std=c++14 $(shell pkg-config --cflags $(PACKAGES))
export LDFLAGS = -Og
export CFLAGS += $(shell pkg-config --cflags $(PACKAGES))
export LDFLAGS +=
export LIBS = $(shell pkg-config --libs $(PACKAGES))
export EXTENSION =
endif
CFLAGS += -Ilib -Idep/fmt
CFLAGS += -Ilib -Idep/fmt -Iarch
export OBJDIR = .obj

View File

@@ -89,7 +89,7 @@ people who've had it work).
| [Brother 120kB](doc/disk-brother.md) | 🦄 | | |
| [Brother 240kB](doc/disk-brother.md) | 🦄 | 🦄 | |
| [Brother FB-100](doc/disk-fb100.md) | 🦖 | | Tandy Model 100, Husky Hunter, knitting machines |
| [Macintosh 800kB](doc/disk-macintosh.md) | 🦖 | | and probably the 400kB too |
| [Macintosh 800kB](doc/disk-macintosh.md) | 🦄 | | and probably the 400kB too |
| [TRS-80](doc/disk-trs80.md) | 🦖 | | a minor variation of the IBM scheme |
{: .datatable }
@@ -105,6 +105,7 @@ at least, check the CRC so what data's there is probably good.
|:-----------------------------------------|:-----:|:------:|-------|
| [AES Superplus / No Problem](doc/disk-aeslanier.md) | 🦖 | | hard sectors! |
| [Durango F85](doc/disk-durangof85.md) | 🦖 | | 5.25" |
| [DVK MX](doc/disk-mx.md) | 🦖 | | Soviet PDP-11 clone |
| [Victor 9000](doc/disk-victor9k.md) | 🦖 | | 8-inch |
| [Zilog MCZ](doc/disk-zilogmcz.md) | 🦖 | | 8-inch _and_ hard sectors |
{: .datatable }
@@ -188,3 +189,8 @@ maintained by Victor Zverovich (`vitaut <https://github.com/vitaut>`) and
Jonathan Müller (`foonathan <https://github.com/foonathan>`) with
contributions from many other people. It is licensed under the terms of the
BSD license. Please see the contents of the directory for the full text.
As an exception, `dep/emu` contains parts of the OpenBSD C library
code, Todd Miller and William A. Rowe (and probably others). It is licensed
under the terms of the 3-clause BSD license. Please see the contents of the
directory for the full text. It's been lightly modified by me.

View File

View File

@@ -9,6 +9,9 @@
#define BROTHER_DATA_RECORD_CHECKSUM 3
#define BROTHER_DATA_RECORD_ENCODED_SIZE 415
#define BROTHER_TRACKS_PER_DISK 78
#define BROTHER_SECTORS_PER_TRACK 12
class Sector;
class Fluxmap;
@@ -22,9 +25,15 @@ public:
void decodeDataRecord();
};
extern void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor,
int track, int sector);
extern void writeBrotherSectorData(std::vector<bool>& bits, unsigned& cursor,
const Bytes& data);
class BrotherEncoder : public AbstractEncoder
{
public:
virtual ~BrotherEncoder() {}
public:
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors);
};
extern FlagGroup brotherEncoderFlags;
#endif

View File

@@ -3,6 +3,7 @@
#include "fluxmap.h"
#include "decoders/fluxmapreader.h"
#include "decoders/decoders.h"
#include "encoders/encoders.h"
#include "record.h"
#include "brother.h"
#include "sector.h"

167
arch/brother/encoder.cc Normal file
View File

@@ -0,0 +1,167 @@
#include "globals.h"
#include "record.h"
#include "decoders/decoders.h"
#include "encoders/encoders.h"
#include "brother.h"
#include "crc.h"
#include "sectorset.h"
#include "writer.h"
FlagGroup brotherEncoderFlags;
static DoubleFlag clockRateUs(
{ "--clock-rate" },
"Encoded data clock rate (microseconds).",
3.83);
static DoubleFlag postIndexGapMs(
{ "--post-index-gap" },
"Post-index gap before first sector header (milliseconds).",
1.0);
static DoubleFlag sectorSpacingMs(
{ "--sector-spacing" },
"Time between successive sector headers (milliseconds).",
16.2);
static DoubleFlag postHeaderSpacingMs(
{ "--post-header-spacing" },
"Time between a sector's header and data records (milliseconds).",
0.69);
static StringFlag sectorSkew(
{ "--sector-skew" },
"Order in which to write sectors.",
"05a3816b4927");
static int encode_header_gcr(uint16_t word)
{
switch (word)
{
#define GCR_ENTRY(gcr, data) \
case data: return gcr;
#include "header_gcr.h"
#undef GCR_ENTRY
}
return -1;
};
static int encode_data_gcr(uint8_t data)
{
switch (data)
{
#define GCR_ENTRY(gcr, data) \
case data: return gcr;
#include "data_gcr.h"
#undef GCR_ENTRY
}
return -1;
};
static void write_bits(std::vector<bool>& bits, unsigned& cursor, uint32_t data, int width)
{
cursor += width;
for (int i=0; i<width; i++)
{
unsigned pos = cursor - i - 1;
if (pos < bits.size())
bits[pos] = data & 1;
data >>= 1;
}
}
static void write_sector_header(std::vector<bool>& bits, unsigned& cursor,
int track, int sector)
{
write_bits(bits, cursor, 0xffffffff, 31);
write_bits(bits, cursor, BROTHER_SECTOR_RECORD, 32);
write_bits(bits, cursor, encode_header_gcr(track), 16);
write_bits(bits, cursor, encode_header_gcr(sector), 16);
write_bits(bits, cursor, encode_header_gcr(0x2f), 16);
}
static void write_sector_data(std::vector<bool>& bits, unsigned& cursor, const Bytes& data)
{
write_bits(bits, cursor, 0xffffffff, 32);
write_bits(bits, cursor, BROTHER_DATA_RECORD, 32);
uint16_t fifo = 0;
int width = 0;
if (data.size() != BROTHER_DATA_RECORD_PAYLOAD)
Error() << "unsupported sector size";
auto write_byte = [&](uint8_t byte)
{
fifo |= (byte << (8 - width));
width += 8;
while (width >= 5)
{
uint8_t quintet = fifo >> 11;
fifo <<= 5;
width -= 5;
write_bits(bits, cursor, encode_data_gcr(quintet), 8);
}
};
for (uint8_t byte : data)
write_byte(byte);
uint32_t realCrc = crcbrother(data);
write_byte(realCrc>>16);
write_byte(realCrc>>8);
write_byte(realCrc);
write_byte(0x58); /* magic */
write_byte(0xd4);
while (width != 0)
write_byte(0);
}
static int charToInt(char c)
{
if (isdigit(c))
return c - '0';
return 10 + tolower(c) - 'a';
}
std::unique_ptr<Fluxmap> BrotherEncoder::encode(
int physicalTrack, int physicalSide, const SectorSet& allSectors)
{
if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_DISK)
|| (physicalSide != 0))
return std::unique_ptr<Fluxmap>();
int bitsPerRevolution = 200000.0 / clockRateUs;
const std::string& skew = sectorSkew.get();
std::vector<bool> bits(bitsPerRevolution);
unsigned cursor = 0;
for (int sectorCount=0; sectorCount<BROTHER_SECTORS_PER_TRACK; sectorCount++)
{
int sectorId = charToInt(skew.at(sectorCount));
double headerMs = postIndexGapMs + sectorCount*sectorSpacingMs;
unsigned headerCursor = headerMs*1e3 / clockRateUs;
double dataMs = headerMs + postHeaderSpacingMs;
unsigned dataCursor = dataMs*1e3 / clockRateUs;
const auto& sectorData = allSectors.get(physicalTrack, 0, sectorId);
fillBitmapTo(bits, cursor, headerCursor, { true, false });
write_sector_header(bits, cursor, physicalTrack, sectorId);
fillBitmapTo(bits, cursor, dataCursor, { true, false });
write_sector_data(bits, cursor, sectorData->data);
}
if (cursor > bits.size())
Error() << "track data overrun";
fillBitmapTo(bits, cursor, bits.size(), { true, false });
// The pre-index gap is not normally reported.
// std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl;
std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
fluxmap->appendBits(bits, clockRateUs*1e3);
return fluxmap;
}

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

@@ -153,6 +153,9 @@ void MacintoshDecoder::decodeSectorRecord()
uint8_t formatByte = decode_data_gcr(header[3]);
uint8_t wantedsum = decode_data_gcr(header[4]);
if (encodedSector > 11)
return;
_sector->logicalTrack = _track->physicalTrack;
_sector->logicalSide = decode_side(encodedSide);
_sector->logicalSector = encodedSector;

View File

@@ -37,7 +37,7 @@ AbstractDecoder::RecordType MxDecoder::advanceToNextRecord()
const FluxMatcher* matcher = nullptr;
_sector->clock = _clock = _fmr->seekToPattern(ID_PATTERN, matcher);
readRawBits(32); /* skip the ID mark */
readRawBits(32); /* skip the track number */
_logicalTrack = decodeFmMfm(readRawBits(32)).reader().read_be16();
}
else if (_currentSector == 10)
{
@@ -67,7 +67,7 @@ void MxDecoder::decodeSectorRecord()
gotChecksum += br.read_le16();
uint16_t wantChecksum = br.read_le16();
_sector->logicalTrack = _track->physicalTrack;
_sector->logicalTrack = _logicalTrack;
_sector->logicalSide = _track->physicalSide;
_sector->logicalSector = _currentSector;
_sector->data = bytes.slice(0, SECTOR_SIZE);

View File

@@ -15,6 +15,7 @@ public:
private:
nanoseconds_t _clock;
int _currentSector;
int _logicalTrack;
};
#endif

29
dep/emu/charclass.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* Public domain, 2008, Todd C. Miller <Todd.Miller@courtesan.com>
*
* $OpenBSD: charclass.h,v 1.1 2008/10/01 23:04:13 millert Exp $
*/
/*
* POSIX character class support for fnmatch() and glob().
*/
static struct cclass {
const char *name;
int (*isctype)(int);
} cclasses[] = {
{ "alnum", isalnum },
{ "alpha", isalpha },
{ "blank", isblank },
{ "cntrl", iscntrl },
{ "digit", isdigit },
{ "graph", isgraph },
{ "lower", islower },
{ "print", isprint },
{ "punct", ispunct },
{ "space", isspace },
{ "upper", isupper },
{ "xdigit", isxdigit },
{ NULL, NULL }
};
#define NCCLASSES (sizeof(cclasses) / sizeof(cclasses[0]) - 1)

481
dep/emu/fnmatch.c Normal file
View File

@@ -0,0 +1,481 @@
/*
* This has been lightly tweaked by me, David Given, to change the exported name
* so that it doesn't conflict with the real fnmatch (if any).
*/
/* $OpenBSD: fnmatch.c,v 1.16 2011/12/06 11:47:46 stsp Exp $ */
/* Copyright (c) 2011, VMware, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the VMware, Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 2008 Todd C. Miller <millert@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* Authored by William A. Rowe Jr. <wrowe; apache.org, vmware.com>, April 2011
*
* Derived from The Open Group Base Specifications Issue 7, IEEE Std 1003.1-2008
* as described in;
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html
*
* Filename pattern matches defined in section 2.13, "Pattern Matching Notation"
* from chapter 2. "Shell Command Language"
* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13
* where; 1. A bracket expression starting with an unquoted <circumflex> '^'
* character CONTINUES to specify a non-matching list; 2. an explicit <period> '.'
* in a bracket expression matching list, e.g. "[.abc]" does NOT match a leading
* <period> in a filename; 3. a <left-square-bracket> '[' which does not introduce
* a valid bracket expression is treated as an ordinary character; 4. a differing
* number of consecutive slashes within pattern and string will NOT match;
* 5. a trailing '\' in FNM_ESCAPE mode is treated as an ordinary '\' character.
*
* Bracket expansion defined in section 9.3.5, "RE Bracket Expression",
* from chapter 9, "Regular Expressions"
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03_05
* with no support for collating symbols, equivalence class expressions or
* character class expressions. A partial range expression with a leading
* hyphen following a valid range expression will match only the ordinary
* <hyphen> and the ending character (e.g. "[a-m-z]" will match characters
* 'a' through 'm', a <hyphen> '-', or a 'z').
*
* Supports BSD extensions FNM_LEADING_DIR to match pattern to the end of one
* path segment of string, and FNM_CASEFOLD to ignore alpha case.
*
* NOTE: Only POSIX/C single byte locales are correctly supported at this time.
* Notably, non-POSIX locales with FNM_CASEFOLD produce undefined results,
* particularly in ranges of mixed case (e.g. "[A-z]") or spanning alpha and
* nonalpha characters within a range.
*
* XXX comments below indicate porting required for multi-byte character sets
* and non-POSIX locale collation orders; requires mbr* APIs to track shift
* state of pattern and string (rewinding pattern and string repeatedly).
*
* Certain parts of the code assume 0x00-0x3F are unique with any MBCS (e.g.
* UTF-8, SHIFT-JIS, etc). Any implementation allowing '\' as an alternate
* path delimiter must be aware that 0x5C is NOT unique within SHIFT-JIS.
*/
#include "fnmatch.h"
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include "charclass.h"
#define RANGE_MATCH 1
#define RANGE_NOMATCH 0
#define RANGE_ERROR (-1)
static int
classmatch(const char *pattern, char test, int foldcase, const char **ep)
{
struct cclass *cc;
const char *colon;
size_t len;
int rval = RANGE_NOMATCH;
const char * const mismatch = pattern;
if (*pattern != '[' || pattern[1] != ':') {
*ep = mismatch;
return(RANGE_ERROR);
}
pattern += 2;
if ((colon = strchr(pattern, ':')) == NULL || colon[1] != ']') {
*ep = mismatch;
return(RANGE_ERROR);
}
*ep = colon + 2;
len = (size_t)(colon - pattern);
if (foldcase && strncmp(pattern, "upper:]", 7) == 0)
pattern = "lower:]";
for (cc = cclasses; cc->name != NULL; cc++) {
if (!strncmp(pattern, cc->name, len) && cc->name[len] == '\0') {
if (cc->isctype((unsigned char)test))
rval = RANGE_MATCH;
break;
}
}
if (cc->name == NULL) {
/* invalid character class, treat as normal text */
*ep = mismatch;
rval = RANGE_ERROR;
}
return(rval);
}
/* Most MBCS/collation/case issues handled here. Wildcard '*' is not handled.
* EOS '\0' and the FNM_PATHNAME '/' delimiters are not advanced over,
* however the "\/" sequence is advanced to '/'.
*
* Both pattern and string are **char to support pointer increment of arbitrary
* multibyte characters for the given locale, in a later iteration of this code
*/
static int fnmatch_ch(const char **pattern, const char **string, int flags)
{
const char * const mismatch = *pattern;
const int nocase = !!(flags & FNM_CASEFOLD);
const int escape = !(flags & FNM_NOESCAPE);
const int slash = !!(flags & FNM_PATHNAME);
int result = FNM_NOMATCH;
const char *startch;
int negate;
if (**pattern == '[')
{
++*pattern;
/* Handle negation, either leading ! or ^ operators (never both) */
negate = ((**pattern == '!') || (**pattern == '^'));
if (negate)
++*pattern;
/* ']' is an ordinary character at the start of the range pattern */
if (**pattern == ']')
goto leadingclosebrace;
while (**pattern)
{
if (**pattern == ']') {
++*pattern;
/* XXX: Fix for MBCS character width */
++*string;
return (result ^ negate);
}
if (escape && (**pattern == '\\')) {
++*pattern;
/* Patterns must be terminated with ']', not EOS */
if (!**pattern)
break;
}
/* Patterns must be terminated with ']' not '/' */
if (slash && (**pattern == '/'))
break;
/* Match character classes. */
if (classmatch(*pattern, **string, nocase, pattern)
== RANGE_MATCH) {
result = 0;
continue;
}
leadingclosebrace:
/* Look at only well-formed range patterns;
* "x-]" is not allowed unless escaped ("x-\]")
* XXX: Fix for locale/MBCS character width
*/
if (((*pattern)[1] == '-') && ((*pattern)[2] != ']'))
{
startch = *pattern;
*pattern += (escape && ((*pattern)[2] == '\\')) ? 3 : 2;
/* NOT a properly balanced [expr] pattern, EOS terminated
* or ranges containing a slash in FNM_PATHNAME mode pattern
* fall out to to the rewind and test '[' literal code path
*/
if (!**pattern || (slash && (**pattern == '/')))
break;
/* XXX: handle locale/MBCS comparison, advance by MBCS char width */
if ((**string >= *startch) && (**string <= **pattern))
result = 0;
else if (nocase && (isupper(**string) || isupper(*startch)
|| isupper(**pattern))
&& (tolower(**string) >= tolower(*startch))
&& (tolower(**string) <= tolower(**pattern)))
result = 0;
++*pattern;
continue;
}
/* XXX: handle locale/MBCS comparison, advance by MBCS char width */
if ((**string == **pattern))
result = 0;
else if (nocase && (isupper(**string) || isupper(**pattern))
&& (tolower(**string) == tolower(**pattern)))
result = 0;
++*pattern;
}
/* NOT a properly balanced [expr] pattern; Rewind
* and reset result to test '[' literal
*/
*pattern = mismatch;
result = FNM_NOMATCH;
}
else if (**pattern == '?') {
/* Optimize '?' match before unescaping **pattern */
if (!**string || (slash && (**string == '/')))
return FNM_NOMATCH;
result = 0;
goto fnmatch_ch_success;
}
else if (escape && (**pattern == '\\') && (*pattern)[1]) {
++*pattern;
}
/* XXX: handle locale/MBCS comparison, advance by the MBCS char width */
if (**string == **pattern)
result = 0;
else if (nocase && (isupper(**string) || isupper(**pattern))
&& (tolower(**string) == tolower(**pattern)))
result = 0;
/* Refuse to advance over trailing slash or nulls
*/
if (!**string || !**pattern || (slash && ((**string == '/') || (**pattern == '/'))))
return result;
fnmatch_ch_success:
++*pattern;
++*string;
return result;
}
int fnmatch(const char *pattern, const char *string, int flags)
{
static const char dummystring[2] = {' ', 0};
const int escape = !(flags & FNM_NOESCAPE);
const int slash = !!(flags & FNM_PATHNAME);
const char *strendseg;
const char *dummyptr;
const char *matchptr;
int wild;
/* For '*' wild processing only; surpress 'used before initialization'
* warnings with dummy initialization values;
*/
const char *strstartseg = NULL;
const char *mismatch = NULL;
int matchlen = 0;
if (strnlen(pattern, PATH_MAX) == PATH_MAX ||
strnlen(string, PATH_MAX) == PATH_MAX)
return (FNM_NOMATCH);
if (*pattern == '*')
goto firstsegment;
while (*pattern && *string)
{
/* Pre-decode "\/" which has no special significance, and
* match balanced slashes, starting a new segment pattern
*/
if (slash && escape && (*pattern == '\\') && (pattern[1] == '/'))
++pattern;
if (slash && (*pattern == '/') && (*string == '/')) {
++pattern;
++string;
}
firstsegment:
/* At the beginning of each segment, validate leading period behavior.
*/
if ((flags & FNM_PERIOD) && (*string == '.'))
{
if (*pattern == '.')
++pattern;
else if (escape && (*pattern == '\\') && (pattern[1] == '.'))
pattern += 2;
else
return FNM_NOMATCH;
++string;
}
/* Determine the end of string segment
*
* Presumes '/' character is unique, not composite in any MBCS encoding
*/
if (slash) {
strendseg = strchr(string, '/');
if (!strendseg)
strendseg = strchr(string, '\0');
}
else {
strendseg = strchr(string, '\0');
}
/* Allow pattern '*' to be consumed even with no remaining string to match
*/
while (*pattern)
{
if ((string > strendseg)
|| ((string == strendseg) && (*pattern != '*')))
break;
if (slash && ((*pattern == '/')
|| (escape && (*pattern == '\\')
&& (pattern[1] == '/'))))
break;
/* Reduce groups of '*' and '?' to n '?' matches
* followed by one '*' test for simplicity
*/
for (wild = 0; ((*pattern == '*') || (*pattern == '?')); ++pattern)
{
if (*pattern == '*') {
wild = 1;
}
else if (string < strendseg) { /* && (*pattern == '?') */
/* XXX: Advance 1 char for MBCS locale */
++string;
}
else { /* (string >= strendseg) && (*pattern == '?') */
return FNM_NOMATCH;
}
}
if (wild)
{
strstartseg = string;
mismatch = pattern;
/* Count fixed (non '*') char matches remaining in pattern
* excluding '/' (or "\/") and '*'
*/
for (matchptr = pattern, matchlen = 0; 1; ++matchlen)
{
if ((*matchptr == '\0')
|| (slash && ((*matchptr == '/')
|| (escape && (*matchptr == '\\')
&& (matchptr[1] == '/')))))
{
/* Compare precisely this many trailing string chars,
* the resulting match needs no wildcard loop
*/
/* XXX: Adjust for MBCS */
if (string + matchlen > strendseg)
return FNM_NOMATCH;
string = strendseg - matchlen;
wild = 0;
break;
}
if (*matchptr == '*')
{
/* Ensure at least this many trailing string chars remain
* for the first comparison
*/
/* XXX: Adjust for MBCS */
if (string + matchlen > strendseg)
return FNM_NOMATCH;
/* Begin first wild comparison at the current position */
break;
}
/* Skip forward in pattern by a single character match
* Use a dummy fnmatch_ch() test to count one "[range]" escape
*/
/* XXX: Adjust for MBCS */
if (escape && (*matchptr == '\\') && matchptr[1]) {
matchptr += 2;
}
else if (*matchptr == '[') {
dummyptr = dummystring;
fnmatch_ch(&matchptr, &dummyptr, flags);
}
else {
++matchptr;
}
}
}
/* Incrementally match string against the pattern
*/
while (*pattern && (string < strendseg))
{
/* Success; begin a new wild pattern search
*/
if (*pattern == '*')
break;
if (slash && ((*string == '/')
|| (*pattern == '/')
|| (escape && (*pattern == '\\')
&& (pattern[1] == '/'))))
break;
/* Compare ch's (the pattern is advanced over "\/" to the '/',
* but slashes will mismatch, and are not consumed)
*/
if (!fnmatch_ch(&pattern, &string, flags))
continue;
/* Failed to match, loop against next char offset of string segment
* until not enough string chars remain to match the fixed pattern
*/
if (wild) {
/* XXX: Advance 1 char for MBCS locale */
string = ++strstartseg;
if (string + matchlen > strendseg)
return FNM_NOMATCH;
pattern = mismatch;
continue;
}
else
return FNM_NOMATCH;
}
}
if (*string && !(slash && (*string == '/')))
return FNM_NOMATCH;
if (*pattern && !(slash && ((*pattern == '/')
|| (escape && (*pattern == '\\')
&& (pattern[1] == '/')))))
return FNM_NOMATCH;
}
/* Where both pattern and string are at EOS, declare success
*/
if (!*string && !*pattern)
return 0;
/* pattern didn't match to the end of string */
return FNM_NOMATCH;
}

21
dep/emu/fnmatch.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef FNMATCH_H
#define FNMATCH_H
#ifdef __cplusplus
extern "C" {
#endif
#define FNM_NOMATCH 1 /* Match failed. */
#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
#define FNM_PERIOD 0x04 /* Period must be matched by period. */
#define FNM_CASEFOLD 0x08 /* Fold cases */
extern int fnmatch(const char *pattern, const char *string, int flags);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -139,6 +139,11 @@ the port and proceed normally.
## Building the client
**Before you read this:** If you're on Windows, good news! You can download a
*precompiled version of the FluxEngine client [from the GitHub releases
*page](https://github.com/davidgiven/fluxengine/releases/latest). Simply unzip
*it somewhere and run it from a `cmd` window (or other shell).
The client software is where the intelligence, such as it is, is. It's pretty
generic libusb stuff and should build and run on Windows, Linux and OSX as
well, although on Windows it'll need MSYS2 and mingw32. You'll need to

65
doc/disk-mx.md Normal file
View File

@@ -0,0 +1,65 @@
Disk: DVK MX
============
The DVK (in Russian, ДВК, Диалоговый вычислительный комплекс or Dialogue
Computing Complex) was a late 1970s Soviet personal computer, a cut-down
version of the professional SM EVM (СМ ЭВМ, abbreviation of Система Малых ЭВМ
--- 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 Durango F85, held precariously"></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.
Reading discs
-------------
```
fluxengine read mx
```
You should end up with an `mx.img` which will vary in length depending on the format. The default is double-sided 80-track. For the other formats, use:
* single-sided 40-track: `-s :s=0:t=0-79x2`
* double-sided 40-track: `-s :s=0-1:t=0-79x2`
* single-sided 40-track: `-s :s=0:t=0-79`
* double-sided 40-track: `-s :s=0-1:t=0-79`
Useful 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

BIN
doc/dvk3m.jpg Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

View File

@@ -1,92 +0,0 @@
#include "globals.h"
#include "record.h"
#include "decoders/decoders.h"
#include "brother.h"
#include "crc.h"
static int encode_header_gcr(uint16_t word)
{
switch (word)
{
#define GCR_ENTRY(gcr, data) \
case data: return gcr;
#include "header_gcr.h"
#undef GCR_ENTRY
}
return -1;
};
static int encode_data_gcr(uint8_t data)
{
switch (data)
{
#define GCR_ENTRY(gcr, data) \
case data: return gcr;
#include "data_gcr.h"
#undef GCR_ENTRY
}
return -1;
};
static void write_bits(std::vector<bool>& bits, unsigned& cursor, uint32_t data, int width)
{
cursor += width;
for (int i=0; i<width; i++)
{
unsigned pos = cursor - i - 1;
if (pos < bits.size())
bits[pos] = data & 1;
data >>= 1;
}
}
void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor,
int track, int sector)
{
write_bits(bits, cursor, 0xffffffff, 31);
write_bits(bits, cursor, BROTHER_SECTOR_RECORD, 32);
write_bits(bits, cursor, encode_header_gcr(track), 16);
write_bits(bits, cursor, encode_header_gcr(sector), 16);
write_bits(bits, cursor, encode_header_gcr(0x2f), 16);
}
void writeBrotherSectorData(std::vector<bool>& bits, unsigned& cursor, const Bytes& data)
{
write_bits(bits, cursor, 0xffffffff, 32);
write_bits(bits, cursor, BROTHER_DATA_RECORD, 32);
uint16_t fifo = 0;
int width = 0;
if (data.size() != BROTHER_DATA_RECORD_PAYLOAD)
Error() << "unsupported sector size";
auto write_byte = [&](uint8_t byte)
{
fifo |= (byte << (8 - width));
width += 8;
while (width >= 5)
{
uint8_t quintet = fifo >> 11;
fifo <<= 5;
width -= 5;
write_bits(bits, cursor, encode_data_gcr(quintet), 8);
}
};
for (uint8_t byte : data)
write_byte(byte);
uint32_t realCrc = crcbrother(data);
write_byte(realCrc>>16);
write_byte(realCrc>>8);
write_byte(realCrc);
write_byte(0x58); /* magic */
write_byte(0xd4);
while (width != 0)
write_byte(0);
}

View File

18
lib/encoders/encoders.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef ENCODERS_H
#define ENCODERS_H
class Fluxmap;
class SectorSet;
class AbstractEncoder
{
public:
virtual ~AbstractEncoder() {}
public:
virtual std::unique_ptr<Fluxmap> encode(
int physicalTrack, int physicalSide, const SectorSet& allSectors) = 0;
};
#endif

View File

@@ -21,6 +21,7 @@ public:
public:
nanoseconds_t duration() const { return _duration; }
unsigned ticks() const { return _ticks; }
size_t bytes() const { return _bytes.size(); }
const Bytes& rawBytes() const { return _bytes; }

View File

@@ -160,8 +160,9 @@ void readDiskCommand(AbstractDecoder& decoder, const std::string& outputFilename
track->rawrecords.size(),
track->sectors.size());
if (track->sectors.size() > 0)
std::cout << fmt::format("{:.2f}us clock; ",
track->sectors.begin()->clock / 1000.0);
std::cout << fmt::format("{:.2f}us clock ({:.0f}kHz); ",
track->sectors.begin()->clock / 1000.0,
1000000.0 / track->sectors.begin()->clock);
for (auto& sector : track->sectors)
{

View File

@@ -6,9 +6,14 @@
#include "protocol.h"
#include "usb.h"
#include "dataspec.h"
#include "encoders/encoders.h"
#include "fluxsource/fluxsource.h"
#include "fluxsink/fluxsink.h"
#include "fmt/format.h"
#include "record.h"
#include "image.h"
#include "sector.h"
#include "sectorset.h"
FlagGroup writerFlags { &hardwareFluxSourceFlags };
@@ -60,10 +65,12 @@ void writeTracks(
{
if (!outdb)
{
std::cout << "erasing" << std::endl;
std::cout << "erasing\n";
usbSeek(location.track);
usbErase(location.side);
}
else
std::cout << "skipping\n";
}
else
{
@@ -96,3 +103,16 @@ void fillBitmapTo(std::vector<bool>& bitmap,
}
}
void writeDiskCommand(
AbstractEncoder& encoder, const Geometry& geometry, const std::string& inputFilename)
{
SectorSet allSectors;
readSectorsFromFile(allSectors, geometry, inputFilename);
writeTracks(
[&](int track, int side) -> std::unique_ptr<Fluxmap>
{
return encoder.encode(track, side, allSectors);
}
);
}

View File

@@ -6,6 +6,8 @@
extern FlagGroup writerFlags;
class Fluxmap;
class AbstractEncoder;
class Geometry;
extern void setWriterDefaultDest(const std::string& dest);
@@ -15,5 +17,7 @@ extern void fillBitmapTo(std::vector<bool>& bitmap,
unsigned& cursor, unsigned terminateAt,
const std::vector<bool>& pattern);
extern void writeDiskCommand(
AbstractEncoder& encoder, const Geometry& geometry, const std::string& inputFilename);
#endif

View File

@@ -48,7 +48,7 @@ buildlibrary() {
objs=
for src in "$@"; do
local obj
obj="$OBJDIR/${src%%.cc}.o"
obj="$OBJDIR/${src%%.c*}.o"
objs="$objs $obj"
echo build $obj : cxx $src
@@ -83,8 +83,37 @@ buildprogram() {
objs="$objs $OBJDIR/$src"
done
echo build $prog : link $objs
echo build $prog-debug$EXTENSION : link $objs
echo " flags=$flags"
echo build $prog$EXTENSION : strip $prog-debug$EXTENSION
}
buildsimpleprogram() {
local prog
prog=$1
shift
local flags
flags=
while true; do
case $1 in
-*)
flags="$flags $1"
shift
;;
*)
break
esac
done
local src
src=$1
shift
buildlibrary lib$prog.a $flags $src
buildprogram $prog lib$prog.a "$@"
}
runtest() {
@@ -95,12 +124,12 @@ runtest() {
buildlibrary lib$prog.a \
"$@"
buildprogram $OBJDIR/$prog$EXTENSION \
buildprogram $OBJDIR/$prog \
lib$prog.a \
libbackend.a \
libfmt.a
echo build $OBJDIR/$prog.stamp : test $OBJDIR/$prog$EXTENSION
echo build $OBJDIR/$prog.stamp : test $OBJDIR/$prog-debug$EXTENSION
}
buildlibrary libfmt.a \
@@ -108,22 +137,27 @@ buildlibrary libfmt.a \
dep/fmt/posix.cc \
buildlibrary libbackend.a \
lib/aeslanier/decoder.cc \
lib/amiga/decoder.cc \
lib/apple2/decoder.cc \
lib/brother/decoder.cc \
lib/brother/encoder.cc \
arch/aeslanier/decoder.cc \
arch/amiga/decoder.cc \
arch/apple2/decoder.cc \
arch/brother/decoder.cc \
arch/brother/encoder.cc \
arch/c64/decoder.cc \
arch/f85/decoder.cc \
arch/fb100/decoder.cc \
arch/ibm/decoder.cc \
arch/macintosh/decoder.cc \
arch/mx/decoder.cc \
arch/victor9k/decoder.cc \
arch/zilogmcz/decoder.cc \
lib/bytes.cc \
lib/c64/decoder.cc \
lib/common/crunch.c \
lib/crc.cc \
lib/dataspec.cc \
lib/decoders/decoders.cc \
lib/decoders/fluxmapreader.cc \
lib/decoders/fmmfm.cc \
lib/encoder.cc \
lib/f85/decoder.cc \
lib/fb100/decoder.cc \
lib/encoders/encoders.cc \
lib/flags.cc \
lib/fluxmap.cc \
lib/fluxsink/fluxsink.cc \
@@ -136,21 +170,19 @@ buildlibrary libbackend.a \
lib/fluxsource/streamfluxsource.cc \
lib/globals.cc \
lib/hexdump.cc \
lib/ibm/decoder.cc \
lib/image.cc \
lib/macintosh/decoder.cc \
lib/mx/decoder.cc \
lib/reader.cc \
lib/sector.cc \
lib/sectorset.cc \
lib/sql.cc \
lib/usb.cc \
lib/victor9k/decoder.cc \
lib/writer.cc \
lib/zilogmcz/decoder.cc \
buildlibrary libfrontend.a \
src/fe-cwftoflux.cc \
src/fe-erase.cc \
src/fe-fluxtoau.cc \
src/fe-fluxtovcd.cc \
src/fe-inspect.cc \
src/fe-readadfs.cc \
src/fe-readaeslanier.cc \
@@ -176,12 +208,20 @@ buildlibrary libfrontend.a \
src/fe-writetestpattern.cc \
src/fluxengine.cc \
buildprogram fluxengine-debug$EXTENSION \
buildprogram fluxengine \
libfrontend.a \
libbackend.a \
libfmt.a \
echo "build fluxengine$EXTENSION : strip fluxengine-debug$EXTENSION"
buildlibrary libemu.a \
dep/emu/fnmatch.c
buildsimpleprogram brother120tool \
-Idep/emu \
tools/brother120tool.cc \
libbackend.a \
libemu.a \
libfmt.a \
runtest dataspec-test tests/dataspec.cc
runtest flags-test tests/flags.cc

View File

@@ -37,7 +37,7 @@ static double clockRate;
static void syntax()
{
std::cout << "Syntax: cwftoflux <cwffile> <fluxfile>\n";
std::cout << "Syntax: fluxengine convert cwftoflux <cwffile> <fluxfile>\n";
exit(0);
}
@@ -116,7 +116,7 @@ static void read_track()
sqlWriteFlux(outputDb, track_number, trackheader.side, fluxmap);
}
int main(int argc, const char* argv[])
int mainConvertCwfToFlux(int argc, const char* argv[])
{
if (argc != 3)
syntax();

100
src/fe-fluxtoau.cc Normal file
View File

@@ -0,0 +1,100 @@
#include "globals.h"
#include "flags.h"
#include "fluxmap.h"
#include "sql.h"
#include "bytes.h"
#include "protocol.h"
#include "dataspec.h"
#include "fluxsource/fluxsource.h"
#include "decoders/fluxmapreader.h"
#include "fmt/format.h"
#include <fstream>
static FlagGroup flags { &hardwareFluxSourceFlags };
static DataSpecFlag source(
{ "--source", "-s" },
"source for data",
":d=0:t=0:s=0");
static StringFlag output(
{ "--output", "-o" },
"output AU file to write",
"output.au");
static SettableFlag highDensityFlag(
{ "--high-density", "--hd" },
"set the drive to high density mode");
static SettableFlag withIndex(
{ "--with-index" },
"place index markers in the right hand channel");
int mainConvertFluxToAu(int argc, const char* argv[])
{
flags.parseFlags(argc, argv);
const auto& locations = source.get().locations;
if (locations.size() != 1)
Error() << "the source dataspec must contain exactly one track (two sides count as two tracks)";
const auto& location = *(locations.begin());
std::cerr << "Reading source flux...\n";
setHardwareFluxSourceDensity(highDensityFlag);
std::shared_ptr<FluxSource> fluxsource = FluxSource::create(source);
const auto& fluxmap = fluxsource->readFlux(location.track, location.side);
unsigned totalTicks = fluxmap->ticks() + 2;
unsigned channels = withIndex ? 2 : 1;
std::cerr << "Writing output file...\n";
std::ofstream of(output, std::ios::out | std::ios::binary);
if (!of.is_open())
Error() << "cannot open output file";
/* Write header */
{
Bytes header;
header.resize(24);
ByteWriter bw(header);
bw.write_be32(0x2e736e64);
bw.write_be32(24);
bw.write_be32(totalTicks * channels);
bw.write_be32(2); /* 8-bit PCM */
bw.write_be32(TICK_FREQUENCY);
bw.write_be32(channels); /* channels */
of.write((const char*) header.cbegin(), header.size());
}
/* Write data */
{
Bytes data;
data.resize(totalTicks * channels);
memset(data.begin(), 0x80, data.size());
FluxmapReader fmr(*fluxmap);
unsigned timestamp = 0;
while (!fmr.eof())
{
unsigned ticks;
int op = fmr.readOpcode(ticks);
if (op == -1)
break;
timestamp += ticks;
if (op == F_OP_PULSE)
data[timestamp*channels + 0] = 0x7f;
if (withIndex && (op == F_OP_INDEX))
data[timestamp*channels + 1] = 0x7f;
}
of.write((const char*) data.cbegin(), data.size());
}
std::cerr << "Done. Warning: do not play this file, or you will break your speakers"
" and/or ears!\n";
return 0;
}

83
src/fe-fluxtovcd.cc Normal file
View File

@@ -0,0 +1,83 @@
#include "globals.h"
#include "flags.h"
#include "fluxmap.h"
#include "sql.h"
#include "bytes.h"
#include "protocol.h"
#include "dataspec.h"
#include "fluxsource/fluxsource.h"
#include "decoders/fluxmapreader.h"
#include "fmt/format.h"
#include <fstream>
static FlagGroup flags { &hardwareFluxSourceFlags };
static DataSpecFlag source(
{ "--source", "-s" },
"source for data",
":d=0:t=0:s=0");
static StringFlag output(
{ "--output", "-o" },
"output VCD file to write",
"output.vcd");
static SettableFlag highDensityFlag(
{ "--high-density", "--hd" },
"set the drive to high density mode");
int mainConvertFluxToVcd(int argc, const char* argv[])
{
flags.parseFlags(argc, argv);
const auto& locations = source.get().locations;
if (locations.size() != 1)
Error() << "the source dataspec must contain exactly one track (two sides count as two tracks)";
const auto& location = *(locations.begin());
std::cerr << "Reading source flux...\n";
setHardwareFluxSourceDensity(highDensityFlag);
std::shared_ptr<FluxSource> fluxsource = FluxSource::create(source);
const auto& fluxmap = fluxsource->readFlux(location.track, location.side);
std::cerr << "Writing destination VCD...\n";
std::ofstream of(output, std::ios::out);
if (!of.is_open())
Error() << "cannot open output file";
of << "$timescale 1ns $end\n"
<< "$var wire 1 i index $end\n"
<< "$var wire 1 p pulse $end\n"
<< "$upscope $end\n"
<< "$enddefinitions $end\n"
<< "$dumpvars 0i 0p $end\n";
FluxmapReader fmr(*fluxmap);
unsigned timestamp = 0;
unsigned lasttimestamp = 0;
while (!fmr.eof())
{
unsigned ticks;
int op = fmr.readOpcode(ticks);
if (op == -1)
break;
unsigned newtimestamp = timestamp + ticks;
if (newtimestamp != lasttimestamp)
{
of << fmt::format("\n#{} 0i 0p\n", (uint64_t)((lasttimestamp+1) * NS_PER_TICK));
timestamp = newtimestamp;
of << fmt::format("#{} ", (uint64_t)(timestamp * NS_PER_TICK));
}
if (op == F_OP_PULSE)
of << "1p ";
if (op == F_OP_INDEX)
of << "1i ";
lasttimestamp = timestamp;
}
of << "\n";
return 0;
}

View File

@@ -12,7 +12,7 @@
#include "track.h"
#include "fmt/format.h"
static FlagGroup flags;
static FlagGroup flags { &readerFlags };
static SettableFlag dumpFluxFlag(
{ "--dump-flux", "-F" },

View File

@@ -3,6 +3,7 @@
#include "reader.h"
#include "fluxmap.h"
#include "decoders/decoders.h"
#include "encoders/encoders.h"
#include "brother/brother.h"
#include "sector.h"
#include "sectorset.h"

View File

@@ -1,108 +1,28 @@
#include "globals.h"
#include "flags.h"
#include "fluxmap.h"
#include "sector.h"
#include "sectorset.h"
#include "decoders/decoders.h"
#include "encoders/encoders.h"
#include "brother/brother.h"
#include "image.h"
#include "writer.h"
#include "fmt/format.h"
#include "image.h"
#include <fstream>
#include <ctype.h>
static FlagGroup flags { &writerFlags };
static FlagGroup flags { &writerFlags, &brotherEncoderFlags };
static StringFlag inputFilename(
{ "--input", "-i" },
"The input image file to read from.",
"brother.img");
static DoubleFlag clockRateUs(
{ "--clock-rate" },
"Encoded data clock rate (microseconds).",
3.83);
static DoubleFlag postIndexGapMs(
{ "--post-index-gap" },
"Post-index gap before first sector header (milliseconds).",
1.0);
static DoubleFlag sectorSpacingMs(
{ "--sector-spacing" },
"Time between successive sector headers (milliseconds).",
16.2);
static DoubleFlag postHeaderSpacingMs(
{ "--post-header-spacing" },
"Time between a sector's header and data records (milliseconds).",
0.69);
static StringFlag sectorSkew(
{ "--sector-skew" },
"Order in which to write sectors.",
"05a3816b4927");
static int charToInt(char c)
{
if (isdigit(c))
return c - '0';
return 10 + tolower(c) - 'a';
}
int mainWriteBrother(int argc, const char* argv[])
{
setWriterDefaultDest(":d=0:t=0-77:s=0");
flags.parseFlags(argc, argv);
SectorSet allSectors;
BrotherEncoder encoder;
Geometry geometry = {78, 1, 12, 256};
readSectorsFromFile(allSectors, geometry, inputFilename);
int bitsPerRevolution = 200000.0 / clockRateUs;
std::cerr << bitsPerRevolution << " bits per 200ms revolution" << std::endl
<< fmt::format("post-index gap: {:.3f}ms\n", (double)postIndexGapMs);
const std::string& skew = sectorSkew;
writeTracks(
[&](int track, int side) -> std::unique_ptr<Fluxmap>
{
if ((track < 0) || (track > 77) || (side != 0))
return std::unique_ptr<Fluxmap>();
std::vector<bool> bits(bitsPerRevolution);
unsigned cursor = 0;
for (int sectorCount=0; sectorCount<geometry.sectors; sectorCount++)
{
int sectorId = charToInt(skew.at(sectorCount));
double headerMs = postIndexGapMs + sectorCount*sectorSpacingMs;
unsigned headerCursor = headerMs*1e3 / clockRateUs;
double dataMs = headerMs + postHeaderSpacingMs;
unsigned dataCursor = dataMs*1e3 / clockRateUs;
auto& sectorData = allSectors.get(track, 0, sectorId);
fillBitmapTo(bits, cursor, headerCursor, { true, false });
writeBrotherSectorHeader(bits, cursor, track, sectorId);
fillBitmapTo(bits, cursor, dataCursor, { true, false });
writeBrotherSectorData(bits, cursor, sectorData->data);
}
if (cursor > bits.size())
Error() << "track data overrun";
fillBitmapTo(bits, cursor, bits.size(), { true, false });
// The pre-index gap is not normally reported.
// std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl;
std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
fluxmap->appendBits(bits, clockRateUs*1e3);
return fluxmap;
}
);
writeDiskCommand(encoder, geometry, inputFilename);
return 0;
}

View File

@@ -3,6 +3,9 @@
typedef int command_cb(int agrc, const char* argv[]);
extern command_cb mainErase;
extern command_cb mainConvertCwfToFlux;
extern command_cb mainConvertFluxToAu;
extern command_cb mainConvertFluxToVcd;
extern command_cb mainInspect;
extern command_cb mainReadADFS;
extern command_cb mainReadAESLanier;
@@ -15,9 +18,9 @@ extern command_cb mainReadDFS;
extern command_cb mainReadF85;
extern command_cb mainReadFB100;
extern command_cb mainReadIBM;
extern command_cb mainReadVictor9K;
extern command_cb mainReadMac;
extern command_cb mainReadMx;
extern command_cb mainReadVictor9K;
extern command_cb mainReadZilogMCZ;
extern command_cb mainRpm;
extern command_cb mainSeek;
@@ -36,16 +39,18 @@ struct Command
static command_cb mainRead;
static command_cb mainWrite;
static command_cb mainConvert;
static std::vector<Command> commands =
{
{ "erase", mainErase, "Permanently but rapidly erases some or all of a disk." },
{ "convert", mainConvert, "Converts various types of data file.", },
{ "inspect", mainInspect, "Low-level analysis and inspection of a disk." },
{ "read", mainRead, "Reads a disk, producing a sector image.", },
{ "rpm", mainRpm, "Measures the disk rotational speed.", },
{ "seek", mainSeek, "Moves the disk head.", },
{ "testbulktransport", mainTestBulkTransport, "Measures your USB bandwidth.", },
{ "upgradefluxfile", mainUpgradeFluxFile, "Upgrades a flux file from a previous version of this software.", },
{ "read", mainRead, "Reads a disk, producing a sector image.", },
{ "write", mainWrite, "Writes a sector image to a disk.", },
{ "writeflux", mainWriteFlux, "Writes a raw flux file. Warning: you can't use this to copy disks.", },
{ "writetestpattern", mainWriteTestPattern, "Writes a machine-generated test pattern to a disk.", },
@@ -75,10 +80,17 @@ static std::vector<Command> writeables =
{ "brother", mainWriteBrother, "Writes 120kB and 240kB Brother word processor disks.", },
};
static void readWriteHelp(std::vector<Command>& subcommands, const std::string& command)
static std::vector<Command> convertables =
{
{ "cwftoflux", mainConvertCwfToFlux, "Converts CatWeasel stream files to flux.", },
{ "fluxtoau", mainConvertFluxToAu, "Converts (one track of a) flux file to an .au audio file.", },
{ "fluxtovcd", mainConvertFluxToVcd, "Converts (one track of a) flux file to a VCD file.", },
};
static void extendedHelp(std::vector<Command>& subcommands, const std::string& command)
{
std::cout << "fluxengine: syntax: fluxengine " << command << " <format> [<flags>...]\n"
"These formats are supported:\n";
"These subcommands are supported:\n";
for (Command& c : subcommands)
std::cout << " " << c.name << ": " << c.help << "\n";
@@ -86,15 +98,15 @@ static void readWriteHelp(std::vector<Command>& subcommands, const std::string&
exit(0);
}
static int mainReadWrite(std::vector<Command>& subcommands, const std::string& command,
static int mainExtended(std::vector<Command>& subcommands, const std::string& command,
int argc, const char* argv[])
{
if (argc == 1)
readWriteHelp(subcommands, command);
extendedHelp(subcommands, command);
std::string format = argv[1];
if (format == "--help")
readWriteHelp(subcommands, command);
extendedHelp(subcommands, command);
for (Command& c : subcommands)
{
@@ -107,10 +119,13 @@ static int mainReadWrite(std::vector<Command>& subcommands, const std::string& c
}
static int mainRead(int argc, const char* argv[])
{ return mainReadWrite(readables, "read", argc, argv); }
{ return mainExtended(readables, "read", argc, argv); }
static int mainWrite(int argc, const char* argv[])
{ return mainReadWrite(writeables, "write", argc, argv); }
{ return mainExtended(writeables, "write", argc, argv); }
static int mainConvert(int argc, const char* argv[])
{ return mainExtended(convertables, "convert", argc, argv); }
static void help()
{

View File

@@ -1,7 +1,7 @@
#include "globals.h"
#include "fmt/format.h"
#include <fstream>
#include <fnmatch.h>
#include "fnmatch.h"
/* Theoretical maximum number of sectors. */
static const int SECTOR_COUNT = 640;