Your Spectrum
Issue 14, May 1985 - Patching Up the 'Drives
Home Contents KwikPik


This article must be read in conjunction with "Running Repairs" in issue 8.


PATCHING UP THE 'DRIVES
Faulty files are now a thing of the past! Using this second instalment of code, Andrew Pennell shows you how to recover unloadable files from that Microdrive cartridge that's giving you hassle. Take it away, Andrew ...

code, you'll need to use the listing given to slightly alter the data you've already got in order to accommodate that given here. The relocator program achieves its object and corrects the problems described above; it then goes on to save the new code under the name "SLC.2". Once you've entered this little goodie, move RAMtop up to, say, 32768 to allow room for the new bytes shown in the second listing. (A word of warning - there's insufficient memory to allow both of these programs to be present simultaneously!)
The second program given here reads in "SLC.2", adds the extra code to it and then saves it out as "SLC.3". In fact, it was while entering this listing myself that I discovered the low memory bug that still remains in the third version of the Interface 1 ROM. I tried a CAT command as soon as I realised that memory was running out and the system crashed in the most spectacular of fashions. But, as long as you don't get RAMtop below the value in line 100, you shouldn't have any problem on any of the Interface ROMs.
When you've sorted the machine code to rights, do a RANDOMIZE USR 32816 to allow the extra commands to be accepted by the syntax checker. Now enter the third listing given, saving it so that it starts at line 9000. It's an extended version of the first part's Basic.

In issue 8 of our most illustrious magazine, I got about half-way through devising a Microdrive repair kit that could smell out faulty files in an article called Running Repairs. Now, to finish it off, I have evolved a way of allowing the recovery of unloadable files from cartridge.

SORRY!

But first, an apology. Part one of this article, Running Repairs, was not quite the pristine job it might have been, and those with sharp eyes will have spotted the odd buglet or two; the pity is, I can't even lay the blame on our poor ol' Ed (Poor yes, but less of the 'old'. Ed.). The problem is that we get a sector list that's minus some of the necessary data ... indeed, there are quite a few sectors missing. As it stands, this produces incorrect results in the 'check file' section.

Anyway, I've modified the code to improve the performance and, although it's still not perfect - some sectors that do exist may not be found on very full cartridges, and some will be marked as 'bad' when they're not - this is not so much of a problem now because one of the functions of the extra code given in this issue, is for it to act as an individual sector read, and this achieves perfect results.
Another problem in Running Repairs was the code's position in memory - RAMtop at 30000 proved too low for the extra Basic. Thus, I've provided a relocator program that'll shift the code for you - that'll teach me to hand in part one of an article before working out part two!

GETTING UNDER WAY!

So, before you enter this issue's section of
THE COMMAND TABLE
COMMANDACTION
*L <drive>Gets the sector list into z$.
*D <drive>Sets the drive number for all the other commands.
*F <sector> CODE <location>Loads the given sector into a given location. IX corresponds to the first location, so it requires 595 bytes.
*S CODE <location>Saves the sector read into the location on the next free sector on the cartridge.
*E <sector>'Removes' the numbered sector from the cartridge.

INTO ACTION

The menu has been extended to cover the extra operations; probably the most useful of these is 'Examine sector', which searches a cartridge for a given sector, and loads it (corrupted or not) into RAM for inspection. Lines 6000 onwards load the sector into locations 60000 on, revealing various details about it. Most important here are the checksums; if either of these are incorrect it means that the file of which it is a part will probably not load, and the sector should be repaired - which is exactly what option 6 does. You can usually tell if tape is physically damaged, because the checksum result will give a different value every time you read it.
A sector is repaired by it being read to address 60000 onwards; this is then written out on to the next available sector, with the checksums re-calculated. It's not, of course, written back on to the same sector as there's every chance that the actual tape is damaged at this point.
Once a sector has been fixed in this way, the 'bad' version should be 'removed' from the cartridge; there's not much point in freeing the faulty sector for further use. Option 7 achieves this by marking it with a strange filename full of CHR$ 0s. That done, the next time you ask for a sector list of the cartridge you'll get a bad sector with the name "??????????"; this is normal, so don't try
to delete it again. The strange name will not show up in a normal CAT. As much of the utility is in Basic, you can reconfigure it to suit, using the extra commands provided; check out the table of commands given with this article.

CODE CONSIDERATIONS

For those blessed with an assembler, it's obviously a bit easier to enter the assembly listing, rather than the accompanying Hex. The listing, in fact, is a bit strange for two reasons. First, it's fragmented, consisting initially of the modifications made to the code in Running Repairs. As the original line numbers were chopped from my listing (ha! - at last something I can blame on someone else) the position of each modification may not be clear. To help, I've included at least one label in each block. The only one that's a bit vague is the main extra section ... it should go directly after TEMPA in the code in Running Repairs. The '*L+' commands in the listing are assembler directives, and should be ignored.
The second odd thing about the listing is that it uses a 'macro'. I've used one called OLD to make it clearer when calling 16K ROM routines with the 8K ROM in place. The usual way to call a routine is with two instructions - namely a RST#10 followed by a DEFW - and this is not exactly crystal clear; with the
macro defined, a much clearer command (such as OLD#20) can be used. Currently, the only assembler that allows macros is the one from Hisoft - if you use another, simply replace it with the more long-winded version. (I cannot claim any originality for this idea. The shadow ROMs were written by Sinclair Research using a similar macro, named OLDCAL, but the Hisoft assembler doesn't allow long macro names.)
And now for the code itself. To begin with, there's a mod allowing the additional routines to be accessed - by alteration of the JP instruction. The other mods are to do with getting around the 'missing sector' problem, and the DEFB 0s are there to pad out the code so that it ends up pretty much like the code you saw in Running Repairs.
If you have a look at the code, you'll see the macro definition, and that's followed by the new syntax checker. Check out the listing itself for further documentation.
Anyway, that's about it. With this little lot, you should be able to reclaim at least some of your unloadable files. The existing program does not alter corrupt data from sectors - only the checksums - and you could add a nice little editor around line 6020 to do just that. Sorry for the long wait between the two parts of this article ... let's hope I don't have to wait so long for you to come up with an editor at line 6020!


This program is available on "ZIPi'T'ape".

*1
This listing is used to alter the code given in Running Repairs to accommodate the code provided in this article - it also corrects the slight problem in the previous listing!
100 CLEAR 29999
110 LOAD *"m";1;"SL.CODE" CODE
120 FOR i=30000 TO 30463
130 LET a=PEEK i: IF a=117 OR a=118 THEN LET a=a+11
140 IF (i>=30141 AND i<=30154) OR (i>=30225 AND i<=30228) THEN LET a=0
150 POKE i+2816,a
160 NEXT i
170 DATA 2,128,25,0,26,130,133,255,140,129
180 DATA 222,201,224,53,229,32
190 RESTORE: FOR i=1 TO 8
200 READ a,b: POKE 32816+a,b
210 NEXT i
220 SAVE *"m";1;"SLC.2" CODE 32816,464


*2
Once you've saved the code from the first listing as "SLC.2", move RAMtop up to, say, 32768, to make room for the listing below, which reads in "SLC.2", adds the extra code to it and then saves it out as "SLC.3".
100 CLEAR 32815
110 LOAD *"m";1;"SLC.2" CODE
120 RESTORE
130 LET s=0
500 FOR i=33280 TO 33788
510 READ a: POKE i,a: LET s=s+a
520 NEXT i
530 IF s<>57690 THEN PRINT "Data error": STOP
540 SAVE *"m";1;"SLC.3" CODE 32816,1000
1000 DATA 245,205,144,131,241,254
1010 DATA 100,40,17,254,102,40
1020 DATA 31,254,115,202,173,130
1030 DATA 254,101,202,10,131,195
1040 DATA 240,1,215,32,0,205
1050 DATA 30,6,205,183,5,42
1060 DATA 214,92,34,251,131,195
1070 DATA 193,5,215,32,0,205
1080 DATA 30,6,254,175,194,40
1090 DATA 0,215,32,0,237,67
1100 DATA 201,92,205,30,6,205
1110 DATA 183,5,197,33,1,0
1120 DATA 34,218,92,42,251,131
1130 DATA 34,214,92,205,232,15
1140 DATA 221,126,25,205,247,23
1150 DATA 42,201,92,221,117,13
1160 DATA 33,255,0,34,201,92
1170 DATA 205,196,18,221,126,41
1180 DATA 221,190,13,40,12,33
1190 DATA 201,92,53,32,239,225
1200 DATA 54,255,195,107,131,221
1210 DATA 229,225,17,67,0,25
1220 DATA 205,169,24,1,14,0
1230 DATA 205,204,129,221,119,11
1240 DATA 17,15,0,25,1,0
1250 DATA 2,205,204,129,221,119
1260 DATA 12,221,54,0,0,221
1270 DATA 229,225,209,1,83,2
1280 DATA 237,176,195,107,131,215
1290 DATA 32,0,254,175,194,240
1300 DATA 1,215,32,0,205,30
1310 DATA 6,205,183,5,237,67
1320 DATA 253,129,33,0,131,34
1330 DATA 220,92,1,10,0,34
1340 DATA 218,92,42,251,131,34
1350 DATA 214,92,205,41,27,221
1360 DATA 110,26,221,102,27,6
1370 DATA 32,126,254,255,32,5
1380 DATA 35,16,248,231,15,221
1390 DATA 229,225,1,67,0,9
1400 DATA 235,42,253,129,9,1
1410 DATA 16,2,237,176,205,61
1420 DATA 18,195,107,131,0,1
1430 DATA 2,3,4,5,6,7
1440 DATA 8,9,215,32,0,205
1450 DATA 30,6,205,183,5,237
1460 DATA 67,253,129,33,0,131
1470 DATA 34,220,92,1,10,0
1480 DATA 34,218,92,42,251,131
1490 DATA 34,214,92,205,232,15
1500 DATA 221,126,25,205,247,23
1510 DATA 219,239,230,1,32,2
1520 DATA 231,14,33,255,0,34
1530 DATA 201,92,205,196,18,58
1540 DATA 253,129,221,190,41,32
1550 DATA 42,62,230,211,239,205
1560 DATA 125,131,1,104,1,245
1570 DATA 11,120,177,32,251,241
1580 DATA 0,221,229,225,17,55
1590 DATA 0,25,205,120,24,62
1600 DATA 238,211,239,221,203,24
1610 DATA 134,205,169,18,195,193
1620 DATA 5,33,201,92,53,32
1630 DATA 197,24,238,221,229,6
1640 DATA 10,221,54,71,0,221
1650 DATA 35,16,248,221,225,221
1660 DATA 203,70,206,201,33,163
1670 DATA 131,58,218,22,6,11
1680 DATA 254,255,202,108,128,33
1690 DATA 207,131,195,108,128,213
1700 DATA 130,41,27,82,130,232
1710 DATA 15,42,131,232,15,251
1720 DATA 130,61,18,101,131,120
1730 DATA 24,88,130,247,23,48
1740 DATA 131,247,23,103,130,196
1750 DATA 18,65,131,196,18,133
1760 DATA 130,169,24,112,131,169
1770 DATA 18,213,130,5,27,82
1780 DATA 130,165,16,42,131,165
1790 DATA 16,251,130,34,19,101
1800 DATA 131,179,21,88,130,50
1810 DATA 21,48,131,50,21,103
1820 DATA 130,169,19,65,131,169
1830 DATA 19,133,130,235,21,112
1840 DATA 131,142,19,1,0


*3
This listing should be saved at line 9000. It's an extended version of the Basic given in Running Repairs.
100 INPUT "Drive number ";d
110 IF d<1 OR d>8 THEN GO TO 100
120 DIM z$(250,13): DIM n$(13)
130 *D d: *L d
135 PRINT "Wait a sec ..."
139 REM find last item
140 FOR i=1 TO 250
150 IF Z$(i,12)<>CHR$ 255 THEN NEXT i
160 LET n=i-1
169 REM ove repetitions
170 FOR i=2 TO n
180 IF z$(i, TO 12)<>z$(i-1, TO 12) THEN GO TO 190
182 IF CODE z$(i,13)>127 THEN LET z$(i)=n$: GO TO 190
184 LET z$(i-1)=n$
190 NEXT i
200 LET c=2
1000 CLS: PRINT INVERSE 1;"      MICRODRIVE REPAIR KIT     "
1005 PRINT ''"0. Output to ";"printer" AND c=2;"screen" AND c=3
1010 PRINT '"1. Full catalogue"
1020 PRINT '"2. Sector list"
1030 PRINT '"3. Bad sector list"
1040 PRINT '"4. Check file"
1050 PRINT '"5. Examine sector"
1060 PRINT '"6. Repair sector"
1070 PRINT '"7. Remove sector"
1080 PRINT '"8. Change drive no."
1090 PRINT
1095 INPUT ;: PRINT #0;"Choose an option";
1100 PAUSE 0: LET a$=INKEY$: INPUT ;
1110 IF a$<"0" OR a$>"8" THEN GO TO 1095
1120 IF a$="0" THEN LET c=5-c: GO TO 1000
1125 IF a$="8" THEN INPUT "Drive no.";d:*D d: GO TO 1000
1130 GO SUB 1000+1000*VAL a$
1140 IF c=2 THEN PRINT "Press any key for menu": PAUSE 0
1150 GO TO 1000
1999 REM Full catalogue
2000 PRINT #c;"Full catalogue"
2010 DIM f$(10): LET f$=z$(1)
2020 FOR i=1 TO n
2030 IF z$(i)=n$ OR z$(i, TO 10)=f$ THEN GO TO 2060
2040 PRINT #c;f$( TO 10)
2050 LET f$=z$(i, TO 10)
2060 NEXT i
2065 PRINT #c;z$(n, TO 10)
2070 RETURN
2999 REM Complete sector list
3000 DIM f$(10): INPUT "Filename (or ENTER for all):",f$
3010 FOR i=1 TO n
3015 IF z$(i)=n$ THEN GO TO 3030
3020 IF f$=n$( TO 10) THEN GO SUB 9500: GO TO 3030
3025 IF z$(i, TO 10)=f$ THEN GO SUB 9500
3030 NEXT i
3040 RETURN
3999 REM Bad sector list
4000 PRINT #c;"Bad sector list"
4010 FOR i=1 TO n
4020 IF z$(i)<>n$ AND z$(i,13)>CHR$ 127 THEN GO SUB 9500
4030 NEXT i
4040 RETURN
4999 REM Check file
5000 DIM f$(10): INPUT "Filename? ";f$
5005 DIM x$(256): LET eof=-1: LET good=1
5010 FOR i=1 TO n
5020 IF z$(i, TO 10)<>f$ THEN GO TO 5100
5030 IF z$(i,13)>CHR$ 127 THEN GO TO 5060
5039 REM good sector
5040 LET x$(CODE z$(i,11)+1)="y"
5050 GO TO 5080
5059 REM bad sector
5060 PRINT #c;"Record ";CODE z$(i,11);" bad on sector ";CODE z$(i,12)
5070 LET good=0
5080 LET a=CODE z$(i,13)
5090 IF a/2<>INT (a/2) THEN LET eof=CODE z$(i,11)
5100 NEXT i
5110 IF eof>=0 THEN GO TO 5120
5111 REM missing EOF
5112 FOR i=250 TO 1 STEP -1
5114 IF x$(i)=" " THEN NEXT i
5116 LET eof=i-1
5118 LET good=0: PRINT #c;"No EOF record"
5120 FOR i=0 TO eof
5130 IF x$(i+1)=" " THEN PRINT "Record ";i;" missing": LET good=0
5140 NEXT i
5150 IF good=1 THEN PRINT "File ";f$;" intact"
5160 IF good=0 THEN PRINT "File ";f$;" corrupted"
5170 RETURN
5999 REM Read a sector
6000 INPUT "Sector no.";s
6010 *F s CODE 60000
6020 IF c=2 THEN CLS
6090 PRINT #c;"Sector ";s
6100 IF PEEK 60000 THEN PRINT #c; FLASH 1;"Not found": RETURN
6110 PRINT #c;"Cart name:";
6120 FOR i=44 TO 53
6130 PRINT #c;CHR$ PEEK (60000+i);
6140 NEXT i: PRINT #c
6150 PRINT #c;"RECFLG:";PEEK 60067
6160 PRINT #c;"RECNUM:";PEEK 60068
6170 PRINT #c;"RECLEN:";PEEK 60069+256*PEEK 60070
6180 PRINT #c;"Filename:";
6190 FOR i=71 TO 80
6200 PRINT #c;CHR$ PEEK (60000+i);
6210 NEXT i: PRINT #c
6220 PRINT #c;"Checksum1:";PEEK 60081,
6230 IF PEEK 60011=PEEK 60081 THEN PRINT #c;"OK"
6240 IF PEEK 60011<>PEEK 60081 THEN PRINT #c;"(should be ";PEEK 60011;")"
6245 PRINT #c;"Checksum2:";PEEK 60594,
6250 IF PEEK 60012=PEEK 60594 THEN PRINT #c;"OK"
6260 IF PEEK 60012<>PEEK 60594 THEN PRINT #c;"(should be ";PEEK 60012;")"
6300 RETURN
6999 REM repair sector
7000 GO SUB 6000
7010 IF PEEK 60000 THEN RETURN
7020 PRINT '"Re-writing to spare sector"
7030 *S CODE 60000
7040 PRINT
7050 RETURN
7999 REM remove sector
8000 INPUT "Sector no.";s
8010 *E s
8020 PRINT "Sector removed"
8030 RETURN
9000 CLEAR 32815: LOAD *"m";1;"SLC.3" CODE: RANDOMIZE USR 32816: RUN
9500 PRINT #c;z$(i, TO 10);" r";CODE z$(i,11);TAB 16;"s";CODE z$(i,12);TAB 21;
9510 LET f=CODE z$(i,13)
9520 IF f/2<>INT (f/2) THEN PRINT #c;"EOF";
9530 IF CODE z$(i,13)>127 THEN PRINT #c;TAB 25;"BAD";
9540 PRINT #c
9550 RETURN
9999 CLEAR: ERASE "m";1;"repair 2": SAVE *"m";1;"repair 2"


* This is the main assembler listing and should be entered using an assembler program. If you've not got an assembler to hand, you can use a Hex loader to type in the figures on the left-hand side of the listing. [It is unnecessary to do this, as the "SLC.3" program creates all the code.]
               100        ORG  #8030 ;**new org**
8030 213A80    110        LD   HL,NEWVEC
8033 22B75C    120        LD   (VECTOR),HL ;alter vector
8036 010000    130        LD   BC,0
8039 C9        140        RET
803A C6CE      200 NEWVEC ADD  A,206
803C FE2A      210        CP   "*"
803E C2F001    220        JP   NZ,#01F0
8041 D7        230        RST  #10
8042 2000      240        DEFW #20 ;next char
8044 F620      245        OR   #20 ;make it l.c.
8046 FE6C      247        CP   "l"
8048 C20082    248        JP   NZ,NVEC2 ;**new jump**
804B D7        249        RST  #10
804C 2000      250        DEFW #20 ;next char
              1055 *L+
              1056 ;
              1057 ;
80B1 CDF717   1060 L2     CALL MOTOR ;switch on
80B4 21FF00   1070        LD   HL,255 ;**new number**
80B7 22C95C   1080        LD   (SECTOR),HL
80BA CDA381   1090 FLOOP  CALL NXHDBF ;next header & buffer
              1100        DEFB 0,0,0,0,0,0,0 ;**blank old code**
              1110        DEFB 0,0,0,0,0,0,0
80CB 2840     1200 LESS   JR   Z,NEXT ;if not used
80CD 3810     1201        JR   C,ISBAD ;if 1st checksum fails
              1375 *L+
              1376 ;
              1377 ;
              1378 ;(rather different)
810D 21C95C   1380 NEXT   LD   HL,SECTOR
8110 35       1390        DEC  (HL)
8111 00000000 1400        DEFB 0,0,0,0
8115 20A3     1430        JR   NZ,FLOOP
              4999 *L+
              5000 ;
              5010 ;REPAIR KIT PART 2
              5020 ;STARTS HERE
              5030 ;
              5031 ;do Macro for 16K ROM calls
8200          5032 OLD    MAC
8200          5033        RST  #10
8200          5034        DEFW =0
8200          5035        ENDM
              5036 ;
              5040 ;further syntax checker
8200 F5       5042 NVEC2  PUSH AF
8201 CD9083   5045        CALL WATRM2 ;alter code
8204 F1       5047        POP  AF
8205 FE64     5050        CP   "d"
8207 2811     5060        JR   Z,SETDRV
8209 FE66     5070        CP   "f"
820B 281F     5080        JR   Z,FINDSC
820D FE73     5090        CP   "s"
820F CAAD82   5100        JP   Z,SAVSEC
8212 FE65     5110        CP   "e"
8214 CA0A83   5120        JP   Z,ERASEC
8217 C3F001   5130        JP   #01F0 ;if none
              5140 ;
821B          5150 SETDRV OLD  #20
821D CD1E06   5160        CALL EVALBC
8220 CDB705   5170        CALL CHKEND
8223 2AD65C   5180        LD   HL,(D_STR1)
8226 22FB83   5190        LD   (DRIVE),HL
8229 C3C105   5200        JP   #05C1 ;end of *D
              5210 ;
The first extra command handler is SETDRV, which handles the *D command simply by finding the value and putting it in DRIVE.
822C          5220 FINDSC OLD  #20
822F CD1E06   5230        CALL EVALBC ;get sector no
8232 FEAF     5240        CP   175 ;"CODE"
8234 C22800   5250        JP   NZ,#0028
8237          5260        OLD  #20
823A ED43C95C 5270        LD   (SECTOR),BC ;sector no
823E CD1E06   5280        CALL EVALBC
8241 CDB705   5290        CALL CHKEND
8244 C5       5300        PUSH BC ;save destination
8245 210100   5310        LD   HL,1
8248 22DA5C   5320        LD   (N_STR1),HL ;name len
824B 2AFB83   5330        LD   HL,(DRIVE)
824E 22D65C   5340        LD   (D_STR1),HL
The next routine is FINDSC, which handles the *F command. After syntax checking, an 'M' channel is created, and each sector examined until the required one is found - or until the sector counter expires. If the sector is found, then its particulars are stored in the said location; if not, then 255 is placed into the location instead. An exit is made via QUITM, which closes the channel before returning to the interpreter.
8251 CDE80F   5350 M2     CALL CREATM
8254 DD7E19   5360        LD   A,(IX+25)
8257 CDF717   5370 M6     CALL MOTOR ;turn on
825A 2AC95C   5380        LD   HL,(SECTOR)
825D DD750D   5390        LD   (IX+13),L ;save sector no
8260 21FF00   5400        LD   HL,255
8263 22C95C   5410        LD   (SECTOR),HL ;count
8266 CDC412   5420 DOAGIN CALL NEXTHD
8269 DD7E29   5430        LD   A,(IX+41) ;sector loaded
826C DDBE0D   5440        CP   (IX+13) ;is it wanted?
826F 280C     5450        JR   Z,GOTIT ;if it's the one
8271 21C95C   5460        LD   HL,SECTOR
8274 35       5470        DEC  (HL)
8275 20EF     5480        JR   NZ,DOAGIN ;do 255 times
8277 E1       5490        POP  HL ;destination
8278 36FF     5500        LD   (HL),255 ;'not found'
827A C36B83   5505        JP   QUITM
827D DDE5     5530 GOTIT  PUSH IX
827F E1       5540        POP  HL
8280 114300   5550        LD   DE,#0043
8283 19       5560        ADD  HL,DE ;HL=RECFLG
8284 CDA918   5570 M10    CALL RDBYTS
8287 010E00   5580        LD   BC,#000E
828A CDCC81   5590        CALL CHKSUM
828D DD770B   5600        LD   (IX+11),A
8290 110F00   5602        LD   DE,#000F
8293 19       5603        ADD  HL,DE
8294 010002   5604        LD   BC,#0200
8297 CDCC81   5605        CALL CHKSUM
829A DD770C   5606        LD   (IX+12),A
829D DD360000 5610        LD   (IX+0),0 ;'found'
82A1 DDE5     5620        PUSH IX
82A3 E1       5630        POP  HL
82A4 D1       5640        POP  DE ;destination
82A5 015302   5650        LD   BC,595
82A8 EDB0     5660        LDIR ;copy whole buffer
82AA C36B83   5665        JP   QUITM
              5700 ;
              5710 ;save data on next free sector
82AD          5720 SAVESC OLD #20
82B0 FEAF     5730        CP   175 ;"CODE"
82B2 C2F001   5740        JP   NZ,#01F0
82B5          5750        OLD  #20
82B8 CD1E06   5760        CALL EVALBC
82BB CDB705   5770        CALL CHKEND
82BE ED43FD81 5780        LD   (FMARK),BC ;store source
82C2 210083   5790        LD   HL,SILLNM
82C5 22DC5C   5800        LD   (T_STR1),HL
82C8 010A00   5810        LD   BC,10
82CB 22DA5C   5820        LD   (N_STR1),HL
82CE 2AFB83   5830        LD   HL,(DRIVE)
82D1 22D65C   5840        LD   (D_STR1),HL
Routine SAVESC handles the *S command and, again, it starts by opening an 'M' channel with a silly filename that should never exist on the cartridge. A full cartridge is tested prior to the data being written onto the next free sector, with the ROM routine WRBUF handling most of the tricky stuff ... including doing the checksums.
82D4 CD291B   5850 M1     CALL OPENM
82D7 DD6E1A   5860        LD   L,(IX+26)
82DA DD661B   5870        LD   H,(IX+27)
82DD 0620     5880        LD   B,32
82DF 7E       5890 FULL?  LD   A,(HL)
82E0 FEFF     5900        CP   #FF
82E2 2005     5910        JR   NZ,ISSPAC ;if at least 1 free sector
82E4 23       5920        INC  HL
82E5 10F8     5930        DJNZ FULL?
82E7 E7       5940        RST  #20
82E8 0F       5950        DEFB #0F ;"Microdrive full"
82E9 DDE5     5960 ISSPAC PUSH IX
82EB E1       5970        POP  HL
82EC 014300   5980        LD   BC,67
82EF 09       5990        ADD  HL,BC
82F0 EB       6000        EX   DE,HL ;DE=RECFLG
82F1 2AFD81   6010        LD   HL,(FMARK)
82F4 09       6020        ADD  HL,BC ;source+67
82F5 011002   6030        LD   BC,595-67
82F8 EDB0     6040        LDIR ;copy into buffer
82FA CD3D12   6050 M4     CALL WRBUF ;send it
82FD C36B83   6070        JP   QUITM
8300 00010203 6090 SILLNM DEFB 0,1,2,3,4,5,6,7,8,9 ;silly filename
              6100 ;
              6110 ;remove an individual sector
830A          6120 ERASEC OLD  #20
830D CD1E06   6130        CALL EVALBC
8310 CDB705   6140        CALL CHKEND
8313 ED43FD81 6150        LD   (FMARK),BC
8317 210083   6160        LD   HL,SILLNM
831A 22DC5C   6170        LD   (T_STR1),HL
831D 010A00   6180        LD   BC,10
8320 22DA5C   6190        LD   (N_STR1),HL
8323 2AFB83   6200        LD   HL,(DRIVE)
8326 22D65C   6210        LD   (D_STR1),HL
The code at ERASEC handles the *E command, by searching for the required sector in a similar way to FINDSC. When it's found, a null filename is written out to it, along with a bit that shows the sector is being 'used'; thus, it's removed from use.
8329 CDE80F   6220 M3     CALL CREATM
832C DD7E19   6230        LD   A,(IX+25)
832F CDF717   6240 M7     CALL MOTOR ;switch on
8332 DBEF     6250        IN   A,(#EF)
8334 E601     6260        AND  1
8336 2002     6270        JR   NZ,NPROT
8338 E7       6280        RST  #20
8339 0E       6290        DEFB #E ;"Write protected"
833A 21FF00   6300 NPROT  LD   HL,255
833D 22C95C   6310        LD   (SECTOR),HL
8340 CDC412   6320 ERALP  CALL NEXTHD ;next sector
8343 3AFD81   6330        LD   A,(FMARK)
8346 DDBE29   6340        CP   (IX+41)
8349 202A     6350        JR   NZ,NOTWON
              6360 ;this is the sector
834B 3EE6     6370        LD   A,#E6
834D D3EF     6380        OUT  (#EF),A ;signal 'write' to ULA
834F CD7D83   6390        CALL CLRBUF
8352 016801   6400        LD   BC,#0168
8355 F5       6410        PUSH AF
8356 0B       6420 WAITBC DEC  BC
8357 78       6430        LD   A,B
8358 B1       6440        OR   C
8359 20FB     6450        JR   NZ,WAITBC
835B F1       6460        POP  AF
835C 00       6470        NOP  ;after a delay
835D DDE5     6480        PUSH IX
835F E1       6490        POP  HL
8360 113700   6500        LD   DE,#0037
8363 19       6510        ADD  HL,DE ;preamble
8364 CD7818   6520 M5     CALL WRBIT ;send it
8367 3EEE     6530        LD   A,#EE
8369 D3EF     6540        OUT  (#EF),A ;put 'write' off
836B DDCB1886 6550 QUITM  RES  0,(IX+24)
836F CDA912   6560 M11    CALL CLOSEM
8372 C3C105   6570        JP   #05C1 ;end of *E
8375 21C95C   6580 NOTWON LD   HL,SECTOR
8378 35       6590        DEC  (HL)
8379 20C5     6600        JR   NZ,ERALP
837B 18EE     6610        JR   QUITM ;if can't find it
837D DDE5     6620 CLRBUF PUSH IX
837F 060A     6630        LD   B,10
8381 DD364700 6640 CLBLP  LD   (IX+71),0
8385 DD23     6650        INC  IX
8387 10F8     6660        DJNZ CLBLP ;make null filename
8389 DDE1     6670        POP  IX
838B DDCB46CE 6680        SET  1,(IX+70); mark it 'used'
838F C9       6690        RET
              7000 ;
              7010 ;alter part 2 for different ROMs
8390 21A383   7020 WATRM2 LD   HL,OLD2
8393 3ADA16   7030        LD   A,(#16DA)
8396 060B     7040        LD   B,11
8398 FEFF     7050        CP   #FF
839A CA6C80   7060        JP   Z,REDOLP
839D 21CF83   7070        LD   HL,NEW2
83A0 C36C80   7080        JP   REDOLP
The final routine is WATRM2, and this does what's necessary to ensure that the program works on all types of ROM. As far as this program is concerned, there's no difference between versions 2 and 3, so no extra steps are taken for the latter version of the Interface 1 ROM. You'll also find that the code given in Running Repairs also works fine on the third version of the ROM.
              7090 ;data for old ROM
83A3 D582291B 7100 OLD2   DEFW M1+1,OPENM
83A7 5282E80F 7110        DEFW M2+1,CREATM
83AB 2A83E80F 7120        DEFW M3+1,CREATM
83AF FB823D12 7130        DEFW M4+1,WRBUF
83B3 65837818 7140        DEFW M5+1,WRBIT
83B7 5882F717 7150        DEFW M6+1,MOTOR
83BB 3083F717 7160        DEFW M7+1,MOTOR
83BF 6782C412 7170        DEFW DOAGIN+1,NEXTHD
83C3 4183C412 7180        DEFW ERALP+1,NEXTHD
83C7 8582A918 7190        DEFW M10+1,RDBYTS
83CB 7083A912 7200        DEFW M11+1,CLOSEM
83CF D582051B 7210 NEW2   DEFW M1+1,#1B05
83D3 5282A510 7220        DEFW M2+1,#10A5
83D7 2A83A510 7230        DEFW M3+1,#10A5
83DB FB822213 7240        DEFW M4+1,#1322
83DF 6583B315 7250        DEFW M5+1,#15B3
83E3 58823215 7260        DEFW M6+1,#1532
83E7 30833215 7270        DEFW M7+1,#1532
83EB 6782A913 7280        DEFW DOAGIN+1,#13A9
83EF 4183A913 7290        DEFW ERALP+1,#13A9
83F3 8582EB15 7300        DEFW M10+1,#15EB
83F7 70838E13 7310        DEFW M11+1,#138E

Home Contents KwikPik