Dear Spectrum fans!
[Management summary: Download
http://www.bartheld.net/temp/mdv2img.zip and
tell me what you think. All help very much appreciated.]
As mentioned in Message-ID: <4j9pqs271vnp$.
d...@news.bartheld.net> (Subject:
Microdrives and stuff with Interface 1), I wondered whether my almost
thirty year old Sinclair Microdrive Cartridges were still usable. Not
because I wanted to retrieve some games I had multifaced there but because
of some private coding stuff I wanted to rescue from decay.
My Speccy, which I had put into some PC-like case, together with a better
power supply, separate voltage regulator, two Microdrives, IF-1 and a
first-generation Multiface One first had to be equipped with a composite
output since I had no TV with an analog tuner anymore. Thanks to Womble's
Retro Repair Shack this was an easy soldering job to do, I connected the
cinch socket to a cheap rear view camera from Amazon and fascinatingly
enough, the little Z80 computer was "booting" right up. "(C) 1983 Sinclair
Research Ltd.". Yeah! Not bad.
Next thing was getting the basic communication right. Davide Guida's spxfr
plus his instructions on building a Speccy-to-PC RS232 cable were very
instructive and so I got my first bit of BASIC transferred from the PC to
the Speccy and back with a whooping 19200 baud.
Of course spxfr is cool for isolated (and few) transfers, but not exactly
what I wanted because some of my data has been saved to MDV (namely some
PAW adventures, Tasword documents etc.) using Romantic Robot's Multiface
One and other software already came on MDV.
Of course, I could use the "tape out" socket, the "Save To Tape" option of
the MF-1 and my PC's soundcard, but this would take ages and still wasn't
what I was imagining. Also the fear came up that there could be data
integrity issues with those cartridges, so I needed something more
elegant. As it turned out, the first problem wasn't software related at
all but affected the hardware, the cartridges themselves to be precise.
As soon as I touched one of those little foam pieces that should ensure
good contact with the drive head with my tweezers, the foam literally
disintegrated and the slick fleece liner fell off. However I figured that
patience and double-sided adhesive foam tape would do the trick. And
indeed, I successfully could fix the foam pads of a few cartridges while
recycling the top fleece from the cartridge without having to extract the
brass spring thingie which would probably never go back in place
correctly.
After that I ran a few tests with an empty cartridge, reformatted, SAVE
*"m";1;"test" CODE 0, 65535 etc. and read back. Excellent. So the tape
itself and the Microdrive mechanics (rubber roller etc.) were still
intact. As it turned out, "old data" from last century wasn't in a shape
this good. Probably due to head alignment/contamination issues, variations
in tape speed (probably the rubber roller had shrunken a bit) and probably
magnetization has "broadened" or copied through the layers of tape on the
spindle, lowering signal-to-noise-ratio.
These problems are better fixed on the PC side since I didn't intend to
address the Microdrives on a hardware/low level without having the IF-1
attached. This might be possible with some Arduino-platform but was beyond
my time schedule and skills.
The idea came up to write some kind of Z80 machine code tool that would be
uploaded onto the Spectrum which spun the tape, read as much sectors as it
could (those with checksum errors probably multiple times) and transfer a
RAW image of those sectors/the cartridge to PC via RS232.
That's where mdv2img entered the stage. Thanks to Andy Pennel's "Master
Your ZXMicrodrive 1st Edition", a few Your Sinclair issues, Gianluca
Carri's "Spectrum Shadow ROM Disassembly" and a few other tools (namely
Gerton's WinZ80 emulator) I successfully coded a tool that even created a
graphic map of the cartridge's sector in the lower part of the Spectrum's
attribute area, allowed configuring how many retries should be attempted
for sectors with HDCHK, DESCHK and DCHK errors and a few other
specialties.
The attribute color map is like this:
HDCHK DESCHK DCHK
- - -
- - X
- X -
- X X
X - -
X - X
X X -
X X X
BLUE GREEN RED
- but it eventually all boils down to: "If it's not black or bright white,
you're in big trouble." ;-)
On WinZ80 everything ran fine and consistent, so I decided to give it a go
on the real machine. Some minor changes had to be done. The most
mentionable ones were to
delay sector extraction a bit after starting the drive motor to allow for
some settling and to increase the sector counter (that's used as an
indicator for the maximum number of sectors to skip before giving up) to 16
bits. So I could initialize it with 512 because the emulator seems to be
a bit more forgiving. Afterwards, the crude BASIC loader below worked like
a charm
10 FORMAT "b";19200
20 CLEAR 32767
30 LOAD *"b" CODE 32768
40 PAUSE 0
50 RANDOMIZE USR 32768
60 GOTO 40
on the Speccy side, spxfr and the binary Z80 machine code file on the
other.
I had to add 9 bytes of header to make it a .snp file spxfr understands
(it's basically how the Spectrum would SAVE *"b" CODE 32768,xxxx via
RS232) and it was uploaded to the Spectrum fine from within the PC at 19200
baud. The next iteration brought up .snp/.tap files that had the machine
code embedded as a few BASIC DATA lines together with some configuration
GUI to simplify matters.
After uploading the code, I ran Termite on the PC side, activated (RAW)
RS232 logging (a bit tweaking of the logfile filter was necessary here) at
19200,8,N,1, inserted one cartridge after the other (changing log file
name after each change as appropriate) and hit SPACE on the Sinclair each
time.
It took a few spins to complete, but I eventually managed. In the following
discussion, I use these definitions:
'-': no error
'H': header checksum error (HDCHK)
'R': record descriptor checksum error (DESCHK)
'D': data block checksum error (DCHK)
Findings (with mdv2img configured to a max. of seven error retries):
1) Some sectors are perfectly good. Just one read and that's it.
2) Some sectors produce exactly the same error type, i. e. "--D" three or
even seven times.
3) Other sectors seem to be unstable and show "H-D" two times and "--D"
another five times.
It can happen, that a sector has a defect header ("H" error class) so I'm
probably not reading the sector number I intended to, since the error
could have affected the HDNUMB byte. That can add complications since
probably collisions can arise (a "broken" sector 0xA0 with wrong header
checksum with a "good" sector 0xA0 with correct header checksum read
elsewhere).
For that reason, it might be a wise idea to throw away sectors with "H"
errors without mercy unless that exact sector number is unoccupied.
Data block ("D") errors _could_ be thrown away, if there's another good
copy of them. Unfortunately this is rarely the case, just once during my
tests:
--D
--D
H-D
H-D
H--
H-D
H-D
but this comes in conjunction with a defect header, so probably it wasn't
even the sector I intended to read but some surrogate.
As a matter of fact, the only remedy to "D" errors would be bit averaging
(if there's enough statistics) to make
00000000
01000000
01000000
01001000
01000000
00000000
00000000
========
01000000
(i. e. more "1"s that "0"s result in "1" and vice versa) and hope for the
best. At least this sector will be loadable again but at the risk of a
crash later if machine code (or compressed data) is affected.
Fortunately, a nice side aspect is, that there are VERY few record
descriptor checksum errors ("R" class). Which means that the filesystem
itself (=the logical structure between sectors) is pretty much intact.
Just one single "R" error in one sector will kill the whole file which
might span over sectors containing the bad one.
Moral is: I'm not quite sure how to interpret the data that I got.
So I wrote some forensic C++ code for the PC to allow better analyzing
and even repairing microdrive cartridge images, making use of the
redundancy that is in there. The last step was to write a .mdr
file that WinZ80 can understand so the data can be emulated.
Here comes mdv2img.exe - but it's at a rather early stage and still needs
much tweaking. I. e. the bit averaging fixes and file system
reconstruction details are not implemented yet. But it *CAN* rewrite
checksums based on various policies to make data blocks readable again and
it *WILL* occupy unused sectors with those that have bad checksums if it
needs (and is told) to.
The results are .mdr files having 137923 bytes (254 sectors à 543 bytes
plus one "write protection" byte) that you can virtually mount in WinZ80.
I've uploaded a .zip archive containing the aforementioned tools (binary
and source) along with some demonstrational cartridge images (a perfect
right out of the emulator, then a freshly formatted cartridge and finally
a tough one with Lunar Jetman, Galaxians and Pheenix) for you to play
with. The games cartridge refused to load anything else but the BASIC
loader saying "File not found.". If we can restore that one, I believe
nearly everything is possible.
Check out my homepage at:
http://www.bartheld.net/temp/mdv2img.zip (about
400k).
For your own experiments, you should get the Termite terminal along with
the Logfile and Hexview plugin from
http://www.compuphase.com/software_termite.htm,
spxfr from
http://www.angelfire.com/games6/atari2600/spxfr/index.html and
probably tniASM from
http://www.tni.nl/products/tniasm.html if you want to
tweak the machine code.
Then connect everything as discussed above, type
FORMAT "b";19200
LOAD *"b"
and transfer Mdv2img.snp using spxfr. The program will autostart, POKE the
machine code (takes some time), ask for a few configuration values
(generally, 0 will produce reasonable defaults) and wait for you to press
the space key. Then stop spxfr, insert the cartridge you want to rip, load
Termite onto your PC, activate RAW file logging (i. e. to image.bin) and
chose the right COM port plus baud rate (19200).
Hit SPACE now.
The Speccy will spin up the Microdrive, wait about 1/2s, start loading
sectors and transfer the sectors to PC (can take a few minutes). After the
process has completed, you can select a new log file, insert a new
cartridge and repeat.
Afterwards, you'll end up with a bunch of image01.bin, image02.bin, ...
files. Use mdv2img.exe -i image##.bin -s to analyse them (mdv2img.exe -i
image##.bin -s > image##.bin.log pipes into a logfile) and mdv2img.exe -i
image##.bin -r image##.mdr to repair and use with WinZ80.
The following policies currently apply
enum tPolicies // policies of the reconstruction system
{
eNONE=0x0000,
eFIX_HEADER=0x0001, // recreate broken headers (HDCHK mismatches)
eFIX_RECORD=0x0002, // recreate broken records (DESCHK mismatches)
eFIX_DATA=0x0004, // recreate broken data blocks (DCHK)
eACCEPT_ERRORS=0x0008, // tolerate the above errors when writing back sectors
eOVERWRITE_SECTORS=0x0010, // overwrite already existing sectors
eOVERWRITE_OUTPUT=0x0020, // overwrite output file
eALLOW_NONSTANDARD_MDR=0x0040, // allow nonstandard .mdr output files (i. e. sector numbers outside [1...254]
}; // enum tPolicies
const unsigned int cPOLICIES=eFIX_DATA|eACCEPT_ERRORS|eOVERWRITE_OUTPUT; // only fix data blocks, tolerate errors, overwrite output files
which IMHO make sense. Feel free to fire up Microsoft Developer
Studio/Visual C++ and tweak the code as you like.
What I would really appreciate is input on the Z80 assembler code (there
might be bugs) and some support on more sophisticated methods to tackle
those checksum errors. I already added the CBitwiseAverage class to the
source (see helper.h) but it's currently not used anywhere. Also somebody
who has a clue about the Microdrive file system (i. e. how Sinclair BASIC
would load a file spanning more sectors) and can contribute some C++ code
regarding that aspect would be a great help.
When the mdv2img-Project is a bit more mature, I'll put up a homepage with
more tools, links, photos and screenshots of the process. Probably I also
crosspost to the World of Spectrum forum to get a larger audiency.
Good luck, happy coding and have fun!
Volker
--
@: I N F O at B A R T H E L D dot N E T
3W:
www.bartheld.net