Your Spectrum
Issue 6, August 1984 - Microdrive File Rename
Home Contents KwikPik


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

.
A L L . C H A N G E !
.
.
Ever wanted to rename a Microdrive file? Providing the code to create the necessary new command, Andrew Pennell brings Microdrives one step nearer the expensive disk systems they emulate.
Although Sinclair Research's Interface 1 unit allows good use of the Microdrives from Basic, there is one command noticeable only by its absence - that of RENAME. It's provided by most disk operating systems and associated Basics, but not for the dear old Speccy. Here, therefore, is the machine code you've been waiting for - although, I'm afraid that it's for 48K owners only.
Listing 1 shows the Basic loader to create the machine code; enter it with great care - the checksum should spot most typing errors, but some may slip through. After entering and executing, SAVE the program in case it's wrong. To test it, enter RANDOMIZE USR 28000, which enables it. Then, with an unimportant cartridge, try to rename a file; the syntax to use is

*R1;"oldname" TO "newname"

where 'TO' is the keyword (and 'r' is also accepted). Naturally, '1' in the example can be replaced with any drive number, up to '8' (should you be lucky enough to have that many!). Having entered the command, the file 'oldname' will be renamed to 'newname', although there are a couple of limitations. Firstly, data files (that is, those created with OPEN/PRINT/CLOSE) will not be renamed, and will produce the error 'Wrong file type'. A second limitation is that the file 'oldname' must be under about 37K in length - otherwise it'll be flagged 'Out of memory'.
The program has been written so that if any error occurs during the process (except perhaps a power cut!) then the file will remain intact, under one of the names. If you try to rename a non-existent file, you'll come across the 'File not found' message, and an attempt to define a new name that's already present on the cartridge will force 'Writing to a read file'.
The source code is shown in Listing 2, and uses the facility of the Interface 1 to add commands to the Basic interpreter. The remainder of this explanation assumes a basic knowledge of machine code with the Microdrives, and of how to add commands; for this I suggest you read chapters eight and nine respectively of Master your ZX Microdrive - and Toni Baker's Extending Basic article (see issue 3).
The code is placed at 28000 decimal, to give some room for small Basic programs, and over 37K to store the file. The routine SETUP is the one entered directly from Basic, and the first creates the Interface system variables, using
  10 REM    MICRODRIVE RENAME
  20 REM (C) A. Pennell 1984
  30 REM
 100 RESTORE 1000: CLEAR 27999
 105 LET s=0
 110 FOR i=28000 TO 28254
 120 READ a: POKE i,a: LET s=s+a
 130 NEXT i
 140 IF s<>27057 THEN PRINT "Data error": STOP
 150 PRINT "Data OK. Code starts @28000, 255long."
1000 DATA 207,49,33,188,109,34
1010 DATA 183,92,33,116,109,34
1020 DATA 237,92,207,50,1,0,0
1030 DATA 201,33,145,109,58,218
1040 DATA 22,254,255,40,3,33
1050 DATA 165,109,6,5,94,35,86
1060 DATA 35,126,18,35,126,19
1070 DATA 18,35,16,243,201,238
1080 DATA 109,41,27,47,110,172
1090 DATA 21,50,110,169,18,73
1100 DATA 110,238,20,79,110,110
1110 DATA 29,238,109,5,27,47
1120 DATA 110,157,25,50,110,142
1130 DATA 19,73,110,223,24,79
1140 DATA 110,121,29,195,40,0
1150 DATA 198,206,254,42,194
1160 DATA 240,1,215,32,0,246
1170 DATA 32,254,114,32,237,215
1180 DATA 32,0,205,30,6,254,59
1190 DATA 32,227,205,47,6,254
1200 DATA 204,32,220,205,84,110
1210 DATA 205,47,6,205,183,5
1220 DATA 205,84,110,42,220,92
1230 DATA 229,205,5,27,225,34
1240 DATA 220,92,221,203,24,70
1250 DATA 40,2,231,17,219,239
1260 DATA 230,1,32,2,231,14,221
1270 DATA 203,67,86,32,2,231
1280 DATA 22,221,229,225,17,82
1290 DATA 0,25,17,99,110,1,9
1300 DATA 0,237,176,237,83,233
1310 DATA 92,33,108,110,237,91
1320 DATA 100,110,25,48,5,253
1330 DATA 54,0,3,239,205,157
1340 DATA 25,205,142,19,33,99
1350 DATA 110,17,230,92,1,9,0
1360 DATA 237,176,205,84,110
1370 DATA 33,108,110,34,228,92
1380 DATA 205,223,24,205,84,110
1390 DATA 205,121,29,195,193
1400 DATA 5,33,218,92,17,95,110
1410 DATA 6,4,195,167,5
Listing 1 (above): The Basic loader to create the RENAME machine code.
Listing 2 (below): The disassembled listing, roughly split into five columns: address, Hex code, line numbers (unique to the disassembler used), labels and mnemonics.
                 10 ; MICRODRIVE RENAME
                 20 ; (C) A.PENNELL 1984
                 30 ;
6D60           1000        ORG  28000
6D60 CF        1010 SETUP  RST  8
6D61 31        1020        DEFB #31 ;make vars
6D62 21BC6D    1030        LD   HL,NEWSYN
6D65 22B75C    1040        LD   (VECTOR),HL ;change VECTOR
6D68 21746D    1050        LD   HL,WATROM
6D6B 22ED5C    1060        LD   (HD_11),HL
6D6E CF        1070        RST  8
6D6F 32        1080        DEFB #32 ;call WATROM to modify CALLs
6D70 010000    1090        LD   BC,0
6D73 C9        1100        RET
               1110 ; modify routine for different ROMs
6D74 21916D    1120 WATROM LD   HL,OLDROM
6D77 3ADA16    1130        LD   A,(#16DA)
6D7A FEFF      1140        CP   #FF
6D7C 2803      1150        JR   Z,YESOLD
6D7E 21A56D    1160        LD   HL,NEWROM ;to suit new ROM
6D81 0605      1170 YESOLD LD   B,5 ;no of CALLs to alter
6D83 5E        1180 REDOLP LD   E,(HL)
6D84 23        1190        INC  HL
6D85 56        1200        LD   D,(HL) ;DE=CALL+1
6D86 23        1210        INC  HL
6D87 7E        1220        LD   A,(HL)
6D88 12        1230        LD   (DE),A
6D89 23        1240        INC  HL
6D8A 7E        1250        LD   A,(HL)
6D8B 13        1260        INC  DE
6D8C 12        1270        LD   (DE),A ;alter CALL
6D8D 23        1280        INC  HL
6D8E 10F3      1290        DJNZ REDOLP
6D90 C9        1300        RET
               1309 ; data table for old ROM
6D91 EE6D291B  1310 OLDROM DEFW L1+1,#1B29 ;OPEN_M
6D95 2F6EAC15  1320        DEFW L2+1,#15AC ;LDBYTS
6D99 326EA912  1330        DEFW L3+1,#12A9 ;CLOSEM
6D9D 496EEE14  1340        DEFW L4+1,#14EE ;SVBYTS
6DA1 4F6E6E1D  1350        DEFW L5+1,#1D6E ;ERASEM
               1359 ; data table for new ROM
6DA5 EE6D051B  1360 NEWROM DEFW L1+1,#1B05 ;OPEN_M
6DA9 2F6E9D19  1370        DEFW L2+1,#199D ;LDBYTS
6DAD 326E8E13  1380        DEFW L3+1,#138E ;CLOSEM
6DB1 496EDF18  1390        DEFW L4+1,#18DF ;SVBYTS
.
.
hook code #31, then alters VECTOR to point to the new command routine. It then calls WATROM using hook code #32, before RETurning to Basic. The routine WATROM actually modifies the program to suit the ROM in the Interface 1. As you may be aware, Interface 1 will shortly be sporting a new ROM which has most of its routines in different places. To cater for this, the tables OLDROM and NEWROM allow the program to modify itself to suit either, using location #16DA to test the ROM's type. It had to be called indirectly via hook code #32 because the Shadow ROM must be in place for it to work.
Location SYNERR is just a jump to #28 in the Shadow ROM which produces a syntax error when in the line editor. NEWSYN is the new command handler, which first ensures that the command starts with *R or *r. That done, the drive number is scanned, a semi-colon checked for, then the old filename scanned. Next, the character following it (that is, the TO token) is checked, then the routine SWOP called. This is explained later, and only has significance during 'run-time'.
The new name is scanned, and a check made to ensure that there's no more to the statement. Control only passes to line 2200 during 'run-time', which again calls SWOP. This routine swaps the parameters (start address and length) for the old and new names, which are stored in N_STR1, T_STR1 and N_STR3, T_STR3. The Shadow ROM routines act on the parameters in the former two.
The next action taken is for OPEN_M to be called, while preserving T_STR1. As the Shadow ROM is in place, hook codes cannot be used, so routines vary according to ROM type. OPEN_M takes identical action to hook code #22 - that is, create an 'M' channel addressed by IX. The old file is then checked to see if it exists, whether it's a PRINT file, and whether the cartridge is write-protected or not. If it passes all the criterion the nine-byte file header is copied to FREE, and the length of the file is tested to see if there's room for it and if not an error is produced. The shadow routine LDBYTS is called which loads the rest of the file into locations FREE+9 onwards, and then the channel is closed.
Next, the header is copied back from FREE to HD-00 to HD-11, and the bytes SAVEd on to the required cartridge. Routine SVBYTS does a lot of the fiddly bits for you, like opening an 'M' channel, setting the PRINT file flag and testing to see if it's already there. Finally, the old file is erased - by calling ERASEM - and an exit made via #05C1 (which is the same in both ROMs, thankfully).
.
.
.
6DB5 4F6E791D  1400        DEFW L5+1,#1D79 ;ERASEM
6DB9 C32800    2000 SYNERR JP   #28 ;syntax error
               2005 ; new command routine
6DBC C6CE      2010 NEWSYN ADD  A,206
6DBE FE2A      2020        CP   "*"
6DC0 C2F001    2030        JP   NZ,#01F0 ;check "*"
6DC3 D7        2040        RST  #10
6DC4 2000      2050        DEFW #20 ;next-char
6DC6 F620      2060        OR   #20 ;make it lower case
6DC8 FE72      2070        CP   "r"
6DCA 20ED      2080        JR   NZ,SYNERR
6DCC D7        2090        RST  #10
6DCD 2000      2100        DEFW #20
6DCF CD1E06    2110        CALL #061E ;do drive no
6DD2 FE3B      2120        CP   ";"
6DD4 20E3      2130        JR   NZ,SYNERR
6DD6 CD2F06    2140        CALL #062F ;do old name
6DD9 FECC      2150        CP   204 ;"TO"
6DDB 20DC      2160        JR   NZ,SYNERR
6DDD CD546E    2170        CALL SWOP
6DE0 CD2F06    2180        CALL #062F ;do new name
6DE3 CDB705    2190        CALL #05B7 ;check end
6DE6 CD546E    2200        CALL SWOP
6DE9 2ADC5C    2210        LD   HL,(T_STR1)
6DEC E5        2220        PUSH HL ;save start on stack
6DED CD051B    2250 L1     CALL OPEN_M
6DF0 E1        2255        POP  HL
6DF1 22DC5C    2260        LD   (T_STR1),HL ;restore start
6DF4 DDCB1846  2265        BIT  0,(IX+24)
6DF8 2802      2270        JR   Z,FOUND
6DFA E7        2280        RST  #20
6DFB 11        2290        DEFB #11 ;"File not found"
6DFC DBEF      2300 FOUND  IN   A,(#EF)
6DFE E601      2310        AND  1
6E00 2002      2320        JR   NZ,NPROT
6E02 E7        2330        RST  #20
6E03 0E        2340        DEFB #0E ;"Write protected"
6E04 DDCB4356  2350 NPROT  BIT  2,(IX+67)
6E08 2002      2360        JR   NZ,NPRINT
6E0A E7        2370        RST  #20
6E0B 16        2380        DEFB #16 ;"Wrong file type"
6E0C DDE5      2390 NPRINT PUSH IX
6E0E E1        2400        POP  HL
6E0F 115200    2410        LD   DE,82
6E12 19        2420        ADD  HL,DE ;=1st byte in header
6E13 11636E    2430        LD   DE,FREE
6E16 010900    2440        LD   BC,9
6E19 EDB0      2450        LDIR ;copy header to FREE
6E1B ED53E95C  2460        LD   (HD_0D),DE ;start=FREE+9
6E1F 216C6E    2461        LD   HL,FREE+9
6E22 ED5B646E  2462        LD   DE,(FREE+1) ;=file length
6E26 19        2463        ADD  HL,DE
6E27 3005      2464        JR   NC,L2 ;if it will fit
6E29 FD360003  2465        LD   (IY+0),3 ;"Out of memory"
6E2D EF        2466        RST  #28 ;do BASIC ROM error
6E2E CD9D19    2470 L2     CALL LDBYTS ;load the file
6E31 CD8E13    2480 L3     CALL CLOSEM ;close the channel
6E34 21636E    2490        LD   HL,FREE
6E37 11E65C    2500        LD   DE,HD_00
6E3A 010900    2510        LD   BC,9
6E3D EDB0      2520        LDIR ;copy header to HD_00 etc
6E3F CD546E    2530        CALL SWOP
6E42 216C6E    2570        LD   HL,FREE+9
6E45 22E45C    2580        LD   (#5CE4),HL ;new start
6E48 CDDF18    2590 L4     CALL SVBYTS ;save data & close channel
6E4B CD546E    2600        CALL SWOP
6E4E CD791D    2610 L5     CALL ERASEM ;erase old file
6E51 C3C105    2620        JP   #05C1 ;then exit
               2700 ;
               2710 ; Swop contents of N_STR1 & T_STR1 with 3
6E54 21DA5C    2720 SWOP   LD   HL,N_STR1
6E57 115F6E    2730        LD   DE,N_STR3
6E5A 0604      2740        LD   B,4
6E5C C3A705    2750        JP   #05A7
6E5F 0000      9000 N_STR3 DEFW 0
6E61 0000      9010 T_STR3 DEFW 0
6E63 00        9020 FREE   NOP
              10000 ; CONSTANTS
5CB7          10010 VECTOR EQU  #5CB7
5CDA          10020 N_STR1 EQU  #5CDA
5CDC          10030 T_STR1 EQU  #5CDC
5CE2          10040 N_STR2 EQU  #5CE2
5CE4          10050 T_STR2 EQU  #5CE4
5CE6          10060 HD_00  EQU  #5CE6
5CE7          10065 HD_0B  EQU  #5CE7
5CE9          10070 HD_OD  EQU  #5CE9
5CED          10080 HD_11  EQU  #5CED
              12000 ; (NEW) SHADOW ROM ROUTINES
1D79          12080 ERASEM EQU  #1D79
1B05          12090 OPEN_M EQU  #1B05
199D          12100 LDBYTS EQU  #199D
18DF          12110 SVBYTS EQU  #18DF
138E          12120 CLOSEM EQU  #138E
6E64          12130        END
Home Contents KwikPik