Your Spectrum
Issue 2, March 1984 - Microdrives
Home Contents KwikPik
The ZX Microdrives are with us, or at least some of us, and have a great deal to offer at a low cost. Unfortunately, there are one or two problems, not least of which are a couple of bugs in the Microdrive ROM. Andrew Pennel presents three short machine code routines to circumvent the major traumas.
The first problem we're dealing with appears as a result of a serious bug in the ROM; this causes the machine to crash if there is insufficient memory space, and a LOAD *"m" or SAVE *"m" command is entered. The relevant Microdrive motor switches on, but no SAVEing or LOADing occurs, and you cannot halt the proceedings. The only way out is to remove the plug during rotation, something which might easily damage the cartridge. To get round the problem, before making such a command enter RANDOMIZE USR 23296 (or whatever the value of 'st' in line 10 has been made). If an 'Out of memory' error appears, it means that a SAVE or LOAD to Microdrive is dangerous, so don't try it. If no error message occurs, it means there is sufficient room and all such commands will be carried out.
Another problem can occur when you have a lot of OPENed streams. For each OPENED stream, a certain amount of memory is consumed, ranging from 11 to 595 bytes. The only way to get the use of all the memory is to CLOSE# or CLEAR#, but these sometimes fail to clear the memory, particularly if an error such as BREAK occurs during such a command. The second machine code routine, at st+8 (ie. 23304 if in the printer buffer), is designed to supplement the CLEAR# routine by removing any remaining memory areas of additional streams. Before using it, though, always do a CLEAR# first for example, CLEAR#: RANDOMIZE USR 23304.
The final routine will prove extremely
While there's plenty to recommend about Sinclair Research's elusive Microdrive device, as with most innovations there's room for improvement. The first part of this article is for all users and explains the problems and tells how to use the 'cures'; and the second part is for those who know some machine code and who appreciate fuller explanations.
Before presenting the listings, here is a very useful feature that can greatly decrease the loading times of some programs. Say you have a Basic program that loads another file such as a SCREEN$ or some machine code. If you SAVE the Basic then SAVE the second file, there may well be a considerable delay when you re-load it between the Basic part, and the second file. This is because two files SAVEd directly after one another cannot usually LOAD directly after each other. To be sure of fast loading, after each SAVE,
do a VERIFY, then the next SAVE, and so on. This method ensure minimum time taken for loading.
Figure 1 is a listing of a Basic program that contains all the data for the machine code routines; it's loaded into the printer buffer area of memory, at locations 23296-23353. However, the machine code is position independent, which means it can be put anywhere that's convenient in memory. Alternative places are the user-defined graphics area and above RAMTOP, and the start location can be altered by changing line 10 of the Basic listing. Do not put the code into a REM statement, ZX81 fashion - for technical reasons this is a very bad place to store Microdrive routines.

   5 REM Printer buffer
  10 LET st=23296
  20 RESTORE 100
  30 FOR i=0 TO 57
  40 READ a: POKE i+st,a
  50 NEXT i
  60 REM test-room=st
  70 REM  clear#+ =st+8
  80 REM  collapse=st+41
  90 REM
  99 REM Test-Room
 100 DATA 207,49,1,147,2,195,5,31
 199 REM CLEAR# more
 200 DATA  17,240,92,42,79,92,229,167,237,82,225,196,229,25,42,79,92,
 299 REM Collapse
 300 DATA 42,79,92,17,73,163,25,208,33,240,92,17,182,92,195,229,25 
Figure 1. The Basic program containing the Microdrive 'cure-all'.

                 10 ;      Test-room for
                 20 ;      Microdrive commands
5B00             30        ORG  23296    ;printer buffer
5B00 CF          40 TESTRM RST  8
5B01 31          50        DEFB #31      ;create extra system variables
5B02 019302      60        LD   BC,659   ;required space
5B05 C3051F      70        JP   #1F05    ;test-room
                 80 ;
                 90 ;      True CLEAR#
5B08 11F05C     100 CLEAR  LD   DE,23792
5B0B 2A4F5C     110        LD   HL,(CHANS)
5B0E E5         120        PUSH HL
5B0F A7         130        AND  A
5B10 ED52       140        SBC  HL,DE
5B12 E1         150        POP  HL
5B13 C4E519     160        CALL NZ,#19E5 ;reclaim maps if CHANS<>23792
5B16 2A4F5C     170        LD   HL,(CHANS)
5B19 111400     180        LD   DE,20
5B1C 19         190        ADD  HL,DE
5B1D EB         200        EX   DE,HL
5B1E 2A535C     210        LD   HL,(PROG)
5B21 2B         220        DEC  HL
5B22 1A         230        LD   A,(DE)
5B23 FE80       240        CP   #80
5B25 C4E519     250        CALL NZ,#19E5 ;reclaim channel bytes
5B28 C9         260        RET
                270 ;
                280 ;set constants
5C4F            290 CHANS  EQU  23631
5C53            300 PROG   EQU  23635
                310 ;
                320 ;
                330 ;COLLAPSE to remove extra system variables
5B29 2A4F5C     340 COLAPS LD   HL,(CHANS)
5B2C 1149A3     350        LD   DE,#A349
5B2F 19         360        ADD  HL,DE
5B30 D0         370        RET  NC       ;return if no variables anyway
5B31 21F05C     380        LD   HL,#5CF0 ;end of area
5B34 11B65C     390        LD   DE,#5CB6 ;start of area
5B37 C3E519     400        JP   #19E5    ;reclaim the area
5B3A            410        END
Figure 2. The assembler listing of the three routines presented in Figure 1.

useful for converting certain cassette programs on to Microdrive, particularly those containing machine code in REM statements. Many commercial games contain such REM statements of this kind as the first line in a program, with subsequent commands such as RANDOMIZE USR 23760. However, with Interface 1 in use, the location of the first line in a program can, and does, change which normally makes the machine 'fall over' when it tries the USR statement. The third machine code routine starts at st+41 (23337 in the printer buffer) and removes the extra system variables; thus the first line will be in the same place as it would if there was no Interface 1 connected. Note that any error (except 'OK') and any Microdrive commands will move the line back to its previous position. Written originally for the game, Valhalla, the routine has proved useful on a number of other occasions too. Microdrive ROM doesn't quite get right. When doing a SAVE *"m" or LOAD *"m", a total of 659 free bytes are required, made up of 595 bytes for the CHANS buffer, 32 bytes for the Microdrive map, and 32 bytes for stack usage. Sad to say, the Interface 1 ROM only checks for 627 bytes - the ROM authors having overlooked the stack usage - thus causing the crash. The routine itself is quite straightforward. Firstly hook code #31 is used to make sure the 58 bytes of extra system variables are in existence, then the ROM routine at #1F05 is executed to test for 659 free bytes.
Before we discuss the CLEAR# supplementary routine, it would be useful to examine the relevant section of the Spectrum memory map - see Figure 3.
To remove all the extra memory areas after a CLEAR#, any Microdrive maps (plus any additional channel information) have to be reclaimed from
the memory map, and everything above shifted down, while all the system pointers are altered. The ROM routine at #19E5 is designed to do just that with the location of the first bytes to be reclaimed in DE, and the first location to be left alone in HL. The routine initially tests to see if CHANS is equal to 23792, and if it does not then any bytes in the Microdrive maps area are reclaimed. Then the byte at CHANS+20 is tested to see if it is the end marker of #80. If it is not then any extra channel information is reclaimed.
The third routine, COLAPS, first checks to see if CHANS is less than 23735, and returns if it is. If it is not then it means that the extra system variables exist; these are reclaimed, again using the ROM routine at #19E5. The extra bytes are created by the Interface 1 whenever an error occurs, when an incorrect Basic line is entered, or when an Interface 1 command is entered.


Those not understanding Z-80 machine code are likely to find the rest of this article something of a closed book although, of course, you can still use the routines. Figure 2 is the assembler listing of all the routines, and it was produced on the excellent HiSoft GENS assembler, which uses the unusual method of signifying hexadecimal numbers by preceding them with '#'.
The first routine starts at TESTRM, and carries out a memory test that the
Memory Map

Figure 3. The area of the Spectrum memory map affected by the second of the three routines.

Home Contents KwikPik