CONTENTS INTRODUCTION USE OF HOOK CODES EXTENSIONS TO BASIC Basic loader program Assembler Listings Main program A simple ‘double POKE’ routine: POKE * x,y Pokeing strings into memory: POKE n,”s” Memory dump: *L n Modified EDIT function: *E n An improved sound command: BEEP *a,b,c,d A faster and more complete catalogue: * CAT n Pseudo—random file handling: READ #S,N Adding data to a file: RESTORE #S Extending the RS—232 channel Extending Spectrum BASIC THE SHADOW ROM DISASSEMBLY The restart routines The control routine The syntax checking routines The RS—232 link routines The Network routines The Microdrive routines The ‘Hook code’ routines The Microdrive command routines The ‘not used’ routines APPENDIX Labels sorted by address value Labels sorted alphabetically ‘Shadow’ system variables Channels Bibliography Index to routines Shadow ROM issue 2 How to tell which edition Interface 1 you have Basic loader program for edition 2 Shadow ROM Extended BASIC commands from assembler for edition 2 Shadow ROM What to do if you have an unknown ROM INTRODUCTION The Sinclair ZX Interface I adds enormously to the power of the ZX Spectrum, allowing it to send and receive data over an RS—232 link, to use the Local Area Network, and to store information on the Microdrives. Equally impressive is its ability to expand the BASIC provided with the computer, adding new and powerful commands. Much of this power is due to the 8K monitor program which is housed in an 8K Read Only Memory in the Interface 1. This ROM, which is kept between memory adresses 0000H and 1FFFH is "paged" back and forth with the main ROM so that both ROMs appear to occupy the same section of memory. This book provides a complete listing of this program, fully commented and explained, permitting you to use these routines in your programs. In addition, many examples are given of how to expand the Spectrum's BASIC by using the Interface 1 to define new commands. I feel that this book should be of interest to all users of the Interface 1. Those without experience in machine code programming can use the new BASIC commands provided, whether or not they own an assembler. More ambitious programmers will find numerous hints for the creation of the their own routines, and the algorithms controlling the Microdrive, the RS—232 link, and the Local Area Network will be of interest to even the most expert programmer. I should like, finally, to thank Massimiliano, Carlo, Giovanna, Sylvia, and Mr. Alfred Milgrom (of Melbourne House Ltd.). A special thanks must go to the entire staff of Sinclair Research Ltd. Gianluca Carri Florence, Italy, January 1985. USE OF HOOK CODES While the disassembly of the ROM given here will be a valuable aid to machine code programmers wishing to use the Interface I, there is one problem: Sinclair Research have not used the same ROM in every Interface 1. There are two different editions of the ROM. Each, of course, does the same job of running the Microdrives, the RS—232 interface, and the Local Area Network, but there are a number of minor differences in the actual code contained in the ROMs. The differences between the two editions are described in appendix 7. Does this mean that we can never rely on being able to write programs that can run on all machines? Far from it. Sinclair Research have provided a way to access a number of the ROM routines in a way which can be guaranteed to work on all machines. To do this, we use what are called hook codes. These consist of a RST 8 instruction followed by a byte whose value depends on which hook code you are using. Their effect is to page the ROM in, call a routine in the Interface 1's 'shadow ROM', then page the main ROM back in and return control to the users program. This provides 'transparant' access to the Interface 1 — the user doesn't need to know anything about the ROM, only about the various hook codes. The following example shows the use of hook code 20H (which tests to see if a key has been pressed) from machine code: ORG 7D00H ;32000 dec EXAMPLE RST 0008H ;hook code restart DEFB 20H ;check keypress RET END To do the same thing from BASIC: POKE 32000,207: POKE 32001,32: POKE 32002,201: RANDONISE USR 32000 The hook codes available for your use are numbered from 1BH to 32H (27 to 50 decimal). The hook codes are all fully described in the disassembly, from 1981H to 1B6DH. If you use the hook codes within your programs, instead of calling the shadow ROM subroutines, there will be no need to change your program if Sinclair make further changes to the ROM. Otherwise you will need to update all the absolute references to the shadow ROM. In using hook codes, only the contents of the A register may be passed to the subroutines being called. The subroutines do not preserve any registers, so be sure to save all of the main set of registers before you use any hook codes. Some of the more complex routines corrupt HL', the return address to BASIC, so you may wish to preserve this. Although the individual hook codes are dealt with in detail in the disassembly, here is a brief summary of their actions: 1BH - Accepts a character from the keyboard. 1CH - A character is output to stream 2, which is normally the upper part of the screen. 1DH - Accepts a byte of data from the RS—232 link. 1EH - Sends a byte of data to the RS—232 link. 1FH - A character is output to stream 3, which is normally the ZX printer. 20H - Tests for keypress. The next twelve hook codes refer to the Microdrives. 21H - Select drive. Can be used to turn any drive on, or all drives off. 22H - Open channel. Allows the user to create a microdrive channel. 23H - Close channel. The Microdrive channel is reclaimed. 24H - Delete file. Used to erase a named file from a Microdrive channel. 25H - Read sequential. Allows the user to fetch the 'next' record of a named file. 26H - Write record. Writes a new record onto the next free sector of a microdrive cartridge. 27H - Read random. Similar to 'read sequential', except that the record read need not be the next one in the file. 28H - Reads a record from a specified sector of tape. 29H - Reads the record from the next sector of tape that passes under the read head of the Microdrive. 2AH - Writes a record to a specified sector of tape. 2BH - Due to a programming error, this has the same effect as 'create channel' in the first issue ROM. This should be corrected in later issues. 2CH - Reclaims the memory used by a Microdrive channel. The following four hook codes refer to the local area network. 2DH - Opens a network channel. 2EH - Closes a network channel. 2FH - Fetches a 'packet' of information from a network channel. 30H - Sends a packet over a network channel. 31H - Creates the new system variables used by the Interface 1. This happens when the system is powered up, and when NEW is typed, but it also can be done manually. 32H - This routine is different from the other hook codes in that it can be used to call any routine in the shadow ROM. The shadow ROM is paged in, the routine whose address is held in the system variable HD-11 (held at address 5CEDH) is called, and the main ROM is paged back in. Another use for hook code 32H is paging in the Shadow ROM. If you want the Shadow ROM to sit in main memory, where the main ROM normally is, and to be directly accessible to your program, use the following program fragment to page the Shadow ROM in: LD HL,LABEL LD (23789),HL RST 8 DEFB 32H LABEL POP HL POP HL To page the main ROM back in, simply do CALL 0700H For more information about the hook codes and the ZX Interface 1, see the 'Spectrum Microdrive Book' by Dr. Ian Logan. also published by Melbourne House. EXTENSIONS TO BASIC This section of the book shows how to add a number of new commands to the Spectrums BASIC. Those with no knowledge of machine code, or simply no interest in it can simply type the routines that follow into their Spectrums, save them onto tape or Microdrive, and instantly have a more powerful BASIC. Machine code programmers will find the programs valuable examples of how to use the Interface 1 ROM routines, and should be interested by the way in which new commands are added to BASIC. A later section will explain how this is done. The extensions to BASIC consist of a number of machine code routines, each of which makes up a new BASIC command, along with a main program which will prepare the computer to run the new commands. The new BASIC includes improvements to the POKE, CAT, and BEEP commands, a better version of EDIT, more versatile file handling for the Microdrives, an extension to the RS—232 channel, and a useful memory dump command which will list the contents of an area of memory, in both hexadecimal and ASCII form. Sinclair Research have released two different versions of the Interface 1. Each of the versions contains a slightly different program in its ROM. The newer version of the ROM has corrected a number of errors contained in the previous edition, as well as adding some new routines. Because new code has been added to the Shadow ROM at various points, many of the routines in the ROM are no longer located at the same address as before. As the extensions to BASIC given in this book make use of many routines from the Shadow ROM, you will have to do slightly different things to implement the BASIC extensions, depending on which edition of the Interface 1 you own. First of all you'll have to figure out which edition of the Interface you own. Instructions on how to do this are given in Appendix 8 on page 155. If you find you have an edition 1 ROM in your Interface 1, you will find instructions on how to add the new commands to Basic on page 11 for those who have an assembler, or on page 7 for those who don't have access to an assembler. If you have an edition 2 ROM, then turn to Appendix 10 on page 161 if you have an assembler, or Appendix 9 on page 157 if you don't, for instructions on how to add the new BASIC commands to your Spectrum. Although there are only two editions of the Shadow ROM at the moment, there is some possibility that Sinclair Research may release further editions of the Interface 1. Should you own one of these, it is likely that the extended BASIC commands given here will not work properly with it. If the extended BASIC commands do not work for you, and you suspect that you might have a third edition or later Shadow ROM, turn to Appendix 11 on page 165 to find out how you can implement the new commands. Basic loader program (For owners of Interface 1s equipped with the edition 1 ROM) If you do not have an Assembler, you may enter the routines into your Spectrum with the following BASIC loader program. Enter this program into your Spectrum. 1 CLEAR 63743 10 FOR A=63744 TO 65046 STEP 12 20 PRINT "ADDRESS:";A'' 30 LET C=0 40 FOR B=l TO 12 50 LET Z=A+B-1: IF Z<=65046 THEN INPUT X: PRINT X: POKE Z,X: LET =C+X 60 NEXT B 70 PRINT '"CHECKSUM=";C 80 INPUT "THIS IS WROMG ? (Y/N) ";LINE Y$: IF CODE Y$=89 OR CODE Y$=l2l THEN PRINT "Retype from address ";A: PAUSE 100: CLS: GO TO 20 90 IF CODE Y$<>78 AND CODE Y$<>l10 THEN GO TO 80 100 CLS: NEXT A 110 PRINT "SAVING THE PROGRAM" 120 SAVE *"M";1;"SHADP"CODE 63744,1303 When you have finished typing this program into the Spectrum, you should 'RUN' it. You should then type, from the listing on the next page, the 12 bytes from the address shown on the screen. When you have typed the first 12 bytes, a 'checksum' should be displayed on the screen; if it matches with the one printed on the listing, at the right—hand side of each line, then you have not made mistakes in typing the numbers, and you may enter "N" or "n" to continue with the next line. If the checksums do not match, you must enter 'y' or 'Y', and then retype the whole line. When all numbers have been entered, the program will automatically be saved on Microdrive cartridge (there must be a cartridge with at least 2K free into Microdrive 1). IF you wish to save the program on tape, line 120 of the listing should be modified. When at later time you wish to use the routines, you have simply to place the cartridge into Microdrive I, and then to enter the following direct commands: CLEAR 63743: LOAD *"M";1;"SHADP"CODE: RANDOMIZE USR 63744 And the new commands should be available. Note that if you use NEW command, you must re—enter the command 'RANDOMIZE USR 63744' to reinitialise the VECTOR system variable. 63744: 207 49 33 9 249 34 183 92 201 215 24 0 1296 63756: 254 244 202 45 249 254 42 202 114 249 254 215 2324 63768: 202 11 250 254 227 202 188 251 254 229 202 12 2282 63780: 252 254 224 202 175 252 195 240 1 215 32 0 2042 63792: 254 42 194 75 249 215 121 28 205 183 5 215 1786 63804: 153 30 197 215 153 30 197 225 193 113 35 112 1653 63816: 195 193 5 215 130 28 254 44 194 240 1 215 1714 63828: 32 0 215 140 28 205 183 5 215 241 43 197 1504 63840: 213 215 153 30 80 89 225 193 120 177 202 193 1890 63852: 5 237 176 195 193 5 215 32 0 254 207 202 1721 63864: 102 250 246 32 254 108 194 197 249 215 32 0 1879 63876: 215 130 28 205 183 5 215 153 30 96 105 124 1489 63888: 205 135 30 125 205 135 30 62 32 205 169 30 1363 63900: 229 6 6 197 126 205 158 30 35 16 249 193 1450 63912: 225 126 230 127 254 32 56 6 254 128 48 2 1488 63924: 24 2 62 32 205 169 30 35 16 235 62 13 885 63936: 205 169 30 24 202 254 101 194 240 1 215 32 1667 63948: 0 215 130 28 205 183 5 215 153 30 253 203 1620 63960: 12 126 202 240 1 120 230 192 194 240 1 237 1795 63972: 67 73 92 237 123 61 92 33 7 250 229 42 1306 63984: 61 92 229 33 127 16 229 237 115 61 92 253 1545 63996: 54 0 255 215 169 15 33 56 15 229 199 225 1465 64008: 195 180 18 215 32 0 254 42 194 240 1 215 1586 64020: 121 28 254 44 194 240 1 215 121 28 205 183 1634 64032: 5 215 148 30 245 215 148 30 167 40 54 79 1376 64044: 6 0 197 215 148 30 167 40 44 79 6 0 932 64056: 197 215 153 30 197 205 0 7 225 209 193 241 1872 64068: 229 245 197 229 213 205 181 3 209 225 193 241 2370 64080: 167 237 66 48 240 61 225 32 235 33 193 5 1542 64092: 34 237 92 207 50 253 54 0 0 239 215 32 1413 64104: 0 205 30 6 205 183 5 205 109 6 62 2 1018 64116: 215 1 22 205 232 15 221 126 25 205 247 23 1537 64128: 205 196 18 33 9 251 17 24 0 205 5 251 1214 64140: 205 65 19 32 239 33 9 251 203 78 32 232 1390 64152: 58 9 251 33 12 251 182 230 2 194 169 250 1641 64164: 205 254 18 24 215 58 13 251 183 40 209 58 1528 64176: 10 251 183 32 203 221 126 41 221 190 13 40 1531 64188: 22 205 33 251 205 0 251 221 126 13 183 194 1704 64200: 128 250 221 126 41 221 119 13 195 128 250 221 1913 64212: 229 175 205 247 23 205 0 251 221 229 225 17 2027 64224: 44 0 25 205 178 251 205 0 251 205 56 29 1449 64236: 123 203 63 215 40 45 215 227 45 205 0 251 1632 64248: 221 225 205 196 16 195 193 5 62 13 195 102 1628 64260: 29 229 195 173 24 0 0 0 0 0 0 0 650 64272: 0 0 0 0 0 0 0 0 0 0 0 0 0 64284: 0 0 0 0 0 33 140 92 54 255 33 13 620 64296: 251 205 178 251 62 32 205 102 29 58 9 251 1633 64308: 203 87 194 62 251 62 245 195 102 29 33 24 1487 64320: 251 126 183 202 99 251 254 3 202 157 251 61 2040 64332: 245 62 228 205 102 29 58 29 251 230 31 198 1668 64344: 96 205 102 29 241 200 62 36 195 102 29 33 1330 64356: 32 251 126 230 192 192 43 62 202 205 102 29 1668 64368: 94 35 86 235 17 16 39 205 143 251 17 232 1370 64380: 3 205 143 251 17 100 0 205 143 251 17 19 1345 64392: 0 205 143 251 17 1 0 62 255 60 183 237 1414 64404: 82 48 250 25 246 48 195 102 29 62 175 205 1467 64416: 102 29 35 229 35 35 205 112 251 62 44 205 1344 64428: 102 29 225 195 112 251 6 10 126 205 102 29 1392 64440: 35 16 249 201 215 32 0 254 35 194 240 1 1472 64452: 215 121 28 205 183 5 215 148 30 245 215 148 1758 64464: 30 254 16 210 99 6 215 1 22 221 42 81 1197 64476: 92 221 126 4 254 77 194 45 6 221 203 24 1467 64488: 70 194 50 17 241 221 119 13 221 126 25 205 1502 64500: 247 23 33 255 0 34 201 92 205 132 11 175 1414 64512: 221 119 11 221 119 12 205 247 23 195 193 5 1571 64524: 215 32 0 215 130 28 205 183 5 215 148 30 1406 64536: 254 16 210 99 6 215 1 22 221 42 81 92 1259 64548: 221 126 4 254 71 194 45 6 221 203 24 70 1445 64560: 194 2 9 221 126 25 205 247 23 33 255 0 1340 64572: 34 201 92 205 165 17 56 19 40 14 221 203 1267 64584: 67 78 49 11 221 126 41 221 119 13 24 3 964 64596: 205 254 18 205 18 19 32 227 219 239 230 1 1667 64608: 202 197 26 205 75 26 218 163 17 221 110 69 1529 64620: 221 102 70 221 117 11 221 116 12 221 203 24 1539 64632: 198 205 62 30 205 196 18 221 126 13 221 190 1685 64644: 41 32 245 62 230 211 239 1 104 1 205 250 1621 64656: 24 221 229 225 11 55 0 25 205 120 24 62 1207 64668: 238 211 239 205 254 18 221 126 68 221 119 13 1933 64680: 175 205 247 23 195 193 5 215 32 0 254 33 1577 64692: 40 1l 254 47 40 33 254 63 40 54 195 240 1271 64704: 1 215 121 28 205 183 5 215 148 30 167 202 1520 64716: 245 253 50 16 254 215 148 30 61 50 15 254 1591 64728: 195 193 5 215 121 28 205 183 5 215 148 30 1543 64740: 50 17 254 215 148 30 50 18 254 175 50 22 1283 64752: 254 195 193 5 215 32 0 215 130 28 205 183 1655 64764: 5 215 148 30 254 1 40 12 62 3 253 203 1226 64776: 124 142 205 24 23 195 193 5 62 3 215 30 1230 64788: 23 33 17 0 167 237 66 218 47 5 205 19 1037 64800: 11 213 33 5 0 25 17 53 253 115 35 114 874 64812: 62 3 50 216 92 209 195 74 11 254 165 210 1541 64824: 64 12 253 203 1 134 254 32 56 85 32 4 1130 64836: 253 203 1 198 245 62 1 50 19 254 241 205 1732 64848: 60 12 58 15 254 71 58 14 254 184 48 5 1033 64860: 60 50 14 254 201 205 105 253 175 50 19 254 1640 64872: 201 62 1 50 19 254 61 50 14 254 58 20 1044 64884: 254 167 196 90 12 58 21 254 167 196 90 12 1517 64896: 58 18 254 71 58 22 254 60 184 32 8 58 1077 64908: 17 254 167 196 90 12 175 50 22 254 201 254 1692 64920: 13 32 12 58 19 254 167 62 1 50 19 254 941 64932: 200 24 194 254 6 32 33 42 14 254 58 16 1127 64944: 254 71 14 0 12 44 125 188 48 167 144 40 1107 64956: 4 48 251 24 243 197 62 32 205 53 253 193 1565 64968: 13 32 246 201 254 23 192 17 221 253 42 81 1575 64980: 92 1 5 0 9 115 35 114 201 50 15 92 729 64992: 17 229 253 24 237 17 53 253 205 210 253 58 1809 65004: 15 92 71 58 15 254 184 48 5 253 54 0 1049 65016: 10 239 58 14 254 144 200 48 5 237 68 79 1356 65028: 24 187 197 205 105 253 193 72 24 179 0 80 1519 65040: 20 12 60 1 13 10 0 116 Assembler Listings (For Interface 1s equipped with the edition 1 Shadow ROM.) The following is a complete, fully commented assembler listing of the machine code programs which make the new BASIC commands possible. These consist of a main program which sets up the new system variables needed by the Interface 1, and a number of small programs, one of which is used by each new command. The equate statements used by these routines are included in a seperate table at the end of the listings. To add the new BASIC commands to your Spectrum, enter the assembler program on the following pages, as well as the table of EQU statements that follows it, into your assembler, assemble it, and save the resulting machine code on tape or microdrive. When you wish to use the new BASIC commands, load the machine code file into your Spectrum at 63744 (F900 Hex.), and do RANDOMIZE USR 63744 to make the new commands available. All readers of this book should at least glance through this section, as interspersed with the listings of the new commands are examples of their use, and explanations of their functions. A brief explanation of the manner in which new commands are added to BASIC is given later in the book, and it may prove useful in understanding what is being done in this section. Main program The program starts at the address F900 hex (63744 decimal), and is located above RAMTOP. When it is used for the first time, you must use a command RANDOMIZE USR 63744 to initialise the system variable VECTOR. You must do this whenever the initial VECTOR contents are defaulted back to ERR_6 (01F0). This happens when you use a NEW command to delete the BASIC program from the memory. ORG 0F900H ; MAINPG EQU $ ; RST ERROR_1 ;Create new system variables if DEFB HOOK31 ;nonexistent. LD HL,STSYN ;Store start address of new routine LD (VECTOR),HL ;into VECTOR. RET Note that initially 'hook code' +31 is used to create the new system variables if they do not already exist. Failure to do so in your programs will cause a probable crash when you try to POKE something into the location where the 'new' system variables should be. The address of the syntax module routine STSYN is then stored into VECTOR. This causes the routine STSYN to be used whenever a command fails the syntax of the main ROM interpreter, and then that of the shadow ROM interpreter. The system variable CH_ADD will point to the first character of the command that produces the error. The routine STSYN is listed below. STSYN RST CALBAS DEFW GET_CHAR ;Fetch command code. CP POKE ;Jump to the appropriate routine, JP Z,PGM1 ;depending on the command code. CP "*" JP Z,PGM3 CP BEEP JP Z,PGM5 CP READ JP Z,PGM7 CP RESTORE JP Z,PGM8 CP LPRINT JP Z,PGM9 JP ERR_6 ;Give an error if none of these. Note that the 'main' ROM restart GET_CHAR is used to fetch the command code into the A register; then a jump is made to the required syntax module routine. If the command code is still wrong, the error is confirmed by jumping to ERR_6. A simple 'double POKE' routine: Poke * x,y The first implemented 'new' command is a 'double POKE' command. That is, a POKE command that uses word operands (16 bits) instead of byte operands (8 bits). The syntax is 'POKE *x,y•, where 'a' is the address in the range 0..65535, and 'y' is the value to be poked at location 'a', again in the range 0..65535. Note that the standard Intel format is used, i.e. the low byte goes before the high byte in memory. You may use the new POKE command, for example, to store values into two—byte system variables: POKE *23675,32000 is a rather straightforward way of changing to '32000' the contents of the UDG system variable, as compared with the usual: POKE 23675,32000~256*INT (32000/256) POKE 23676,INT (32000/256) The machine code program used to do this is very simple: PGM1 RST CALBAS DEFW NEXT_CHAR ;Advance CH_ADD. CP "*" ;Jump if it is not a POKE *x,y command. JP NZ,PGM2 RST CALBAS DEFW NEXT_2NUM ;Evaluate the two parameters. CALL ST_END ;Confirm end of statement. RST CALBAS DEFW FIND_INT2 ;Fetch number to be POKEd. PUSH BC ;Save it. RST CALBAS DEFW FIND_INT2 ;Fetch address. PUSH BC ;Move it into HL. POP HL POP BC ;Restore value. LD (HL),C ;POKE the low byte. INC HL LD (HL),B ;POKE the high byte. JP END1 ;Finished. Initially the syntax of the new command is checked; CH_ADD is advanced to the character that follows the token 'POKE', and if the character '*' is not present, a jump is made to the command for pokeing strings into memory (because the current command is not POKE *x,y). Assuming that our current command is POKE *x,y, the 'main' ROM routine NEXT_2NUM is then used to evaluate two numeric expressions (separated by a comma), following the character pointed by CH_ADD. An error will occur if the expressions have incorrect syntax. Otherwise the syntax is correct and the call to ST_END returns to the 'main' ROM during syntax checking. During runtime the execution continues, and the main ROM routine FIND_INT2 is used to fetch the values from the calculator stack. After the POKE * has been done, control is returned to the main ROM interpreter by jumping to END1. Pokeing strings into memory: POKE n,"s" This command makes it possible to POKE a string in memory, starting from the address 'n'. For example, the statement: POKE 30000, "FRED BLOGGS" Will POKE the ASCII values of the characters in the string "FRED BLOGGS", starting from the address 30000. You may check this by reading back the values with PEEK: FOR A=30000 TO 30010: PRINT CHR$ PEEK A;: NEXT A Note that the routine fails the syntax of the interpreter by using a different parameter type (i.e. a string instead of a number), while the previous routine used a '*' character following the command code. PGM2 RST CALBAS ;Evaluate the address. DEFW EXPT_1NUM CP COMMA ;A separator must be present. JP NZ,ERR_6 ;Report the error if it is not present. RST CALBAS ;Advance CH_ADD. DEFW NEXT_CHAR RST CALBAS ;Evaluate string expression. DEFW EXPT_EXP CALL ST_END ;Confirm end of statement, RST CALBAS ;Fetch string parameters. DEFW STK_FETCH PUSH BC ;Save 'length' and 'start'. PUSH DE RST CALBAS ;Fetch address. DEFW FIND_INT2 LD D,B ;Move address into DE. LD E,C POP HL ;Restore string 'start' and 'length'. POP BC LD A,B ;Exit with null string. OR C JP Z,END1 LDIR ;The actual POKE. JP END1 ;Finished. The routine is entered from the POKE *x,y routine with CH_ADD pointing to the character following the 'POKE' token. The main ROM routines EXPT_ 1NUM and EXPT_EXP are then used, respectively to evaluate a numeric and a string expression. A comma must be placed between them as separator. During runtime, the main ROM routines STK_FETCH and FIND_INT2 are used to fetch the string parameters, and the value of the numeric expression. No action is taken iF the string has null length. Memorydump: *L n This routine creates a new command '*L n' that lists the memory contents, starting from the address n, in both hexadecimal and ASCII. Unprintable ASCII codes ate printed as spaces. For example, the following statement: *L 31920 Will list the contents of the memory starting from address 31920. Note that when dumping memory at addresses lower than 16384, the 'shadow' ROM code is shown. Try for example to dump from the address 695, that is the start of the 'shadow ROM report messages table. The result will be as follows: 02B7 00 50 72 6F 67 72 Progr 02BD 61 6D 20 66 69 6E am fin 02C3 69 73 68 65 64 01 ished 02C9 41 6F 6E 73 65 6E Nonsen 02CF 73 65 20 69 6E 20 se in 02D5 42 41 53 49 43 02 BASIC .... .... The routine follows: PGM3 RST CALBAS ;Advance CH_ADD. DEFW NEXT_CHAR ;Jump if the command is CAT. CP CAT JP Z,PGM6 OR 20H ;Make the letter lower case. CP "l" ;Jump if this is not an "*L" command. JP NZ,PGM4 RST CALBAS DEFW NEXT_CHAR ;Advance CH_ADD. RST CALBAS DEFW EXPT_1NUM ;Evaluate start address. CALL ST_END ;Confirm end of statement. RST CALBAS ;Fetch start address. DEFW FIND_INT2 LD H,B ;Move it into HL. LD L,C AGAIN LD A,H ;Display high byte of address in hex. CALL DISP_HEX LD A,L ;Display low byte. CALL DISP_HEX LD A,SPACE ;Print a space. CALL DISP_CH PUSH HL ;Save current address. LD B,6 ;Display 6 bytes. PUSH BC ;Save counter for later, L_LOOP LD A,(HL) ;Fetch a byte. CALL DISPHEX2 ;Display it in hex. INC HL ;Examine each byte in turn. DJNZ L_LOOP POP BC ;Restore counter and address. POP HL C_LOOP LD A,(HL) ;Fetch a byte. AND 7FH ;Clear bit 7. CP SPACE ;Reject codes lower than SPACE. JR C,REJECT CP 80H ;Reject codes greater than 7FH. JR NC,REJECT JR ACCEPT REJECT LD A,SPACE ;Replace invalid codes with 'space' ;code. ACCEPT CALL DISP_CH ;Print the character. INC HL ;Advance pointer. DJNZ C_LOOP ;Continue the toop. LD A,CR ;Finally print a carriage return. CALL DISP_CH JR AGAIN ;Jump back. This time, the interpreter syntax is failed by starting the command with a non—standard character, namely, a '*'. The letter 'L' (for 'L'ist) maybe either upper or lower case. Note that the shadow ROM routines DISP_HEX, DISP_HEX2 and DISP_CH are used to print characters onto stream 2 (the screen). Note also that the command will never end during runtime. This, however, will not result in an endless loop, as you may simply press BREAK when the 'scroll' message is displayed on the screen, to stop the listing. The output may be directed to a device other than the screen by first using an OPEN command. i.e. OPEN #2,"T" will direct the output to the RS232 "T" channel. The main ROM routines EXPT_1NUM and FIND_INT2 are used to evaluate and fetch the given parameter 'n'. Modified EDIT function: *E n The normal 'EDIT' function is not very well implemented; if you wish, for example, to EDIT line 4385 of your program, you must first make the line 'current' by using something like LIST 4385, and then (after having pressed BREAK to stop the listing) press the EDIT key. By using this routine, you may type simply '*E 4385' to do the same thing. The listing of the routine follows: PGM4 CP "e" ;Error if it is not the '*E' command. JP NZ,ERR_6 RST CALBAS ;Advance CH_ADD. DEFW NEXT_CHAR RST CALBAS ;Evaluate line number. DEFW EXPT_1NUM CALL ST_END ;Confirm end of statement. RST CALBAS ;Fetch line number. DEFW FIND_INT2 BIT 7,(IY+PPC_HI) ;Accept only as 'direct' command. JP Z,ERR_6 LD A,B ;Error with line number out of range. AND 0C0H JP NZ,ERR_6 LD (E_PPC),BC ;Make this line 'current'. LD SP,(ERR SP) ;Clear machine stack. LD HL,ENDED ;Final return address. PUSH HL LD HL,(ERR_SP) ;Save current error address. PUSH HL LD HL,ED_ERROR ;The new error address. PUSH HL LD (ERR_SP),SP LD (IY+ERR_NR),0FFH ;Clear the error. RST CALBAS DEFW ED_EDIT ;Copies the line into the editing area. LD HL,ED_LOOP ;Return to 'EDitor LOOP', and to ENDED PUSH HL ;below when finished. RST MAIN_ROM ; ;NOTE: Main ROM in use. ; ENDED POP HL ;Remove +l303 from the stack. JP 12B4H ;Jump back to the main execution loop. Note that the command is rejected at runtime (BIT 7,PPC_HI) if it is not a 'direct' one: this is because an EDIT command used within a program does not make sense. The command is also rejected if you specify wrong line numbers. If you use a nonexistent line number, the next existent number is used. The routine enters the main ROM 'EDITOR' subroutine, after having copied the line into the editing area, and returns to the main execution loop when finished. An improved sound command: BEEP *a,b,c,d The standard 'BEEP x,y' command is very limited: it will only make sounds of a constant pitch. This routine creates a new 'BEEP' command that accepts four parameters, giving an endless range of possible sound effects. The syntax of the new command is 'BEEP * a,b,c,d', where 'a' and 'b' are the values that the main ROM 'BEEPER' subroutine accepts as 'pitch' and 'length', 'c' is a 'step' value that will be subtracted from 'a' until it reaches zero, and 'd' is a 'repeat' value that defines how many times the whole sound must be made. Try the following statement: BEEP * 100,255,10,1 The following BASIC program will generate a wide range of sounds: 10 LET a=RND*1000+10 20 LET b=RND*6+1 30 LET c=RND*50+1 40 LET d=RND*3+1 50 BEEP *a,b,c,d 60 GO TO 10 The routine is listed below: PGM5 RST CALBAS ;Advance CH_ADD. DEFW NEXT_CHAR CP "*" ;The '*' must be present. JP NZ,ERR_6 RST CALBAS ;Evaluste 'a','b' DEFW NEXT_2NUM CP COMMA ;A separator must be found after 'b'. JP NZ,ERR_6 RST CALBAS ;Evaluate 'c','d'. DEFW NEXT_2NUM CALL ST_END ;Confirm end of statement. RST CALBAS ;Fetch 'd'. DEFW FND_INTl PUSH AF ;Save it. RST CALBAS ;Fetch 'c'. DEFW FND_INTl AND A ;Give an error if c=0. JR Z,RANGE LD C,A ;Otherwise move it into BC. LD B,0 PUSH BC ;Save it. RST CALBAS ;Fetch 'b'. DEFW FND_INT1 AND A ;Give an error if b=0. JR Z,RANGE LD C,A ;Move it into BC. LD B,0 PUSH BC ;Save 'b' briefly. RST CALBAS ;Fetch 'a'. DEFW FIND_INT2 PUSH BC ;Save it temporarily. CALL UNPAGE ;Use main ROM. POP HL ;Restore 'a', 'b', 'c' and 'd' values. POP DE POP BC POP AF LOOP2 PUSH HL ;Save 'a' for next pass. LOOP1 PUSH AF ;Save values. PUSH BC PUSH HL PUSH DE CALL BEEPER ;Emit a sound. POP DE ;Restore values. POP HL POP BC POP AF AND A SBC HL,BC ;Subtract 'step' from 'a'. JR NC,LOOP1 ;Continue while subtraction possible. DEC A ;Decrease 'd' POP HL ;Restore 'a' for repetition. JR NZ,L00P2 ;Repeat the sound until d=0. LD HL,END1 ;Note how the return is made to the LD (HD_11),HL ;shadow ROM. RST ERROR_1 DEFB HOOK32 ; RANGE LD (IY+ERR_NR),0 ;Call the error handling routine. RST ROMERR Note that 'b', 'c' and 'd' must be in the range l..255, ('d' may be set to 8, but this will give the same effect that you would expect from a value of 256.) Be careful that you choose the right length for your sound, as the the BREAK key will not work in the middle of a sound. If you have some difficulty in choosing the correct 'a' and 'b' values, you may calculate them as shown below: a = 437500/frequency-30.l25 b = frequency * time (frequency=Hz, time=sec.) You may also use the following BASIC program which calculates the values for A and B, starting from the 'x', 'y' values used in a normal BEEP command. For example, the sound obtained with BEEP 0.01,10 requires '908' and '4' as A and B values. 10 DATA 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392, 415.3, 440, 466.16, 493.88 20 INPUT "TIME (SEC.) ? ";t 30 INPUT "PITCH ? ";p 40 LET i=INT p: LET pi=p-i 50 LET pk=(pi*.0577622606)+1 60 LET a=i+60: LET b=-6 70 LET b=b+1: LET a~a-12 80 IF SGN a()-1 THEN GO TO 70 90 LET a=a+l2 100 RESTORE: FOR x=0 TO a: READ c: NEXT x 110 LET f=(pk*c)*2-b: IF f*t=0 THEN PRINT "ERROR": STOP 120 PRINT "A=";INT (437500/f-30.125)'"B=";INT (f*t) A faster and more complete catalogue:* CAT n After some 'general purpose' commands come some more complicated routines that use the new Interface's devices. This routine adds a new command '* CAT n' that gives a full catalogue of a cartridge held in the microdrive 'n'. The command runs about 2—3 seconds faster than the standard 'CAT n' command, does not limit the output to 59 names, and provides information on the nature of the file, its length, etc., that is not given when the standard 'CAT' command is used. Since the names are printed as they are found on the cartridge, the list is not alphabetically ordered. Along with each filename the following information will appear: 'PRINT' If it is a PRINT—type file. 'CODE sssss,nnnnn' If it is a 'bytes' file; 'sss' and 'nnn' are respectively the start address and the length of the file. 'DATA x' If it is a numeric array named 'x'. 'DATA x$' If it is a string array named 'x$' 'LINE nnnnn' If it is a BASIC program with autostart at line 'nnn'. If nothing is printed after the filename, then the file is a normal BASIC program saved without the autostart. The routine is listed below. PGM6 RST CALBAS ;Advance CH_ADD. DEFW NEXT_CHAR CALL EXPT_NUM ;Evaluate drive number. CALL CHECK_M_2 ;Check range of drive number. CALL ST_END ;Confirm end of statement. LD A,2 ;Use stream 2 (screen). RST CALBAS DEFW CHAN_OPEN CALL SET_T_MCH ;Create a temporary "m" channel. LD A,(IX+CHDRIV) ;Turn on drive motor. CALL SEL_DRIVE CATLOOP CALL GET_M_HD02 ;Get a header. LD HL,RDESC ;And a record descriptor from the address LD DE,18H ;RDESC. CALL GETD CALL CHKS_HD R ;Repeat until the checksum is correct. JR NZ,CATLOOP LD HL,RDESC ;Repeat also if loaded wrong block type BIT 0,(HL) ;(header). JR NZ,CATLOOP LD A,(RDESC) ;Jump forward with 'not free' sectors. LD HL,RDESC+3 OR (HL) AND 2 JP NZ,PRI_NA CALL RES_B_MAP ;Mark 'free' sectors. JR CATLOOP ; PRI_NA LD A,(RDESC+4) ;Ignore names starting with CHR$ 0. OR A JR Z,CATLOOP LD A,(RDESC+1) ;Ignore other than first records. OR A JR NZ,CATLOOP LD A,(IX+HDNUMB) ;Jump forward when the whole tape has CP (IX+CHREC) ;been examined. JR Z,ENDCAT CALL OUTNAM ;Examine current record. CALL PRCR ;Print a carriage return. LD A,(IX+CHREC) ;Jump unless first time (CHREC=0). OR A JP NZ,CATLOOP LD A,(IX+HDNUMB) ;Store current sector number (to LD (IX+CHREC),A ldetect when the whole tape has been JP CATLOOP ;examined). ; ENDCAT PUSH IX ;Save channel start address. XOR A ;Turn off drive motors. CALL SEL_DRIVE CALL PRCR ;Leave a blank line. PUSH IX ;Make HL point to HDNANE. POP HL LD DE,2CH ADD HL,DE CALL PRNANE ;Print cartridge name. CALL PRCR ;Print a carriage return. CALL FREESECT ;Fetch number of 'free' sectors. LD A,E SRL A ;A holds the number of Kbytes left. RST CALBAS ;Store this number on calculator stack. DEFW STACK_A RST CALBAS ;Print the number on the screen. DEFW PRINT_FP CALL PRCR ;Final carriage return. POP IX ;Restore channel start address. CALL DEL_M_BUF ;Reclaim the channel. JP END1 ;Finished. ; PRCR LD A,CR ;Print a carriage return. JP PRCHAR ; GETD PUSH HL ;Save start address. JP GT_M_BLK ;Fetch descriptor and header information. ; RDESC DEFB l8H ;Space to store record descriptor. ; OUTNAM LD HL,SCR_CT ;Suppresa scrolling. LD (HL),0FFH LD HL,RDESC+4 ;Print record name. CALL PRNAME LD A,SPACE ;Follow it with a space. CALL PRCHAR LD A,(RDESC) ;This is 'RECFLG'. BIT 2,A ;Jump if this is not a JP NZ,NOTPRINT ;'PRINT—type' file. LD A,PRINT ;Otherwise print the keyword 'PRINT'. JP PRCHAR ; LD A,(HL) OR A ;Jump with type=0 (program files). JP Z,PROG CP 3 ;Jump with type=3 (bytes). JP Z,BYTES DEC A ;Save zero flag (set with numeric PUSH AF ;arrays). LD A,DATA ;Print the keyword DATA. CALL PRCHAR LD A,(RDESC+20) ;Fetch array name. AND 1FH ;Clear bit 5,6,7. ADD A,60H ;Obtain an ASCII code. CALL PRCHAR ;Print array name. POP AF ;Return with numeric arrays. RET Z LD A,"$" ;But print '$' with string arrays. JP PRCHAR ; PROG LD HL,RDESC+23 ;Fetch high byte of autostart line no. LD A,(HL) AND 0C0H ;Return if no autostart was specified. RET NZ DEC HL ;Point to the low byte. LD A,LINE ;Print the keyword LINE, and then CALL PRCHAR ;the line number: ; FPRINT LD E,(HL) ;Fetch entry indirectly. INC HL LD D,(HL) EX DE,HL ;Move value into DE. ; PRNUM LD DE,10000 ;Print first digit. CALL PRDIG LD DE,1000 ;Print second digit. CALL PRDIG LD DE,100 ;Print third digit. CALL PRDIG LD DE,10 ;Print fourth digit. CALL PRDIG LD DE,1 ;Print last digit. PRDIG LD A,-1 ;Counter. OUTD INC A ;Increment the counter. OR A ;Clear carry flag. SBC HL,DE ;'Trial subtraction'. JR NC,OUTD ;Continue until borrowing found. ADD HL,DE ;Balance last SBC. OR 30H ;Make the counter an ASCII character JP PRCHAR ;and print it. ; BYTES LD A,CODE ;Print the keyword CODE. CALL PRCHAR INC HL ;Save pointer to 'length'. PUSH HL INC HL INC HL CALL FPRINT ;Print the 'start'. LD A,COMMA ;Print a comma. CALL PRCHAR POP HL ;Finally print the 'length'. JP FPRINT ; PRNAME LD B,10 ;Counts ten characters. PRLOOP LD A,(HL) ;Fetch character, CALL PRCHAR ;Print it. INC HL ;Advance the pointer. DJNZ PRLOOP ;Loop for the whole name. RET The routine can be divided into eleven different sections: 1. A 'temporary "m" channel' and map is created in the CHANS area. 2. The required Microdrive is turned on. 3. The current sector number is stored into CHREC. 4. A 'header' is loaded from the cartridge into the "m" channel header area. 5. The 'record descriptor' and the 'header informations' are loaded into the RDESC area. 6. If the 'header' indicates 'free' sector, the appropriate map bit is reset and the program loops back to step (4) 7. The filename and the various information are taken from the RDESC area and printed on the screen. 8. The program continues looping back to (4) until the whole tape has been examined; this is done by comparing the current sector number against CHREC one. 9. The cartridge name is taken from HDNAME and printed. 10. The number of 'free sectors' is used to print the number of Kbytes left in the cartridge. 11. The Microdrive motor is turned off, and the channel is reclaimed. Names starting with CHR$ 18 are not printed; records other than 'first' ones are not examined, so as to avoid the printing of a filename more than once. Note that the form *CAT #S;N is not supported, because there is not sufficient time to send the information fetched to a channel other than the screen, before the next tape sector is due to be examminined. If you wish to direct the catalogue to a printer, you must use first a command such as: OPEN #2;"m";d;"CAT" and then use the *CAT n command. Finally 'CLOSE #2' will send the catalogue to the Microdrive. It can then be printed with either: MOVE "m";d;"CAT" TO #3 (with the ZX printer) MOVE "m";d;"CAT" TO "b" (with RS232 printers) The catalogue can then be erased with ERASE "m";n;"CAT" (where 'n' is the drive number). In this case, you must take care that the output of the catalogue will not require more than 512 characters to be printed (otherwise unpredictable results may occur when the Spectrum tries to send the record to the Microdrive while the CAT command is operative). This can be done by making sure that there are fewer than 20 files on the cartridge. Note that to fail the syntax of the interpreter, the command begins with a '*' character; the command may not begin with a 'new' command token, such as CAT, SAVE, ERASE, CLS, etc. Pseudo-random file handling: READ #S,N This command will permit a 'pseudo—random' handling of Microdrive files. When READ #S,N is executed, the 'read' Microdrive channel attached to the stream 'S' is used, and record 'n' of that file is loaded into the channel buffer. Since the Microdtive system splits the main 'PRINT—type' files into records 512 bytes long, you may write items with 'length=512', thereby having each record contain a single item, and then read back that item with the READ #S,N command. Such an application is shown by using the following BASIC program. Each item is made by 8 elements (length=63 characters + carriage return) of an array, exactly 512 bytes. Without the READ #S,N command you have to read sequentially all items before reaching the desired one. 10 DIM a$(24,63) 20 REM Some data for the file 30 DATA "THE MICRODRIVES", "give you fast access to a large memory.", "", "Each Microdrive can hold up to 100 Kbytes on a single", "removable cartridge.", "Note that the Microdrive nearest the computer is always known as", "Microdrive 1, and the next along is Microdrive 2, and so on.", "There is also a light on the front of each Microdrive." 40 DATA "THE CARTRIDGES", "come in a protective box; and should always be kept in their", "box when not in use.", "But remember...", "Never take the cartridge out of the Microdrive while the light", "is on.", "Never switch the power on or of while a cartridge is in the", "Microdrive." 50 DATA "THE NETWORK", "enables you and your friends to play computer games together", "and to send each other programs and data.", "This means that only one of you need ever type in a program.", "Using the lead supplied with each Interface you can link up", "as few as two and as many as 64 Spectrum computers." 60 OPEN #4;"M";1;"FILE" 70 FOR a=l TO 24: READ a$(a): NEXT a 80 CLOSE #4 90 CLEAR: REM The file has been cleared. 100 OPEN #4;"M";1;"FILE" 110 CLS: PRINT "Press a key for your choice: "''"0. MICRODRIVES"''"l. CARTRIDGES"''"2. NETWORK"''"3. STOP" 120 PAUSE 0: LET a$=INKEY$; IF a$<"0" OR a$>"3" THEN GO TO 110 130 IF a$="3" THEN CLOSE #4: STOP 140 READ #4,VAL a$ 150 CLS: FOR a=1 TO 8: INPUT #4;a$: PRINT a$: NEXT a 160 PAUSE 0: GO TO 110 If the stream(s) specified in the command is not opened, the error "invalid stream" will occur. "Invalid device expression" will occur if the stream is not attached to an "m" channel; "Reading a 'write' file" will occur if the channel is opened for writing. The cartridge is simply searched for the 'n'th record of the file 'n' being in range 0..255), then it is loaded and CHBYTE cleared so as to direct INKEY$ and INPUT commands to the first byte loaded. If the record is not found, or if any reading error occurs, the error 'File not found' will be reported. The listing of the routine follows. PGM7 RST CALBAS ;Advance CH_ADD. DEFW NEXT_CHAR CP "#" ;A hash sign must be present JP NZ,ERR_6 ;after READ. RST CALBAS ;Evaluate 's','n' DEFW NEXT_2NUM CALL ST_END ;Confirm end of statement. RST CALBAS ;Fetch 'n'. DEFW FND_INT1 PUSH AF ;Save it for later. RST CALBAS ;Fetch 's'. DEFW FND_INT1 CP 10H ;Give an error if 's' is greater than 15 JP NC,NREPORT-2 RST CALBAS DEFW CHAN_OPEN ;Use this stream. LD IX,(CURCHL) ;Fetch channel start address. LD A,(IX+4) ;Fetch channel specifier. CP "M" ;Error if not an "M" channel. JP NZ,NREPORT—3 BIT 0,(IX+CHFLAG) ;Error if the file is opened for JP NZ,RWF—ERR ;writlng. POP AF ;Store record number into CHREC. LD (IX+CHREC),A LD A,(IX+CHDRIV) ;The drive motor is turned on. CALL SEL_DRIVE LD HL,0FFH ;Counts 255 sectors. LD (SECTOR),HL CALL GET_R_LP ;Fetch record. XOR A ;C1ear CHBYTE. LD (IX,CHBYTE),A LD (IX+CHBYTE+1),A CALL SEL_DRIVE ;Switch off drive motor. JP END1 ;Finished. Adding data to a file: RESTORE #S Normally, if you try to write data onto a Microdrive file that has previously been CLOSEd, the error 'Writing to a 'read' file' will occur. This makes the operation of extending a file with more data difficult, as one has to create a new file, copy into it the 'old' one and the 'new' data, and then erase the 'old' file. This is not easy, and is a very slow process. This command will convert the 'read' file attached to the stream 's' back to a 'write' file, thus permiting the addition of more data. When you have finished adding data, you may CLOSE the stream that returns a 'read' file. You may use RESTORE #S again to convert it into a 'write' file if you wish. The following BASIC program will demonstrate this. 5 PRINT "CREATING THE FILE" 10 OPEN #4;"M";1;"NUMBERS" 20 FOR N=1 TO 10 30 PRINT #4;N'N*N 40 NEXT N 50 CLOSE #4 60 PRINT '"READING THE FILE" 70 OPEN #4;"M";l;'NUMBERS" 80 PRINT 90 FOR B=1 TO 10 100 INPUT #4;M;N 110 PRINT "THE SQUARE OF ";M;" IS ";N 120 NEXT B 130 PRINT '"EXTENDING THE FILE" 140 RESTORE #4 150 FOR N=11 TO 20 160 PRINT #4;N'N*N 170 NEXT N 180 CLOSE #4 190 PRINT '"READING EXTENDED FILE" 200 OPEN #4;"M";1;"NUMBERS" 210 PRINT 220 FOR B=l TO 20 230 INPUT #4;M;N 240 PRINT "THE SQUARE OF ";M;" IS ";N 250 NEXT B 260 CLOSE #4 The routine is as folllows: PGM8 RST CALBAS ;Advance CH_ADD. DEFW NEXT CHAR RST CALBAS DEFW EXPT_1NUM ;Evaluate stream number. CALL ST_END ;Confirm end of statement. RST CALBAS ;Fetch stream number. DEFW FND_INT1 CP 10H ;Reject stream number > 15. JP NC,NREPORT-2 RST CALBAS ;Use this stream. DEFW CHAN_OPEN LD IX,(CURCHL) ;Fetch channel start address. LD A,(IX+4) ;Fetch channel specifier. CP "M" ;Error if not an "m" channel. JP NZ,NREPORT—3 BIT 0,(IX+CHFLAG) ;Error also with 'write' files. JP NZ,NREPORT—N LD A,(IX+CHDRIV) ;Turn on drive motor. CALL SEL_DRIVE LD HL,0FFH ;Counts through 255 sectors. LD (SECTOR),HL LOOP CALL G_HD_R ;Fetch header and data block. JR C,NXTS ;Jump with any error. JR Z,RESBIT ;Jump with 'free' sectors. BIT 1,(IX+RECFLG) ;Jump if this is not the last record in JR Z,NXTS ;the file. LD A,(IX+HDNUMB) ;Otherwise fetch sector number to CHREC. LD (IX+CHREC),A JR NXTS RESBIT CALL RES_B_MAP ;Mark 'free' sector. NXTS CALL DEC_SECT ;Continue until the whole tape has been JR NZ,LOOP ;examined. IN A,(0EFH) ;Error with write—protected cartridge. AND 1 JP Z,RS—SH CALL RD_SECTOR ;Fetch the EOF record. JP C,RS—SH2 ;Error with wrong checksum. LD L,(IX+RECLEN) ;Use RECLEN as current position. LD H,(IX+RECLEN+l) LD (IX+CHBYTE),L LD (IX+CHBYTE+1),H SET 0,(IX+CHFLAG) ;Make this a 'write' file. CALL IN_CHK ;Set 'free sector' descriptor. SLOOP CALL GET_M_HD02 ;Fetch a header block. LD A,(IX+CHREC) ;Continue if this is not the one. CP (IX+HDNUMB) JR NZ,SLOOP LD A,0E6H ;Start writing. OUT (0EFH),A LD BC,0168H ;Wait to create a first gap. CALL DELAY_BC PUSH IX ;Make HL point to data block preamble. POP HL LD DE,37H ADD HL,DE CALL OUT_M_BUF ;Erase this sector. LD A,0EEH ;'End of writing' signal. OUT (0EFH),A CALL RES_B_MAP ;Mark 'free' this sector, LD A,(IX+RECNUM) ;Copy RECNUM into CHREC. LD (IX+CHREC),A XOR A Switch off drive motor. CALL SEL_DRIVE JP END1 ;Finished. The steps involved in doing the RESTORE #S command are as follows: 1. A 'Microdrive map' is set—up, for use when the channel is made a 'write' channel. 2. The last record of the file is loaded into the channel area. 3. That record is erased from the cartridge. 4. The channel is marked 'write channel'. As with the READ #S,N command, errors are reported if the stream 'S' is closed, or if it is opened with other than "m" channel, or with "m" channels opened for writing. Extending the RS-232 channel This routine creates three new commmands for time user who has an RS232 printer connected to their Spectrum. Time first command is LPRINT ? n. If n=1, a new RS232 channel is opened, so subsequent LPRINT and LLIST commands will use this for their outputs. If n=0, the "p" channel is defaulted for the LPRINT and LLIST Commands (the ZX Printer). The channel opened has more features than the normal "t" channel. The TAB function and the comma are supported on the printer, the 'leading space bug' present with the "t" channel has been corrected, the CR and LF codes are re—definable, an auto CR feature is supported, and finally a re—definable form—feed code is sent after a certain amount of lines printed, so as to advance to the next page before the printing head reaches the end of the sheet. The second command is LPRINT ! x,y. The parameter 'x' will define the width of the line. If, for example, you specify a width equal to 32, the standard Spectrum screen format is used. A width of 40, 80, 132 columns, or other, is suitable depending on your choice, and on the maximum width that your printer allows. The parameter 'y' will define the number of columns used as step when printing the 'comma' control code. The default value for 'x' and 'y' are 80 and 20. The last command is LPRINT / x,y. In this case, 'x' will define the number of lines that will be printed before the form feed code (which advances to the next page) is sent to the printer (default=60, suitable for 66—line sheets). The parameter 'y' is the form—feed code that your printer accepts; the standard value is 12. You may store codes other than form—feed, such as linefeed, etc., to obtain different results when the 'x' lines have been printed. The CR code is sent as 'CR' followed by 'LF' (Line Feed). If your printer does not need the LF code, you may end up with a double spacing between lines; the problem may be eliminated with POKE 65045,0. The assembly code for our final extension to BASIC is listed below. PGM9 RST CALBAS ;Advance CH_ADD. DEFW NEXT CHAR CP "!" JR Z,OUT1 ;Jump with LPRINT !x,y CP "/" JR Z,OUT2 ;Jump with LPRINT /x,y CP "?" JR Z,OUT3 ;jump with LPRINT ?n JP ERR_6 ;Error if none of these. ; OUT1 RST CALBAS ;Evaluate 'x,y'. DEFW NEXT_2NUM CALL ST_END ;Confirm end of statement. RST CALBAS ;Fetch 'y'. DEFW FND_INT1 AND A ;Reject spacing=0. JP Z,OTRNG LD (CMMSP),A ;Store this value. RST CALBAS ;Fetch 'x'. DEFW FND_INT1 DEC A ;Range of 'x' is from 0 onwards. LD (WIDTH),A ;Store the value. JP END1 ;Finished. ; OUT2 RST CALBAS ;Evaluate 'x,y' DEFW NEXT_2NUM CALL ST_END ;Confirm end of statement. RST CALBAS ;Fetch 'y' DEFW FND_INT1 LD (FFC),A ;Store it. RST CALBAS ;Fetch 'x'. DEFW FND_ NT1 LD (LPAGE),A ;Store it. XOR A LD (CLINE),A ;Clear line counter. JP END1 ;Finished. ; OUT3 RST CALBAS ;Advance CH_ADD. DEFW NEXT_CHAR RST CALBAS DEFW EXPT_1NUM ;Evaluate 'n' CALL ST_END ;Confirm end of statement. RST CALBAS ;Fetch 'n' DEFW FND_INT1 CP 1 JR Z,NEWOUT ;Open new channel if n=1. LD A,3 ;Otherwise stream 3 reverts to "p" RES 1,(IY+FLAGS3) ;channel. CALL CLOSE JP END1 ;Finished. ; NEWOUT LD A,3 RST CALBAS DEFW STR_DATA1 ;Fetch current stream data. LD HL,11H AND A SBC HL,BC JP C,NREPORT—C ;Error if stream is already opened. CALL OP_RS_CH ;Open a "t" channel. PUSH DE ;Save stream data. LD HL,5 ;Make HL point to 'address of output ADD HL,DE ;routine'. LD DE,NRSOUT ;Change this address to NRSOUT below. LD (HL),E INC HL LD (HL),D LD A,3 ;Use stream 3. LD (5CD8H),A POP DE ;Restore stream data. JP OP_STREAM ;Attach channel to a stream. ; NRSOUT CP 0A5H ;Use shadow ROM routine with token codes. JP NC, TCHAN—OUT+4 RES 0,(IY+FLAGS) ;Clear 'leading space' flag. CP SPACE ;Jump forward with control codes lower JR C,CTRL ;than 20H. JR NZ,NOSPC ;Jump if not a space. SET 0,(IY+FLAGS) ;Otherwise set 'leading space' flag. NOSPC PUSH AF ;Save the code temporarily. LD A,1 ;Accept next CR code. LD (CLRCR),A POP AF ;Restore the code. CALL TCHAN_OUT ;Use "t" channel to print it, LD A,(WIDTH) LD B,A LD A,(POSN) CP B JR NC,NLIN ;Jump if POSN>WIDTH. INC A ;Otherwise increment POSN. LD (POSN),A RET ; NLIN CALL ENDLI ;Advance to next line. XOR A ;Disable next CR code. LD (CLRCR),A RET ; ENDLI LD A,1 ;Accept next CR code. LD (CLRCR),A DEC A LD (POSN),A ;Clear POSN. LD A,(CRCD) ;Fetch CR code. AND A CALL NZ,BCHAN_OUT ;Send it unless zero. LD A,(LFEED) ;Fetch LF code. AND A CALL NZ,BCHAN_OUT ;Send it unless zero. LD A,(LPAGE) LD B,A LD A,(CLINE) INC A CP B JR NZ,NOFEED ;Jump if not the end of the page. LD A,(FFC) ;Fetch form feed code. AND A CALL NZ,BCHAN_OUT ;Send it unless zero. XOR A NOFEED LD (CLINE),A ;Store new line number. RET ; CTRL CP CR ;Jump if the code is not CR. JR NZ,NOCR LD A,(CLRCR) AND A ;Check current state of CR flag. LD A,1 ;Reset flag to 1 for later. LD (CLRCR),A RET Z ;Do not do a CR if CLRCR=0. JR ENDLI ;Otherwise loop back. ; NOCR CP PRCOMMA ;Jump if not a comma. JR NZ,NOCOMMA LD HL,(POSN) ;L= POSN H= WIDTH LD A,(CMMSP) LD B,A LD C,0 ONESPC INC C ;Increment counters. INC L LD A,L CP H JR NC,NLIN ;Jump if POSN>=WIDTH. CHKPOS SUB B ;Jump if reached the correct place, or JR Z,SPLOOP ;continue if not. JR NC,CHKPOS JR ONESPC ; SPLOOP PUSH BC ;Print 'C' spaces by calling recursively LD A,SPACE ;this routine. CALL NRSOUT POP BC DEC C JR NZ,SPLOOP RET ; NOCOMMA CP TAB ;Return if not the TAB code. RET NZ LD DE,PAR1 ;Alter output address. ; ALTOP LD HL,(CURCHL) LD B,5 ADD HL,BC LD (HL),E ;Store new output address. INC HL LD (HL),D RET ; PAR1 LD (TVDATA+1),A ;Store 'n'. LD DE,PAR2 ;Output address for next byte. JR ALTOP ; PAR2 LD DE,NRSOUT ;Restore initial output address. CALL ALTOP LD A,(TVDATA+1) ;Fetch column 'n'. LD B,A LD A,(WIDTH) CP B JR NC,GOOD OTRNG LD (IY+ERR_NR),0AH ;Error if 'n' is greater than WIDTH. RST ROMERR GOOD LD A,(POSN) SUB B RET Z ;Return if already in place. JR NC,GRT ;Jump if POSN>'n'. NEG ;A=number of spaces required. LD C,A JR SPLOOP ;Jump back. GRT PUSH BC CALL ENDLI ;First advance to next line. POP BC LD C,B JR SPLOOP ;Jump back to insert the spaces. ; POSN DEFB 0 WIDTH DEFB 80 CMMSP DEFB 20 FFC DEFB 12 LPAGE DEFB 60 CLRCR DEFB 1 CRCD DEFB CR LFEED DEFB 0AH CLINE DEFB 0 ; END The EQU statements given here define all the labels referred to in the preceding program: ; ;Shadow ROM addresses ; MAIN_ROM EQU 00H CALBAS EQU 10H SH_ERR EQU 20H ROMERR EQU 08H NEWVAR EQU 30H ERR_6 EQU 01F0H NREPORT—C EQU 052FH ST_END EQU 05B7H END1 EQU 05C1H EXPT_NUM EQU 061EH NREPORT—2 EQU 0663H CHECK_M_2 EQU 066DH NREPORT—3 EQU 062DH UNPAGE EQU 0700H NREPORT—N EQU 0902H OP_RS_CH EQU 0B13H OP_STREAM EQU 0B4AH TCHAN_ OUT EQU 0C3CH BCHAN_OUT EQU 0C5AH SET_T_MCH EQU 0FE8H DEL_M_BUF EQU 10C4H RWF—ERR EQU 1132H GET_R_LP EQU 1184H RS—SH2 EQU 11A3H G_HD_RC EQU 11A5H GET_M_HD2 EQU 12C4H RES_B_MAP EQU 12FEH DEC_SECT EQU 1312H CHKS_HD_R EQU 1341H CLOSE EQU 1718H SEL_DRIVE EQU 17F7H OUT_M_BUF EQU 1878H GT_M_BLK EQU 18ADH DELAY_BC EQU 18FAH RD_SECTOR EQU 1A4BH RS—SH EQU 1AC5H FREESECT EQU 1D38H PRCHAR EQU 1D66H IN_CHK EQU 1E3EH DISP_HEX EQU 1E87H DISPHEX2 EQU IE9EH DISP_CH EQU 1EA9H ; ;Main ROM addresses ; ERROR_1 EQU 08H GET_CHAR EQU 18H NEXT_CHAR EQU 20H BEEPER EQU 03B5H ED_LOOP EQU 0F38H ED_EDIT EQU 0FA9H ED_ERROR EQU 107FH CHAN_OPEN EQU 1601H STR_DATA1 EQU 1727H NEXT_2NUM EQU 1C79H EXPT_1NUM EQU 1C82H EXPT_EXP EQU 1C8CH FND_INT1 EQU 1E94H FIND_INT2 EQU 1E99H STK_FETCH EQU 2BF1H STACK_A EQU 2D28H PRINT_FP EQU 2DE3H ; ;System variables ; TVDATA EQU 5C0EH ERR_SP EQU 5C3DH E_PPC EQU 5C49H CHURCHL EQU 5C51H SCR_CT EQU 5C8CH VECTOR EQU 5CB7H SECTOR EQU 5CC9H HD_11 EQU 5CEDH ; ;Offsets ; ERR_NR EQU 00H FLAGS EQU 01H CHBYTE EQU 0BH PPC_HI EQU 0CH CHREC EQU 0DH CHFLAG EQU 18H CHDRIV EQU 19H HDNUMB EQU 29H RECFLG EQU 43H RECNUM EQU 44H RECLEN EQU 45H FLAGS3 EQU 7CH ; ;Hook codes ; HOOK31 EQU 31H HOOK32 EQU 32H ; ;Keywords ; BEEP EQU 0D7H CAT EQU 0CFH CODE EQU 0AFH DATA EQU 0E4H LINE EQU 0CAH LPRINT EQU 0E0H POKE EQU 0F4H PRINT EQU 0F5H READ EQU 0E3H RESTORE EQU 0E5H ; ;ASCII ; PRCOMMA EQU 06H CR EQU 0DH TAB EQU 17H SPACE EQU 28H COMMA EQU 2CH Extending Spectrum BASIC The information given in this section, together with the examples given earlier should be sufficient to allow experienced machine code programmers to write their own new BASIC commands, and incorporate them into the Spectrum's BASIC. Non—programmers may still be interested in the details of the Spectrum's BASIC interpreter, and of the ingenious mechanism used to extend it. Please note that this information is primarily designed to give a general explanation of how we have implemented our extended BASIC commands. It is not intended to be a step by step guide to writing new BASIC commands. A fuller explanation of this material is given in The Spectrum Microdrive Book by Dr. Ian Logan, also published by Melbourne House. We should first consider the workings of the Spectrums syntax checking routine. When the syntax checker detects an error in a statement, either as it is entered, or at runtime, a jump is made to the error handling routine. This is done by a RST 8 instruction, followed by a byte which defines the error type. Note the similarities between this and the hook codes discussed earlier. As with the normal hook codes, the RST 8 causes a jump to the Shadow ROM where there is a second examination of the current BASIC statement, to see if it really is an error. It is this 'second chance' that makes it possible for the new BASIC commands provided by the Interface 1 to exist. These new commands are perceived as errors by the Spectrums ROM, so the error routine is called. This passes control to the Interface 1, where the Shadow ROM does its own syntax checking, recognizes the new commands, and performs the appropriate action for each new command, before passing control back to the main Spectrum ROM. Code is provided in the Shadow ROM for checking commands starting with the following keywords: CAT, FORMAT, MOVE, ERASE, OPEN, SAVE, LOAD, VERIFY, MERGE, CLS, and CLEAR. More interesting to us, however, is what happens when a statement 'fails the syntax' (that is, is found to be syntactically incorrect) of both the main ROM and the Shadow ROM. When this happens, the Shadow ROM decides that it really has found an error, and jumps to the address which is stored in a system variable called VECTOR. This address is normally that of a main ROM error handling routine, which will print out an error message and cease execution. However, since the variable VECTOR is in RAM, we can change the value it holds to that of our own syntax checking routine, which will check the statement yet again, to see if it is one of the new commands that we have defined. If the statement is one of our new statements, our syntax checker will call a machine language subroutine which will perform the appropriate actions before returning control to the main ROM, otherwise it will call a routine to print an error message. So, the control routine that must be added to handle a new statement must have two parts: Firstly, there must be a syntax routine which will identify the new command, any parameters that go with it, and the end of the statement it is in. Secondly, there must be a routine which will do the actual work of the command. Finally, of course, the system variable VECTOR must have been redirected to point to the syntax routine, so that 'errors' detected by the Shadow ROM will be redirected to your routine. The syntax of your new command can be anything which will be rejected by the syntax checkers in both the main ROM and the Shadow ROM. Note however, that your command must not start with any of the eleven keywords which are recognised by the Shadow ROM (see above). The execution of the new commands then, is a fairly complex procedure, comprised of the following steps: (i) Command is rejected as being syntactically incorrect by the syntax checking routine in main ROM. Accordingly, an error routine is called, using a RST 8 command. (ii) This causes control to be transfered to the syntax checking routine in the Shadow ROM. (iii) The Shadow ROM syntax checker rejects your statement, and calls the routine whose address is stored in the variable VECTOR. This would normally be the main ROMs "report an error" routine, but since you have previously changed the contents of VECTOR to point to your own syntax checking routine, it will be your routine that is called. (iv) Your syntax routine checks to see that you have given what it regards as a correct command. Once it decides that you have, it calls a routine which you have written to do whatever task is required of the new BASIC command. (v) Your routine returns control to the BASIC program which is currently running. Although the task of extending the Spectrum's BASIC is quite complex a close study of the examples given in this book should be quite rewarding. THE SHADOW ROM DISASSEMBLY The restart routines THE 'RETURN TO MAIN ROM' RESTART This restart is used to return to the "main" ROM, starting from the address held in the stack before calling this routine. 0000 MAIN-ROM POP HL Remove return address from the machine stack. 0001 LD (FLAGS3),+00 Clear FLAGS3. 0005 JP 0700,UNPAGE Return to 'main' ROM. THE 'START' This is the main entry point to the 'shadow' ROM; it is paged in when the Program Counter reaches the address +0008 that is, the address of the main ROM 'ERROR' routine. (The other time in which the "shadow" ROM is paged in is when the Program Counter reaches the address +1708 i.e., the middle of the CLOSE command routine, which is not able to deal with Interface's channels.) 0008 ST-SHADOW LD HL,(CH-ADD) The first instruction is common to both ROMs. 000B POP HL Get the return address 000C PUSH HL (usually points to the error code) 000D JP 009A,START-2 Jump forward. THE 'CALL A MAIN ROM ROUTINE' RESTART This routine allows for a subroutine in the 'main' ROM to be called from the 'shadow' ROM, and can be called by using a RST 10 instruction, followed by the address of the 'main' ROM subroutine. 0010 CALBAS LD (H-L),HL Save HL into SBRT. 0013 POP HL Get the return address (points to the address following the RST 10). 0014 PUSH DE Save DE temporarily. 0015 JR 0081,CALBAS-2 Jump forward. 0017 DEFB +FF Unused location. THE 'TEST IF SYNTAX IS BEING CHECKED' RESTART This corresponds to the 'main' ROM 'SYNTAX-Z' subroutine. A test of bit 7 of FLAGS wHL give the Zero flag set during syntax checking, and reset during execution. 0018 CHKSYNTAX BIT 7,(FLAGS) Test bit 7 of FLAGS. 001C RET Finished. 001D DEFB +FF,+FF,+FF Unused locations. THE 'SHADOW ERROR' RESTART Jumps to the required routine to deal with 'new' report messages. This routine can be called by using a RST 20 instruction followed by the error code (in the range +FF...+16). 0020 SH-ERR RST 18,CHKSYNTAX Jump to ST-ERROR if checking 0021 JR Z,0068,ST-ERROR syntax, or 0023 JR 003A,TEST-SP to TEST-SP during runtime. 0025 DEFB +FF,+FF,+FF Unused locations. THE 'MAIN ROM ERROR' RESTART Before calling this routine, (ERR-NR) must contain the error code. 0028 ROMERR RES 3,(TVFLAG) Signal 'the mode is to be considered unchanged' 002C JR 0040,RMERR-2 jump forward. 002E DEFB +FF,+FF Unused locations. THE 'CREATE NEW SYSTEM VARIABLES' RESTART The routine is entered at 01F7. 0030 NEWVARS JP 01F7,CRT-VARS Jump forward immediately. 0033 DEFB +FF,+FF,+FF Unused locations. 0036 DEFB +FF,+FF THE 'MASKABLE INTERRUPT' ROUTINE While the 'shadow' ROM is paged-in, the keyboard is not scanned. 0038 INT-SERV EI Enable interrupts. 0039 RET Return immediately. THE 'TEST-SP' ROUTINE Check if it is necessary to print the required report message. 003A TEST-SP CALL 0077,CHECK-SP Use 'main' ROM error handler if required. 003D JP 0258,REP-MSG Print the report message. THE 'MAIN ROM ERROR' ROUTtNE The pressing of BREAK during the loading of 'autorun' programs wHL reset the system; otherwise the error routine continues. 0040 RMERR-2 RST 18,CHKSYNTAX Jump forward if checking syntax. 0041 JR Z,0068,ST-ERROR 0043 CALL 0077,CHECK-SP Use 'main' ROM error handler if required. 0046 CALL 17B9,RCL-T-CH Reclaim all temporary channels & switch off drive motors. 0049 BIT 1,(FLAGS3) Jump forward if not 004D JR Z,0068,ST-ERROR during the loading of 004F BIT 4,(FLAGS3) an 'autorun' program. 0053 JR Z,0068,ST-ERROR 0055 LD A,(ERR-NR) Fetch the error code. 0058 CP +14 Check if attempting to BREAK into the loading of an autorun program. 005A JR NZ,0068,ST-ERROR Jump if not. 005C LD HL,+0000 Otherwise reset the system 005F PUSH HL by jumping to the address 0060 RST 0,MAIN-ROM +0000 in the 'main' ROM. 0061 DEFB +FF,+FF,+FF Unused locations. 0064 DEFB +FF,+FF THE 'NON-MASKABLE INTERRUPT' ROUTINE As with maskable interrupts, there are no service routines. 0066 NMINT-SRV RETN Return immediately. THE 'ST-ERROR' ROUTINE This routine must be entered with the error code in (ERR-NR), and has the same effect as the 'main' ROM 'ERROR' restart. 0068 STERROR LD HL,(CHADD) The address of the character reached 006B LD (X-PTR),HL by the interpreter is copied into the error pointer. 006E LD SP,(ERR-SP) Clear machine stack. 0072 LD HL,+16C5 Return via 'main' ROM 'SET-STK' 0075 PUSH HL routine to the error handler 0076 RST 0,MAIN-ROM routine. THE 'CHECK-SP' ROUTINE Use the 'main' ROM error handler only if bit 2 of FLAGS3 is set. 0077 CHECK-SP BIT 2,(FLAGS3) Return. (Normally bit 2 is always 007B RET Z reset) 007C LD SP,(ERR-SP) Make error handler routine the 0080 RST 0,MAIN-ROM return addrcs0 & exit. THE 'CALBAS-2' ROUTINE This routine uses the SBRT area to call the required routine in the 'main' ROM. 0081 CALBAS-2 LD E,(HL) Fetch the address of the subroutine 0082 INC HL to be called Into the DE 0083 LD D,(HL) register pair. 0084 LD (5CBD),DE Use the address with the CALL in SBRT area. 0088 INC HL Points to the return address. 0089 EX (SP),HL Exchange with initial value of DE register pair (see 0014). 008A EX DE,HL Restore initial value of DE. 008B LD HL,+0000 Signal "a 'main' ROM routine has been 008E PUSh HL called". 008F LD HL,+0008 Return address to the shadow ROM 0092 PUSH HL is +0008. 0093 LD HL,+5CB9 Call indirectly the 0096 PUSH HL SBRT subroutine after having 0097 JP 0700,UNPAGE paged-out the 'shadow' ROM. The control routine This routine is called from ST-SHADOW at 0008 when the shadow ROM is paged-in. It has 3 main tasks: - If the paging of the shadow ROM is the return after a call to a 'main' ROM subroutine, then it returns to the calling routine. - If an Interface's channel has been requested, it jumps to the required 'input' or 'output' routine. - If an error has occurred in the 'main' ROM, a check is made to see if the error code is a 'hook code' (and calls the required routine if it is). If it is not a 'hook code', then it checks to determine whether the error is "Nonsense in BASIC", "Invalid filename", or "Invalid stream". If it is any of these, probably a 'new' command has been used. If so, the routine corresponding to the command is called, otherwise the error is produced by jumping to the address 01F0 (held in the VECTOR system variable - thus altering this address to point a routine in RAM wHL give the possLDility of adding more 'new' commands). In all other cases, the main ROM error handler is used. 009A START-2 PUSH AF Save A register. 009B LD A,H Check if the return address 009C OR L is zero. 009D JR NZ,00A5,START-3 Jump forward if it is not. 009F POP AF Otherwise a 'main' ROM routine 00A0 POP HL has been called; clear stack. 00A1 LD HL,(H-L) Restore HL and return to the 00A4 RET calling routine. Now see if an Interface's channel has been requested. 00A5 START-3 PUSH DE Save DE temporarily. 00A6 LD DE,+15FE If a channel has been requested, this is the return address stored by the CALL 162C inside the 'main' ROM 'CALL-SUB' subroutine. 00A9 SBC HL,DE Jump forward if no 00AB POP DE channels have been requested. 00AC JR NZ,00BC,START-4 00AE POP AF Restore A register (character to be transmitted if during 'output'). 00AF LD HL,+0700 Make return address the 00B2 PUSH HL UNPAGE routine. 00B3 LD HL,+0004 DE now holds (address of routine pointer - 4). 00B6 ADD HL,DE HL holds the address of the routine pointer. 00B7 LD E,(HL) Fetch the low byte. 00B8 INC HL 00B9 LD D,(HL) Fetch the high byte. 00BA EX DE,HL Move the address to HL. 00BB JP (HL) Jump to the appropriate 'input' or 'output' routine. At this point, the shadow ROM has surely been paged-in by an error in the 'main' ROM. 00BC START-4 RST 30,NEWVARS Create interface variables if 00BD LD A,+01 non-existent, then send some 00BF OUT (+F7),A signals to the Interface 1. 00C1 LD A,+EE 00C3 OUT (+EF),A 00C5 POP AF Remove A temporarily. 00C6 POP HL Return address (points to the error code after a RST 8). 00C7 PUSH AF Save A again. 00C8 RST 10,CALBAS This calls a single 'LD A,(HL)' 00C9 DEFW +007B instruction, so the error code is fetched from the main ROM code. 00CB LD (ERR-NR),A Store the error code. 00CE CP +FF Check if the error is 'OK'. 00D0 JR NZ,00E9,TESTCODE Jump if it is not. 00D2 BIT 1,(FLAGS3) This is set when using the 'shadow' ROM for the first time (i.e. after a NEW command). 00D6 JR Z,00E7,NREPORT-0 Give an error if not the first time. 00D8 BIT 7,(PPC-hi) Give an error also if the 00DC JR Z,00E7,NREPORT-0 line is not in the editing area. 00DE LD HL,(E-LINE) Otherwise fetch the command code from 00E1 LD A,(HL) the editing area. 00E2 CP +F7 Check if the command is 'RUN'. 00E4 JP Z,0A95,LOAD-RUN Load the 'run' program from Microdrive if so. 'Program finished' 00E7 NREPORT-0 RST 20,SH-ERR Call the error handling 00E8 DEFB +FF routine. The error code in A determines the task to be executed. 00E9 TEST-CODE SUB +1B Reduce the range. 00EB JP NC,1981,HOOK-CODE Jump if it's a hook code, or an invalid code (greater than 0-32). 00EE CP +F0 Jump if the error is 00F0 JR Z,00FB,COPYCHADD 'Nonsense in BASIC'. 00F2 CP +F3 Also if 'Invalid filename'. 00F4 JR Z,00FB,C0PYCHADD 00F6 CP +FC Or 'Invalid stream'. 00F8 JP NZ,0028,ROMERR If none of these, use 'main' ROM error handler to signal the error. 00FB COPYCHADD LD HL,(CH-ADD) The character pointer 00FE LD (CHADD-),HL is saved. 0101 POP AF Clear the stack. 0102 BIT 5,(FLAGX) Use 'main' ROM error handler also if 0106 JP NZ,0028,ROMERR in INPUT mode, or 0109 BIT 0,(FLAGS3) during execution of a 'new' command. 010D JP NZ,0028,ROMERR 0110 SET 0,(FLAGS3) Signal "execution of a 'new' command" 0114 RST 18,CHKSYNTAX Jump if during runtime. 0115 JR NZ,011B,RUNTIME 0117 LD (PPC-hi),+FF Signal "syntax time". Now a loop is entered to find the line that has produced the error. 011B RUNTIME LD B,(SUBPPC) Statement counter. 011E LD C,+00 Counter of ' " ' characters. 0120 BIT 7,(PPC-hi) Jump forward if the line 0124 JR Z,0130,PROG-LINE is in the program area. 0126 PUSH BC Save counters. 0127 RST 10,CALBAS Call main ROM 'E-LINE-NO' (it fetches 0128 DEFW +19FB the number of the line in the editing area, but is actually used to update CH-ADD to the 1st char. in the line). 012A POP BC Restore counters. 012B RST l0,CALBAS Call GET-CHAR in the main ROM to 012C DEFW +0018 update HL to the 1st character in the line. 012E JR 016F,S-STAT Jump forward. 0130 PROG-LINE LD HL,(PROG) Fetch start of program area. 0133 SC-L-LOOP LD A,(PPC-hi) Compare the number of the tine to be 0136 CP (HL) searched with that of the 'current' line. 0137 JR NC,013B,TEST-LOW Jump if the 'current' line no. is less than or equal to that of the line to be searched for. Nonsense in BASIC. 0139 NREPORT-1 RST 20,SH-ERR Call the error handling 013A DEFB +00 routine. 013B TEST-LOW INC HL Points to low byte of line no. 013C JR NZ,0144,LINE-LEN Jump if the 'current' line is not the expected one. 013E LD A,(PPC-lo) Compare also the high byte of 0141 CP (HL) the line numbers. 0142 JR C,0139,NREPORT-1 Give an error if the line dDEs not exist. 0144 LINE-LEN INC HL Increment the pointer. 0145 LD E,(HL) Fetch low byte of the length. 0146 INC HL 0147 LD D,(HL) Fetch high byte. 0148 INC HL Points to start of the line. 0149 JR Z,0l6F,S-STAT Jump if the line is found, 014B ADD HL,DE otherwise points to next line. 014C JR 0l33,SC-L-LOOP Continue until found. 014E SKIP-NUN LD DE,+0006 Length of a floating point number. 0151 ADD HL,DE Skip the floating point representat. This loop advances the pointer 'HP until it reaches the start of the statement that has produced the error. 0152 EACH-ST LD A,(HL) Get a character from line. 0153 CP +0E Is it the 'number' marker ? 0155 JR Z,0l4E,SKIP-NUM If so, advance the pointer after the 'number'. 0157 INC HL Points to next character. 0158 CP +22 Is the character a '"'? 015A JR NZ,015D,CHKEND Jump it it is not. 015C DEC C Decrement counter for each '"' found 015D CHKEND CP +3A Is the character a colon? 015F JR Z,0165,CHKEVEN Jump if it is. 0161 CP +CB Jump unless the character is 'THEN'. 0163 JR NZ,0l69,CHKEND-L Check whether the number of quotes 0165 CHKEVEN BIT 0,C found is even (i.e. colon or THEN are out of a string). 0167 JR Z,016F,S-STAT Jump if the statement is finished. 0169 CHKEND-L CP +80 Check whether the line is finished. 016B JR NZ,0152,EACH-ST Continue the loop if not. 016D JR 0139,NREPORT-1 Give an error (because a wrong number of quotes have been found). 016F S-STAT DJNZ 0152,EACH-ST Continue with next statement. 0171 DEC HL Now HL holds the start address of the required statement. 0172 LD (CH-ADD),HL Update CH-ADD to this address. 0175 RST 18,CHKSYNTAX Jump forward if during runtime. 0176 JR NZ,01AA,CL-WORK 0178 BIT 7,(PPC-hi) Give an error report if the line is 017C JP Z,01F0,ERR-6 not in the editing area. The final loop is made during syntax checking, for removing all 6-byte floating point numbers inserted in the line by the 'main' ROM interpreter. 017F DEC HL This balances the INC below. 0180 LD C,+00 Clear C register. 0182 RCLN-NUM INC HL Points to next character. 0183 LD A,(HL) Fetch the character. 0184 CP +0E Jump if the character is not the 0186 JR NZ,01A5,NEXTNUM start of a 'number'. 0188 PUSH BC Save the counter. 0189 LD BC,+0006 '6' bytes have to be reclaimed. 018C RST 10,CALBAS Call RECLAIM-2 in the 'main' ROM to 018D DEFW +19E8 reclaim the 'number'. 018F PUSH HL Save HL (points after the reclaimed 'number' ). 0190 LD DE,(CHADD-) Jump forward if the '6' bytes 0194 AND A reclaimed were after the character 0195 SBC HL,DE pointed by CHADD-. 0197 JR NC,01A3,NXT-1 0199 EX DE,HL Otherwise CHADD- needs to be updated. First move it into HL. 019A LD BC,+0006 The character pointed by CHADD- has 019D AND A been moved '6' bytes down. 019E SBC HL,BC 01A0 LD (CHADD-),HL Store the new value. 01A3 NXT-1 POP HL Restore pointer and counter. 01A4 POP BC 01A5 NEXTNUM LD A,(HL) Jump back into the loop until 01A6 CP +0D the line is finished. 01A8 JR NZ,0182,RCLM-NUM Now the working areas and the new system variables are cleared. 01AA CL-WORK RST 10,CALBAS Clear work areas by calling main 01AB DEFW +16BF ROM 'SET-WORK' routine. 01AD CALL 024D,RES-VARS Reset some 'new' variables to +FF. Finally, the command code is fetched from the line, and if it is a 'new' command, the appropriate routine is called. 01B0 RST 10,CALBAS Call NEXT-CHAR in the main ROM to 01B1 DEFW +0020 fetch the command code. 01B3 SUB +CE Reduce range of the code. 01B5 CP +01 Ia the command a 'CAT' 01B7 JP Z,0486,CAT-SYN Check CAT syntax if so. 01BA CP +02 Also for 'FORMAT',... 01BC JP Z,04B4,FRMT-SYN 01BF CP +03 ...'MOVE',... 01C1 JP Z,053D,MOVE-SYN 01C4 CP +04 ...'ERASE',... 01C6 JP Z,053l,ERASE-SYN 01C9 CP +05 ...'OPEN',... 01CB JP Z,04ED,OPEN-SYN 01CE CP +2A ...'SAVE',... 01D0 JP Z,082F,SAVE-SYN 01D3 CP +21 ...'LOAD',... 01D5 JP Z,0894,LOAD-SYN 01D8 CP +08 ...'VERIFY',... 01DA JP Z,089E,VERIF-SYN 01DD CP +07 ...'MERGE',... 01DF JP Z,08A8,MRG-SYN 01E2 CP +2D ...'CLS#',... 01E4 JP Z,0559,CLS#-SYN 01E7 CP +2F ...and 'CLEAR#' command. 01E9 JP Z,057F,CLR#-SYN If the command that has produced the error was none of these, a jump is made to the address held in VECTOR system variable. 01EC ERR-V LD HL,(VECTOR) Jump to the address held in 01EF JP (HL) VECTOR (normally ERR-6 below). Now the error produced by the main ROM is confirmed. 01F0 ERR-6 LD HL,(CHADD-) Restore initial CH-ADD contents. 01F3 LD (CH-ADD),HL 01F6 RST 28,ROMERR Give the appropriate error. THE 'CREATE NEW SYSTEMS VARIABLES' ROUTINE This routine is used to create the 'new' system variables if nonexistent and it is called from the restart 0030. Many variables are initialised to its default value. 01F7 CRT-VARS LD HL,(CHANS) Fetch start of channel area. 01FA LD DE,+A349 This is FFFF-5CB6. 01FD ADD HL,DE The carry flag is now set it the CHANS area starts after the address +5CB6. 01FE JR C,0235,VAR-EXIST Jump if the 'new' variables already exist. 0200 LD HL,+0224 Pre-load machine-stack with the 0203 PUSH HL address DEFAHLT below. 0204 LD HL,(STKBOT) Clear the calculator 0207 LD (STKEND),HL stack. 020A LD HL,+5C92 Set MEM with the address of 020D LD (MEM),HL MEMBOT area. 0210 LD HL,+5CB5 One location before the new space is needed. 0213 LD BC,+003A Length of space needed. 0216 LD DE,+0000 Signal 'a main ROM routine has been 0219 PUSH DE called'. 021A LD E,+08 Store return address to the 021C PUSH DE shadow ROM. 021D LD DE,+1655 Return address to main ROM 0220 PUSH DE is MAKE-ROOM. 0221 JP 0700,UNPAGE After the 'insertion' of the new space has been made, the program continues here with the initialisation of some variables. 0224 DEFAULT LD HL,+023A Base address of 'default values' table. 0227 LD BC,+0013 Length of table. 022A LD DE,+5CB6 Start of 'new variables' area. 022D LDIR Store default values. 022F LD A,+01 Set COPIES to +01. 0231 LD (COPIES),A 0234 RET Finished. If the new variables already exist, bit 1 of FLAGS3 is reset. 0235 VAR-EXIST RES 1,(FLAGS3) 'New variables already exist'. 0239 RET Finished. THE 'SYSTEM VARIABLES DEFAHLT VALDES' TABLE This table contains the default values of all the 'new' system variables from FLAGS3 to SER-FL. 023A DEFB +02 Default value for FLAGS3 (bit 1 is set to signal that the aheadow ROM has been paged for the first time (see 00D2). 023B DEFW +01F0 Default for VECTOR is ERR-6 address. 023D LD HL,+0000 This short subroutine is the SBRT 0240 CALL +0000 'variable', used to call main ROM 0243 LD (H-L),HL routines from the shadow ROM. 0246 RET 0247 DEFW +000C default for BAUD is +000C (i.e. 9600 baud). 0249 DEFB +01 Default for NTSTAT. 024A DEFB +00 Default for IOBORD colour (black). 024B DEFW +0000 Default for SER-FL. THE 'RESET NEW SYSTEM VARIABLES' SUBROUTINE Before using the 'new' system variables from NTRESP to HD-11, their values are reset to +FF. 024D RES-VARS LD HL,NTRESP Points to the 1st variable. 0250 LD B,+22 The block is made by '34' bytes. 0252 EACH-VAR LD (HL),+FF Store +FF in all the bytes in 0254 INC HL the block. 0255 DJNZ 0252,EACH-VAR 0257 RET Finished. THE 'SHADOW REPORT PRINTING' ROUTINE This routine is very similar to 'MAIN-3' (+1303) in the 'main' ROM, but the report message printed is one of the 'shadow' report. 0258 REP-MSG LD (FLAGS3),+00 First clear FLAGS3. 025C EI Enable interrupts. 025D HALT Accept one interrupt. 025E CALL 17B9,RCL-T-CH Reclaim temporary channels and switch off drive motors. 0261 RES 5,(FLAGS) Signal 'ready for a new key'. 0265 BIT 1,(FLAGS2) Jump if the printer buffer 0269 JR Z,026E,FETCH-ERR has not been used, otherwise call 026B RST 10,CALBAS COPY-BUFF in the main ROM to empty 026C DEFW +0ECD the buffer. 026E FETCH-ERR POP HL This address points to the error code (after a RST 20). 026F LD A,(HL) Fetch error code. 0270 LD (ERR-NR),A Store it into ERR-NR. 0273 INC A Increment error number. 0274 PUSH AF Save the new value. 0275 LD HL,+0000 The system variables 0278 LD (FLAGX),H FLAGX, X-PTR-hi and DEFADD are all 027B LD (X-PTR-hi),H set to zero. 027E LD (DEFADD),HL 0281 INC L Now HL holds +0001. 0282 LD (+5C16),HL Displacement for stream 0 is made +0001 (i.e. reset stream 0 to the "K" channel). 0285 RST 10,CALBAS Clear work areas, calculator stack 0286 DEFW +16B0 by calling SET-MIN. 0288 RES 5,(FLAGX) Signal 'editing mode'. 028C RST 10,CALBAS Clear lower screen by calling 028D DEFW +0D6E CLS-LOWER. 028F SET 5,(TVFLAG) Signal 'the lower screen is to be cleared'. 0293 RES 3,(TVFLAG) Signal 'the mode is to be conside- red unchanged'. 0297 POP AF Restore error number. 0298 LD HL,+02B7 Base address of 'report messages' table. 029B LD B,+04 Hake BC hold a sufficiently high number. 029D CPIR Advance HL to the required report message in the table. 029F PR-REP-LP LD A,(HL) Fetch character of message. 02A0 CP +20 Print it unless reached the 02A2 JR C,02AC,END-PR-MS 'marker' of next message. 02A4 PUSH HL Save pointer. 02A5 RST 10,CALBAS Call main ROM 'PRINT-A' restart 02A6 DEFW +0010 to print the character. 02A8 POP HL Restore pointer. 02A9 INC HL Point to next character. 02AA JR 029F,PR-REP-LP Continue with next character. 02AC END-PR-MS LD SP,(ERR-SP) Clear machine stack. 02B0 INC SP Ignore also the address +1303 02B1 INC SP pointed by ERR-SP (that is replaced with the +1349 below). 02B2 LD HL,+1349 Return to the main ROM in the 02B5 PUSH HL middle of the 'print report message 02B6 RST 0,MAIN-ROM routine. THE 'SHADOW' REPORT MESSAGES Before each report there is the correspondent error code, incremented by 1. 02B7 DEFB +00 02B8 DEFM "Program finished" 02C8 DEFB +01 02C9 DEFM "Nonsense in BASIC" 02DA DEFB +02 02DB DEFM "Invalid stream number" 02F0 DEFB +03 02F1 DEFM "Invalid device expression" 030A DEFB +04 030B DEFM "Invalid name" 0317 DEFB +05 0318 DEFM "Invalid drive number" 032C DEFB +06 032D DEFM "Invalid station number" 0343 DEFB +07 0344 DEFM "Missing name" 0350 DEFB +08 0351 DEFM "Missing station number" 0367 DEFB +09 0368 DEFM "Missing drive number" 037C DEFB +0A 037D DEFM "Missing baud rate" 038E DEFB +0B 038F DEFM "Header mismatch error" 03A4 DEFB +0C 03A5 DEFM "Stream already open" 03B8 DEFB +0D 03B9 DEFM "Writing to a 'read' file" 03D1 DEFB +0E 03D2 DEFM "Reading a 'write' file" 03E8 DEFB +0F 03E9 DEFM "Drive 'write' protected" 0400 DEFB +10 0401 DEFM "Microdrive full" 0410 DEFB +11 0411 DEFM "Microdrive not present" 0427 DEFB +12 0428 DEFM "File not found" 0436 DEFB +13 0437 DEFM "Hook code error" 0446 DEFB +14 0447 DEFM "CODE error" 0451 DEFB +15 0452 DEFM "MERGE error" 045D DEFB +16 045E DEFM "Verification has failed" 0475 DEFB +17 0476 DEFM "Wrong file type" 0485 DEFB +18 The syntax checking routines The routines in this section of the shadow ROM check the syntax of the 'new' commands and call the command routines during runtime. THE 'CAT' COMMAND SYNTAX ROUTINE This routine checks that the command is in the form CAT n, or CAT #s,n then sets S-STR1 and D-STR1 system variables before exiting in syntax time or executing the CAT during runtime. 0486 CAT-SYN LD HL,S-STR1 First make the screen 0489 LD (HL),+02 'current' stream. 048B RST 10,CALBAS Advance CH-ADD with a call to 048C DEFW +0020 'NEXT-CHAR' in the main ROM. 048E CP +0D If the line ends here, jump to 0490 JR Z,0494,MISSING-D produce an error. 0492 CP +3A Give an error also if the 0494 MISSING-D JP Z,0683,NREPORT-9 statement ends with a colon. 0497 CP +23 Jump if after the keyword 0499 JR NZ,04A6,CAT-SCRN there is not the 'hash' character. 049B CALL 064E,EXPT-STRM Otherwise evaluate stream number. 049E CALL 05B1,SEPARATOR Give an error if after the stream 04A1 JR NZ,04B2,OREPORT-1 number there is no separator. 04A3 RST 10,CALBAS Advance CH-ADD to next 04A4 DEFW +0020 character. 04A6 CAT-SCRN CALL 061E,EXPT-NUM Evaluate drive number. 04A9 CALL 05B7,ST-END Confirm end of statement and exit during syntax time. 04AC CALL 066D,CHECK-M-2 Checks that drive number held in D-STR1 is in range. 04AF JP 1E70,CAT-RUN Do the CATalogue. 'Nonsense, in BASIC' 04B2 OREPORT-1 RST 20,SH-ERR Call the error handling 04B3 DEFB +00 routine. THE 'FORMAT' COMMAND SYNTAX ROUTINE A FORMAT command may have one of the following forms: FORMAT "m";n;"name" -FORMAT "b";n - FORMAT "t";n - FORMAT "n";n. This routine handles all forms and sets N-STR1, L-STR1 and D-STR1 as required before exiting during syntax checking, or executing the command during runtime. 04B4 FRMT-SYN CALL 05F2,EXPT-SPEC Evaluate (string)(separator)(number) and set L-STR1, D-STR1. 04B7 CALL 05Bl,SEPARATOR If there is not a further 04BA JR NZ,04BF,NO-FOR-M separator, no filename is to be expected, so jump. 04BC CALL 062F,EXPT-NAME Evaluate "name" and set N-STR1. 04BF NO-FOR-M CALL 05B7,ST-END Confirm end of statement and exit during syntax checking. 04C2 LD A,(L-STR1) Fetch channel specifier. 04C5 CP +54 Jump with FORMAT "T" 04C7 JR Z,04CD,FOR-B-T 04C9 CP +42 Test for FORMAT "B" - note that the routine is the same as that of FORMAT "T". 04CB JR NZ,04D3,NOT-FOR-B Jump with "N" and "M" channels. 04CD FOR-B-T CALL 06B0,TEST-BAUD Check that D-STR1 holds a valid baud rate. 04D0 JP 0AC9,SET-BAUD Set BAUD variable from D-STR1 value (the actual FORMAT with RS232 link). 04D3 NOT-FOR-B CP +4E Jump if not a FORMAT "N" command. 04D5 JR NZ,04E7,FOR-M 04D7 CALL 068F,TEST-STAT Check that D-STR1 holds a valid station number. 04DA LD A,(D-STR1) Give an error if attempting to 04DD AND A FORMAT "n"';0 (i.e. with the 04DE JP Z,069F,NREPORT-6 'broadcast' specifier). 04E1 LD (NTSTAT),A This is the actual FORMAT command with the network. 04E4 JP 05C1,END1 Finished. 04E7 FOR-M CALL 0685,TEST-MNAM Check that the various parameters are correct. 04EA JP 1E75,FOR-RUN Do the FORMAT "M" command. ThE 'OPEN' COMMAND SYNTAX ROUTINE This routine deals with OPEN #s;"m";n;"name" - OPEN #s;"b" - OPEN #s;"t" - OPEN #s;"n";n commands. All parameters are stored into S-STR1, N-STR1, D-STR1 and L-STR1 variables before exiting during syntax checking or executing the command during runtime. 04ED OPEN-SYN CALL 064E,EXPT-STRM Evaluate stream number. 04F0 CALL 05B1,SEPARATOR Give an error report if the separator 04F3 JR NZ,04B2,OREPORT-1 has been missed after 'stream no.' 04F5 CALL 05F2,EXPT-SPEC Evaluate channel specifier, (separator numeric expression). 04F8 CALL 05B1,SEPARATOR Jump if no further separator is 04FB JR NZ,0500,NOT-OP-M present. 04FD CALL 062F,EXPT-NAME Otherwise evaluate "name". 0500 NOT-OP-M CALL 05B7,ST-END Confirm end of statement and exit if syntax is being checked. 0503 LD A,(S-STR1) Fetch stream number. 0506 RST 10,CALBAS Call main ROM 'STR-DATA1' routine; 0507 DEFW +1727 on exit, BC holds 'stream data'. 0509 LD HL,+0011 In fact, jump if the current stream 050C AND A is already opened with a 'new' 050D SBC HL,BC channel. 050F JR C,052F,NREPORT-C 0511 LD A,(L-STR1) Fetch channel specifier. 0514 CP +54 Jump if opening a 't' channel. 0516 JR Z,051C,OPEN-RS 0518 CP +42 Jump if not a 'b' channel. 051A JR NZ,051F,NOT-OP-B 051C OPEN-RS JP 0B47,OP-RSCHAN Do the OPEN referred to RS232 link. 051F NOT-OP-B CP +4E Jump if not a 'n' channel (i.e. 0521 JR NZ,0520,OP-M-C with 'm' channel). 0523 CALL 068F,TEST-STAT Check that D-STR1 holds a valid station number. 0526 JP 0EA3,OPEN-N-ST Do the OPEN referred to the network. 0529 OP-M-C CALL 0685,TEST-MNAM Check that all parameters are valid. 052C JP 1E7A,OP-RUN Do the OPEN "M" command. 'Stream already open' 052F NREPORT-C RST 20,SH-ERR Call the error handling 0530 DEFB +0B routine. THE 'ERASE' COMMAND SYNTAX ROUTINE This command has only one form and, thus, this routine is more straightforward than the preceding ones. 0531 ERASE-SYN CALL 06A3,EXPT-EXPR Evaluate ("m";n;"name") 0534 CALL 05B7,ST-END Confirm end of statement and exit during syntax checking. 0537 CALL 0685,TEST-MNAM Check that all parameters are valid. 053A JP 1E66,ERASE-RUN Do the ERASE command. THE 'MOVE' COMMAND SYNTAX ROUTINE A 'MOVE' command requires two sets of parameters, for the 'input' channel and for the 'output' channel. These parameters are stored respectively in the two areas D-STR1 and D-STR2. 053D MOVE-SYN CALL 06B9,EXPT-EXP1 Evaluate stream number, or channel expression. 0540 CALL 059F,EX-D-STR Exchange D-STR1 and D-STR2 contents. 0543 RST 10,CALBAS Call GET-CHAR in the main ROM. 0544 DEFW +0018 0546 CP +CC The keyword 'TO' must be present 0548 JR NZ,0584,NONSENSE between the two expressions. 054A CALL 06B9,EXPT-EXP1 Evaluate 2nd stream number, or channel expression. 054D CALL 059F,EX-D-STR Exchange again D-STR areas. 0550 RST 10,CALBAS Call GET-CHAR in the main ROM. 0551 DEFW +0018 0553 CALL 05B7,ST-END Confirm end of statement and exit during syntax checking. 0556 JP 1E6B,MOVE-RUN Do the MOVE command, THE 'CLS#' COMMAND ROUTINE This routine has the tasks of both 'syntax checking' and 'execution'. During runtime, ATTR-P, ATTR-T, MASK-P, MASK-T, P-FLAG and BORDCR system variables are reset to the 'initiaP value (as after a NEW command). 0559 CLS#-SYN RST 10,CALBAS Advance CH-ADD after the 055A DEFW +0020 keyword CLS. 055C CP +23 The character must be a '#'. 055E JR NZ,0584,NONSENSE 0560 RST 10,CALBAS Advance CH-ADD again. 0561 DEFW +0020 0563 CALL 05B7,ST-END Confirm end of statement and exii during syntax checking. 0566 LD HL,+0038 +38 is the attribute byte. 0569 LD (ATTR-P),HL Store +38 into ATTR-P, clear MASK-P. 056C LD (ATTR-T),HL Store +38 into ATTR-T, clear MASK-T. 056F LD (BORDCR),L Store +38 also for lower screen attribute. 0572 LD (P-FLAG),H Clear P-FLAG. 0575 LD A,+07 Set white border. 0577 OUT (+FE),A 0579 RST 10,CALBAS Call main ROM 'CLS' routine. 057A DEFW +0D6B 057C JP 05Cl,END1 Finished. THE 'CLEAR#' COMMAND ROUTINE As in the previous routine, this routine both 'checks' and 'executes' the command. All streams are closed in turn, with bit 1 of FLAGS3 set to signal that the remaining buffer contents are to be erased (no data is sent, as opposed to the case of a CLOSE# command). 057F CLR#-SYN RST 10,CALBAS Advance CH-ADD. 0580 DEFW +0020 0582 CP +23 The character must be a '#'. 0584 NONSENSE JP NZ,04B2,OREPORT-1 0587 RST 10,CALBAS Advance CH-ADD again. 0588 DEFW +0020 058A CALL 05B7,ST-END Confirm end of statement and exit during syntax checking. 058D XOR A Start with stream 0. 058E ALL-STRMS PUSH AF Save stream number. 058F SET 1,(FLAGS3) Signal 'CLEAR# command'. 0593 CALL 1718,CLOSE Close the current stream. 0596 POP AF Restore stream number. 0597 INC A Each stream in turn is examined. 0598 CP +10 Continue until all streams 0..15 059A JR C,058E,ALL-STRMS have been closed. 059C JP 05C1,END1 Finished. THE 'EXCHANGE FILE SPECIFIERS' SUBROUTINE This subroutine exchanges the contents of D-STR1 area with those of the D-STR2 area and vice-versa. 059F EX-D-STR LD HL,+5CD6 Start of first area. 05A2 LD DE,+5CDE Start of 2nd area. 05A5 LD B,+08 Both areas are 8 bytes in length. 05A7 ALL-BYTES LD A,(DE) Fetch a byte from D-STR2. 05A8 LD C,(HL) Fetch a byte from D-STR1. 05A9 LD (HL),A Store into D-STR1 the byte coming from D-STR2. 05AA LD A,C Byte from D-STR1. 05AB LD (DE),A Store it into D-STRZ. 05AC INC HL Advance the pointers. 05AD INC DE 05AE DJNZ 05A7,ALL-BYTES Continue until the areas have been exchanged. 05B0 RET Finished. THE 'SEPARATOR' SUBROUTINE This short subroutine is called several times to see if the character held in the accumulator is a valid separator (i.e. a comma or a semicolon). A return with the Zero flag reset is made if the character is not a separator. 05B1 SEPARATOR CP +2C Is the character a comma? 05B3 RET Z Return with zero flag set if so. 05B4 CP +3B Is the character a semicolon? 05B6 RET Return with zero flag set if so. THE 'END OF STATEMENT' ROUTINE After the syntax of the 'new' commands has been checked, a jump is made here to confirm that the statement is finished. An error report is given if there are some characters left in the line. A return is made to the calling routine only during runtime, otherwise the control returns to the 'main' ROM interpreter. 05B7 ST-END CP +0D Jump if the statement ends 05B9 JR Z,05BF,TEST-RET with ENTER. 05BB CP +3A Give an error if character is not 05BD JR NZ,0584,NONSENSE a colon (i.e. the statement is not finished). 05BF TEST-RET RST 18,CHKSYNTAX Return only during runtime, 05C0 RET NZ otherwise continue below. THE 'RETURN TO THE MAIN INTERPRETER' ROUTINE The control returns to the main interpreter, when a 'new' command has been checked or executed, for the interpretation of the next statement. 05C1 END1 LD SP,(ERR-SP) Clear machine stack. 05C5 LD (ERR-NR),+FF Clear error code. 05C9 LD HL,+1BF4 Return address to main ROM is 05CC RST 18,CHKSYNTAX STMT-NEXT if syntax being checked. 05CD JR Z,05E0,RETAD-RUN-SYN 05CF LD A,+7F Give, an error if BREAK is pressed 05D1 IN A,(+FE) during runtime. 05D3 RRA 05D4 JR C,05DD,RETAD-RUN 05D6 LD A,+FE 05D8 IN A,(+FE) 05DA RRA 05DB JR NC,05E2,BREAK-PGM 05DD RETAD-RUN LD HL,+1B7D Return address during runtime is STMT-R-1. 05E0 RETAD-SYN PUSH HL Save the return address. 05E1 RST 0,MAIN-ROM Return to the main ROM interpreter. 'BREAK into program' 05E2 BREAK-PGM LD (ERR-NR),+14 Store the error code and call 05E6 RST 28,ROMERR the error handling routine. THE 'EVALUATE STRING EXPRESSION' SUBROUTINE A call to the main ROM 'EXPT-EXP' (class-9A) subroutine is made, to evaluate a string expression. During runtime the parameters of the string (start and length) are returned in the DE and BC register pairs. 05E7 EXPT-STR RST 10,CALBAS Call 'EXPT-EXP' in the main ROM. 05E8 DEFW +1C8C 05EA RST 18,CHKSYNTAX Return if syntax is being checked 05EB RET Z 05EC PUSH AF Save the zero flag and the character following the string. 05ED RST 10,CALBAS Call 'STK-FETCH' in the main ROM to 05EE DEFW +2BF1 fetch the parameters. 05F0 POP AF Zero flag reset to signal 'runtime' 05F1 RET Finished. THE 'EVALUATE CHANNEL SPECIFIER' SUBROUTINE The subroutine is entered at EXPT-SPEC or at EXP-SPEC2 depending upon whether or not the character pointer is to be updated to the next character. A single character string is evaluated, and its upper case ASCII value is stored into L-STR1 during runtime. If a separator is present after the single character string, then the routine continues into EXPT-NUM. 05F2 EXPT-SPEC RST 10,CALBAS Advance CH-ADD. 05F3 DEFW +0020 05F5 EXP-SPEC2 CALL 95E7,EXPT-STR Evaluate string expression. 05F8 JR Z,060C,TEST-NEXT Jump if syntax is being checked. 05FA PUSH AF Save the character following the string. 05FB LD A,C 'A' holds the low byte of the string length. 05FC DEC A Jump if there is more than one 05FD OR B character in the string (also if the 05FE JR NZ,062D,NREPORT-3 string is null). 0600 LD A,(DE) Fetch the channel specifier. 0601 RST 10,CALBAS Call 'ALPHA' to see whethe nt isi 0602 DEFW +2C8D valid letter. 0604 JR NC,062D,NREPORT-3 Jump if it is not a valid letter 0606 AND +DF Make the letter upper case. 0608 LD (L-STR1),A Store the channel specifier. 060B POP AF The 'next character' is restored. 060C TEST-NEXT CP +0D Return if it is ENTER, or a colon, 060E RET Z 060F CP +3A 0611 RET Z 0612 CP +A5 Return also with a keyword. 0614 RET NC 0615 CALL 05B1,SEPARATOR Otherwise a separator must be found. 0618 JP NZ,04B2,OREPORT-1 Give an error if not found. 061B RST 10,CALBAS A numeric expression (i.e. drive 061C DEFW +0020 no.,station no., baud rate) is expected. But first advance CH-ADD past the separator. THE 'EVALUATE NUMERIC EXPRESSION' SUBROUTINE This subroutine is used whenever a single numeric expression is to be evaluated. The result is returned during runtime into the BC register pair and into the D-STR1 system variable. 061E EXPT-NUM RST 10,CALBAS Call EXPT-NUM in the main ROM to 061F DEFW +1C82 evaluate the expression. 0621 RST 18,CHKSYNTAX Return if syntax is being checked. 0622 RET Z 0623 PUSH AF Save character following the expression and zero flag. 0624 RST 10,CALBAS Call FIND-INT2 to fetch the 0625 DEFW +1E99 value from calculator stack. 0627 LD (D-STR1),BC Store the value. 062B POP AF Restore character and zero flag. 062C RET Finished. 'Invalid device expression' 062D NREPORT-3 RST 20,SH-ERR Call the error handling 062E DEFB +02 routine. THE 'EVALUATE FILENAME' SUBROUTiNE A string expression is evaluated and, provided that the length is within the range 1..10 characters, the 'length' and the 'start' of that string are stored into N-STR1 and (N-STR1 + 2). 062F EXPT-NAME RST 10,CALBAS Advance CH-ADD. 0630 DEFW +0020 0632 CALL 05E7,EXPT-STR Evaluate the string. 0635 RET Z Return if syntax is being checked. 0636 PUSH AF Save zero flag and 'next character'. 0637 LD A,C Give an error with null string. 0638 OR B 0639 JR Z,064C,NREPORT-4 063B LD HL,+000A Give the error also if 'length' 063E SBC HL,BC exceeds ten characters. 0640 JR C,064C,NREPORT-4 0642 LD (N-STR1),BC Store the 'length'. 0646 LD (N-STR1+2),DE Store the 'start'. 064A POP AF Restore A and zero flag. 064B RET Finished. 'Invalid name' 064C NREPORT-4 RST 20,SH-ERR Call the error handling 064D DEFB +03 routine. THE 'EVALUATE STREAM NUMBER' SUBROUTINE A single numeric expression is evaluated and the result, in the range 0..15, is stored into S-STR1 variable during runtime. 064E EXPT-STRM RST 10,CALBAS Advance CH-ADD. 064F DEFW +0020 0651 RST 10,CALBAS Call EXPT-1NUM to evaluate a numeric 0652 DEFW +1C82 expression. 0654 RST 18,CHKSYNTAX Return if syntax is being checked. 0655 RET Z 0656 PUSH AF Save 'next character' and zero flag. 0657 RST 10,CALBAS Call FIND-INT1 to fetch the value. 0658 DEFW +1E99 065A CP +10 Test for numbers greater than 15. 065C JR NC,0663,NREPORT-2 065E LD (S-STR1),A Store stream number. 0661 POP AF Restore A and zero flag. 0662 RET Finished. 'Invalid stream number' 0663 NREPORT-2 RST 20,SH-ERR Call the error handling 0664 DEFB +01 routine. THE 'CHECK "M" PARAMETERS' SUBROUTINE A return to the calling routine is made only if L-STR1 denotes the Microdrive device being used, and if D-STR1 holds a valid drive number. 0665 CHECK-M LD A,(L-STR1) Fetch channel specifier. 0668 CP +4D Is it "M"? 066A JP NZ,062D,NREPORT-3 Report the error if it is not. 066D CHECK-M-2 LD DE,(D-STR1) Fetch drive number. 0671 LD A,E Report an error if zero. 0672 OR D 0673 JR Z,0681,NREPORT-5 0675 INC DE Test against +FFFF. 0676 LD A,E Report an error if no drive number 0677 OR D has been evaluated. 0678 JR Z,0683,NREPORT-9 067A DEC DE Balance the 'INC' above. 067B LD HL,+0008 Is drive number within range 1..8? 067E SBC HL,DE 0680 RET NC Return if in range. 'Invalid drive number' 0681 NREPORT-5 RST 20,SH-ERR Call the error handling 0682 DEFB +04 routine. 'Missing drive number' 0683 NREPORT-9 RST 20,SH-ERR Call the error handling 0684 DEFB +08 routine. THE 'CHECK "M" PARAMETERS AND FILENAME' SUBROUTINE This subroutine adds to the tests performed by the previous one, also a check to N-STR1-hi, that holds +FF when no filename has been evaluated. 0685 TEST-MNAM CALL 0665,CHECK-M Check "m" parameters. 0688 LD A,(N-STR1-hi) Fetch high byte of name length. 068B AND A Is it 0? 068C RET Z Return if so. 'Missing name' 068D RST 20,SH-ERR Call the error handling 068E DEFB +06 routine. THE 'CHECK STATION NUMBER' SUBROUTINE A return to the calling routine is made only if D-STR1 holds a valid station number in the range 0..64. 068F TEST-STAT LD DE,(D-STR1) Fetch station number. 0693 INC DE Test against +FFFF. 0694 LD A,E 0695 OR D No station number has been 0696 JR Z,06A1,NREPORT-8 evaluated, so give an error 0698 DEC DE Balance the 'INC' above. 0699 LD HL,+0040 Return only if the value is no 069C SBC HL,DE greater than 64 decimal. 069E RET NC 'Invalid station number' 069F RST 20,SH-ERR Call the error handling 06A0 DEFB +05 routine. 'Missing station number' 06A1 NREPORT-8 RST 20,SH-ERR Call the error handling 06A2 DEFB +07 routine. THE 'EVALUATE "X";N;"NAME"' SUBROUTINE A call to the subroutine EXPT-SPEC will evaluate the '"X";N', while the subroutine EXPT-NAME is used to evaluate the filename. A separator must be found between them. 06A3 EXPT-EXPR CALL 05F2,EXPT-SPEC Evaluate channel specifier and drive number. 06A6 CALL 05B1,SEPARATOR A separator must be present. 06A9 JP NZ,04B2,OREPORT-1 06AC CALL 062F,EXPT-NAME Evaluate the filename. 06AF RET Finished. THE 'CHECK BAUD RATE' SUBROUTINE This routine simply checks that D-STR1 holds a valid baud rate (i.e. it is not set to +FFFF). Any value below +FFFF is accepted (but later rounded to the nearest 'standard' value). 06B0 TEST-BAUD LD HL,(D-STR1) Fetch baud rate. 06B3 INC HL Accept any value except +FFFF. 06B4 LD A,L 06B5 OR H 06B6 RET NZ 'Missing baud rate' 06B7 RST 20,SH-ERR Call the error handling 06B8 DEFB +09 routine. THE 'EVALUATE STREAM OR EXPRESSION' SUBROUTINE This subroutine is used to deck the syntax of the MOVE Command. If the 'current' character is a hash sign (#), then a stream number is evaluated and stored into S-STR1 during runtime. Otherwise a channel expression like '"x";n ["name"]' is evaluated, and N-STR1, D-STR1 and L-STR1 are set as required and, if the channel specifier is "M" or "N", the parameters are checked to be in range. 06B9 EXPT-EXP1 RST 10,CALBAS Advance CH-ADD. 06BA DEFW +0020 06BC CP +23 Is the present code an hash sign? 06BE JP Z,064E,EXPT-STRM Evaluate stream number if so, 06C1 CALL 05F5,EXP-SPEC2 otherwise evaluate "x";n. 06C4 CALL 05B1,SEPARATOR Jump if there is no further 06C7 JR NZ,06CC,ENDHERE separator. 06C9 CALL 062F,EXPT-NAME Otherwise deal with "filename". 06CC ENDHERE RST 18,CHKSYNTAX Return if syntax is being checked. 06CD RET Z 06CE LD A,(LSTR-1) Fetch channel specifier. 06D1 CP +54 Return if It is "T". 06D3 RET Z 06D4 CP +42 Return if it is "B". 06D6 RET Z 06D7 CP +4E But check station no. if it is "N". 06D9 JP Z,068F,TEST-STAT 06DC JP 0685,TEST-MNAM Otherwise check "m" parameters. 06DF...06FF Unused locations (all set to .FF). THE 'UNPAGE' SUBROUTINE This subroutine is actually made by a single RET instruction, but the hardware detects that the Program Counter reaches the address +0700 and pages-in the 'main' ROM. 0700 UNPAGE RET RETurn to 'main' ROM. THE 'EVALUATE PARAMETERS' SUBROUTINE This very important subroutine is called to evaluate the syntax of the SAVE, LOAD, VERIFY and MERGE commands referred to the 'new' channels. The subroutine is entered with CH-ADD pointing to the command code; on exit during runtime the variables D-STR1, L-STR1, N-STR1, HD-00, HD-0B, HD-0D, HD-0F, HD-11 are properly set. 0701 EXPT-PRMS RST 10,CALBAS The next character is fetched from 0702 DEFW +0020 the line. 0704 CP +2A It must be a '*'. 0706 JR NZ,073C,OREP-1-2 Give an error if not a '*'. 0708 RST 10,CALBAS Advance CH-ADD past the '*'. 0709 DEFW +0020 070B CALL 05F5,EXP-SPEC2 Evaluate "x";n. 070E CALL 05B1,SEPARATOR Check that the separator dDEs exist. 0711 JR NZ,0716,NO-NAME Jump if no name is to be expected. 0713 CALL 062F,EXPT-NAME Evaluate "filename". 0716 NO-NAME PUSH AF The next character is saved. 0717 LD A,(L-STR1) Fetch channel specifier. 071A CP +4E Jump if the channel is not "N", 071C JR NZ,0122,NOT-NET 071E SET 3,(FLAGS3) otherwise signal "networking". 0722 NOT-NET POP AF Restore 'next character'. 0723 CP +0D Jump if the statement ends with 0725 JR Z,0750,END-EXPT ENTER, or 0727 CP +3A with a colon. 0729 JR Z,0750,END-EXPT 072B CP +AA Jump if the statement continues with 072D JR Z,0771,SCREEN$ SCREEN$. 072F CP +AF Jump with CODE. 0731 JR Z,0789,CODE 0733 CP +CA Jump with LINE. 0735 JR Z,973E,LINE 0737 CP +E4 Jump with DATA, otherwise give 0739 JP Z,07D2,DATA an error report. 'Nonsense in BASIC' 073C OREP-1-2 RST 20,SH-ERR Call the error handling 073D DEFB +00 routine. Now deal with LINE. 073E LINE RST 10,CALBAS Advance CH-ADD. 073F DEFW +0020 0741 RST 10,CALBAS Call EXPT-1NUM to evaluate the 0742 DEFW +1C82 autostart line number. 0744 CALL 05B7,ST-END Confirm end of statement, and exit during syntax checking. 0747 RST 10,CALBAS Fetch the autostart line number from 0748 DEFW +1E99 the calculator stack. 074A LD (HD-11),BC Store autostart line number. 074E JR 0753,PROG Jump forward. If there are no parameters (i.e. BASIC program), the syntax checking ends here. 0750 END-EXPT CALL 05B7,ST-END Confirm end of statement and exit during syntax checking. 0753 PROG XOR A Store 0 into HD-00 (signalling 0754 LD (HD-00),A 'program' file type). 0757 LD HL,(E-LINE) Address past the last location of variables area. 075A LD DE,(PROG) The 'start' of data is fetched 075E LD (HD-0D),DE from PROG, and stored into HD-0D. 0762 SCF This calculates 0763 SBC HL,DE ((E-LINE)-(PROG))-1, i.e. the length of the program and its variables. 0765 LD (HD-0B),HL The 'length' is stored. 0768 LD HL,(VARS) Now calculate (VARS)-(PROG), 076B SBC HL,DE i.e. the length of the program only. 076D LD (HD-0F),HL Store it into HD-0F. 0770 RET Finished. If the token is SCREEN$, the parameters are entered directly into the system variables. 0771 SCREEN$ RST 10,CALBAS Advance CH-ADD. 0772 DEFW +0020 0774 CALL 05B7,ST-END Confirm end of statement and exit during syntax checking. 0777 LD HL,+1B00 The 'length' of the display file 077A LD (HD-0B),HL and attributes is stored. 077D LD HL,+4000 The start address of the display 0780 LD (HD-0D),HL file. 0783 LD A,+03 Signal 'bytes' file type. 0785 LD (HD-00),A 0788 RET Finished. Now deal with CODE. 0789 CODE RST 10,CALBAS Advance CH-ADD. 078A DEFW +0020 078C CP +0D If there ate no further parameters, 078E JR Z,079A,DEFLT-0 jump to use '0' as default value. 0790 CP +3A Jump it there are parameters to be 0792 JR NZ,PAR-1 evaluated (i.e. the next character is not a colon). 0794 BIT 5,(FLAGS3) Give an error if SAVE "name"CODE is 0798 JR NZ,OREP-1-2 encountered by itself 079A DEFLT-0 RST 10,CALBAS A call to main ROM routine 'USE-ZERO' 079B DEFW +1CE6 is made to use a value of zero as default 079D JR 07A7,TEST-SAVE Jump forward. 079F PAR-1 RST 10,CALBAS Otherwise call EXPT-1NUM to use the 07A0 DEFW +1C82 specified value. 07A2 CALL 0581,SEPARATOR Jump if a separator is present. 07A5 JR Z,0782,PAR-2 07A7 TEST-SAVE BIT 5,(FLAGS3) Give an error if a parameter has been 07AB JR NZ,073C,OREP-l-2 missed in a SAVE name CODE command. 07AD RST 10,CALBAS Use zero also for the 2nd parameter, 07AE DEFW +1CE6 07B0 JR 07B8,END-CODE Jump forward. 07B2 PAR-2 RST 10,CALBAS Advance CH-ADD. 07B3 DEFW +0020 07B5 RST 10,CALBAS Evaluate the 2nd parameter by calling 07B6 DEFW +1CB2 EXPT-1NUM. 07B8 END-CODE RST 10,CALBAS Call GET-CHAR to fetch the 'last' 07B9 DEFW +0018 character in the statement. 07BB CALL 05B7,ST-END Confirm end of statement and exit if syntax is being checked. 07BE RST 10,CALBAS Fetch the "length" from the 07BF DEFW +1E99 calculator stack and 07C1 LD (HD-0B),BC store it. 07C5 RST 10,CALBAS Fetch the "start" from the calculator 07C6 DEFW +1E99 stack and store it. 07C8 LD (HD-0D),BC 07CC LD A,+03 Signal 'bytes' file type. 07CE LD (HD-00),A 07D1 RET Finished. Finally the routine to evaluate DATA parameters. 07D2 DATA BIT 6,(FLAGS3) Jump unless attempting to MERGE 07D6 JR Z,07DA,NO-M-ARR an array. 'MERGE error' 07D8 RST 20,SH-ERR Call the error handling 07D9 DEFB +14 routine. 07DA NO-M-ARR RST 10,CALBAS Advance CH-ADD to point to 07DB DEFW +0020 the array name. 07DD RST 10,CALBAS Call LOOK-VARS to look for the 07DE DEFW +28B2 array name. 07E0 SET 7,C Set bit 7 of array name. 07E2 JR NC,07F2,EXISTING Jump if handling an existing array. 07E4 LD HL,+0000 Signal 'using a new array'. 07E7 BIT 4,(FLAGS3) Jump forward if LOADing the array. 07EB JR NZ,080E,LD-DATA 07ED LD (ERR-NR),+01 Give the error report 'Variable not 07F1 RST 28,ROMERR found' if trying to SAVE a nonexistent array. 07F2 EXISTING JR Z,07F6,G-TYPE Continue only when handling a numeric or alphanumeric array, NOTE: This test fails to exclude simple strings, but the 'bug' (present in the main ROM) is corrected at 07FF. 07F4 NONS-BSC RST 20,SH-ERR 'Nonsense in BASIC' 07F5 DEFB +00 07F6 G-TYPE RST 18,CHKSYNTAX Jump forward if syntax is 07F7 JR Z,081C,END-DATA being checked. 07F9 BIT 5,(FLAGS3) Jump forward if not during a SAVE 07FD JR Z,0803,VR-DATA command. 07FF BIT 7,(HL) Give an error if trying to SAVE 0801 JR Z,07F4,NONS-BSC a simple string. 0803 VR-DATA INC HL Point to the 'length' of the array. 0804 LD A,(HL) Fetch low byte. 0805 LD (HD-0B-lo),A Store it. 0808 INC HL Point to high byte of 'length'. 0809 LD A,(HL) Fetch high byte. 080A LD (HD-0B-hi),A Store it. 080D INC HL Advance to the start of the array. 080E LD-DATA LD A,C Store array name into HD-0F. 080F LD (HD-0F-lo),A 0812 LD A,+01 Signal 'numeric array'. 0814 BIT 6,C Jump if really a numeric array. 0816 JR Z,0819,NUM-ARR 0818 INC A Otherwise A=2 to signal 'alphanumeric array'. 0819 NUM-ARR LD (HD-00),A Store file type. 081C END-DATA EX DE,HL DE holds the 'start' of the array (or +0000 with 'NEW' array to be loaded). 081D RST 10,CALBAS Advance CH-ADD. 081E DEFW +0020 0820 CP +29 Check that the ')' dDEs exist. 0822 JR NZ,07F4,NONS-BSC Report an error if not. 0824 RST 10,CALBAS Advance CH-ADD. 0825 DEFW +0020 0827 CALL 05B7,ST-END Confirm end of statement and exit during syntax checking. 082A LD (HD-0D),DE Store "start" of the array. 082E RET Finished. THE 'SAVE' COMMAND SYNTAX ROUTINE The actual saving is handled directly with "B" and "N" channels, or by SAVE-RUN if the 'N" channel is being used. 082F SAVE-SYN SET 5,(FLAGS3) Signal "Saving". 0833 CALL 0701,EXPT-PRMS Check syntax and set variables. 0836 LD A,(L-STR1) Fetch channel specifier. 0839 CP +42 Jump with "B" channel being used. 083B JR Z,084F,SA-HEADER 083D CP +4E Jump with other than "N" channel 083F JR NZ,0849,SAVE-M being used (i.e. with "M" channel). 0841 CALL 068F,TEST-STAT Check station number. 0844 CALL 0EA9,OP-TEMP-N Open a temporary "N" channel. 0847 JR 084F,SA-HEADER Jump forward. 0849 SAVE-M CALL 0685,TEST-MNAM Check "M" parameters. JP 1E7F,SAVE-RUN Jump forward. Now a loop is entered to SAVE to the "N" or "B" devices the 'header', i.e. the nine bytes taken from the system variables HD-00 to HD-11. 084F SA-HEADER LD B,+09 Nine bytes are to be saved. 0851 LD HL,+5CE6 Start of HD variables. 0854 HD-LOOP CALL 0880,SA-BYTE Save the byte pointed by HL. 0857 INC HL Each header byte in turn is saved. 0858 DJNZ 0854,HD-LOOP 085A LD HL,(HD-0D) Fetch 'start of data block'. 085D BIT 3,(FLAGS3) Jump if "B" channel is being used. 0861 JR Z,086E,SA-BLOCK 0863 LD A,(HD-00) Jump also if saving a block of memory 0866 CP +03 (i.e. SAVE..CODE). 0868 JR NC,086E,SA-BLOCK 086A LD DE,+0014 Otherwise the data to be saved have 086D ADD HL,DE been moved up by '276' bytes after the insertion of the "N" channel. 086E SABLOCK LD BC,(HD-0B) Fetch the 'length' of the block. 0872 SA-BLK-LP LD A,C Jump forward when the counter has 0873 OR B reached zero. 0874 JR Z,087D,S-BLK-END 0876 CALL 0880,SA-BYTE Send the byte pointed by HL. 0879 DEC BC Decrement 'length'. 087A INC HL Point to next byte. 087B JR 0872,SA-BLK-LP Jump back until the whole block has been saved. 087D S-BLK-END JP 0988,TST-MR-M Jump forward to send the 'end of file' block (only with Network). THE 'SAVE A BYTE TO NETWORK OR RS232 LINK' SUBROUTINE The byte pointed by the HL register pair is fetched and sent by using the "B" or the "N" channel output routing, depending upon the state of bit 3 of the FLAGS3 variable. 0880 SA-BYTE PUSH HL Save HL and BC register pairs. 0881 PUSH BC 0882 BIT 3,(FLAGS3) Test 'networking' bit. 0886 LD A,(HL) Fetch the byte to be saved. 0887 JR NZ,088E,SA-NET Jump if network is being used. 0889 CALL 0C5A,BCHAN-OUT Otherwise send the byte through the RS232 link. 088C JR 0891,SA-B-END Exit. 088E SA-NET CALL 0D6C,NCHAN-OUT Use "N" channel output routine to send the byte. 0891 SA-B-END POP BC Restore registers and return. 0892 POP HL 0893 RET TUE 'LOAD' COMMAND SYNTAX ROUTINE The syntax is checked with a single call to the EXPT-PRMS subroutine. 0894 LOAD-SYN SET 4,(FLAGS3) Signal 'doing a LOAD command'. 0898 CALL 0701,EXPT-PRMS Check syntax and set variables. 089B JP 08AF,LD-VF-MR Do the LOAD. THE 'VERIFY' COMMAND SYNTAX ROUTINE Again the syntax checking is handled by EXPT-PRMS. 089E VERIF-SYN SET 7,(FLAGS3) Signal 'doing a VERIFY command'. 08A2 CALL 0701,EXPT-PRMS Check syntax and set variables. 08A5 JP O8AF,LD-VF-MR Do the VERIFY. THE 'MERGE' COMMAND SYNTAX ROUTINE The syntax is handled by EXFT-PRMS the routine continues into the LOAD-VERIFY-MERGE routine below. 08A8 MRG-SYN SET 6,(FLAGS3) Signal 'doing a MERGE command'. 08AC CALL 0701,EXPT-PRMS Check syntax and set variables. THE "LOAD-VERIFY-MERGE' COMMANDS ROUTINE The action to be performed depends on the state of bits 4,6,7 of FLAGS3. The 'old' header Is expected to be in the HD area, and is immediately transferred into the D-STR2 area, while the 'new' header is loaded into the HD area. 08AF LD-VF-MR LD HL,+5CE6 Start of HD area. 08B2 LD DE,+5CDE Start of D-STR2 area. 08B5 LD BC,+0007 There are '7' bytes to be copied (HD-11 is not affected). 08B8 LDIR Copy the 'old' header into the D-STR2 area. 08BA LD A,(L-STR1) Fetch channel specifier. 08BD CP +4E Jump if network is being used. 08BF JR Z,08CD,TS-L-NET 08C1 CP +42 Jump if RS232 link is being used. 08C3 JR Z,08D3,TS-L-RS 08C5 CALL 0685,TEST-MNAM Check "M" parameters. 08C8 CALL 1580,F-M-HEAD Fetch first nine bytes from cartridge and store into HD area. 08CB JR 08F2,TEST-TYPE Jump forward. 08CD TS-L-NET CALL 068F,TEST-STAT Check station number. 08D0 CALL 0EA9,OP-TEMP-N Open a temporary "N" channel. 08D3 TS-L-RS LD HL,+5CE6 Start of HD area. 08D6 LD B,+09 Nine bytes are now expected. 08D8 LD-HEADER PUSH HL Save HL and BC register pairs. 08D9 PUSH BC 08DA BIT 3,(FLAGS3) Jump if using RS232 link. 08DD JR Z,08E7,LD-HD-RS 08E0 LD-HD-NET CALL 0D12,NCHAN-IN Fetch a byte from "N" channel. 08E3 JR NC,08E0,LD-HD-NET Repeat until the byte is acceptable. 08E5 JR 08EC,LD-HDR-2 Jump forward. 08E7 LD-HD-RS CALL 0B81,BCHAN-IN Fetch a byte from RS232 link. 08EA JR NC,08E7,LD-HD-RS Repeat until the byte is acceptable. 08EC LD-HDR-2 POP BC Restore registers. 08ED POP HL 08EE LD (HL),A Store the byte into the HO area. 08EF INC HL Advance the pointer. 08F0 DJNZ 08D8,LD-HEADER Go around the loop again. 08F2 TEST-TYPE LD A,(5CDE) Fetch 'old' type from D-STR2 08F5 LD B,A area and store into B register. 08F6 LD A,(HD-00) Fetch 'new' file type. 08F9 CP B Compare with the 'old' one. 08FA JR NZ,0902,NREPORT-N Give an error if it does not match. 08FC CP +03 Jump if handling a block of bytes. 08FE JR Z,0911,T-H-CODE 0900 JR C,0904,TST-MERGE Jump with other types (but refuse types greater than 3). 'Wrong file type' 0902 NREPORT-N RST 20,SH-ERR Call the error handling 0903 DEFB +16 routine. 0904 TST-MERGE BIT 6,(FLAGS3) Jump if doing a MERGE. 0908 JR NZ,0967,MERGE-BLK 090A BIT 7,(FLAGS3) Jump if not doing a VERIFY (i.e. 090E JP Z,09A3,LD-PR-AR doing a LOAD). Now deal with loading of files of type 3 (i.e. CODE and SCREENS), or verifying of all file types. 0911 T-M-CODE BIT 6,(FLAGS3) Allow for the loading or 0915 JR Z,0919,LD-BLOCK verifying, but not for the mergeing of a 'CODE' block. 'MERGE error' 0917 RST 20,SH-ERR Call the error handling 0918 DEFB +14 routine. 0919 LD-BLOCK LD HL,(+5CDF) Get 'old' length from D-STR2. 091C LD DE,(HD-0B) Get 'new' length. 0920 LD A,H Jump forward if 'old' length is 0 0921 OR L (i.e. not specified in the command). 0922 JR Z,0932,LD-BLK-2 0924 SBC HL,DE Accept the 'old' length if it is 0926 JR NC,0932,LD-BLK-2 greater than or equal to the 'new' one. 0928 BIT 4,(FLAGS3) But give an error if attempting 092C JR Z,0930,NREPORT-L to LOAD or VERIFY a larger block than has been requested. 'CODE error' 092E RST 20,SH-ERR Call the error handling 092F DEFB +13 routine. 'Verification has failed' 0930 NREPORT-L RST 20,SH-ERR Call the error handling 0931 DEFB +15 routine. 0932 LD-BLK-2 LD HL,(5CE1) Get 'old' start from D-STR2. 0935 LD A,(IX+4) Fetch specifier from the channel area. 0938 CP +CD Jump if not "M"+80, i.e. not a 093A JR NZ,0941,LD-BLK1 temporary "M" channel. 093C LD HL,(5CE4) But if the "M" channel is being used, the 'start' has been stored into +5CE4 (see +1583). 093F JR 0952,LD-BLK4 Jump forward. 0941 LD-BLK-3 BIT 3,(FLAGS3) Jump if not using the network. 0945 JR Z,0952,LD-BLK-4 0947 LD A,(HD-00) Jump if it is a block of bytes. 094A CP +03 094C JR Z,0952,LD-BLK-4 094E LD BC,+01l4 Otherwise the data has been moved 0951 ADD HL,BC up by '276' bytes after the insertion of the "N" channel. 0952 LD-BLK-4 LD A,H Use 'old' start if it has been 0953 OR L specified in the command, 0954 JR NZ,0959,LD-BLK-5 otherwise use 'new' start. 0956 LD HL,(HD-0D) 0959 LD-BLK-5 LD A,(HD-00) Use the 'start' in HL for types 095C AND A other than 'program'. 095D JR NZ,0962,LD~NO-PGM 095F LD HL,(PROG) But with 'program' type, the 'start' is pointed by PROG. 0962 LD-NO-PGM CALL 0A5C,LV-ANY Do the actual LOADing or VERIFYing. 0965 JR 0988,TST-MR-M Jump forward to close the channel used. Now consider the MERGEing of a program. 0967 MERGE-BLK LD A,(HD-11-hi) Continue only if the content of 096A AND +C0 HD-11 is sufficiently high, i.e. if 096C JR NZ,0973,NO-AUTOST the program was not saved with 'autostart' 096E CALL 17B9,RCL-T-CH Otherwise reclaim channels and give 0971 RST 20,SH-ERR a 'MERGE error'. 0972 DEFB +14 0973 NO-AUTOST LD BC,(HD-0B) Fetch 'length' of program to be 0977 PUSH BC merged and save it. 0978 INC BC Allows for a further location to insert the 'end marker'. 0979 RST 10,CALBAS Call BC-SPACES to make the 097A DEFW +0030 required room in workspace. 097C LD (HL),+80 Mark the end of the space. 097E EX DE,HL HL now points to the start of the space created. 097F POP DE Restore length of program. 0980 PUSH HL Save 'start' pointer. 0981 CALL 0A5C,LV-ANY Load the program in the workspace. 0984 POP HL Restore 'start' pointer. 0985 RST 10,CALBAS Do the mergeing with the existing 0986 DEFW +08CE program by entering into the main ROM 'MERGE' control routine. 0988 TST-MR-M LD A,(IX+4) Jump if the specifier is not "M"+80 098B CP +CD i.e. if other than "M" channel has 098D JR NZ,0994,TST-MR-N been used. 098F CALL 12A9,CLOSE-M2 Close the "M" channel. 0992 JR 09A0,MERGE-END Jump forward. 0994 TST-MR-N BIT 3,(FLAGS3) Exit immediately if the "B" output 0998 JR Z,09A0,MERGE-END has been used. 099A CALL 0EF5,SEND-NEOF Why? 099D CALL 17B9,RCL-T-CH Reclaim the channel. 09A0 MERGE-END JP 05C1,END1 Finished. The final branch of the routine deals with the LOADIng of a program or an array. 09A3 LD-PR-AR LD DE,(HD-0B) Fetch 'new' length. 09A7 LD HL,(5CE1) Fetch 'old' start (set to 0 when loading a 'new' array). 09AA PUSH HL Save it temporarily. 09AB LD A,H Jump if not a 'new' array. 09AC OR L 09AD JR NZ,09B5,LD-PROG 09AF INC DE Increment 'length' by 3, i.e. allows 09B0 INC DE for the insertion of array name and 09B1 INC DE two-byte length. 09B2 EX DE,HL Move 'length' into HL. 09B4 JR 09BE,TST-SPACE Jump forward. 09B5 LD-PROG LD HL,(5CDF) Fetch 'old' length (i.e. length of existing program or array) from D-STR2 area. 09B8 EX DE,HL HL holds the 'new' length. 09B9 SCF Jump forward if the program (or 09BA SBC HL,DE array) being loaded is no longer 09BC JR C,09C7,TST-TYPE than the existing one. 09BE TST-SPACE LD DE,+0005 Otherwise a check must be made to 09C1 ADD HL,DE ensure that there is sufficient space 09C2 LD B,H in memory for the program (or array) 09C3 LD C,L to be loaded, with a call to main ROM 09C4 RST 10,CALBAS 'TEST-ROOM' subroutine. 09C5 DEFW +1F05 09C7 TST-TYPE POP HL Restore 'old' start (+0000 when handling a 'new' array). 09C8 LD A,(HD-00) Jump if 'type' indicates a 09CB AND A BASIC program (+00). 09CC JR Z,0A15,SET-PROG 09CE LD A,H Jump unless an 'old' array is to be 09CF OR L erased before 09D0 JR Z,09F3,CRT-NEW loading the 'new' one. 09D2 LD A,(IX+4) If the channel specifier denotes 09D5 CP +CD other than temporary "M" channels 09D7 JR NZ,09DE,T-LD-NET (i.e. "M"+80H), the 'start' is already held in HL. 09D9 LD HL,(5CE4) Otherwise the start address of the array is fetched from D-STR2 area. 09DC JR 09E8,RCLM-OLD 09DE T-LD-NET BIT 3,(FLAGS3) Jump if using the 515232 link. 09E2 JR Z,09E8,RCLM-OLD 09E4 LD DE,+0114 Otherwise the array has been moved 09E7 ADD HL,DE '276' bytes up after the insertion of "N" channel. 09E8 RCLM-OLD DEC HL Points to the high byte of 'array length'. 09E9 LD B,(HL) Fetch high byte. 09EA DEC HL Points to the low byte. 09EB LD C,(HL) Fetch low byte. 09EC DEC HL Points to the array name. 09ED INC BC Include 'length' and 'name' in the 09EE INC BC array length. 09EF INC BC 09F0 RST 10,CALBAS Call RECLAIM-2 to delete the array. 09F1 DEFW +19E8 09F3 CRT-NEW LD HL,(E-LINE) Points to the end of variables area. 09F6 DEC HL 09F7 LD BC,(HD-0B) Fetch the length of the array to be loaded. 09FB PUSH BC Save it. 09FC INC BC Include in the length one byte for 09FD INC BC array name and two for 'length of 09FE INC BC array 09FF LD A,(5CE3) Fetch array name from D-STR2 area. 0A02 PUSH AF Save it briefly. 0A03 RST 10,CALBAS Call MAKE-ROOM to create the space 0A04 DEFW +1655 for the array. 0A06 INC HL Points to the first 'new' location inserted. 0A07 POP AF Restore array name and store into 0A08 LD (HL),A the 1st location. 0A09 POP DE Fetch 'array length'. 0A0A INC HL Store it into the following two 0A0B LD (HL),E locations. 0A0C INC HL 0A0D LD (HL),D 0A0E INC HL The array will be loaded from this location. 0A0F END-LD-PR CALL 0A5C,LV-ANY Load array or BASIC program. 0A12 JP 0988,TST-MR-M Jump back to close the channel. If the file loaded is a program, the space required is to be crested and some actions to be performed. 0A15 SET-PROG RES 1,(FLAGS3) Signal 'no autostart' 0A19 LD DE,(PROG) Fetch start of existing program. 0A1D LD HL,(E-LINE) Fetch end of existing program. 0A20 DEC HL 0A21 RST 10,CALBAS Call RECLAIM-1 in the main ROM to 0A22 DEFW +19E5 delete the program. 0A24 LD BC,(HD-0B) Fetch length of program and variables. 0A28 LD HL,(PROG) Fetch start address of program. 0A2B RST 10,CALBAS Call MAKE-ROOM to create the 0A2C DEFW +1655 required space. 0A2E INC HL Points to the first location. 0A2F LD BC,(HD-0F) Fetch program length. 0A33 ADD HL,BC Calculate and store the start of 0A34 LD (VARS),HL variables area. 0A37 LD A,(HD-11-hi) This is set to +FF when no autostart 0A3A LD H,A is required. 0A3B AND +C0 0A3D JR NZ,0A4E,NO-AUTO Jump with 'no autostart'. 0A3F SET 1,(FLAGS3) Signal 'autostart' (see +0049). 0A43 LD A,(HD-11-lo) Fetch low byte of autostart line 0A46 LD L,A number. 0A47 LD (NEWPPC),HL Store autostart line no. 0A4A LD (NSPPC),+00 Clear NSPPC to signal 'jump'. 0A4E NO-AUTO LD HL,(PROG) Fetch start address of program area. 0A51 LD DE,(HD-0B) Fetch program length. 0A55 DEC HL Make DATADD point to the last byte 0A56 LD (DATADD),HL of the CHANS area. 0A59 INC HL Balance the DEC above. 0A5A JR 0A0F,END-LD-PR Jump back to LOAD the new program. THE 'LOAD OR VERIFY' SUBROUTINE This subroutine is used to LOAD or VERIFY (depending upon the state of bit 7 of FLAGS3 system variable) a block of bytes. It must be entered with the 'start' and the 'length' in the HL and DE register pairs, and with all system variables properly set. 0A5C LV-ANY LD A,D Return if 'length' is zero. 0A5D OR E 0A5E RET Z 0A5F LD A,(IX+4) Fetch channel specifier and jump if 0A62 CP +CD handling with RS232 or network. 0A64 JR NZ,0A6A,LV-BN 0A66 CALL 15A9,LV-MCH LOAD or VERIFY from Microdrive. 0A69 RET Finished. 0A6A LV-BN PUSH HL Save 'start' and 'length'. 0A6B PUSH DE 0A6C BIT 3,(FLAGS3) Jump if RS232 link is being used. 0A70 JR Z,0A79,LV-B 0A72 LV-N CALL 0D12,NCHAN-IN Fetch a byte by using the "N" channel 0A75 JR NC,0A72,LV-N Input routine. 0A77 JR 0A7E,LV-BN-E Jump forward. 0A79 LV-B CALL 0B81,BCHAN-IN Fetch a byte by using the "B" channel 0A7C JR NC,0A79,LV-B input routine. 0A7E LV-BN-E POP DE Restore 'length' and decrease it. 0A7F DEC DE 0A80 POP HL Restore 'start'. 0A81 BIT 7,(FLAGS3) Jump when VERIFYING. 0A85 JR NZ,0A8A,VR-BN 0A87 LD (HL),A The actual LOAD, i.e. store the received byte. 0A88 JR 0A8F,LVBN-END Jump forward. 0A8A VR-BN CP (HL) The actual VERIFY, i.e. compare the received byte with that held in memory. 0A8B JR Z,0A8F,LVBN-END Continue only if the bytes are equal. 'Verification has failed' 0A8D RST 20,SH-ERR Call the error handling 0A8E DEFB +15 routine. 0A8F LVBN-END INC HL Move 'start' on to address the next location. 0A90 LD A,E Repeat until 'length' has reached 0. 0A91 OR D 0A92 JR NZ,0A6A,LV-BN 0A94 RET Finished. THE 'LOAD "RUN" PROGRAM' ROUTINE First the various system variables are properly set, then a nine-byte header is fetched from the first record of the program called 'run'. The routine continues into the middle of the LOAD~VERIFY-MERGE commands routine. 0A95 LOAD-RUN LD BC,+0001 Load from drive 1. 0A98 LD (D-STR1),BC 0A9C LD BC,+0003 The filename 'run' is three 0A9F LD (N-STR1),BC characters in length. 0AA3 LD BC,+0AC6 The filename is stored from this 0AA6 LD (N-STR1+2),BC location. 0AAA SET 4,(FLAGS3) Signal 'loading'. 0AAE CALL 0753,PROG Set HD variablea as required. 0AB1 LD HL,+5CE6 Copy 'old' header into D-STR2 area. 0AB4 LD DE,+5CDE 0AB7 LD BC,+0009 0ABA LDIR Clear the 'jump' signal set by using 0ABC SET 7,(NSPPC) the RUN command. 0AC0 CALL 1580,F-M-HEAD Load the 'new' 9-byte header. 0AC3 JP 08F2,TEST-TYPE Jump back in the middle of the LOAD-VERIFY-MERGE commands routine. 0AC6 DEFM "run" The 'run' filename. The RS-232 link routines THE 'SET "BAUD" SYSTEM VARIABLE' ROUTINE This routine is entered with a baud rate in the range 0. .65534 in the system variable D-STR1. It rounds the value to the nearest 'standard' value and sets the BAUD system variable with the appropriate timing constant. It is used by the 'FORMAT' command routine. 0AC9 SET-BAUD LD BC,(D-STR1) Fetch baud rate. 0ACD LD HL,+0AEF Start of RS232 timing constants table. 0AD0 NXT-ENTRY LD E,(HL) Fetch an entry in the DE register 0AD1 INC HL pair. 0AD2 LD D,(HL) 0AD3 INC HL 0AD4 EX DE,HL Pass the value to HL. 0AD5 LD A,H Fetch high byte. 0AD6 CP +48 Jump if the end of the table has been 0AD8 JR NC,0AE4,END-SET reached. 0ADA AND A Jump also if this value is greater 0ADB SBC HL,BC than or equal to the supplied one. 0ADD JR NC,0AE4,END-SET 0ADF EX DE,HL Restore the 'pointer' in HL. 0AE0 INC HL Skip the constant and jump back 0AE1 INC HL to examine the next table entry. 0AE2 JR 0AD0,NXT-ENTRY 0AE4 END-SET EX DE,HL Restore the pointer in HL. 0AE5 LD E,(HL) Fetch the timing constant. 0AE6 INC HL 0AE7 LD D,(HL) 0AE8 LD (BAUD),DE Store the constant. 0AEC JP 05C1,END1 Finished. THE 'RS232 TIMING CONSTANTS' TABLE The '9' entries in this table are the 'standard' baud rate values (from 75 to 19200), each one followed by the 'timing constant' to be stored in the BAUD system variable. 0AEF DEFW +0032 First baud rate=50 (but the constant 0AF1 DEFW +0A82 is for 75 baud). 0AF3 DEFW +006E 2nd baud rate=110. 0AF5 DEFW +04C5 Constant for 110 baud. 0AF7 DEFW +012C 3rd baud rate=300. 0AF9 DEFW +01BE Constant for 300 baud. 0AFB DEFW +0258 4th baud rate=600. 0AFD DEFW +00DE Constant. 0AFF DEFW +04B0 5th baud rate=1200. 0B01 DEFW +006E Constant. 0B03 DEFW +0960 6th baud rate=2400. 0B05 DEFW +0036 Constant. 0B07 DEFW +12C0 7th baud rate=4800. 0B09 DEFW +001A Constant. 0B0B DEFW +2580 8th baud rate=9600. 0B0D DEFW +000C Constant. 0B0F DEFW +4B00 Last baud rate=l9200. 0B11 DEFW +0005 Constant. THE 'OPEN RS232 CHANNEL IN CHANS AREA' SUBROUTINE This subroutine opens a permanent "B" or "T" channel (depending upon the specifier held in L-STR1) at the end of the CHANS area. On return, the DE register pair will hold the start of the channel. 0B13 OP-RS-CH LD HL,(PROG) The start address 0B16 DEC HL of the channel. 0B17 LD BC,+000B The channel is '11' bytes in length. 0B1A PUSH BC 0B1B RST 10,CALBAS Call MAKE-ROOM to create the required 0B1C DEFW +1655 space. 0B1E POP BC Restore 'length'. 0B1F PUSH DE Save address of last byte in the inserted area. 0B20 CALL 1691,REST-N-AD Restore start address of 'filename' if it has been moved up after the insertion of the new space. 0B23 POP DE Restore 'end of channel' address. 0B24 LD HL,+0B6E Last byte in the "T" channel data table. 0B27 LD BC,+000B Length of the table. 0B2A LDDR Copy the 'T' channel data. 0B2C INC DE Point to the 1st location of the channel. 0B2D LD A,(L-STR1) Fetch channel specifier. 0B30 CP +42 Return if the requested channel was 0B32 RET NZ not the 'B' channel. 0B33 PUSH DE Save channel start address. 0B34 LD HL,+0005 Point to the 'shadow ROM output 0B37 ADD HL,DE routine' pointer. 0B38 LD DE,+0C5A the address of the BCHAN—OUT routine. 0B3B LD (HL),E Store the low byte. 0B3C INC HL 0B3D LD (HL),D Store the high byte. 0B3E INC HL Point to the 'shadow ROM input routine' pointer. 0B3F LD DE,+0B75 The address of the B—INPUT routine, 0B42 LD (HL),E Store the low byte. 0B43 INC HL 0B44 LD (HL),D Store the high byte. 0B45 POP DE Restore channel start address. 0B46 RET Finished. THE 'ATTACH CHANNEL TO A STREAM' ROUTINE The entry point is OP-RSCHAN if the channel is "B" or "T", otherwise the routine is entered at OP-STREAM with "N" channel (from 0EA6), with DE holding the channel start address. The correct displacement is calculated for the stream whose number is held in S-STR1, and stored in the STRMS area. 0B47 OP-RSCHAN CALL 0Bl3,OP-RS-CH Create the channel area. 0B4A OP-STREAM LD HL,(CHANS) Calculate the displacement to be 0B4D DEC HL stored in STRMS. 0B4E EX DE,HL 0B4F AND A 0B50 SBC HL,DE 0B52 EX DE,HL Pass the displacement to DE. 0B53 LD HL,+5C16 Location in STRMS for stream 0. 0B56 LD A,(S-STR1) Fetch stream number and 0B59 RLCA double it. 0B5A LD C,A Move the offset to the BC register 0B5B LD B,+00 pair. 0B5D ADD HL,BC Index into the STRMS area. 0B5E LD (HL),E Store the displacement. 0B5F INC HL 0B60 LD (HL),D 0B61 JP 05C1,END1 Finished. THE '"T" CHANNEL DATA' TABLE The '11' bytes that composes a "T" RS232 channel are as follows: 0B64 DEFW +0008 Main ROM 'output' routine. 0B66 DEFW +0008 Main ROM 'input' routine. 0B68 DEFB +54 "T" (channel specifier). 0B69 DEFW +0C3C Shadow ROM 'output' routine. 0B6B DEFW +0B6F Shadow ROM 'input' routine. 0B6D DEFW +000B Length of this channel. THE '"T" CHANNEL INPUT' ROUTINE The actual 'input' is handled by the CALL-INP routine; the service routine is TCHAN-IN below. 0B6F T-INPUT LD HL,+0B7B Address of TCHAN-IN routine. 0B72 JP 0CBD,CALL-INP Jump forward. THE '"B" CHANNEL INPUT' ROUTINE As with the "T" channel, the 'input' is handled by CALL-INP; however the service routine is BCHAN-IN. 0B75 B-INPUT LD HL,+0B81 Address of BCHAN-IN routine. 0B78 JP 0CBD,CALL-INP Jump forward. THE '"T" CHANNEL INPUT' SERVICE ROUTINE The only difference in respect to the "B" input is that the most significant bit of the received character is always cleared. 0B7B TCHAN-IN CALL 0B81,BCHAN-IN Use the "B" channel input service routine. 0B7E RES 7,A Accept only codes in the range +00... +7F (ASCII 7 bit). 0B80 RET Finished. THE '"B" CHANNEL INPUT' SERVICE ROUTINE This subroutine is also called by using the hook code +1D; it always returns carry set if an acceptable byte has been read in the A register from the RS232 link, or zero flag set when no byte has been read. 0B81 BCHAN-IN LD HL,+5CC7 Fetch contents of SER-FL-lo system 0B84 LD A,(HL) variable. 0B85 AND A Proceed in receiving the byte if it 0B86 JR Z,0B8E,REC-BYTE holds zero. 0B88 LD (HL),+00 Otherwise clear SER-FL-lo and fetch 0B8A INC HL the byte from SER-FL-hi. 0B8B LD A,(HL) 0B8C SCF Signal 'acceptable code'. 0B8D RET 0B8E REC-BYTE LD A,+7F Read port +7FFE. 0B90 IN A,(+FE) 0B92 RRCA Rotate bit 0 into carry. 0B93 JR C,0B9A,REC-PROC Jump if SPACE not being pressed. 0B95 LD (ERR-NR),+14 Otherwise give the 'Break into 0B99 RST 28,ROMERR program' error report. 0B9A REC-PROC DI Disable interrupts. 0B9B LD A,(IOBORD) Fetch new border colour. 0B9E OUT (+FE),A Change border colour. 0BA0 LD DE,(BAUD) Fetch timing constant. 0BA4 LD HL,+0320 Repeat '800' times the test. 0BA7 LD B,D Copy timing constant into the BC 0BA8 LD C,E register pair. 0BA9 SRL B Make BC hold (constant/2). 0BAB RR C 0BAD LD A,+FE Make high the CTS line. 0BAF OUT (+EF),A Now a loop is entered to check if a 'start bit' is found from the TXdata line. A 'start bit' is detected if the TXdata line is high for at least '77' T cycles. If after about 25 ms no 'start bit' is found, the routine continues forward. 0BB1 READ-RS IN A,(+F7) Read TXdata line. 0BB3 RLCA Shift state into carry. 0BB4 JR NC,0BC5,TST-AGAIN Jump if the line has a low level. 0BB6 IN A,(+F7) Repeat the test three times, i.e. make 0BB8 RLCA sure that TXdata is still high after 0BB9 JR NC,0BC5,TST-AGAIN 77 T cycles, 0BBB IN A,(+F7) 0BBD RLCA 0BBE JR NC,0BC5,TST-AGAIN 0BC0 IN A,(+F7) 0BC2 RLCA 0BC3 JR C,0BD1,START-BIT Jump if the beginning of a 'start bit' is found. 0BC5 TST-AGAIN DEC HL Decrease the counter. 0BC6 LD A,H Repeat the test until the counter 0BC7 OR L reaches zero. 0BC8 JR NZ,0BB1,READ-RS 0BCA PUSH AF Save zero flag set. 0BCB LD A,+EE Make the CTS line low again. 0BCD OUT (+EF),A 0BCF JR 0BF0,WAIT-1 Jump forward to repeat the test. This loop is used to read the eight data bits that follows the 'start' bit. First, a delay equal to ((BAUD)*1.5)*26 T cycles is entered, so the first reading is made at the middle of the first data bit. The seven subsequent readings are separated by a delay of (47+26*(BAUD)) T cycles, that is the length of each bit. 0BD1 START-BIT LD H,B Get (BAUD/2) into HL. 0BD2 LD L,C 0BD3 LD B,+80 Set a marker into bit 7. 0BD5 DEC HL Decrease HL three times, i.e. short 0BD6 DEC HL the loop by 78 T cycles, balancing 0BD7 DEC HL the time spent before. 0BD8 SERIAL-IN ADD HL,DE Add (BAUD) to HL. 0BD9 NOP Wait 4 T cycles. 0BDA BD-DELAY DEC HL Insert a delay (26*BAUD) T cycles in 0BDB LD A,H length. 0BDC OR C 0BDD JR NZ,0BDA,BD-DELAY 0BDF ADD A,+00 Wait 7 T cycles. 0BE1 IN A,(+F7) Read a bit. 0BE3 RLCA Shift it into carry flag, then into 0BE4 RR B the B register. 0BE6 JR NC,0BD8,SERIAL-IN Repeat until the 'marker' is found (i.e., 8 bits have been read), 0BE8 LD A,+EE Make the CTS line having a low level. 0BEA OUT (+EF),A 0BEC LD A,B Fetch the received byte. 0BED CPL Complement it (the bits are sent inverted through the RS232 link). 0BEE SCF Signal 'acceptable codes' when exit. 0BEF PUSH AF Save the byte and carry flag. 0BF0 WAIT-1 ADD HL,DE Make HL hold (BAUD). 0BF1 WAIT-2 DEC HL Wait until the first stop bit is 0BF2 LD A,H finished. 0BF3 OR L 0BF4 JR NZ,0BF1,WAIT-2 0BF6 ADD HL,DE 0BF7 ADD HL,DE 0BF8 ADD HL,DE HL now holds (BAUD)*3. Now a loop similar to that at 0BB1 is entered. If the TXdata line is found high for at least 77 T cycles, the 'sending' device is sending the 'start' bit for a second byte, even if the CTS line has a low signal level. This byte is to be read and stored into SER-FL. 0BF9 T-FURTHER DEC HL Decrease counter. 0BFA LD A,L Repeat test until it has reached 0. 0BFB OR H 0BFC JR Z,0C36,END-RS-IN Exit if there is no further byte to be received. 0BFE IN A,(+F7) Read TXdata line. 0C08 RLCA Shift received bit into carry. 0C01 JR NC,0BF9,T-FURTHER Jump back with TXdats low. 0C03 IN A,(+F7) Otherwise repeat the test three times 0C05 RLCA to ensure that TXdata is still 0C06 JR NC,0BF9,T-FURTHER high after 77 T cycles, 0C08 IN A,(+F7) 0C0A RLCA 0C0B JR NC,0BF9,T-FURTMER 0C0D IN A,(+F7) 0C0E RLCA 0C10 JR NC,0BF9,T-FURTHER 0C12 LD H,D Fetch timing constant into HL. 0C13 LD L,E 0C14 SRL H Calculate (BAUD)/2 into HL. 0C16 RR L The next instructions are the same as those stored from 0BD3 above, so they are not commented. 0C18 LD B,+00 0C1A DEC HL 0C1B DEC HL 0C1C DEC HL 0C1D SER-IN-2 ADD HL,DE 0C1E NOP 0C1F BD-DELAY2 DEC HL 0C20 LD A,H 0C21 OR L 0C22 JR NZ,0C1F,BD-DELAY2 0C24 ADD A,+00 0C26 IN A,(+F7) 0C28 RLCA 0C29 RR B 0C2B JR NC,0C1D,SER-IN-2 Finally, the last byte received is stored into SER-FL, and the first one returned into the A register. 0C2D LD HL,+5CC7 Points to SER-FL-lo 0C30 LD (HL),+01 Set it to +01, indicating that SER-FL-hi holds a valid byte. 0C32 INC HL Points to SER-FL-hi. 0C33 LD A,B Fetch the received byte. 0C34 CPL Complement it and store into 0C35 LD (HL),A SER-FL-hi. 0C36 END-RS-IN CALL 0CA9,BORDREST Restore border colour. 0C39 POP AF Restore first byte and flags. 0C3A EI Enable interrupts. 0C3B RET Finished. THE '"T" CHANNEL OUTPUT' ROUTINE The "t" channel output involves the 'sending' over the RS232 link of the character held into the A register, provided that it is within the range +20...+7F. Characters from +80 to +A4 are sent as '?', while tokens are de-tokenised. Codes lower than +20 are ignored, except for +0D that sends both CR and LF codes. The routine unfortunately contains a mistake as it does not suppress the 'leading space' flag (bit 0 of FLAGS) as required. The result is that when sending two tokens (i.e., THEN GOTO), two spaces are inserted between them, instead of one. The correct routine should include the following two instructions after the final 'RET C': 'JR NZ,BCHAN-OUT' and 'SET 0,(FLAGS)', and a 'RES 0,(FLAGS)' before the 'CP +7F'. 0C3C TCHAN-OUT CF +A5 Jump if the code is not a token code. 0C3E JR C,0C46,NOT-TOKEN 0C40 SUB +A5 Reduce range of token, 0C42 RST 10,CALBAS and detokenise it by calling 0C43 DEFW +0C10 recursively this routine via main ROM 0C45 RET 'PO-TOKENS' routine. 0C46 NOT-TOKEN CP +7F Jump if the character is not a 0C48 JR C,0C4C,NOT-GRAPH graphic character. 0C4A LD A,+3F Otherwise send a '?'. 0C4C NOT-GRAPH CP +0D Is the code 'ENTER'? 0C4E JR NZ,0C57,NOT-CR Jump if not. 0C50 CALL 0C5A,BCHAN-OUT Otherwise send the CR code. 0C53 LD A,+0A Follow it with a linefeed code. 0C55 CALL 0C5A,BCHAN-OUT 0C57 NOT-CR CP +20 Ignore all codes lower than +20, 0C59 RET C otherwise use BCHAN-OUT below to send the character. THE '"B" CHANNEL OUTPUT' ROUTINE The 8 bits that forms the byte held in the A register are sent inverted through the RS232 link, after an initial 'start' bit (high), and followed by two 'stop' bits (or rather a 'double length' stop bit, with low signal level). As with 'b' channel input, the bits have a fixed length, depending upon the selected baud rate. This subroutine is also called by the 'hook code' +1E. 0C5A BCHAN-OUT LD B,+0B Counts '11' bits. 0C5C CPL Invert the eight data bits. 0C5D LD C,A C holds the byte to be sent. 0C5E LD A,(IOBORD) Fetch new border colour. 0C61 OUT (+FE),A Change border colour. 0C63 LD A,+EF Reset CTS and select RS232. 0C65 OUT (+EF),A 0C67 CPL 0C68 OUT (+F7),A Make RXdata have a low signal level. 0C6A LD HL,(BAUD) Fetch timing constant. 0C6D LD D,H Copy into DE register pair. 0C6E LD E,L 0C6F BD-DEL-1 DEC DE Firstly wait (26*(BAUD)) T cycles. 0C70 LD A,D 0C7l OR E 0C72 JR NZ,0C6F,BD-DEL-1 0C74 TEST-DTR LD A,+7F Read port +7FFE (SPACE key). 0C76 IN A,(+FE) 0C78 OR +FE Read port +FEFE (CAPS SHIFT key) only 0C7A IN A,(+FE) if SPACE is being pressed. 0C7C RRA Test bit 0. 0C7D JP NC,0CB4,BRK-INOUT Give an error if BREAK is pressed. 0C80 IN A,(+EF) Read DTR line. 0C82 AND +08 Only bit 3. 0C84 JR Z,0C74,TEST-DTR Jump back until DTR is found high. 0C86 SCF Set carry flag (start bit). 0C87 DI Disable interrupts. 0C88 SER-OUT-L ADC A+00 In fact, shift carry into bit 0 of accumulator. 0C8A OUT (+F7),A Send this bit over RS232 link. 0C8C LD D,H Copy timing constant into DE. 0C8D LD E,L 0C8E BD-DEL-2 DEC DE Wait 26*(BAUD) T cycles after having 0C8F LD A,D sent each bit. 0C90 OR E 0C9l JR NZ,0C8E,BD-DEL-2 0C93 DEC DE Wait 6 T cycles. 0C94 XOR A Clear A for next pass. 0C95 SRL C Shift the bit to be sent into carry. 0C97 DJNZ 0C88,SER-OUT-L Loop for all 11 bits. 0C99 DI Enable interrupts. 0C9A LD A,+01 0C9C LD C,+EF 0C9E LD B,+EE 0CA0 OUT (+F7),A Make RXdata having a high level. 0CA2 OUT (C),B Turn off RS232. 0CA4 BD-DEL-3 DEC HL Insert a final delay before returning 0CA5 LD A,L via the border-restore routine 0CA6 OR H below. 0CA7 JR NZ,0CA4,BD-DEL-3 THE 'BORDER COLOUR RESTORE' SUBROUTINE This subroutine is used whenever the border colour has been changed to IOBORD during an I/O operation, and needs to be restored to its original state. 0CA9 BORD-REST LD A,(BORDCR) Fetch lower screen attribute. 0CAC AND +38 Only bits 3,4,5, i.e. BORDER. 0CAE RRCA Rotate colour into bits 0,l,2. 0CAF RRCA 0CB0 RRCA 0CB1 OUT (+FE),A Restore colour. 0CB3 RET Finished. THE 'BREAK INTO I/O OPERATION' ROUTINE Whenever BREAK is pressed during an I/O operation, the interrupts have to be enabled, the border colour to be restored and the error "BREAK into program" to be given. 0CB4 BRK-INOUT EI Enable interrupts. 0CB5 CALL 0CA9,BORD-REST Restore border colour. 0CB8 LD (ERR-NR),+l4 Store error code and give the error. 0CBC RST 28,ROMERR THE 'CALL-INP' ROUTINE All inputs from "B", "T", "N" and "M" channels are handled by loading HL with the address of the service 'input' routine for the channel, and then jumping to this routine. The routine handles both INPUT and INKEY$ commands referred to the 'new' channels. 0CBD CALL-INP RES 3,(TVFLAG) 'The mode is to be considered as being unchanged' 0CC1 PUSH HL Save address of the service routine. 0CC2 LD HL,(ERR-SP) Points to the error address. 0CC5 LD E,(HL) Fetch low byte of error addres 0CC6 INC HL 0CC7 LD D,(HL) Fetch high byte. 0CC8 AND A Prepare for a true subtraction. 0CC9 LD HL,+107F This is ED-ERROR. 0CCC SBC HL,DE Jump forward if not during an INPUT 0CCE JR NZ,0CFB,INKEY$ command. Now deal with 'INPUT #' command referred to an Interface channel. 0CD0 POP HL Restore address of service routine. 0CD1 LD SP,(ERR-SP) Clear machine stack. 0CD5 POP DE Remove ED-ERROR. 0CD6 POP DE The old value of ERR-SP 0CD7 LD (ERR-SP),DE is restored. 0CDB IN-AGAIN PUSH HL Save address of the service routine. 0CDC LD DE,+0CE1 Return address is INPUT-END below. 0CDF PUSH DE 0CE0 JP (HL) Jump to the service routine. When the character has been read from the required channel, a return is made here to add the character to the INPUT line, or to return if the character is ENTER. 0CE1 INPUT-END JR C,0CED,ACC-CODE Jump with acceptable codes. 0CE3 JR Z,0CEA,NO-READ Jump with no data read. 0CE5 OREPORT-8 LD (ERR-NR),+07 Otherwise report the 'End of file' 0CE9 RST 28,ROMERR error. 0CEA NO-READ POP HL Restore address of service routine 0CEB JR 0CDB,IN-AGAIN and try again. 0CED ACC-CODE CP +0D Jump if the code is ENTER. 0CEF JR Z,0CF7,END-INPUT 0CF1 RST 10,CALBAS Otherwise the character is to be added 0CF2 DEFW +0F85 to the INPUT line - so enter into the main ROM 'ADD-CHAR' subroutine. 0CF4 POP HL Restore address of service routine 0CF5 JR 0CDB,IN-AGAIN and read the next byte. 0CF7 END-INPUT POP HL Remove address of service routine. 0CF8 JP 0700,UNPAGE Return to the main ROM calling routine. Enter here to deal with the INKEY$ function (a single character is returned). 0CFB INKEY$ POP HL Address of service routine. 0CFC LD DE,+0D01 Return address is INK$-END below. 0CFF PUSH DE 0D00 JP (HL) Jump to the service routine. After having read the byte, a return is made here. 0D01 INK$-END RET C Return with acceptable codes, or 0D02 RET Z no character read. 0D03 BIT 4,(FLAGS3) Give the 'end of file' error if bit 0D07 JR Z,0CE5,OREPORT-8 4 of FLAGS3 is reset. 0D09 OR +01 Otherwise the MOVE command has been 0D0B RET used - so return with carry and zero flags both reset. The Network routines THE '"N" CHANNEL INPUT' ROUTINE The actual 'input' is handled via the CALL-INP routine above. The service routine is NCHAN-IN. 0D0C N-INPUT LD HL,+0D12 Address of NCHAN-IN routine. 0D0F JP 0CBD,CALL-INP Jump to the control routine. THE '"N" CHANNEL INPUT' SERVICE ROUTINE The actual "n" input involves the reading of the byte from the network buffer. If no other bytes are found in the buffer, a further data block is to be received (provided that the 'current' block is not the 'EOF' one) before reading the byte. 0D12 NCHAN-IN LD IX,(CURCHL) Fetch start of "n" channel. 0D16 LD A,(NCOBL) This holds 0 while 'receiving'. 0D19 AND A Jump if it is a "read" file. 0D1A JR Z,0D1E,TEST-BUFF 'Reading a 'write' file' 0D1C RST 20,SH-ERR Call the error handling 0D1D DEFB +0D routine. 0D1E TEST-BUFF LD A,(NCIBL) Fetch number of bytes to be read from the buffer. 0D21 AND A If NCIBL holds zero, then the buffer 0D22 JR Z,0D38,TST-N-EOF is empty. 0D24 LD E,(NCCUR) Otherwise fetch the current position. 0D27 DEC A Decrease number of bytes to be read from the buffer. 0D28 SUB E Subtract position from the result. 0D29 JR C,0D38,TST-N-EOF Jump if all bytes have been read. 0D2B LD D,+00 Clear D register. 0D2D INC E Update the character position. 0D2E LD (NCCUR),E 0D31 ADD IX,DE Points to 'byte to be read - 20'. 0D33 LD A,(IX+20) Read the byte. 0D36 SCF Carry is set to signal 'acceptable byte'. 0D37 RET Finished. If no data is found in the buffer, consider whether this data block is the last one. 0D38 TST-N-EOF LD A,(NCTYPE) Fetch packet type. 0D3B AND A Jump if packet type = 0. 0D3C JR Z,0D3F,GET-N-BUF Indicating a normal packet. 0D3E RET Otherwise return with both zero and carry flags reset to signal 'end of file'. A further data block is to be received if the current data block is not the 'EOF' one. 0D3F GET-N-BUF LD A,(IOBORD) Fetch new border colour. 0D42 OUT (+FE),A Change border colour. 0D44 DI Disable interrupts. 0D45 TRY-AGAIN CALL 0F1E,WT-SCOUT Wait for a 'scout' leader. 0D48 JR NC,0D5F,TIME-OUT Jump if 'time out' occurs. 0D4A CALL 0E18,GET-NBLK Wait for header and data block. 0D4D JR NZ,0D5F,TIME-OUT Jump with any error. 0D4F EI Enable interrupts. 0D51 CALL 0CA9,BORD-REST Restore border colour. 0D53 LD (NCCUR),+00 The position is 0. 0D57 LD A,(NTTYPE) Copy this byte 0D5A LD (NCTYPE),A to signal the packet type. 0D5D JR 0D1E,TEST-BUFF Try now to fetch the byte. 0D5F TIME-OUT LD A,(NCIRIS) Fetch destination station no. 0D62 AND A There is no 'time-out' when 0D63 JR Z,0D45,TRY-AGAIN broadcasting (NCIRIS=0). 0D65 DI Enable interrupts. 0D66 CALL 0CA9,BORD-REST Restore border colour. 0D69 AND +00 Return with zero flag set and carry 0D6B RET reset, signalling that no data has been read. THE '"N" CHANNEL OUTPUT' ROUTINE The routine that handles the "n" channel output is quite straightforward. It involves the storing of the byte held in the A register into the 255-byte buffer; whenever this is filled, the subroutine S-PACK-1 is called, so the data block is sent over the network. 0D6C NCHAN-OUT LD IX,(CURCHL) Point to start of channel. 0D70 LD B,A Save temporarily into B the byte to be sent. 0D71 LD A,(NCIBL) This holds 0 for 'write' channel. 0D74 AND A Set zero flag as required. 0D75 LD A,B Restore the byte to be sent. 0D76 JR Z,0D7A,TEST-OUT Continue only if using a 'write' channel (NCIBL=0). 'Writing to a 'read' file' 0D78 RST 20,SH-ERR Call the error handling 0D79 DEFB +0C routine. 0D7A TEST-OUT LD E,(NCOBL) Fetch length of output buffer. 0D7D INC E Include the current byte in the length count. 0D7E JR NZ,0D88,ST-BF-LEN Jump unless the buffer is filled. 0D80 PUSH AF Save the byte to be sent. 0DB1 XOR A Signal normal packet type. 0D82 CALL 0DAB,S-PACK-1 Send the packet. 0D85 POP AF Restore the byte to be sent. 0D86 LD E,+01 'Only 1 byte in the buffer'. 0D88 ST-BF-LEN LD (NCOBL),E Store new buffer length. 0D8B LD D,+00 Make IX point to 'first free byte in 0D8D ADD IX,DE the buffer - 20). 0D8F LD (IX+20),A Store byte in the buffer. 0D92 RET Finished. THE 'OUT-BLK-N' SUBROUTINE This subroutine calls the OUTPAK subroutine to send over the network the block of bytes starting from (HL), and whose length is held into the E register. Then a 'response byte' is to be received into the NTRESP system variable (provided that you are not using the broadcast). The zero flag is returned reset if no response byte has been received. This subroutine is called from SEND-PACK below to send the header and then the data block over the network. 0D93 OUT-BLK-N CALL 0FC5,OUTPAK Send the block. 0D96 LD A,(NCIRIS) This holds zero when broadcasting. 0D99 AND A 0D9A RET Z Return if broadcasting. 0D93 LD HL,+5CCD Address of NTRESP system variable. 0D9E LD (HL),+00 First clear NTRESP. 0DA0 LD E,+01 A single byte is to be received into NTRESF. 0DA2 CALL 0F92,INPAK Get response byte (+01). 0DA5 RET NZ Return with zero flag reset if the network was inactive. 0DA6 LD A,(NTRESP) Now fetch the response byte. 0DA9 DEC A It must be +01. 0DAA RET Return with zero flag reset if it is not +01. THE 'S-PACK-1' SUBROUTINE This subroutine simply calls SEND-PACK below. If broadcasting, a certain delay is to be inserted after having sent the packet. 0DAB S-PACK-1 CALL 0DB2,SEND-PACK Send the packet. 0DAE RET NZ Return if not broadcasting. 0DAF JP 0E0F,BR-DELAY Otherwise exit through the delay routine. THE 'SEND-PACK' SUBROUTINE This subroutine is also called by using 'hook code' +30. It sends over the network a SCOUT leader, followed by the header and the data block for the "n" channel pointed by the IX register. On entry, the A register may hold +01 or +00 depending upon whether the block is the 'end of file' one or not. NCNUMB is incremented before returning. The zero flag is returned set if the destination station number denotes that the 'broadcasting' is being used. 0DB2 SEND-PACK LD (NCTYPE),A Store packet type, i.e. +00 for normal, +01 for end of file. 0DB5 LD B,(NCOBL) Fetch block length. 0DB8 LD A,(IOBORD) Fetch new border colour. 0DBB OUT (+FE),A 0DBD PUSH IX Make DE point to the start of the 0DBF POP DE "n" channel. 0DC0 LD HL,+0015 Add this offset to point to 0DC3 ADD HL,DE the start of the 255-byte buffer. Now the checksum of the data block is calculated. 0DC4 XOR A First clear A register. 0DC5 CHKS1 ADD A,(HL) Add this byte. 0DC6 INC HL Point to next location. 0DC7 DJNZ 0DC5,CHKS1 Repeat for all bytes in the block. 0DC9 LD (NCDCS),A Store the checksum obtained. 0DCC LD HL,+000B Now points to NCIRIS. 0DCF ADD HL,DE 0DD0 PUSH HL Save the pointer. The checksum of the header is calculated. 0DD1 LD B,+07 Checksum is for 7 bytes. 0DD3 XOR A Clear A register. 0DD4 CHKS2 ADD A,(HL) Add this byte. 0DD5 INC HL Point to next location. 0DD6 DJNZ 0DD4,CHKS2 Repeat for all bytes. 0DD8 LD (HL),A Store checksum into NCHCS. Now the SCOUT leader, followed by the 8-byte header, is sent, and a response code is received (if not broadcasting). 0DD9 DI Disable interrupts. 0DDk SENDSCOUT CALL 9Fb1,SEND-SC Send the SCOUT (i.e. a leader followed by station number). 0DD0 POP HL Restore pointer to NCIEIS, 0DD1 PUSH HL i.e. Start of header block. 0DD1 LD 1,48 The header Is made by '8' bytes. 0DE1 CALL 9II93,OUT-BLK-N The header is sent, and the response code received. 0DE4 JR NZ,0DDA,SENDSCOUT Repeat until successfully. 0DE6 PUSH IX Make HL point to the start of the "n" 0DE8 POP HL channel. 0DE9 LD DE,+0015 Now points to the start of the data 0DEC ADD HL,DE block. 0DED LD E,(NCOBL) Get block length. 0DF0 LD A,E If NCOBL is zero (i.e. if the buffer 0DF1 AND A is empty); no data needs to be sent. 0DF2 JR Z,0DFD,INC-BLKN 0DF4 LD B,+20 Wait 418 T cycles before proceeding. 0DF6 SP-DL-1 DJNZ 0DF6,SP-DL-1 Now the data block is sent, and NCNUMB updated. 0DF8 CALL 0D93,OUT-BLK-N Send the data block and get the response code. 0DF8 JR NZ,0DDA,SENDSCOUT Repeat until succesfully. 0DF0 INC_BLKN INC (NCNUMB-lo) Increment low byte of block number. 0E00 JR NZ,0E05,SP-N-END 0E02 INC (NCNUMB-hi) Increment also high byte when low byte reaches zero. 0E05 SP-N-END POP HL Restore pointer to NCIRIS. 0E06 CALL 0CA9,BORD-REST Restore border colour. 0E09 EI Enable interrupts. 0E0k LD A,(NCIRIS) Get destination station number. 0E00 AND A Set zero flag if NCIRIS is 0 (i.e. broadcasting). 0E01 RET Finished. THE 'BR-DELAY' SUBROUTINE This short subroutine inserts a delay of about 40 msec. when it is called. Its task is that of separating outputs during 'broadcasts' transmissions. 0E01 BR-DELAY LD DE,+1500 Set a counter. 0E12 DL-LOOP DEC DE Decrease it. 0E13 LD A,E Check whether the counter has reached 0E14 OR D zero. 0E15 JR NZ,0E12,DL-LOOP Repeat if not. 0E17 RET Finished. THE 'HEADER AND DATA BLOCK RECEIVING' ROUTINES The following two subroutines are used to get from the Network an 8-byte header and a data block respectively. Both require that the IX register point to the start of the "n" channel. The zero flag is returned reset with any error. 0E18 GET-NBLK LD HL,+5CCE Point to NTDEST, i.e. first byte of header block. 0E1B LD E,+08 Length of the block. 0E1D CALL 0F92,INPAK Receive the header. 0E20 RET NZ Return with network inactive (i.e. no header has been found). 0E21 LD HL,+5CCE Points again to NTDEST. Now the header checksum is calculated, and compared with NTCHS checksum. 0E24 XOR A First clear A. 0E25 LD B,+07 Checksum for next 7 bytes. 0E27 CHKS3 ADD A,(HL) Add this byte. 0E28 INC HL Point to next location. 0E29 DJNZ 0E27,CHKS3 Repeat for all bytes. 0E2B CP (HL) Compare with NTCHS checksum. 0E2C RET NZ Return if they do not match. Some other tests are now made. 0E2D LD A,(NTDEST) Fetch destination station number. 0E30 AND A Jump if broadcasting. 0E31 JR Z,0E40,BRCAST 0E33 CP (NCSELF) Otherwise compare with NCSELF. 0E36 RET NZ Return if this data block is for another Spectrum. 0E37 LD A,(NTSRCE) Source station number. 0E3A CP (NCIRIS) Compare against NCIRIS. 0E3D RET NZ Return if the transmitting Spectrum is not the required one. 0E3E JR 0E45,TEST-BLKN Jump forward. 0E40 BRCAST LD A,(NCIRIS) Make sure that it is broadcasting 0E43 OR A (i.e. NTDEST and NCIRIS both 0). 0E44 RET NZ Return if you are not waiting for a broadcast. 0E45 TEST-BLKN LD HL,(NTNUMB) Fetch number of block being transmitted. 0E48 LD E,(MCNUMB-lo) Fetch number of expected block. 0E4B LD D,(NCNUMB-hi) 0E4E AND A 0E4F SBC HL,DE Jump if the block received is the 0E51 JR Z,0E65,GET-NBUFF expected one. 0E53 DEC HL Accept also the previous block 0E54 LD A,H (already received, but 'response' 0E55 OR C lost). 0E56 RET NZ But refuse other blocks. 0E57 CALL 0E65,GET-NBUFF Receive the block. 0E5A DEC (NCNUMB-lo) Decrease NCNUMB, i.e. 'ignore' this 0E5D JR NC,0E62,GETNB-END block. 0E5F DEC (NCNUMB-hi) 0E62 GETNB-END OR +01 Return with zero flag reset, so that 0E64 RET the procedure is repeated. Now follows the second routine, used to get the data block from the network. 0E65 GET-NBUFF LD A,(NTDEST) This holds zero when broadcasting. 0E68 AND A 0E69 CALL NZ,0FBE,SEND-RESP Send the 'response' code (for the header) unless broadcasting. 0E6C LD A,(NTLEN) Fetch data block length. 0EbF AND A Jump if the data block is empty. 0E73 JR Z,0E93,STORE-LEN 0E72 PUSH IX Make HL point to the start of the 0E74 POP HL channel. 0E75 LD DE,+0015 Point to the start of data buffer. 0E78 ADD HL,DE 0E79 PUSH HL Save start address. 0E?A LD E,A Length of the block to be received goes into E. 0E7B CALL 0F92,INPAK Receive the data block. 0E7E POP HL Restore start address. 0E7F RET NZ Return if the network was inactive. 0E83 LD A,(NTLEN) Pass length of data block to the 0E83 LD B,A B register. 0E84 LD A,(NTDCS) Start with the data block checksum. 0E87 CHKS4 SUB (HL) Subtract current byte. 0E88 INC HL Point to next location. 0E89 DJNZ 0E87,CHKS4 Repeat for all bytes in the block. 0E8B RET NZ Return if the checksum is wrong. 0E8C LD A,(NTDEST) This holds 0 when broadcasting. 0E8F AND A 0E93 CALL NZ,0FBE,SEND-SCOUT Send response code for the data block (unless broadcasting). 0E93 STORE-LEN LD A,(NTLEN) Fetch data block length. 0E96 LD (NCIBL),A Copy it into NCIBL. 0E99 INC (NCNUMB-lo) Finally increment block number. 0E9C JR NZ,0EA1,GETBF-END 0E9E INC (NCNUMB-hi) 0EA1 GETBF-END CP A Return with zero flag set to signal 0EA2 RET 'block successfully received'. THE 'OPEN "N" CHANNEL' COMMAND ROUTINE This routine is the actual OPEN command referred to the network. It is called from the 'OPEN' command syntax routine to attach a permanent "n" channel to a stream. 0EA3 OPEN-N-ST CALL 0EB5.OP-PERM-N Open a permanent "n" channel. 0EA6 JP 0B4A,OP-STREAM Attach it to a stream. THE 'OPEN TEMPORARY "N" CHANNEL' SUBROUTINE This subroutine is also called by using the 'hook code' +2D. It simply opens a permanent 'n' channel, and then makes it "temporary" by setting bit 7 of the channel specifier. The variables are to be set as for the OP-PERM-N subroutine below. The start of the channel area is returned in the IX index register. 0EA9 OP-TEMP-N CALL 0EB5,OP-PERM-N Open a permanent "n" channel. 0EAC LD IX,(CURCHL) Fetch start of channel area. 0EB1 SET 7,(IX+4) Make the channel temporary. 0EB4 RET Finished. THE 'OPEN PERMANENT "N" CHANNEL" SUBROUTINE On entry, D-STR1 must hold the destination station number to be copied into NCIRIS, while NTSTAT must hold the own station number to be copied into NCSELF. A permanent "n" channel is created into the CHANS area, and it is made, the 'current' channel. The routine returns the channel base address into the DE register pair. 0EB5 OP-PERN-N LD HL,(PROG) Fetch start address of the channel 0EB8 DEC HL created. 0EB9 LD BC,+0114 Length of the channel. 0EBC PUSH BC Save it briefly. 0EBD RST 10,CALBAS Call main ROM 'MAKE-ROOM' subroutine 0EBE DEFW +1655 to make the required space. 0EC3 INC HL Point to the first new location. 0EC1 POP BC Restore 'length' of space inserted. 0EC2 CALL I691,RESThN.,.AD Restore start address of 'filename' possibly moved up after the insert ion. 0EC5 LD (CHURCHL),HL Make the Channel 'current' 0EC8 EX DE,HL Pass 'start' to DE. 0EC9 LD HL,+0EEA Start of "n" Channel data. 0ECC LD BC,+000B Length of data. 0ECF LDIR Copy the data into the channel area. 0ED1 LD A,(DSTR-1) Fetch destination station number. 0ED4 LD (DE),A Copy it into NCIRIS. 0ED5 INC DE Points to NCSELF. 0ED6 LD A,(NTSTAT) Fetch own station number. 0ED9 LD (DE),A Copy it into NCSELF. 0EDA INC DE Points to NCNUMB. 0EDB XOR A Clear it. 0EDC LD (DE),A 0EDD LD H,D Fill the remaining bytes with zeros. 0EDE LD L,E 0EDF INC DE 0EE0 LD BC,+0106 0EE3 LDIR 0EE5 LD DE,(CURCHL) Fetch start address of the channel. 0EE9 RET Finished. THE '"N" CHANNEL DATA' TABLE The '11' bytes that composes the initial part of a "N" channel are as follows: 0EEA DEFW +0008 Main ROM 'output' routine. 0EEC DEFW +0008 Main ROM 'input' routine. 0EEE DEFB +43 "N" (channel specifier) 0EEF DEFW +0D6C Shadow ROM 'output' routine. 0EF1 DEFW +0D0C Shadow ROM 'input' routine. 0EF3 DEFW +0114 Length of "n" channel. THE 'SEND EOF BLOCK TO NETWORK' SUBROUTINE This subroutine is used whenever the remaining buffer contents of the current "n" channel have to be sent as the "end of file" block. 0EF5 SEND-NEOF LD IX,(CURCHL) Fetch start address of channel. 0EF9 LD A,(NCOBL) Fetch data block length. 0EFC AND A Return if this is a 'read' channel 0EFD RET Z (NCOBL=0). 0EFE LD A,+01 Signal 'EOF' packet. 0F00 JP 0DAB,S-PACK-1 Send packet and exit. THE 'NETWORK STATE' SUBROUTINE This subroutine returns when the network is considered to be 'resting', i.e. when the network line is inactive for 3-4 ms. The exact time is 'randomised' as to prevent Spectrums from claiming the network at the same time. 0F03 NET-STATE LD A,R Get a random value. 0F05 CP +C0 Allow only the range 192..255. 0F07 LD B,A Pass the value to B. 0F08 CALL 0F8E,CHK-REST Check network state. 0F0B JR C,0F03,NET-STATE Repeat until the network is resting, or BREAK pressed. 0F0D RET Return when 'ready to claim'. THE 'CHECK-RESTING' SUBROUTINE This subroutine checks the state of the network and returns with carry reset if it is inactive for a 'sufficient' time determined by the value passed to the B register ((B * 54) - 22) T cycles). 0F0E CHK-REST LD A,+7F First check SPACE key. 0F10 IN A,(+FE) 0F12 RRCA 0F13 JR NC,0F4D,E-READ-N Give an error if it is pressed. 0F15 MAKESURE PUSH BC Wait 21 T cycles. 0F16 POP BC 0Fl7 IN A,(+F7) Check network state. 0F19 RRCA Only bit 0. 0F1A RET C Return if the network is already claimed by another Spectrum. 0F1B DJNZ 0F15,MAKESURE Repeat the test. 0F1D RET Return with carry reset when network is resting. THE 'WAIT-SCOUT' SUBROUTINE This subroutine is used to identify a SCOUT leader from the network. This is done by checking the network line for about 7000 T cycles, to prove whether it is resting. After this, the network is examined until it is active. At this point, the SCOUT is identified. The subroutine returns the carry flag reset if 'time-out' has occurred and no SCOUT has been identified. Remember that there are no 'time-outs' when broadcasting. 0F1E WT-SCOUT LD HL,+01C2 Set a counter. 0F21 CLAIMED LD B,+80 This constant allows the network to be tested for 6890 T cycles. 0F23 CALL 0F9E,CHK-REST Check network state. 0F26 JR NC,0F35,WT-SYNC Jump for waiting the SCOUT. 0F28 DEC HL Loop again if the network is active, 0F29 DEC HL until the counter reaches zero. 0F2A LD A,H 0F2B OR C 0F2C JR NZ,0F21,CLAIMED 0F2E LD A,(NCIRIS) There is no 'time-out' when 0F31 AND A broadcasting. 0F32 JR Z,0F21,CLAIMED 0F34 RET Return with carry reset to signal 'time-out'. Now the SCOUT pulse is waited for. 0F35 WT-SYNC IN A,(+F7) Read the network line. 0F37 RRCA Only bit 0. 0F38 JR C,0F56,SCOUT-END Jump if the SCOUT is identified. 0F3A CD A,+7F Check SPACE key. 0F3C IN A,(+FE) 0F3E RRCA 0F3F JR NC,0F4O,E-READ-N Give an error if it is pressed. 0F41 DEC HL decrease counter. 0F42 LD A,H Repeat until it reaches zero. 0F43 OR C 0F44 JR NZ,0F35,WT-SYNC 0F46 CD A,(NCIRIS) There is no 'time-out' when 0F49 AND A broadcasting. 0F4A JR Z,0F35,WT-SYNC 0F4C RET Carry reset signals 'time-out', 0F4D E-READ-N EI Enable interrupts. 0F4E CALL 0CA9,BORD-REST Restore border colour. 0F51 LD (ERR-NR),+14 Give the error 'BREAK into program'. 0F55 RST 28,ROMERR NOTE: The above routine is a 'duplicate' of BRK-INOUT at 0CB4. When the SCOUT has been identifIed, the routine waits until it is finished. 0F56 SCOUT-END LD L,+09 Set a counter. 0F58 LP-SCOUT DEC L Decrease it. 0F59 SCF Return with carry set (to signal 0F5A RET Z 'scout identified') when the counter reaches zero. 0F5B LD B,+0E Wait a while. 0F5D DELAY-SC DJNZ 0F5D,DELAY-SC 0F5F JR 0F58,LP-SCOUT Go back into the loop, THE 'SEND-SCOUT' SUBROUTINE This is the opposite of the preceding routine; the SCOUT leader, followed by an 8-bit station number, is sent over the network. After having sent every bit, a test is made to see if the network has the expected state from the current bit value; if any error is found, then the whole procedure is repeated. 0F61 SEND-SC CALL 0F03,NET-STATE Wait until the network Is resting. 0F64 LD C,+F7 Output port. 0F66 LD HL,+0009 H=0 (leader bit value) L=9 (bit counter). 0F69 LD A,(NTSTAT) Fetch global station number, 0F6C LD E,A Pass it to the E register. 0F6D IN A,(+F7) Start again if some data is found 0F6F RRCA into the network line. 0F70 JR C,0F61,SEND-SC 0F72 ALL-BITS OUT (C),H Send a bit. 0F74 LD D,H Save the bit into D. 0F75 LD H,+00 Clear H. 0F77 RLC E Rotate 'station no.' left. 0F79 RL H Bit 7 of station no. goes into bit 0 of H. 0F7B LD B,+08 Wait 196 T cycles. 0F7D S-SC-DEL DJNZ 0F7D,S-SC-DEL 0F7F IN A,(+F7) Read the network. 0F81 AND +01 Only bit 0. 0F83 CP D Repeat again the procedure if the 0F84 JR Z,0F61,SEND-SC network does not have the right state from the current bit value. 0F86 DEC L Decrease bit counter. 0F87 JR NZ,0F72,ALL-BITS Send all bits. 0F89 LD A,+01 Make network inactive. 0F8B OUT (+F7),A 0F8D LD B,+0E Wait 184 T cycles. 0F8F END-S-DEL DJNZ 0F8F,END-S-DEL 0F91 RET Finished. THE 'INPAK' SUBROUTINE This basic subroutine is used to receive from the network a block of bytes. On entry. HL must hold the address from which the bytes will be loaded, while E must hold the length of the block. The subroutine returns with the zero flag reset if the network is found inactive and no data has been read. The bits are read every 40 T cycles. 0F92 INPAK LD B,+FF Set a counter. 0F94 N-ACTIVE IN A,(+F7) Read the network. 0F96 RRA Only bit 3. 0F97 JR C,0F9D,INPAK-2 Jump if found active. 0F99 BJNZ 0F94,N-ACTIVE Otherwise try again. 0F9B INC B Return with zero flag reset to 0F9C RET indicate 'network inactive'. Now the block is received. 0F9D INPAK-2 LD B,E B holds the length of the block. 0F9E INPAK-L LD E,+80 Set a marker into bit 7. 0FAI LD A,+CE Make Wait and CTS having a low level, 0FA2 OUT (+EF),A enable network comm. 0FA4 NOP Wait 48 T cycles at the start of each 0FA5 NOP byte. 0FA6 INC IX 0FA8 DEC IX 0FAA INC IX 0FAC DEC IX 0FAE UNTIL-MK LD A,+00 Wait 7 T cycles. 0FB0 IN A,(+F7) Get a bit into carry 0FB2 RRA flag. 0FB3 RR E Shift the bit into E. 0FB5 JP NC,0FAE,UNTIL-MK Repeat for 8 bits. 0FB8 LD (HL),E Store the received byte. 0FB9 INC HL Point to next location. 0FBA DJNZ 0F9E,INPAK-L Get next byte. 0FBC CP A Return with zero flag set to signal 0FBD RET 'successfully read'. THE 'SEND RESPONSE BYTE' SUBROUTINE A 'response byte' is simply a byte +01 that is sent over the network to confirm that some data has been successfully received. 0FBE SEND-RESP LD A,+0l This is the response byte. 0FC0 LD HL,+5CCD Store it into NTRESP. 0FC3 LD (HL),A 0FC4 LD E,A A 'single byte' is to be sent. The subroutine continues into OUTPAK below. THE 'OUTPAK' SUBROUTINE This is the opposite to the INPAK subroutine and thus, is used to send over the network a block of bytes. Again, on entry HL must hold the address fro which the block is stored, and E must hold its length. Initially a leader (length 98 T cycles) is sent, followed by each byte, with an initial 'start' period, and then the 8 bits (each 40 T cycles). 0FC5 OUTPAK XOR A Begin with a 'start' leader. 0FC6 OUT (+F7),A 0FC8 LD B,+04 Insert the required delay. 0FCA DEL_O-1 DJNZ 0FCA,DEL_O-1 0FCC OUTPAK-L LD A,(HL) Get the byte to be sent, 0FCD CPL Send the bits inverted. 0FCE SCF The start bit is high. 0FCF RLA Rotate bit into A. 0FD0 LD B,+0A '10' bits to be sent (start, data, stop). 0FD2 UNT-MARK OUT (+F7),A Send the bit. 0FD4 RRA Next bit. 0FD5 AND A But clear carry. 0FD6 DEC B becrease bit counter. 0FD7 LD D,+00 Wait 7 T cycles. 0FD9 JP NZ,0FB2,UNT-MARK Loop for all bits. 0FDC INC HL Point to next location in the block. 0FDD DEC E Decrease 'block length'. 0FDE PUSH HL Wait 22 T cycles. 0FDF POP HL 0FE0 JP NZ,0FCC,OUTPAK-L Loop until all bytes have been sent. 0FE3 LD A,+01 0FE5 OUT (+F7),A Finally make the network inactive. 0FE7 RET Finished. The Microdrive routines THE 'SET A TEMPORARY "M" CHANNEL' SUBROUTINE This very important subroutine sets a temporary "M" channel in the CHANS area; the Microdrive map is created unless it already exists (if another channel refers to the same drive). The subroutine returns with the IX register pointing to the start of the channel, and with the HL register holding a suitable displacement to be eventually inserted in the STRHS area to attach the channel to a stream. Note that the HL' register is corrupted if you call this routine from your own program. 0FE8 SET-T-MCH EXX Swap registers. 0FE9 LD HL,+0000 Signal 'map to be created'. 0FEC EXX Swap registers again. 0FED LD IX,(CHANS) Start of channel area. 0FF1 LD DE,+0014 Points to the start of the channels 0FF4 ADD IX,DE Other than the 'standard' ones. 0FF6 CHK-LOOP LD A,(IX+0) Jump forward it the CHANS area is 0FF9 CP +80 finished. 0FFB JR Z,1034,CHAN-SPC 0FFD LD A,(IX+4) Fetch channel specifier. 1000 AND +7F Clear bit 7. 1002 CP +4D Jump if this is not an "m" channel. 1004 JR NZ,102A,NEXT-CHAN 1006 LD A,(D-STR1) Fetch drive number. 1009 CP (CHDRIV) Jump if this channel uses a different l00C JR NZ,102A,NEXT-CHAN drive. 100E EXX Swap registers. 100F LD L,(CHMAP-lo) Move address of map area into H'L' 1012 LD H,(CHMAP-hi) 1015 LXX Swap registers again. 1016 LD BC,(N-STR1) Length of filename. 101A LD HL.(N-STR1+2) Start address of filename. 101D CALL 131E,CHK-NAME Check name against 'CHNAME' of this channel. 1020 JR NZ,102A,NEXT-CHAN Jump if not the same file. 1022 BIT 3,(IX+24) This is set with 'write' files. 1026 JR Z,102A,NEXT-CHAN Continue with 'read' files. 1028 RST 20,SH-ERR Give the 'Reading a 'write' file' 1029 DEFB +0D error if the file is already opened for writing. 102A NEXT-CHAN LD E,(IX+9) Fetch length of channel into the DE 102D LD D,(lX+10) register pair. 1030 ADD IX,DE Point to the next channel. 1032 JR 0FF6,CHK-LOOP Back again. Now the space for the new channel is created at the end of the CHANS area. 1034 CHAN-SPC LD HL,(PROG) Fetch the start address of the 1037 DEC HL channel, 1038 PUSH HL Save it. 1039 LD BC,+0253 Length is '595' bytes. 103C RST 10,CALBAS Call MAKE-ROOM to create the required 103D DEFW +1655 space. 103E POP DE Restore start address of the channel. 1040 PUSH DE 1041 LD HL,+13CC Start of "M" channel data. 1044 LD BC,+0019 Length of data. 1047 LDIR Store data into the channel. 1049 LD A,(D-STR1) Fetch drive number. 104C LD (CHDRIV),A Initialise CHDRIV. 104F LD BC,+0253 Length of channel. 1052 PUSH IX Fetch start of channel into HL. 1054 POP HL 1055 CALL 1691,REST-N-AD Restore start of 'filename' possibly moved after the 'insertion' of the channel. 1058 EX DE,HL The start address of the filename goes to HL. 1059 LD BC,(N-STR1) Fetch length of filename. 105D BIT 7,B Jump if the name does not exist 105F JR NZ,106F,TEST-MAP (N-STR1 = +FFFF). The channel name is transferred into CHNAME. 1061 T-CH-NAME LD A,B The loop continues until 'length' 1062 OR C reaches zero. 1063 JR Z,106F,TEST-MAP Fetch character of name. 1065 LD A,(HL) 1066 LD (IX+14),A Store it into CHNAME. 1069 INC HL Point to next locations. l06A INC IX 106C DEC BC Decrease 'length'. 106D JR 106l,T-CH-NAME Continue with next character. Now the 'map' is created unless it already exists. 106F TEST-MAP POP IX Restore start address of channel. 1071 EXX Use alternate registers. 1072 LD A,H Address of map, or +0000 if the map 1073 OR L does not exist. 1074 JR NZ,108A,ST-MAP-AD Jump if the map already exists. 1076 LD HL,(CHANS) Otherwise the map is to be created. 1079 PUSH HL 107A DEC HL 107B LD BC,+0020 Length of the map is 32 bytes. 107E RST 10,CALBAS Call MAKE-ROOM to make the space. 107F DEFW +1655 1081 POP HL Restore start of map. 1082 LD BC,+0020 Restore 'start' of channel. 1085 ADD IX,BC 1087 CALL 1691,REST-N-AD Restore 'start' of filename. 108A ST-MAP-AD LD (CHMAP-lo),L Lastly store the start address 108E LD (CHMAP-hi),H of the Microdrive map. All bits in the map are made high; then the 'preambles' are collected from the table at +13E5 and stored in the channel. 1090 LD A,+FF All bits high. 1092 LD B,+20 Length of map. l094 FILL-MAP LD (HL),A Store +FF into this location. 1095 INC HL Advance the pointer. 1096 DJNZ 1094,FILL-MAP Continue for 32 bytes. 1098 PUSH IX Pass start of channel to HL. 109A POP HL 109B LD DE,+001C Make DE register pair point to the 109E ADD HL,DE header block preamble area. 109F EX DE,HL 10A0 LD HL,+13E5 Start of 'preamble' data. l0A3 LD BC,+000C Preamble is 12 bytes in length. 10A6 LDIR Set-up header preamble. 10A8 PUSH IX Pass again 'start' to HL. 10AA POP HL 10AB LD DE,+0037 Offset for data block preamble. 10AE LD BC,+000C Preamble is again 12 bytes. 10B1 ADD HL,DE Make DE register pair point to the 10B2 EX DE,HL data block preamble. 10B3 LD HL,+13E5 Start of 'preamble data'. 10B6 LDIR Set-up the data block preamble. 10B8 PUSH IX Move 'start' of channel into HL 10BA POP HL register pair. 10BB LD DE,(CHANS) Calculate the required 'stream 10BF OR A offset' into HL. 10C0 SBC HL,DE 10C2 INC HL 10C3 RET Finished. THE 'RECLAIM "M" CHANNEL' SUBROUTINE This subroutine (also called by using 'hook code' +2C) is used to reclaim the "m" channel pointed by the IX index register. Any stream attached to this channel will be closed, and other 'dynamic' areas updated. The map is also reclaimed, unless it is used by another channel. 10C4 DEL-M-BUF LD L,(CHMAP-lo) Fetch address of map into HL. 10C7 LD H,(CHMAP-hi) 10CA PUSH HL Save it for later. 10CB LD A,(CHDRIV) Fetch drive number. 10CE PUSH AF Save it for later. 10CD PUSH IX Make HL point to the start of 10D1 POP HL the channel. 10D2 LD BC,+0253 Length of the channel. 10D5 RST 10,CALBAS RECLAIM-2 is called to delete 10D6 DEFW +19E8 the channel area. 10D8 PUSH IX Make HL point again to the start of 10DA POP HL the (reclaimed) channel. 10DB LD DE,(CHANS) Calculate 'offset' used into STRMS 10DF OR A area for the deleted channel, 10E0 SBC HL,DE possibly attached to a stream. 10E2 INC HL l0E3 LD BC,+0253 Amount of bytes moved down. 10E6 CALL l35F,REST-STRM Close required streams and update data for other streams. Look for any channel that uses the same map as that of the channel deleted. 10E9 POP AF Restore drive number, and start 10EA POP HL address of map. 10EB LD B,A Drive number goes into B. 10EC LD IX,(CHANS) Start of channel area. 10F0 LD DE,+0014 Skip initial 'standard' channels. 10F3 ADD IX,DE 10F5 TEST-MCHL LD A,(IX+0) Jump if the channel area is finished. 10F8 CP +80 10FA JR Z,1114,RCLM-MAP 10FC LD A,(IX+4) Fetch channel specifier. 10FF AND +7F Clear bit 7 (no distinction is made between 'temporary' and 'permanent' channels). 1101 CP +4D Jump if this is not an "m" channel. 1103 JR NZ,113A,NXTCHAN 1105 LD A,(CHDRIV) Fetch drive number of this channel. 1108 CP B If it is the same as that of the 1109 RET Z deleted channel, the map is not to be reclaimed. 110A NXTCHAN LD E,(IX+9) Fetch length of this channel. 110D LD B,(IX+10) 1110 ADD IX,DE Points to next channel. 1112 JR 10F5,TEST-MCHL Back again for next channel. If no channel uses the map used by the deleted one, it is to be deleted too. 1114 RCLM-HAP LD BC,+0020 Length of the map. 1117 PUSH HL Save start of map. 1118 PUSH BC Save length of map. Note: this is not necessary. 1119 RST 10,CALBAS Call RECLAIM-2 to delete the map. 111A DEFW +19E8 111C POP BC Restore length and start of the 111D POP HL deleted map. 111E CALL 1391,REST-MAP Update addresses of other maps. 1121 RET Finished. THE '"M" CHANNEL INPUT' ROUTINE The actual 'input' is handled via CALL-INP. The service routine is MCHAN-IN below. 1122 M-INPUT LD IX,(CURCHL) First make IX point to start of channel. 1126 LD HL,+112C Address of MCHAN-IN routine. 1129 JP 0CBD,CALL-INP Jump to the control routine. THE '"M" CHANNEL INPUT' SERVICE ROUTINE Similarly to the "n" input, the "m" input involves the reading of a byte from the data block. When it is empty, a further block is to be received from Microdrive (Provided that the 'current' data block is not the 'end of file' one) before reading the byte. 112C MCHAN-IN BIT 0,(CHFLAG) This is reset to indicate a 'read' file. 1130 JR Z,1134,TEST-M-BF Jump with 'read' file. 'Reading a write file' 1132 RWF-ERR RST 20,SH-ERR Call the error handling routine. 1133 DEFB +0D 1134 TEST-M-BF LD E,(CHBYTE-lo) Fetch current byte counter. 1137 LD D,(CHBYTE-hi) 113A LD L,(RECLEN-lo) Fetch record length. 113D LD H,(RECLEN-hi) 1140 SCF Include byte to be read. 1141 SEC HL,DE Jump if all bytes have been read. 1143 JR C,1158,CHK-M-EOF 1145 INC DE Include byte to be read in the byte counter. 1146 LD (CHBYTE-lo),E Store pew byte Counter. 1149 LD (CHBYTE-hi),D 114C DEC DE Position of character to be read. 114D PUSH IX Save start address of channel. 114F Abb IX,DE IX now points to 'byte to be read - 82'. 1151 LD A,(IX+82) Fetch the byte. 1154 POP IX Restore start of channel. 1156 SCF Signal 'acceptable code'. 1157 RET Finished. If all bytes in the data block have been read, a check is made to see if it is the 'end of file' block, i.e. the last one. 1158 CHK-M-EOF BIT 1,(RECFLG) This is set to signal 'EOF'. 115C JR Z,1162,NEW-BUFF Jump if not the last block. 115E XOR A Otherwise zero and carry flags are returned reset to signal EOF. 115F ADD A,+0D Returned byte is +0D. 1161 RET Finished. A new data block is now read from the Microdrive unit. 1162 NEW-BUFF LD DE,+0000 The byte counter is cleared. 1165 LD (CHBYTE-lo),E 1168 LD (CHBYTE-hi),D 116B INC (CHREC) Increment record number. 116E CALL 1177,GET-RECD Fetch a new data block. 1171 XOR A Turn off drive motor. 1172 CALL 17F7,SEL-DRIVE 1175 JR 1134,TEST-M-BF Now read the byte. THE 'GET A RECORD' SUBROUTINE This subroutine is used to load a record of a 'PRINT-type file. The number of the wanted record must be stored into CHREC, the drive number into CHDRIV and the filename into CHNAME. If after five passes of the tape the record is not found, or if a checksum error occurs, the error 'File not found' is given. 1177 GET-RECD LD A,(CHDRIV) Fetch drive number. 117A CALL 17F7,SEL-DRIVE Start drive motor. 117D GET-R-2 LD BC,+04FB Initialise SECTOR to 1275 (i.e., at 1180 LD (SECTOR),BC least five passes of the tape). 1184 GET-R-LP CALL 11A5,G-HD-RC Get header and data block. 1187 JR C,119E,NXT-SCT Consider next sector with errors, or 1189 JR Z,119E,NXT-SCT if it is unused. 118B CD A,(RECNUM) Fetch record number. 118E CP (CHREC) Test against CHREC. 1191 JR NZ,119E,NXT-SCT Next sector also if this record is not the expected one. 1193 PUSH IX Fetch base of "m" channel into HL. 1195 POP HL 1196 LD DE,+0052 Points to the start of the buffer. 1199 ADD HL,DE 119A CALL 1346,CHKS-BUFF Return if the checksum is correct. 119D RET Z 119E NXT-SCT CALL 1312,DEC-SECT Decrease SECTOR. 11A1 JR NZ,1184,GET-R-LP Continue until five passes of the tape have been made. 'File not found' 11A3 RS-SH2 RST 20,SH-ERE Call the error handling routine. 11A4 DEFB +11 THE 'GET HEADER AND DATA BLOCK' SUBROUTINE This subroutine is used to collect from the selected Hicrodrive unit a header followed by its data block. Note that the drive motor is to be turned on before calling G-HD-RC. The flags returned denote the following states: - zero set, carry reset The sector is unused. - zero reset, carry reset Successful loading. - carry set With any error. The 'errors' include wrong checksums, and no matching between the wanted filename (CHNAME) and the loaded one (RECNAM). 11A5 G-HD-RC CALL 12C4,GET-M-HD2 Fetch the header. 11A8 LD DE,+001B Make HL point to RECLCG, i.e., 11AB ADD HL,DE start of record area. 11AC CALL 18A9,GET-M-BF Fetch the record. 11AF CALL 1341,CHKS-HD-R Calculate record checksum. 11B2 JR NZ,11D6,G-REC-ERR Exit if the checksum is wrong. 11B4 BIT 0,(RECFLG) This is set to signal a header block. 11B8 JR NZ,11D6,G-REC-ERR Exit if a header instead of a data block has been fetched. 11BA LD A,(RECFLG) Bit 1 of RECFLG and of REGLEN-hi 11BD OR (RECLEN-hi) are both reset with 'unused sector'. 11C0 AND +02 Take only bit 1. 11C2 RET Z Return with unused sectors. 11C3 PUSH IX Make HL point to the start of the 11C5 POP HL channel. 11C6 LD DE,+0047 Points to RECNAM. 11C9 ADD HL,DE 11CA LD BC,+000A Name is ten characters in length. 11CD CALL 131E,CHK-NAME Compare it against CHNAME. 11D0 JR NZ,11D6,G-REC-ERR Exit if they do not match. 11D2 LD A,+FF Exit with zero and carry flags reset 11D4 OR A when successful. 11D5 RET 11D6 G-REC-ERR SCF Exit with carry set if any error has 11D7 RET been detected. THE '"M" CHANNEL OUTPUT' ROUTINE The routine is very similar to that for the "N" channel output. The byte passed to the accumulator is stored into the 512-byte buffer. When it is filled, the record is written onto the Microdrive cartridge. 11D8 MCHAN-OUT LD IX,+FFFA Point to the start of the channel 11DC ADD IX,DE (i.e. DE-6, see 00BA). 11E1 BIT 0,(CHFLAG) Continue only if this is a 'write' 11E2 JR NZ,11E6,NOREAD file. 'Writing to a 'read' file' 11E4 RST 20,SH-ERR Call the error handling routine. 11E5 DEFB +0C 11E6 NOREAD LD E,(CHBYTE-lo) Fetch byte counter. 11E9 LD D,(CHBYTE-hi) 11EC PUSH IX Save start address of channel. 11EE ADD IX,DE Now IX points to 'first free byte in the buffer'-82. 11F0 LD (IX+82),A Store a byte in the buffer. 11F3 POP IX Restore start address of channel. 11F5 INC DE Points to first 'free byte' in the buffer. 11F6 LD (CHBYTE-lo),E Update byte counter, 11F9 LD (CHBYTE-hi),D 11FC BIT 1,D Return if the buffer is not filled 11FE RET Z (position 512 has not been reached). If the buffer is filled, the routine continues into WR-RECD below. THE 'WRITE A RECORD ONTO MICRODRIVE' SUBROUTINE This subroutine is also called by using hook code +26. The record held in the "m" channel pointed by the IX register (with name CHNAME and number CHREC), is written into the first unused sector in the cartridge inserted in the drive CHDRIV. Then the appropriate map bit is set and CHREC is automatically incremented. An error is produced if no more space is available on the cartridge to write the record. 11FF WR-RECD LD A,(CHDRIV) Fetch drive number. 1202 CALL 17F7,SEL-DRIVE Turn on the motor. 1205 CALL 120D,WRITE-PRC Write the record. 1208 XOR A Turn off the motor. 1209 CALL 17F7,SEL-DRIVE 120C RET Finished. 120D WRITE-PRC CALL 1264,CHK-FULL Check if the cartridge is full, 1210 JR NZ,121B,NOFULL and jump if it is not. 1212 CALL 10C4,DEL-M-BUF Otherwise reclaim the channel. 1215 XOR A Turn off drive motors. 1216 CALL 17F7,SEL_DRIVE 'Microdrive full' 1219 RST 20,SH-ERR Call the error handling routine. 121A DEFB +0F 121B NOFULL PUSH IX Save base address of channel. 121D LD B,+0A Counts ten characters. 121F CP-NAME LD A,(IX+14) Copy CHNAME into RECNAM. 1222 LD (IX+71),A 1225 INC IX 1227 DJNZ 121F,CP-NAME 1229 POP IX Restore start of channel. 122B LD C,(CHBYTE-lo) Copy CHBYTE into RECLEN. 122E CD (RECLEN-lo),C 1231 LD A,(CHBYTE-hi) 1234 LD (RECLEN-hi),A 1237 LD A,(CHREC) Copy CHREC into RECNUM. l23A LD (RECNUM),A 123D PUSH IX Make HL point to the start of the data 123F POP HL block workspace, i.e. RECFLG. 1240 LD DE,+0043 1243 ADD HL,DE 1244 CALL 1341,CHKS-HD-R Calculate DESCHK checksum. 1247 LD DE,+000F Hake HL point to the start of the 124A ADD HL,DE 512-byte buffer. 124B CALL 1346,CHKS-BUFF Calculate DCHK checksum. 124E PUSH IX Three useless instructions. 1250 POP HL 1251 LD DE,+0047 1254 CALL 1275,SEND-BLK Send the record to Microdrive. 1257 LD DE,+0000 Clear CHBYTE. 125A LD (CHBYTE-lo),E 125D LD (CHBYTE-hi),D 1260 INC (CHREC) Finally increment record number. 1263 RET Finished. THE 'CHK-FULL' SUBROUTINE This subroutine is used to check whether the currently used Microdrive unit contains a full cartridge, with no 'free tot use' sectors. The zero flag is returned set if the cartridge is full (i.e. if all map bits are set). 1264 CHK-FULL LD L,(CHMAP-lo) Fetch address of the map. 1267 LD H,(CHMAP-hi) i26A LD B,+20 Length of the map. 126C NXT-B-MAP LD A,(HL) Fetch a byte. 126D CP +FF Exit with zero flag reset if not all 126F RET NZ bits are set. 1273 INC HL Point to the next byte, 1271 DJNZ 126C,NXT-B-MAP Loop for all bytes. 1273 XOR A Return with zero flag set to signal 1274 RET that the cartridge is full. TIlE 'SEND-BLK' SUBROUTINE The following subroutine fetches the first 'free' header and then writes the buffer into the sector, provided that the cartridge is not write-protected. Finally the map bit is set. 1275 SEND-BLK PUSH IX Make HL point to the data block 1277 POP HL preamble. 1278 LD DE,+0037 127B ADD HL,BE l27C PUSH HL Save this address. 127D FAILED CALL 12C4,GET-M-HD2 Fetch the first header. 1280 CALL 12DF,CHECK-MAP Check map bit for this header. 1283 JR NZ,127D,FAILED Continue if the sector is not 'free for use'. 1285 EX (SP),HL Now (SP) holds the map bit address; and HL the start of the data block preamble. 1286 PUSH BC Save map bit position. 1287 IN A,(+EF) Jump if the write-protect tab is 1289 AND +01 present. 128B JR NZ,128F,NO-PRT 'Drive 'write' protected' 128D RST 20,SH-ERR Call the error handling routine. 128E DEFB +0E 128F NO-PRT LD A,+E6 Start the writing process. 1291 OUT (+EF),A 1293 LD BC,+0168 Wait until the first gap is finished. 1296 CALL 18FA,DELAY-BC 1299 CALL 1878,OUT-M-BUF Write preamble and data block. 129C LD A,+EE Send a signal when finished. 129E OUT (+EF),A 12A0 POP BC Restore map bit position. 12A1 POP HL Restore map bit address. 12A2 LD A,B Set the required map bit. 12A3 OR (HL) 12A4 LD (HL),A 12A5 RET Finished. THE 'CLOSE FILE' SUBROUTINE This subroutine CLOSEs a 'PRINT-type' "m" channel. If the channel is used for reading, then it is reclaimed; but if it is used for writing, any unsent data in the buffer is written onto the Microdrive cartridge before reclaiming the channel. The entry point CLOSE-M is used when the start address of the channel is held in the HL register pair, while CLOSE-M2 (also used by 'hook code' +23) is used when that address is held in the IX index register. 12A6 CLOSE-M PUSH HL Make IX register point to the start 12A7 POP IX of the channel. 12A9 CLOSE-M2 BIT 0,(CHFLAG) Jump forward when 'reading'. 12AD JR Z,12B6,NOEMP 12AF SET 1,(RECFLG) Otherwise signal 'EOF' record, 12B3 CALL 11FF,WR-RECD and write it onto drive. 1236 NOEMP XOR A Switch off motor. 1237 CALL 17F7,SEL-DRIVE 12BA CALL 10C4,DEL-M-BUF Reclaim the channel. 12BD RET Finished. THE 'MAIN ERROR RESTART' EMULATION ROUTINE This routine, called in the format 'CALL ERR-RS / DEFB nn' emulates the sequence 'RST 8 / DEFB nn' that is used (when the main ROM is paged in) to give an error report. ERR-RS is never called from the shadow ROM code. 12BE ERR-RS POP HL Fetch return address (points to the error code). 12BF LD A,(HL) Fetch error code. 12C0 LD (ERR-NR),A Store it. 12C3 RST 28,ROMERR Give the error report. THE 'FETCH HEADER FROM HICRODRIVE' SUBROUTINE This subroutine is used to fetch a header from the current Microdrive unit (whose motor must be turned on). The header is loaded into HDFLG...HDCHK. The procedure is repeated unless the checksum is correct. 12C4 GET-M-HD2 PUSH IX Make HL point to MDFLAG, i.e. location 12C6 POP HL from which the header will be loaded. 12C7 LD DE,+0028 12CA ADD HL,DE 12CB CALL 18A3,GET-M-HD Fetch the header. 12CE CALL 1341,CHKS-HD-R Calculate checksum. 12D1 JR NZ,12C4,GET-M-HD2 Repeat if it does not match with the 'old' checksum. 12D3 BIT 0,(HDFLAG) Repeat if a record descriptor has 12D7 JR Z,12C4,GET-M-HD2 been loaded instead of a header. 12D9 RET Finished. THE 'CHECK MAP BIT STATE' SUBROUTINE The bit correspondent to a given sector in the microdrive map is checked. The zero flag is returned set if the bit was reset, and vice-versa. Also the B register will hold, on return, a bit set in the position of the map bit; HL will hold the address of that map bit. The entry point is CHK-MAP-2 when the sector number has to be collected from RECNUM, or CHECK-MAP if from HDNUMB. 12DA CHK-KAP-2 CD E,(RECNUM) Fetch sector number. 12DD JR 12E2,ENTRY Jump forward. 12E1 CHECK-MAP LD E,(HDNUMB) Fetch sector number. 12E2 ENTRY LD L,(CHMAP-lo) Fetch map start address. 12E5 LD H,(CHMAP-hi) 12E8 ENTRY-2 XOR A Clear D register. 12E9 LD D,A 12EA LD A,E Move sector number to A. 12EB AND +07 Only 3 less significant bits, (i.e. 'bit position'). 12ED SRL E Shift out the 'position' from E. 12EF SRL E 12F1 SRL E 12F3 ADD HL,DE Calculate map bit address. 12F4 LD B,A Pass 'position' to B. 12F5 INC B Range is now 1..8. 12F6 XOR A Clear A register. 12F7 SCF Set carry flag. 12F8 ROTATE RLA Set a bit in the correct position. 12F9 DJNZ 12F8,ROTATE 12FB LD B,A Exit with B holding that bit. 12FC AND (HL) Set zero flag as required. 12FD RET Finished. THE 'RESET BIT IN MAP AREA' SUBROUTINE This subroutine is used to reset the bit in the map area corresponding to the sector HDNUMB. 12FE RES-B-MAP CALL 12DF,CHECK-MAP Set B and HL registers with position and map address. 1301 LD A,B Pass bit to be reset to A. 1302 CPL Reset only that bit and 1303 AND (HL) leave other bits unchanged. 1304 LD (HL),A Store new map byte. 1305 RET Finished. THE 'CHECK "PSEUDO-MAP" BIT STATE' SUBROUTINE This subroutine is apparently equal to the CHECK-MAP subroutine at 12DA, however it does not refer to the standard map, but to a 'pseudo-map' set up in the 512-byte buffer of the "m" channel. This map is used from the ERASE command to mark the sectors to be erased, 1306 TEST-PMAP PUSH IX Make HL point to the start of the 1308 POP HL buffer. I.e. to the start of 1309 LD DE,+0052 the 'pseudo-map' area. 130C ADD HL,DE 130D LD E,(HDNUMB) Fetch sector number. 1310 JR 12E8,ENTRY-2 Continue into CHECK-MAP. THE 'DECREASE SECTOR NUMBER' SUBROUTINE This short subroutine is frequently called to decrease the content of the system variable SECTOR, used to count a given number of sectors during microdrive operations. The zero flag is returned set when SECTOR reaches zero. 1312 DEC-SECT LD BC,(SECTOR) Decrease (SECTOR). 1316 DEC BC 1317 LD (SECTOR),BC 131B LD A,B Set zero flag if SECTOR has reached 131C OR C zero. 131D RET Finished. THE 'CHECK-NAME' SUBROUTINE Whenever a 'filename' is to be compared against the channel name CHNAME, this subroutine is called. On entry, HL must point to the filename to be compared, while C must contain its length. If the comparison is successful, the zero flag is returned set. 131E CHK-NAME PUSH IX Save start of channel. 1320 LD B,+0A Length of CHNAME. 1322 ALL-CHARS LD A,(HL) Fetch a byte from name. 1323 CP (IX+14) Compare it against CHNAME. 1326 JR NZ,133E,CKNAM-END Jump if it does not match. 1328 INC HL Point to next character. 1329 INC IX 132B DEC B Decrease 'lengths'. 132C DEC C 132D JR NZ,1322,ALL-CHARS Continue until the length of the name reaches zero. 132F LD A,B CHNAME remaining length. 1330 OR A Exit if successful (CHNAME length has 1331 JR Z,133E,CKNAM-END reached zero). 1333 ALLCHR-2 LD A,(IX+14) Otherwise check that the following 1336 CP +20 characters of CHNAME are spaces. 1338 JR NZ,133E,CKNAM-END Signal 'unsuccessful' if not spaces. 133A INC IX Continue until the whole CHNAME has 133C DJNZ 1333,ALCCHR-2 been examined. 133E CKNAM-END POP IX Restore channel start address. 1340 RET Finished. THE 'CALCULATE/COMPARE CHECKSUMS' ROUTINE This routine is used to calculate HDCHK, DESCHK and DCHK checksums, or to compare the previous checksum against the current one; the zero flag is returned set if the checksums match. The entry point is CHKS-HD-R for HDCHK or DESCHK, or CHKS-BUFF for DCHK checksum. In both cases HL must contain on entry the start address of the block for which the checksum is to be obtained. 1341 CHKS-HD-R LD BC,+000E The block length. 1344 JR 1349,CHKS-ALL Skip next instruction. 1346 CHKS-BUFF LD BC,+0200 The block length. 1349 CHKS-ALL PUSH HL Save the start address. 134A LD E,+00 Start with E cleared. 134C NXT-BYTE LD A,E Add the current byte to the 134D ADD A,(HL) previous sum. 134E INC HL Point to next location. 134F ADC A,+01 Include also the carry. 1351 JR Z,1354,STCHK Jump when A reaches zero. 1353 DEC A Otherwise balance the ADD above. 1354 STCHK LD E,A Update sum. 1355 DEC BC Decrement counter. 1356 LD A,B Repeat until the counter reaches 0. 1357 OR C 1358 JR NZ,134C,NXT-BYTE 135A LD A,E Move checksum into A. 135B CP (HL) Compare with previous checksum. 135C LD (HL),A Store new checksum. 135D POP HL Restore start address. 135E RET Finished. THE 'RESTORE STREAM DATA' SUBROUTINE This subroutine is entered with BC holding the length of a reclaimed channel, and HL holding the 'stream displacement' for that channel, The stream that refers to this displacement (i.e. the stream attached to the reclaimed channel) is closed. The other stream displacements are updated if they refer to channels moved down after the reclaiming. 135F REST-STRM PUSH HL Save stream displacement. 1360 LD A,+10 Counts 16 streams. 1362 LD HL,+5C16 Start with STRMS-0 address. 1365 NXT-STRM LD (X-PTR),HL Save current address into X-PTR. 1368 LD E,(HL) Fetch stream displacement for the 1369 INC HL current stream. 136A LD D,(HL) 136B POP HL Restore displacement of stream to be 136C PUSH HL closed. 136D OR A Clear carry. 136E SBC HL,DE Jump if this is not the stream to be 1370 JR NZ,1377,NOTRIGHT closed. 1372 LD DE,+0000 Close the stream by storing a 1375 JR 137E,STO-DISP displacement = 0. 1377 NOTRIGHT JR NC,1384,UPD-POINT Jump if the stream data does not need to be updated. 1379 EX DE,HL HL holds the current displacement. 137A OR A Clear carry. 137B SBC HL,BC Obtain new displacement. 137D EX DE,HL Move it into DE. 137E STO-DISP LD HL,(X-PTR) Store the new displacement for 1381 LD (HL),E the current stream. 1382 INC HL 1383 LD (HL),D 1384 UPD-POINT LD HL,(X-PTR) Fetch pointer of current stream data. 1387 INC HL Advance to data for next stream. 1388 INC HL 1389 DEC A Jump back until all 16 streams have 138A JR NZ,1365,NXT-STRM been examined. 138C LD (X-PTR-lo),A Clear X-PTR. 138F POP HL Restore displacement. 1390 RET Finished. THE 'RESTORE MAP ADDRESSES' SUBROUTINE When a map has been deleted, the addresses of the other 'higher' maps have to be updated. The 'REST-MAP' subroutine does this. HL should hold on entry the address of the deleted map. 1391 REST-MAP LD BC,+0020 Length of map. 1394 LD IX,(CHANS) Point to the first channel other than 1398 LD DE,+0014 'standard' one. 139B ADD IX,DE 139D LCHAN LD A,(IX+0) Return if the CHANS area is finished. 13A0 CP +80 13A2 RET Z 13A3 PUSH HL Save 'start' of map. 13A4 LD A,(IX+4) Fetch channel specifier. 13A7 AND +7F No distinction between 'temporary' and 'permanent' channels is made. 13A9 CP +4D Jump if this is not an "m" channel. 13AB JR NZ,13C1,LPEND 13AD LD E,(CHMAP-lo) Fetch address of map. 13B0 LD D,(CHMAP-hi) 13B3 SBC HL,DE Jump if this map has not been moved. 13B5 JR NC,13C1,LPEND 13B7 EX DE,HL HL = old map address. 13B8 OR A Clear carry. 13B9 SBC HL,BC Calculate actual start address and 13BB LD (CHMAP-lo),L store it. 13BE LD (CMMAP-hi),H 13C1 LPEND POP HL Restore 'start' of deleted map. 13C2 LD E,(IX+9) Fetch channel length. 13C5 LD D,(IX+10) 13C8 ADD IX,DE Point to next channel. 13CA JR 139D,LCHAN Loop again. THE '"M" CHANNEL DATA' TABLE The '25' bytes that compose the initial part of an "M" channel are as follows: 13CC DEFW +0008 Main ROM 'output' routine. 13CE DEFW +0008 Main ROM 'input' routine. 13D0 DEFB +CD "M"+80H (channel specifier). 13D1 DEFW +11D8 Shadow ROM 'output' routine. 13D3 DEFW +1122 Shadow ROM 'input' routine. 13D5 DEFW +0253 Channel length. 13D7 DEFW +0000 Default for CHBYTE. 13D9 DEFB +00 Default for CHREC. 13DA DEFM " (10 spc) " Default for CHNAME. 13E4 DEFB +FF Default for CHFLAG ('write' channel). THE 'PREAMBLE DATA' TABLE The header and the data block preambles are made by the following bytes: 13E5 DEFB +00,+00,+00 13E8 DEFB +00,+00,+00 13EB DEFB +00,+00,+00 13EE DEFB +00,+FF,+FF Each preamble is used to fetch the start of a block of data when reading from the Microdrive unit. THE 'MOVE' COMMAND SUBROUTINE The actual MOVE command involves the 'reading' of a byte from the required stream or channel, and then the 'writing' of that byte onto the 2nd stream or channel. The operation is repeated until the 'end of file' condition occurs. Note that bit 4 of FLAGS3 is set to signal to the CALL-INP subroutine (see 0D03) that the 'end of file' error is not to be reported. 13F1 MOVE SET 4,(FLAGS3) See comment above. 13F5 CALL 1455,OP-STRM Open the first channel. 13F8 LD HL,(CHANS) Store current value 0f CHANS. 13FB PUSH BC 13FC CALL 14C7,EX-DSTR2 Exchange D-STR areas. 13FF CALL 1455,OP-STRM Open second channel. 1402 CALL 14C7,EX-DSTR2 Exchange D-STR areas again. 1405 POP DE Initial start of CHANS. 1406 LD HL,(CHANS) Current start of CHANS. 1409 OR A Clear carry for a true subtraction. 140A SBC HL,DE HL holds the length of the space inserted after the 2nd opening (possible maps inserted). 140C LD DE,(N-STR1) Fetch start of first channel. 1410 ADD HL,DE Calculate 'current' start. 1411 LD (N-STR1),HL Store it. 1414 M-AGAIN LD HL,(N-STR1) Make 'current' the 1st channel 1417 LD (CURCHL),HL 141A I-AGAIN RST 10,CAL8AS Call INPUT-A in the main ROM to 141B DEFW +15E6 read a byte. 141D JR C,1423,MOVE-OUT Jump with acceptable codes. 141F JR Z,141A,I-AGAIN Repeat if no data has been read. 1421 JR 142E,MOVE-EOF Jump when EOF has been reached. 1423 MOVE-OUT LD HL,(N-STR2) Make 'current' the 2nd channel. 1426 LD (CURCHL),HL 1429 RST 10,CALBAS Use main ROM 'PRINT-A' restart to 142A DEFW +0010 send the byte through the 2nd channel 142C JR 1414,M-AGAIN Repeat the whole procedure. 142E MOVE-EOF RES 4,(FLAGS3) Signal that the MOVE command is finished. 1432 LD HL,(CHANS) Store current CHANS address. 1435 PUSH HL 1436 CALL 14C7,EX-DSTR2 Exchange D-STR areas, 1439 CALL 14A4,CL-CHAN Close the second channel. 143C CALL 14C7,EX-DSTR2 Exchange D-STR areas again. 143F POP DE Restore initial address of CHANS. 1440 LD HL,(CHANS) Fetch current CHANS address. 1443 OR A Calculate the amount of bytes 1444 SBC HL,DE reclaimed after the deletion of the second channel. 1446 LD DE,(N-STR1) Calculate the new start address of 144A ADD HL,DE first channel. 144B LD (N-STR1),HL 144E CALL 14A4,CL-CHAN Close the first channel. 1451 CALL 17B9,RCL-T-CH Reclaim temporary channels and switch off drive motors. 1454 RET Finished. THE 'USE STREAM OR TEMPORARY CHANNEL' SUBROUTINE This subroutine is used from the MOVE command routine above to fetch the start address of the channel attached to a stream (if the command is of the type 'MOVE #N TO ...' ), or to open a temporary channel and fetch its start address if the command is in the form 'MOVE "S";N (;"NAME") TO ...'. In both cases the start address of the channel is returned into N-STR1. 1455 OP-STRM LD A,(S-STR1) Fetch stream number. 1458 INC A If stream no. is +FF (i.e. 1459 JR Z,1466,OP-CHAN nonexistent), jump to open a temporary channel. 145B DEC A A holds the stream number. 145C RST 10,CAL8AS Call 'CHAN-OPEN' to select the stream. 145D DEFW +1601 145F LD HL,(CURCHL) Fetch channel start address. 1462 LD (N-STR1),HL Store it. 1465 RET Finished. 1466 OP-CHAN LB A,(L-STR1) Fetch channel specifier 1469 CP +4D Jump if not "m". 146B JR NZ,147F,CHECK-N 146D CALL 1B29,OP-TEMP-M Open a temporary "m" channel. 1470 XOR A Switch off drive motor. 1471 CALL 17F7,SEL-DRIVE 1474 LD (N-STR1),IX Store channel start address. 1478 BIT 2,(RECFLG) Allow only PRINT-type files with the 147C RET Z MOVE command. 'Wrong file type' 147D RST 28,SH-ERR Call the error handling routine. 147E DEFB +16 147F CHECK-N CP +4E Jump if not an "n" channel. 1481 JR NZ,148B,CHECK-R 1483 CALL 0EA9,OP-TEMP-N Open a temporary "n" channel. 1486 LD (N-STR1),IX Store channel start address, 148A RET Finished. 148B CHECK-R CP +54 Jump with "t" channel. 148D JR Z,1495,USE-R 148F CP +42 Jump with "b" channel. 1491 JR Z,1495,USE-R 'Nonsense in BASIC' 1493 RST 28,SH-ERR Call the error handling routine. 1494 DEFB +00 1495 USE-R CALL 0B13,OP-RS-CH Open a permanent "b" or "t" channel. 1498 LD (N-STR1),DE Store channel start address. 149C PUSH DE Make IX point to start of channel. 149D POP IX 149F SET 7,(IX+4) Make the channel 'temporary'. 14A3 RET Finished. THE 'CLOSE "MOVE" CHANNEL' SUBROUTINE This is the opposite subroutine of the preceding one, and is used to CLOSE the channel used by the MOVE command routine. If S-STR1 denotes that a stream was used, no action is made. 14A4 CL-CHAN LD A,(S-STR1) Fetch stream number. 14A7 INC A Return if a stream has been used (i.e. S-STR1<>+FF). 14A8 RET NZ 14A9 LD A,(L-STR1) Fetch channel specifier. 14AC CP +4D Jump if not "m" channel. 14AE JR NZ,14B8,CL-CHK-N 14B0 LD IX,(N-STR1) Fetch channel start address. 14B4 CALL 12A9,CLOSE-M2 Close the "m" channel. 14B7 RET Finished. 14B8 CL-CHK-N CP +4E Return with "b" and "t" channels. 14BA RET NZ 14BB LD IX,(N-STR1) Fetch channel start addreus. 14BF LD (CURCHL),IX Make the "n" channel the 'current' one 14C3 CALL 0EF5,SEND-NEOF Close the "n" channel. 14C6 RET Finished. THE 'EXCHANGE DSTR1 AND DSTR2 CONTENTS' SUBROUTINE This subroutine performs exactly the same task as the EX-D-STR subroutine at 059F, even if it is slightly different. The D-STR1 area is copied into the D-STR2 one, and vice-versa. 14C7 EX-DSTR2 LD DE,+5CD6 Start of 1st area. 14CA LD HL,+5CDE Start of 2nd area. 14CD LD B,+08 Length of both areas. 14CF ALL-BYT-2 LD A,(DE) Fetch byte from D-STR1. 14D0 LD C,(HL) Fetch byte from D-STR2. 14D1 EX DE,HL Exchange pointers. 14D2 LD (HL),C Store into D-STR1. 14D3 LD (DE),A Store into D-STR2. 14D4 EX DE,HL Exchange pointers again. 14D5 INC HL Advance pointers. 14D6 INC DE 14D7 DJNZ 14CE,ALL-BYT-2 Continue for all bytes in the D-STR areas. 14D9 RET Finished. THE 'SAVE DATA BLOCK INTO MICRODRIVE' SUBROUTINE This is the actual SAVE command referred to the Microdrive (see 082F). The '9' bytes that form the 'header information' are collected from the HD variables and passed to the channel data block; then the memory block, whose 'start' and 'length' are held in the system variables HD-0D and HD-0B, is written onto the Microdrive (provided that there is sufficient space available on cartridge). 14DA SA-DRIVE LD A,(D-STR1) Fetch drive number. 14DD CALL 17F7,SEL-DRIVE Turn on drive motor. 14E0 IN A,(+EF) Continue only if the write-protect 14E2 AND +01 tab was not removed. 14E4 JR NZ,14E8,START-SA 'Drive 'write' protected' 14E6 RST 20,SH-ERR Call the error handling 14E7 DEFB +0E routine. 14E8 START-SA LD HL,(HD-0D) Fetch 'start' of data. 14EB LD (5CE4),HL Store it into (N-STR2+2). 14EE CALL 1B29,OP-TEMP-M Open a temporary "m" channel. 14F1 BIT 0,(CHFLAG) Continue only if this file does 14F5 JR NZ,14FC,NEW-NAME not already exist in the cartridge. l4F7 CALL 12A9,CLOSE-M2 Close the channel and report the error 'Writing to a 'read' file' 14FA RST 20,SH-ERR Call the error handling routine. 14FB DEFB +0C 14FC NEW-NAME SET 2,(RECFLG) Signal 'not a PRINT file'. 1500 LD A,(CHDRIV) Fetch drive number. 1503 CALL 17E7,SEL-DRIVE Start motor. 1506 PUSH IX Make HL point to the buffer. 1508 POP HL 1509 LD DE,+0052 150C ADD HL,DE 150D EX DE,HL 150E LD HL,+5CE6 Address of HD-00. 1511 LD BC,+0009 Length of HD variables. 1514 LD (CHBYTE-lo),C Current position is '9'. 1517 LDIR Store header informations. 1519 PUSH DbE Save address of 'first free byte'. 151A LD HL,+0009 Add 9 to 'data length'. 151D LD BC,(HD-0B) 1521 ADD HL,BC 1522 SRL H H holds INT(length/5l2), i.e. number of sectors required. 1524 INC H Allow for a further EOF sector. 1525 PUSH HL Save H register. 1526 CALL 1D38,FREESECT Calculate into E the number of 'free' sectors. 1529 POP HL Restore H. 152A LD A,E Jump if there are sufficient 152B CP H 'free' sectors. 152D JR NC,1530,SA-DRI-2 'Microdrive full' 152E RST 20,SH-ERR Call the error handling routine. 152F DEFB +0F 1530 SA-BRI-2 POP DE Restore address of 'first free byte' in the buffer. 1531 LD HL,(5CE4) Fetch 'start' of block from (N-STR2+2) (see 14EB). 1534 LD BC,(HD-0B) Fetch 'length' of data. 1538 SA-DRI-3 LD A,B Jump when it reaches zero. 1539 OR C 153A JR Z,155E,SA-DRI-4 153D LD A,(CHBYTE-hi) Jump until the buffer space has been 151E CP +02 filled. 1541 JR NZ,1552,SA-DRI-WR 1543 PUSH HL Save registers. 1544 PUSH BC 1545 CALL 123D,WRITE-PRC Write this data block onto cartridge. 1548 POP BC Restore counter. 1549 PUSH IX Make DE point to the start of the 154B POP HL buffer. 154C LD DE,+0052 154E ADD HL,DE 1550 EX DE,HL 1551 POP HL Restore pointer. 1552 SA-DRI-WR LDI Move a byte to the buffer. 1554 INC (CHBYTE-lo) Increment CHBYTE and go back into the 1557 JR NZ,SA-DRI-3 loop. 1559 INC (CHBYTE-hi) 155C JR 1538,SA-DRI-3 155E SA-DRI-4 SET 1,(RECFLG) Mark as 'EOF' record. 1562 CALL 120D,WRITE-PRC Write the last data block. 1565 LD A,(COPIES) Decrease COPIES and exit if it has 1568 DEC A reached zero. 1569 JR Z,1579,END-SA-DR 156B LD (COPIES),A Store new value. 156E RES 1,(RECFLG) Signal 'not EOF'. 1572 LD A,+00 Clear CHREC. 1574 LD (CHREC),A 1577 JR 14FC,NEW-NAME Make another copy. 1579 END-SA-DR XOR A Turn off Microdrive motor. 157A CALL 17F7,SEL-DRIVE 157D JP 10C4,DEL-M-BUF Exit via the delete-channel subroutine. THE 'GET HEADER INFORMATION FROM MICRODRIVE' SUBROUTINE This subroutine is used to collect the first nine bytes of the file into the "m" channel buffer, i.e. the 'header information' when handling files which have been written using the SAVE command (see 08C8). These bytes are copied into the HD system variables. 1580 F-M-HEAD LD HL,(5CE1) Move 'start' of data into +5CE4. 1583 LD (5CE4),HL 1586 CALL 1B29,OP-TEMP-M Open a temporary "m" channel. 1589 BIT 0,(CHFLAG) Continue only if the file is found. 158D JR Z,1591,F-HD-2 'File not found' 158F RST 20,SH-ERR Call the error handling routine. 1590 DEFB +11 1591 F-HD-2 BIT 2,(RECFLG) Continue only if it is not a 1595 JR NZ,1599,F-HD-3 'PRINT-type' tile. 'Wrong file type' 1597 RST 20,SH-ERR Call the error handling routine. 1598 DEFB +16 1599 F-HD-3 PUSH IX Point to the start of the 512-byte 159B POP HL buffer. 159C LD DE,+0052 159F ADD HL,DE 15A0 LD DE,+5CE6 Address of HD-00 variable. 15A3 LD BC,+0009 Length of 'header information'. 15A6 LDIR Copy header into HD variables. 15A8 RET Finished. THE 'LOAD OR VERIFY BLOCK FROM MICRODRIVE' SUBROUTINE This subroutine is called from the 'LOAD OR VERIFY' subroutine (see 0A66) to load or verify (depending upon the state of bit 7 of FLAGS3) a block of bytes in memory, starting from the address held in the HL register pair. The subroutine initially calculates the number of records that composes the file; then starts to collect records and to LOAD or VERIFY the data coming in the 512-Byte buffer. When each record has been loaded or verified, the relevant map bit is set, so as to prevent the record to be used again. The map contents are restored to their initial values before returning. Note that the records may be collected from the Microdrive in a random order. 15A9 LV-MCH LD (HD-0D),HL Store 'start'. 15AC LD E,(IX+83) Get 'new' length directly from the 15AF LD D,(IX+84) 'header information' held in the buffer. 15B2 LD HL,+0008 Increase 'length' by 8. 15B5 ADD HL,DE 15B6 SRL H The number of records that composes the file is computed (INT(length/5l2)) 15B8 INC H Include the 'EOF' record. 15B9 LD A,H Save this value into HD-0B. 15BA LD (HD-0B),A 15BD CALL 1613,SA-MAP Save the map into the stack. 15C0 LD DE,+0009 Subtract the 'header length' from 15C3 LD L,(RECLEN-lo) the 'block length'. 15C6 LD H,(RECLEN-hi) 15C9 OR A 15CA SBC HL,DE 15CC LD (RECLEN-lo),L Store actual data block length. 15CF LD (RECLEN-hi),H 15D2 PUSH IX Make HL point after the nine bytes of 15D4 POP HL 'header information'. 15D5 LD DE,+005B 15D8 ADD HL,DE 15D9 LD DE,(HD-0D) Fetch 'start' saved at 15A9. 15DD JR 15F9,LOOK-MAP Jump forward. 15DF USE-REC CALL 166C,F-REC2 Fetch a record. 15E2 LD A,(RECNUM) Repeat if RECNUM is still zero. 15E5 OR A 15E6 JR Z,15DF,USE-REC Now some calculation is performed to obtain into DE the address from which the data coming from the current record, will be loaded or verified. HL will point to the 512-byte buffer. 15E8 RLA Now A = RECNUM*2. 15E9 DEC A A=RECNUM*2-1. 15EA LD D,A Use it as high byte. 15EB LD E,+F7 Exclude nine bytes of initial header. 15ED LD HL,(HD-0D) Fetch 'start'. 15F0 ADD HL,DE Calculate 'start' to use with this record. 15F1 EX DE,HL Move it to DE. 15F2 PUSH IX Make HL point to the start 15F4 POP HL of the 512-byte buffer. 15F5 LD BC,+0052 15F8 ADD HL,BC 15F9 LOOK-MAP EXX Use alternate registers. 15FA CALL 12DA,CHK-MAP-2 Check bit state for the current record. 15FD JR NZ,15DF,USE-REC Repeat if this record has already been fetched. 15FF LD A,(HL) Set map bit to prevent the record 1600 OR B from being fetched again. 1601 LD (HL),A 1602 EXX Restore initial register values. 1603 CALL 1648,LD-VE-M Load or verify this record. 1606 LD A,(HD-0B) Fetch number of records stored at 15BA above. 1609 DEC A Decrease it and repeat until all 160A LD (ED-0B),A records have been collected. 160D JR NZ,15DF,USE-REC 160F CALL 162D,RE-MAP Restore map contents. 1612 RET Finished. THE 'SAVE MICRODRIVE MAP CONTENTS' SUBROUTINE This subroutine, called from LV-MCH above, simply copies the '32' bytes that form the Microdrive map into the machine stack. 1613 SA-MAP POP HL Store return address in a currently 1614 LD (SECTOR),HL unused variable. 1617 LD L,(CHMAP-lo) Fetch map start address. 161A LD H,(CHMAP-hi) 161D LD BC,+1000 B counts 16 passes (map length/2) 1620 SA-MAP-LP LD E,(HL) Fetch a byte from the map. 1621 LD (HL),C Then clear map byte. 1622 INC HL Point to next location. 1623 LD D,(HL) Fetch another map byte. 1624 LD (HL),C Then clear map byte. 1625 INC HL Point to next location. 1626 PUSH DE Save the two collected bytes into the stack. 1627 DJNZ 1620,SA-MAP-LP Continue the loop. 1629 LD HL,(SECTOR) Fetch return address. 162C JP (HL) Make an indirect return. THE 'RESTORE MICRODRIVE MAP CONTENTS' SUBROUTINE Exactly the opposite of the subroutine above: the 32 bytes at the top of the stack are collected and copied into the Microdrive map. 162D RE-MAP POP HL Fetch return address. 162E LD (SECTOR),HL Store it in a currently unused variable. 1631 LD L,(CHMAP-lo) Fetch map address. 1634 LD H,(CHMAP-hi) 1637 LD DE,+001F Advance to the last map location. l63A ADD HL,DE 163B LD B,+10 Counts 'map/2' bytes. 163D RE-MAP-LP POP DE Fetch two bytes. 163E LD (HL),D Store first byte in the map. 163F DEC HL Previous location. 1640 LD (HL),E Store second byte. 1641 DEC HL Previous location. 1642 DJNZ 163D,RE-MAP-LP Continue the loop. 1644 LD HL,(SECTOR) Fetch return address. 1647 JP (HL) Make an indirect return. THE 'LD-VE-M' SUBROUTINE This subroutine performs the actual LOAD or VERIFY operation. It is entered with HL holding the data start address, and with DE holding the address from which the data have to be loaded or verified. 1648 LD-VE-M LD C,(RECLEN-lo) Fetch record length. 164B LD B,(RECLEN-hi) 164E LD A,(FLAGS3) Jump if VERIFYing. 1651 BIT 7,A 1653 JR NZ,1658,VE-M-E 1655 LDIR LOAD the data. 1657 RET Finished. 1658 VE-M-E LD A,(DE) Fetch an existing byte. 1659 CP (HL) Compare against loaded one. 165A JR NZ,1664,VE-FAIL Jump if they do not match. 165C INC HL Point to next locations. 165D INC DE 165E DEC BC Repeat until the block has been 165F LD A,B verified. 1660 OR C 1661 JR NZ,1658,VE-M-E 1663 RET Finished. 'Verification has failed' 1664 VE-FAIL RST 20,SH-ERR Call the error handling routine. 1665 DEFB +15 THE 'FETCH A RECORD FROM MICRODRIVE' SUBROUTINE This subroutine is used to read from the Microdrive unit, a record of the current file (saved with a SAVE command). An error occurs if no record is found after five passes of the cartridge tape. The entry point is F-REC2 when the Microdrive motor is already turned on. 1666 F-REC1 LD A,(CHDRIV) Fetch drive number. 1669 CALL 17E7,SEL-DRIVE Start drive motor. 166C E-REC2 LD BC,+04FB Count five passes of the tape. 166F LD (SECTOR),BC 1673 UNTILFIVE CALL 11A5,G-HD-RC Fetch header and record. 1676 JR C,168A,F-ERROR Jump with any error, or with 1678 JR Z,168A,F-ERROR unused sectors. 167A CALL 12DA,CHK-MAP-2 Check map bit. 167D JR NZ,168A,F-ERROR Jump also with already fetched records. 167F PUSH IX Make HL point to the start of the 1681 POP HL 512-byte buffer. 1682 LD DE,+0052 1685 ADD HL,DE 1686 CALL 1346,CHKS-BUFF Return only with correct checksum. 1689 RET Z 168A F-ERROR CALL 1312,DEC-SECT Decrease SECTOR. 168D JR NZ,1673,UNTILFIVE And continue until five passes of the tape have been made. 'File not found' 168F RST 20,SH-ERR Call the error handling routine. 1690 DEER +11 THE 'RESTORE ADDRESS OF "FILENAME"' ROUTINE After the 'insertion' of some space, the 'filenames' whose start addresses are held into (N-STR1+2) and (N-STR2+2) have been moved up in the workspace area. This routine is entered with HL holding the channel start address, and with BC holding the number of 'inserted' bytes. The addresses held into (N-STR1+2) and (N-STR2+2) are then updated, unless the filenames are stored into 'no-dynamic' areas (i.e. before the channel or after STKEND). 1691 REST-N-AD PUSH HL Save 'start of channel' twice. 1692 PUSH HL 1693 LD DE,(N-STR2+2) Restore start address of the second 1697 CALL 16AC,TST-PLACE filename. 169A LD (N-STR2+2),DE 169E POP HL Restore channel start address. 169F LD DE,(N-STR1+2) Restore start address of the first 16A3 CALL 16AC,TST-PLACE filename. 16A6 LD (N-STR1+2),DE l6AA POP HL Restore channel start address. 16AB RET Finished. The subroutine which calculates the new filename address is the following: 16AC TST-PLACE SCF Allow for a further byte. 16AD SBC HL,DE No action is made if the filename is 16AF RET NC before the channel, 16B0 LD HL,(STKEND) or if it is after STKEND. 16B3 SBC HL,DE 16B5 RET C 16B6 EX DE,HL Add to DE the number of 'inserted' 16B7 ADD HL,BC bytes, so returning the new filename 16B8 EX DE,HL address. 16B9 RET Finished. 16BA...1707 Unused locations (all set to +FF). THE 'CLOSE-STREAM' ROUTINE The main ROM 'CLOSE' routine at +16E5 is rather inadequate to deal with Interface's channels: First, it has a bug that may crash the system when attempting to CLOSE an unopened stream. This is because the CLOSE-2 routine at +1701 does not check whether the displacement data (found by STR-DATA, +171E) is +0000 (signalling a CLOSEd stream). Thus a channel specifier is loaded from a wrong location (CHANS+3), and finally a call to the INDEXER routine is made to search for the (wrong) specifier into the 'stream look-up table', this will result in a system crash. Secondly, that routine will only clear the stream data in STRMS area and is not able to manipulate and reclaim the interface's channels as required. So the shadow ROM is paged-in by an instruction fetch at the address +1708 (i.e., the middle of the CLOSE-2 routine in the main ROM). The following routine is then used. 1708 CLOSE-CL INC HL The 'INC HL' at +1708 in main ROM. 1709 RST 30,NEWVARS Create new variables if required. 170A SRL A Range of stream number is +03..+12. 170C SUB +03 And now +00..+0F. 170E RES 1,(FLAGS3) Signal 'unsent bytes in the buffer have to be sent'. 1712 CALL 1718,CLOSE Close the stream. 1715 JP 05C1,END1 Finished. THE 'CLOSE' COMMAND SUBROUTINE Any stream +00 to +0F may be CLOSEd by loading the stream number into A and then calling this subroutine. The unsent bytes in 'write'-type files are sent or lost depending upon whether bit 1 of FLAGS3 is reset or set. First a call to STR-DATA1 in the main ROM is made to fetch into BC the 'stream data' for the given stream, and to make HL point to the first of the two data bytes. 1718 CLOSE RST 10,CALBAS Call STR-DATA1. 1719 DEFW +1727 171B LD A,C Return if the stream is already 171C OR B CLOSEd (i.e. stream data = 0). 171D RET Z 171E PUSH BC 171F PUSH HL 1720 LD HL,(CHANS) Make HL point to the start of the 1723 DEC HL channel attached to the stream to 1724 ADD HL,BC be closed. 1725 EX (SP),HL HL now holds the address of the stream data. 1726 RST 20,CALBAS A call in the middle of the main ROM 1727 DEFW +16EB 'CLOSE' routine is made to update STRMS contents. 1729 LD HL,(CHANS) Make HL point to the first of the l72C LD DE,+0014 'new' channels, 172F ADD HL,DE 1730 POP DE Restore channel start address. 1731 SCF Return if the channel is not 1732 SBC HL,DE a 'new' one. 1734 POP BC 1735 RET NC 1736 PUSH BC Save stream data, and 1737 PUSH DE channel start address. 1738 EX DE,HL Move start of channel to HL. 1739 LD (CURCHL),HL Make the channel 'current'. 173C INC HL Advance HL to the channel specifier. 173D INC HL 173E INC HL 173F INC HL 1740 LD A,(HL) Fetch channel specifier. 1741 LD DE,+0005 Points to channel length. 1744 ADD HL,DE 1745 LD E,(HL) Fetch channel length. 1746 INC HL 1747 LD D,(HL) 1748 PUSH DE Save the 'length'. 1749 CP +42 Jump with "b" channel. 174B JR Z,1751,CL-RS-CH 174D CP +54 Jump with "n" and "m" channels. 174F JR NZ,175E,CL-N-CH Now follows the CLOSE routine for the "t" and "b" channels. 1751 CL-RS-CH BIT 1,(FLAGS3) Jump if doing a CLEAR#. 1755 JR NZ,177F,RCLM-CH (i.e. do not send any data). 1757 LD A,+0D Send a carriage return over RS232. 1759 CALL 0C5A,BCHAN-OUT 175C JR 177F,RCLM-CH Jump to reclaim the channel. 175E CL-N-CH CP +4E Jump with "m" channel. 1760 JR NZ,176D,CL-M-CH This is the CLOSE routine for the "n" channel, 1762 BIT 1,(FLAGS3) Jump if doing a CLEAR#. 1766 JR NZ,177F,RCLM-CH 1768 CALL 0EF5,SEND-NEOF Send remaining contents of "n" buffer. 176B JR 177F,RCLM-CH Finally the CLOSE routine for the "m" channel. 176D CL-M-CH CP +4D Jump if not "m" channel. 176F JR NZ,177F,RCLM-CH 1771 POP DE Remove 'channel length'. 1772 POP IX Start of channel. 1774 POP DE Stream data. 1775 BIT 1,(FLAGS3) Send the EOF record on microdrive if 1779 JP Z,12A9,CLOSE-M2 not using CLEAR#. l77C JP 10C4,DEL-M-BUF Reclaim "m" channel. 177F RCLM-CH POP BC Channel length. 1780 POP HL Channel start address. 1781 PUSH BC Save 'length' again. 1782 RST 10,CALBAS Call RECLAIM-2 to delete the channel. 1783 DEFW +19E8 NOTE: If the BREAK key is pressed while the buffer is sent as EOF block, the routine does not reach RCLM-CH or DEL-M-BUF, and it is impossible to delete the channel from BASIC unless using the NEW command. The bug should be eliminated by making the channel 'temporary', by setting bit 7 of channel specifier (at 1740..1741), so the channel will be deleted when any error occurs. Now all data referring to the stream attached to the channels moved down are updated. 1785 XOR A Start with stream 0. 1786 LD HL,+5C16 Address of data for stream 0. 1789 UPD-STRM LD E,(HL) Fetch stream data. 178A INC HL 178B LD D,(HL) 178C DEC HL Point to the first byte. 178D LD (X-PTR),HL Store address into X-PTR. 1790 POP BC Length of channel. 1791 POP HL Stream data for closed channel. 1792 PUSH HL 1793 PUSH BC 1794 AND A Jump if the stream data found is 1795 SBC HL,DE lower than that of the closed stream 1797 JR NC,17A4,UPD-NXT-S (i.e. channel has not been moved). 1799 EX DE,HL HL holds the fetched Stream data. 179A AND A Calculate into DE the new stream data 179B SBC HL,BC to be stored. 179D EX DE,HL 179E LD HL,(X-PTR) Restore stream data address. 17A1 LD (HL),E Store new stream data. 17A2 INC HL 17A3 LD (HL),D 17A4 UPD-NXT-S LD HL,(X-PTR) Make HL point to next stream data. 17A7 INC HL 17A8 INC HL 17A9 INC A Increment stream number. 17AA CP +10 Loop for all 16 streams. 17AC JR C,1789,UPD-STRM 17AE LD (X-PTR-hi),+00 Clear X-PTR. 17B2 POP HL Remove 'channel length' and 17B3 POP HL 'stream data'. 17B4 RES 1,(FLAGS3) Clear 'CLEAR/CLOSE' flag. 17B8 RET Finished. THE 'RECLAIM TEMPORARY CHANNELS' SUBROUTINE This subroutine is called to reclaim from the CHANS area all 'temporary' channels (i.e. with bit 7 of channel specifier set). Also the drive motors are turned off. The routine is always called when any error report occurs, and on some other occasions. 17B9 RCL-T-CH LD IX,(CHANS) Make IX point to first 'non-standard' 17BD LD DE,+0014 channel. 17C0 ADD IX,DE 17C2 EX-CHANS LD A,(IX+3) Jump if the CHANS area is not 17C5 CP +80 finished. 17C7 JR NZ,17D2,CHK-TEMPM 17C9 LD A,+EE Send a signal to the interface. 17CB OUT (+EF),A 17CD XOR A Return via SEL_DRIVE to turn off 17CE JP 17F7,SEL-DRIVE drive motors. 17D1 RET Never executed. 17D2 CHK-TEMPM LD A,(IX+4) Fetch channel specifier. 17D5 CP +CD Jump if not a temporary "m" channel. 17D7 JR NZ,17DE,CHK-TEMPN 17D9 CALL 10C4,DEL-M-BUF Reclaim "m" channel. 17DC JR 17B9,RCL-T-CH Loop again. 17DE CHK-TEMPN CP +CE Jump if not a temporary "n" channel. 17E0 JR NZ,17ED,PT-N-CHAN 17E2 LD BC,+0114 Length of "n" channel. 17E5 PUSH IX Make HL point to start of channel. 17E7 POP HL 17E8 RST 10,CALBAS Call RECLAIM-2 to reclaim channel. 17E9 DEFW +19E8 17EB JR 17B9,RCL-T-CH Loop again. 17ED PT-N-CHAN LD E,(IX+9) Fetch channel length. l7F0 LD D,(IX+10) 17F3 ADD IX,DE Point to next channel. 17F5 JR 17C2,EX-CHANS Loop for the whole CHANS area. THE 'SELECT DRIVE MOTOR' SUBROUTINE This subroutine is also called by using 'hook code' +21. On entry, A must hold a drive number in the range 1. .8; the appropriate drive motor is turned on, and an error occurs if the specified drive is not present (or if it contains no cartridge, or contains an unformatted cartridge). If A holds zero, all motors are turned off. Note that this subroutine returns with interrupts disabled if a motor has been switched on. 17F7 SEL-DRIVE PUSH HL Save HL register pair. 17F8 CP +00 Jump if a drive motor is to be turned 17FA JR NZ,1802,TURN-ON on. 17FC CALL 182A,SW-MOTOR Otherwise switch off all motors. 17FF EI Enable interrupts. 1800 POP HL Restore HL. 1801 RET Finished. 1802 TURN-ON DI Disable interrupts. 1803 CALL 182A,SW-MOTOR Switch motors as required. 1806 LD HL,+1388 First wait about 40 ms. 1809 TON-DELAY DEC HL Decrease counter. 180A LD A,H Has the counter reached zero? 180B OR L 180C JR NZ,1809,TON-DELAY Repeat if not. 180E LD HL,+1388 Repeat 5000 times the following test: 1811 REPTEST LD B,+06 Set a counter. 1813 CMK-PRES CALL 18E9,TEST-BRK Give an error if BREAK is pressed. 1816 IN A,(+EF) Repeat until 'GAP' signal is found low 1818 AND +04 181A JR NZ,1820,NOPRES 181C DJNZ 1813,CHK-PRES Repeat 6 times. 181E POP HL Restore HL. 181F RET Finished. 1820 NOPRES DEC HL Becrease counter. 1821 LD A,H Has the counter reached zero? 1822 OR L 1823 JR NZ,1811,REPTEST Repeat if not. 1825 CALL 17F7,SEL-DRIVE Send 'switch off' signals and enable interrupts. 'Microdrive not present' 1828 RST 20,SH-ERR Call the error handling routine. 1829 DEFB +10 The following subroutine does the actual switching' of the motors, and the selection of the required drive. It is entered with drive number 1...8 (or 0 to switch all motors off) in the A register. The required drive motor is selected, its motor started, while others are disabled. 182A SW-MOTOR PUSH DE Save DE register pair. 182B LB DE,+0100 182E NEG A = 0 - drive number. 1830 ADD A,+09 A = 9 - drive number. 1832 LD C,A Move counter to C. 1833 LD B,+08 Loop for 8 microdrives. 1835 ALL-NOTRS DEC C Switch off this microdrive if it is 1836 JR NZ,184B,OFF-MOTOR not the required one. 1838 LD A,D Otherwise switch on the motor. 1839 OUT (+F7),A 183B LD A,+EE 183D OUT (+EF),A 183F CALL 1867,DEL-S-1 Wait about 1 ms. 1842 LD A,+EC 1844 OUT (+EF),A 1846 CALL 1867,DEL-S-1 Wait about 1 ms. 1849 JR 185C,NXT-MOTOR Continue with next microdrive. 184B OFF-MOTOR LD A,+EF The drive motor Is turned off. 184D OUT (+EF),A 184F LD A,E 1850 OUT (+F7),A 1852 CALL 1867,DEL-S-1 Wait about 1 ms. 1855 LD A,+ED 1857 OUT (+EF),A 1859 CALL 1867,DEL-S-1 Wait about 1 ms, 185C NXT-NOTOR DJNZ 1835,ALL-MOTRS Loop for 8 microdrives. 185E LD A,D End of drive selection. 185F OUT (+F7),A 1861 LD A,+EE 1863 OUT (+EF),A 1865 POP DE Restore DE register pair. 1866 RET Finished. THE '1 MILLISECOND DELAY' SUBROUTINE This subroutine inserts a delay of about 3600 T cycles. It is called from SW-MOTOR above. 1867 DEL-S-1 PUSH BC Save BC register pair. 1868 PUSH AF Save accumulator. 1869 LD BG,+0087 Inserts a delay of 3553 T cycles. 186C CALL 18FA,DELAY-BC 186F POP AF Restore registers. 1870 POP BC 1871 RET Finished. THE 'SEND DATA BLOCK TO MICRODRIVE HEAD' SUBROUTINE This subroutine is used for writing a block of bytes onto a Microdrive cartridge. On entry, HL must hold the start of the block to be written. The block is then sent to the Interface (provided that the write-protect tab is present) in a parallel form (the bytes are converted in a serial form by the hardware). The entry points OUT-M-HD and OUT-M-BUF are used respectively to write headers or data blocks (including preambles). 1872 OUT-M-HD PUSH HL Save block start address. 1873 LD DE,+001E Block length. 1876 JR 187C,0UT-M-BLK Jump forward. 1878 OUT-M-BUF PUSH HL Save block start address. 1879 LD DE,+021F Block length. 187C OUT-N-ELK IN A,(+EF) Check write-protect tab. 187E AND +01 Only bit 0. 1880 JR NZ,1884,NOT-PROT Jump if tab is present. 'Drive 'write' protected' 1882 RST 20,SH-ERR Call the error handling routine. 1883 DEFB +0E 1884 NOT-PROT LD A,(IOBORD) Fetch border colour. 1887 OUT (+FE),A Change border colour. 1889 LD A,+E2 Start writing. 188B OUT (+EF),A 188D INC D Increment high counter and copy it 188E LD A,D into A. 188F LD B,E Low counter. 1890 LD C,+E7 Output port. 1892 NOP Wait 12 T cycles. 1893 NOP 1894 NOP 1895 OUT-M-BYT OTIR Write first block. 1897 DEC A Repeat until the whole block has been 1898 JR NZ,1895,OUT-M-BYT written. 189A LD A,+E6 Stop writing. 189C OUT (+EF),A 189E CALL 0CA9,BORD-REST Restore border colour. 18A1 POP HL Restore block start address. 18A2 RET Finished. THE 'RECEIVE BLOCK FROM MICRODRIVE HEAD' SUBROUTINE This is the opposite routine to the preceding one. On entry, HL must hold the start address of the header block or of the data block (AFTER the preamble). The bytes are collected from Microdrive head and stored In the appropriate block. The entry points are GET-M-HD or GET-M-BUF, depending upon whether the block to be received is a header or a data block. 18A3 GET-M-HD PUSH HL Save start address. 18A4 LD DE,+000F Block length. 18A7 JR 18AD,GET-M-BLK Jump forward. 18A9 GET-M-BUF PUSH HL Save start address. 18AA LD DE,+0210 Block length. 18AD GET-M-BLK LD B,E Copy 'length' into BC in 18AE LD C,D a reversed form. 18AF INC C Increment high byte of 'length'. 18B0 PUSH BC 18B1 CHK-AGAIN LD B,+08 Loop 8 times. 18B3 CHKLOOP CALL 18E9,TEST-BRK Give an error if BREAK pressed. 18B6 IN A,(+EF) The GAP line is read repeatedly; 18B8 AND +04 it must be found 'low' after a 'high' 18BA JR Z,18B1,CHK-AGAIN period. 18BC DJNZ 18B3,CHKLOOP 18BE CHK-AG-2 LD B,+06 18C0 CHK-LP-2 CALL 18E9,TEST-BRK 18C3 IN A,(+EF) 18C5 AND +04 18C7 JR NZ,18BE,CHK-AG-2 18C9 DJNZ 18C0,CHK-LP-2 18CB POP BC Restore BC. 18CC LD A,+EE Start reading. 18CE OUT (+EF),A 18D0 POP HL Restore 'start address'. 18D1 PUSH HL 18D2 DR-READY IN A,(+EF) Read SYNC line to synchronize the 18D4 AND +02 reading with the start of the block. 18D6 JR NZ,18D2,DR-READY Repeat until SYNC is found low. 18D8 CALL 18E9,TEST-BRK Give an error if BREAK pressed. 18DB LD A,C A holds the high counter. 18DC LD C,+E7 Input port. 18DE IN-M-BLK INIR Read first block. 18E0 DEC A Repeat until the whole block has 18E1 JR NZ,18DE,IN-M-BLK been read. 18E3 LD A,+EE Finished. 18E5 OUT (+EF),A 18E7 POP HL Restore block start address. 18E8 RET TIlE 'TEST-BRK' SUBROUTINE The BREAK key is checked and the error 'BREAK into program' is made if it is pressed. 18E9 TEST-BRK LD A,+7F Read port +7FFE. 18EB IN A,(+FE) 18ED RRA Only bit 0. 18EE RET C Return if SPACE not being pressed. 18EF LD A,+FE Read port +FEFE. 18F1 IN A,(+FE) 18F3 RRA Only bit 0. 18F4 RET C Return if CAPS SHIFT not being pressed 18F5 LD (ERR-NR),+14 Store error code. 18F9 RST 28,ROMERR Report the error. THE 'DELAY-BC' SUBROUTINE This subroutine is called to insert delays in the program execution, depending upon the value of BC. The exact delay is (BC * 26 - 43) T cycles. 18FA DELAY-BC PUSH AF Save accumulator. 18FB DELAY-BC1 DEC BC Decrease counter. 1BFC LD A,B Repeat until the counter reaches 0. 18FD OR C 18FE JR NZ,18FB,DELAY-BC1 1900 POP AF Restore accumulator. 1901 RET Finished. The following are two subroutines that are never called from the Shadow ROM code. These subroutines operate evidently on the buffer's contents of a Microdrive channel. 1902 UNKN-1 PUSH HL 1903 PUSH IX 1905 POP HL 1906 LD BC,+0052 1909 ADD HL,BC 190A LD B,H 190B LD C,L 190C LD HL,+0000 190F LD DE,+0000 1912 EXX 1913 LD BC,+0200 1916 LD HL,+0000 1919 LD DE,+0000 191C UNKN-2 EXX 191D LD A,(BC) 191E INC BC 191F ADD A,E 1920 LD E,A 1921 JR NC,1929,UNKN-3 1923 INC D 1924 JR NZ,1929,UNKN-3 1928 EXX 1929 UNKN-3 ADD HL,DE 192A EXX 192B ADC HL,DE 192D DEC BC 192E LD A,B 192F OR C 1930 JR NZ,191C,UNKN-2 1932 LD D,E 1933 EXX 1934 LD A,D 1935 LD E,+00 1937 SLA D 1939 EXX 193A LD E,A 193B RL E 193D RL D 193F EXX 1940 ADD HL,DE 1941 EXX 1942 ADC HL,DE 1944 PUSH HL 1945 EXX 1946 PUSH HL 1947 PUSH BC 1948 POP HL 1949 POP BC 194A LD E,+00 194C LD A,C 194D CP (HL) 194E JR Z,1952,UNKN-4 1950 INC E 1951 LD (HL),A 1952 UNKN-4 INC HL 1953 LD A,B 1954 CP (HL) 1955 JR Z,1959,UNKN-5 1957 INC E 1958 LD (HL),A 1959 UNKN-5 INC HL 195A POP BC 195B LD A,C 195C CP (HL) 195D JR Z,1961,UNKN-6 195F INC E 1960 LD (HL),A 1961 UNKN-6 INC HL 1962 LD A,B 1963 CP (HL) 1964 JR Z,1968,UNKN-7 1966 INC E 1967 LD (HL),A 1968 UNKN-7 LD A,E 1969 OR A 196A POP HL 196B RET l96C UNKN-8 PUSH IX 196E POP HL 196F LD DE,+0052 1972 ADD HL,DE 1973 LD BC,+0200 1976 UNKN-9 LD A,(HL) 1977 XOR +55 1979 LD (HL),A 197A INC HL 197B DEC BC 197C LD A,B 197D OR C 197E JR NZ,1976,UNKN-9 1980 RET The 'Hook code' routines THE 'HOOK-CODE' ROUTINE This routine is entered from 00EB with the A register holding a 'hook code', or an invalid error code. The routine calls a set of subroutines in the shadow ROM, and is intended to help the machine-code user. Only the value held in the accumulator may be passed to the called subroutine. 1981 HOOK-CODE CP +18 Continue with 'hook' codes. 1983 JR C,1987,CLR-ERR 'Hook code error' 1985 RST 20,SH-ERR Call the error handling routine. 1986 DEFB +12 1987 CLR-ERR LD (ERR-NR),+FF The 'error' is cleared. 198B SET 2,(FLAGS) 198F INC HL Advance return address past the error code. 1990 EX (SP),HL Store new return address; the initial value of A goes into H. 1991 PUSH HL Save this value. 1992 ADD A,A Multiply code by two. 1993 LD D,+00 Pass offset into DE. 1995 LD E,A 1996 LD HL,+19A9 Start of 'hook code addresses' table. 1999 ADD HL,DE Index into this table. 199A LD E,(HL) Fetch low byte of the address. 199B INC HL 199C LD D,(HL) Fetch high byte. 199D POP AF Restore initial value of A. 199E LD HL,+0700 Return address is UNPAGE. 19Al PUSH HL 19A2 EX DE,HL Move address to HL. l9A3 JP (HL) Jump to the 'hook code' routine. THE 'HOOK CODE +32' ROUTINE This 'hook code' is designed to call (when the main ROM is paged in) any subroutine held in the shadow ROM. The address of the subroutine to be called is taken from HD-11. 19A4 HOOK-32 LD HL,(HD-11) Fetch address of the routine. 19A7 JP (HL) Jump to the routine. THE 'HOOK CODE +31' ROUTINE This 'hook code' has the task of creating the new system variables if nonexistent. Note that the routine is made by a single RET instruction, because the variables have been created on entry to the shadow RON. 19A8 HOOK-3l RET Jump indirectly to UNPAGE. THE 'HOOK CODE ADDRESSES' TABLE This jump table is made by the 24 addresses of the routines called by using the various 'hook codes'. Note that hook code +2B jumps incorrectly to the same routine as hook code +22. The correct address seems to be +1AF0. 19A9 DEFW +19D9,CONS-IN Hook code +1B. 19AB DEFW +19EC,CONS-OUT Hook code +1C. 19AD DEFW +0B81,BCHAN-IN Hook code +1D. 19AF DEFW +0C5A,BCHAN-OUT Hook code +1E. 1981 DEFW +19FC,PRT-OUT Hook code +1F. 1983 DEFW +1A01,KBD-TEST Hook code +20. 1985 DEFW +17F7,SEL-DRIVE Hook code +21. 1987 DEFW +1B29,OP-TEMP-M Hook code +22. 1989 DEFW +12A9,CLOSE-M2 Hook code +23. 198B DEFW +1D6E,ERASE Hook code +24. 198D DEFW +1A09,READ-SEQ Hook code +25. 198F DEFW +11FF,WR-RECD Hook code +26. 19C1 DEFW +1A17,RD-RANDOM Hook code +27. 19C3 DEFW +1A4B,RD-SECTOR Hook code +28. 19C5 DEFW +1A86,RD-NEXT Hook code +29. 19C7 DEFW +1A91,WR-SECTOR Hook code +2A. 19C9 DEFW +1B29,OP-TEMP-M Hook code +2B. 19CB DEFW +10C4,DEL-M-BUF Hook code +2C. 19CD DEFW +0EA9,OP-TEMP-N Hook code +2D. 19CF DEFW +1A24,CLOSE-NET Hook code +2E. 19D1 DEFW +1A31,GET-PACK Hook code +2F. 19D3 DEFW +0DB2,SEND-PACK Hook code +30. 19D5 DEFW +19A8,HOOK-31 Hook code +31. 19D7 DEFW +19A4,HOOK-32 Hook code +32. THE 'CONSOLE INPUT' SUBROUTINE This subroutine is called by using 'hook code' +1B. It simply waits until a key is pressed and returns the character code in the A register. This 'hook code' has been included because the keyboard is not scanned when the main ROM is paged-in. 19D9 CONS-IN EI Enable interrupts. 19DA RES 5,(FLAGS) Signal 'ready for a new key'. 19DE WTKEY HALT Wait 1/50th of second. 19DF RST 10,CALBAS Call the keboard scan routine 19E0 DEFW +02BF in the main ROM. 19E2 BIT 5,(FLAGS) Repeat the scan if no key has been 19E6 JR Z,19DE,WTKEY pressed. 19E8 LD A,(LAST-K) Fetch character code. 19EB RET Finished. THE 'CONSOLE OUTPUT' SUBROUTINE This subroutine is called by using 'hook code' +1C. The character held in the A register is printed on the screen, with scroll suppressed. 19EC CONS-OUT PUSH AF Save character to be printed. 19ED LD A,+FE Use stream '-2' (Screen). 19EF OUT-CODE LU HL,+5C8C This is SCR-CT. 19F2 LD (HL),+FF Set scroll counter. 19F4 RST 10,CALBAS Call CHAN-OPEN in the main ROM to 19F5 DEFW +1601 select the stream. 1SF7 POP AF Restore character. 19F8 RST 10,CALBAS Call 'PRINT-A' restart to print the 19F9 DEFW +0010 character. 19FB RET Finished. THE 'PRINTER OUTPUT' SUBROUTINE This subroutine is called by using hook code +1F. This is identical to the preceding one, but the output is directed to the stream +03 (normally the ZX Printer). 19FC PRT-OUT PUSH AF Save character to be printed. 19FD LD A,+03 Select stream 3. 19FF JR 196F,OUT-CODE Jump back. THE 'KEYBOARD TEST' SUBROUTINE This is called by using 'hook code' +20. The keyboard is scanned and the zero flag returned reset if any key has been pressed. 1A01 KBD-TEST XOR A Clear A, allowing for the whole keyboard to be examined. 1A02 IN A,(+FE) Read the keyboard. 1A04 AND +1F Only 5 less significant bits. 1A06 SUB +1F Return with sign negative and zero 1A08 RET flag reset if any key has been pressed. THE 'READ SEQUENTIAL' SUBROUTINE This is called by using 'hook code' +25. The subroutine reads into the datablock of the current "m" channel, the next record of a named PRINT-type file. On entry IX must hold the "m" channel start address, and CHREC the number of the current record. CHREC will be automatically incremented. CHDRIV must hold the drive number and CHNAME must hold the file name. 1A09 READ-SEQ BIT 1,(RECFLG) Jump if the current record is not 1A0D JR Z,1A14,INCREC the EOF one. 1A0F LD (ERR-NR),+07 Otherwise signal 'end of file'. 1A13 RST 28,ROMERR Report the error. 1A14 INCREC INC (CHREC) Increment record number and continue into RD-RANDOM. THE 'READ RANDOM' SUBROUTINE This subroutine is called by using 'hook code' +27. The record number CHREC of a PRINT-type file is loaded into the data block. The other variables are to be set as for READ-SEQ above. 1A17 RD-RANDOM CALL 1177,GET-RECD Load CHREC record. 1A1A BIT 2,(RECFLG) Return only if this is a PRINT-type 1A1E RET Z file. 1A1F CALL 10C4,DEL-M-BUF Otherwise reclaim the channel, and report the error. 'Wrong file type' 1A22 RST 20,SH-ERR Call the error handling routine. 1A23 DEFB +16 THE 'CLOSE NETWORK CHANNEL' SUBROUTINE This is called by using 'hook code' +2E. First, the remaining bytes in the "n" channel buffer whose base address is held in the CURCHL system variable, are sent as EOF block (if the channel is opened for writing). The channel is then reclaimed. 1A24 CLOSE-NET CALL 0EF5,SEND-NEOF Send the EOF block if required. 1A27 PUSH IX Move channel start address to HL. 1A29 POP HL 1A2A LD BC,+0114 Length of "n" channel. 1A2D RST 10,CALBAS Call RECLAIM-2 to delete the channel. 1A2E DEFW +19E8 1A30 RET Finished. THE 'GET PACKET FROM NETWORK' SUBROUTINE This is called by using 'hook code' +2F. Unfortunately the subroutine is unusable, because the carry flag (that signals if an error has occurred) is corrupted by exit via the BORD-REST subroutine. You may use GET-N-BUF at 03DF to read a packet. 1A31 GET-PACK LD A,(IOBORD) Fetch border colour. 1A34 OUT (+FE),A Change border colour. 1A36 DI Disable interrupts. 1A37 CALL 0F1E,WT-SCOUT Wait for a 'scout' leader. 1A3A JR NC,1A46,GP-ERROR Jump if 'time-out' occurs. 1A3C CALL 0E18,GET-NBLK Wait for header and data block. 1A3F JR NZ,1A46,GP-ERROR Jump with any error. 1A41 EI Enable interrupts. 1A42 AND A Reset carry to signal 'successful'. 1A43 JP 0CA9,BORD-REST But it is corrupted into BORD-REST. 1A46 CF-ERROR SCF Signal 'error' 1A47 EI Enable interrupts. 1A48 JP 0CA9,BORD-REST Again the carry flag will be corrupted. THE 'READ SECTOR' SUBROUTINE This is called by using 'hook code' +28. Before using this, you must start the required drive motor, and store a sector number into CHREC. The data block stored into the given sector is then read in the channel area (pointed by IX), and used if it is a PRINT-type record. The carry flag is returned reset if the reading is successful. 1A4B RD-SECTOR LD HL,+00F0 Counts through 240 sectors. 1A4E LD (SECTOR),HL 1A51 NO-GOOD CALL 12C4,GET-M-HD2 Get a header. 1A54 LD A,(HDNUM) Fetch current sector number. 1A57 CP (CHREC) Compare with given sector number. 1A5A JR Z,1A63,USE-C-RC Jump if found the required sector. 1A5C CALL 1312,DEC-SECT Otherwise decrease SECTOR. 1A5E JR NZ,1A51,NO-G00D Jump until 240 sectors have been examined. 'File not found' 1A61 RST 20,SH-ERR Call the error handling routine. 1A62 DEFB +11 1A63 USE-C-RC PUSH IX Make HL point to RECFLG (i.e. sTart 1A65 POP HL of data block. 1A66 LD DE,+0043 1A69 ADD HL,DE 1A6A CALL 18A9,GET-M-BUF Read data block. 1A6D CALL 1341,CHKS-HD-R Calculate current checksum. 1A70 JR NZ,1A81,DEL-B-CT Jump if it does not match with old checksum. 1A72 LD DE,+000F Make HL point to start of buffer. 1A75 ADD HL,DE 1A76 CALL 1346,CHKS-BUFF Calculate checksum of buffer. 1A79 JR NZ,1A81,DEL-B-CT Jump if it does not match with old checksum. 1A7B OR A Return with carry flag reset if 1A7C BIT 2,(RECFLG) this is a PRINT-type file. 1A80 RET Z 1A81 DEL-B-CT CALL 1AE0,CLR-BUFF Otherwise clear buffer contents. 1A84 SCF Return with carry flag set to signal 1A85 RET the error. THE 'READ NEXT SECTOR' SUBROUTINE This is used by using 'hook code' +29. The first header and data block that pass through the Microdrive head are copied into the channel area pointed by IX. As with the previous subroutine, the drive motor is to be started before calling it. 1A86 RD-NEXT LD HL,+00F0 Initialise SECTOR to 240. 1A89 LD (SECTOR),HL 1A8C CALL 12C4,GET-M-HD2 Fetch the first header. 1A8F JR 1A63,USE-C-RC Continue back. THE 'WRITE SECTOR' SUBROUTINE This is used by using 'hook code' +2A. It is the opposite routine of 'RD-SECTOR' above. The Microdrive unit is to be started before calling the routine. The current data block in the "m" channel pointed by the IX register is written onto the sector whose number is specified by CHREC. Other channel variables, such as CHNAME, are to be set as required. 1A91 WR-SECTOR LD HL,+00F0 Pass through 240 sectors. 1A94 CD (SECTOR),HL 1A97 PUSH IX Make HL point to the data block 1A99 POP HL preamble. 1A9A LD DE,+0037 1A9D ADD HL,DE 1A9E PUSH HL Save this address. 1A9F LD DE,+000C Now point to RECFLG. 1AA2 ADD HL,DE 1AA3 CALL 1341,CHKS-HD-R Calculate DESCHK checksum. 1AA6 LD DE,+000F Now point to the buffer. 1AAA CALL 1346,CHKS-BUFF Calculate DCHK checksum. 1AAD WR-S-l CALL 12C4,GET-M-HD2 Get a header. 1AB0 LD A,(HDNUMB) Fetch current sector number. 1AB3 CP (CHREC) See whether it is the expected one. 1AB6 JR Z,1ABF,WR-S-2 Jump if so. 1AB8 CALL 1312,DEC-SECT Otherwise decrease SECTOR. 1ABB JR NZ,1AAD,WR-S-l Loop until 240 sectors have been examined. 'File not found' 1ABD RST 20,SH-ERR Call the error handling routine. 1ABE DEFB +11 1ABF WR-S-2 IN A,(+EF) Continue if the write-protect tab 1AC1 AND +01 is present. 1AC3 JR NZ,1AC7,WR-S-3 'Drive write protected' 1AC5 RS-SH RST 20,SH-ERR Call the error handling routine. 1AC6 DEFB +0E 1AC7 WR-S-3 LD A,+E6 Start writing. 1AC9 OUT (+EF),A 1ACB LD BC,+0168 Wait until the first gap is finished. 1ACE CALL 18FA,DELAY-BC 1AD1 POP HL Restore address of data block preamble 1AD2 CALL 1878,OUT-M-BUF Write data block onto cartridge. 1AD5 LD A,+EE Stop writing. 1AD7 OUT (+EF),A 1AD9 CALL 12DF,CHECK-MAP Finally set the appropriate map bit. 1ADC LD A,B 1ADD OR (HL) 1ADE LD (HL),A 1ADF RET Finished. THE 'CLEAR BUFFER CONTENTS' SUBROUTINE This subroutine is called from RD-SECTOR and RD-NEXT subroutines to clear the data received into the "m" buffer, if they are not part of a PRINT-type file. 1AE0 CLR-BUFF PUSH IX Make HL point to the start of the 1AE2 POP HL "m" buffer. 1AE3 LD DE,+0052 1AE6 ADD HL,DE 1AE7 LD D,H Copy this address into DE. 1AE8 LD E,L 1AE9 INC DE 'Destination' is next byte. 1AEA LD BC,+01FF Buffer length - 1. 1AED LDIR Clear the buffer. 1AEF RET Finished. THE 'OPEN A PERMANENT "M" CHANNEL' SUBROUTINE This is the actual OPEN corinnand referred to the "m" channel. A permanent "m" channel is opened, and it is attached to the stream held into S-STR1 (provided that the file is a PRINT-type file). 1AF0 OP-M-STRM LD A,(S-STR1) Fetch stream number. 1AF3 ADD A,A Multiply by two. 1AF4 LD HL,+5Cl6 Address of data for stream 0. 1AF7 LD E,A Use (stream*2) as offset. 1AF8 LD D,+00 1AFA ADD HL,DE Index into STRMS area. 1AFB PUSH HL Save address of data for the required stream. 1AFC CALL 1B29,OP-TEMP-M Open a temporary "m" channel. 1AFF BIT 0,(CHFLAG) Jump if this is a 'read' file. 1B03 JR Z,1B0D,MAKE-PERM 1B05 IN A,(+EF) Jump if the write-protect tab is 1B07 AND +01 present. 1B09 JR NZ,1B0D,MAKE-PERM 'Drive 'write' protected' 1B0B RST 20,SH-ERR Call the error handling routine. 1B0C DEFB +0E 1B0D MAKE-PERN RES 7,(IX+4) Make the channel permanent. 1B11 XOR A Switch off drive motors. 1B12 CALL 17F7,SEL-DRIVE 1B15 BIT 0,(CHFLAG) Jump with 'write' files. 1B19 JR NZ,1B23,STORE-DSP 1B1B BIT 2,(RECFLG) Jump with PRINT-type 'read' files. 1B1F JR Z,1B23,STORE-DSP 'Wrong file type' 1B21 RST 20,SH-ERR Call the error handling routine. 1B22 DEFB +16 1B23 STORE-DSP EX DE,HL DE holds new stream data. 1B24 POP HL Restore stream address. 1B25 LD (HL),E Store stream data into STRMS area. 1B26 INC HL 1B27 LD (HL),D 1B28 RET Finished. THE 'OPEN TEMPORARY "M" CHANNEL' SUBROUTINE This fundamental subroutine is used to open a temporary "m" channel in the CHANS area. First a temporary "m" channel is created. Then the drive whose number is held into D-STR1 is started, and searched for a file whose name is held into N-STR1. A map area is created (unless it already exists), and its contents are setup according to the cartridge contents (the bits reset indicate 'free for use' sectors). Various flags are returned as follows: - bit 0 of CHFLAG set with 'write' files. - bit 1 of RECFLG set with EOF block. - bit 2 of RECFLG set with PRINT-type files. On exit, HL holds a 'stream data' displacement that may be used to attach the channel to a stream. The drive motor will not be switched off. Note that H'L' is corrupted and the user must preserve its value when using this routine from BASIC. 1B29 OP-TEMP-M CALL 0FE8,SET-T-MCH Create a temporary "m" channel. 1B2C PUSH HL Save 'stream displacement' 1B2D LD A,(CHDRIV) Fetch drive number. 1B30 CALL 17F7,SEL-DRIVE Turn on drive motor. 1B33 LD BC,+00FF Count 255 sectors. 1B36 LD (SECTOR),BC 1B3A OP-F-1 CALL 11A5,G-HD-RC Get header and data block. 1B3D JR C,1B5F,OP-F-4 Jump with any error. 1B3F JR Z,1B5C,OP-F-3 Jump with 'free' sectors. 1B41 RES 0,(CHFLAG) Signal 'read file' if the file is already present on cartridge. 1B45 LD A,(RECNUM) Jump if this is not the 1st record. 1B48 OR A 1B49 JR NZ,1B57,OP-F-2 1B4B PUSH IX Make HL point to the data buffer. 1B4D POP HL 1B4E LD DE,+0052 1B51 ADD HL,DE 1B52 CALL 1346,CHKS-BUFF Calculate new DCHK checksum. 1B55 JR Z,1B6C,OF-F-5 Jump it it is equal to the old one. 1B57 OP-F-2 CALL 117D,GET-R-2 Fetch first record of file. 1B5A JR 1B6C,OP-F-5 Jump forward. 1B5C OP-F-3 CALL 12FE,RES-B-MAP Reset map bit to signal 'free sector' 1B5F OP-F-4 CALL 1312,DEC-SECT Decrease SECTOR. 1B62 JR NZ,1B3A,OP-F-1 Consider all 255 sectors. 1B64 RES 1,(RECFLG) 'No EOF'. 1B68 RES 2,(RECFLG) 'PRINT-type file' (opened for writing) 1B6C OP-F-5 POP HL Restore stream 'stream data'. 1B6D RET Finished. The Microdrive command routines THE 'FORMAT' COMMAND ROUTINE The action of FORMATting a new cartridge is performed by this subroutine. It is entered with the drive number into D-STR1, the cartridge name address and length into N-STR1. 1B6E FORMAT CALL 0FE8,SET-T-MCH Create channel and map. 1B71 LD A,(CHDRIV) Fetch drive number. 1B74 CALL 182A,SW-MOTOR Turn on the motor. 1B77 LD BC,+32C8 Wait before checking the write- 1B7A CALL 18FA,DELAY-BC protect tab. 1B7D DI Disable interrupts. 1B7E IN A,(+EF) Continue only if the tab is 1B80 AND +01 present. 1B82 JR NZ,1B86,FORMAT-1 'Drive 'write' protected' 1B84 RST 20,SH-ERR Call the error handling routine. 1B85 DEFB +0E 1B86 FORMAT-1 LD A,+E6 Start writing. 1B88 OUT (+EF),A 1B8A LD BC,+00FF Pass through 255 sectors. 1B8D LD (SECTOR),BC 1B91 PUSH IX Make DE point to HDNAHE. 1B93 POP HL 1B94 LD DE,+002C 1B97 ADD HL,DE 1B98 EX DE,HL 1B99 LD HL,+FFE2 Now make HL point to CHNAME 1B9C ADD HL,DE (i.e. cartridge name). 1B9D LD BC,+000A Name length. 1BA0 LDIR Copy cartridge name into HDNAME. 1BA2 XOR A Use 'invisible' name by storing zero 1BA3 LD (RECNAM),A as first character of the record name. 1BA6 SET 0,(HDFLAG) Mark the header block. 1BAA RES 0,(RECFLG) Mark the data block. 1BAE SET 1,(RECFLG) Mark as 'EOF' block. 1BB2 PUSH IX Make HL point to the start of the 1BB4 POP HL data buffer. 1BB5 LD DE,+0052 1BB8 ADD HL,DE Now the data buffer is filled with bytes +FC; and the checksums are calculated. 1BB9 LD B,+00 Counts 256 bytes. 1BBB LD A,+FC The byte to be stored. 1BBD FILL-B-F LD (HL),A Fill 256 bytes. 1BBE INC HL 1BBF BJNZ 1BBD,FILL-B-F 1BC1 FILL-B-F2 LD (HL),A Fill next 256 bytes. 1BC2 INC HL 1BC3 DJNZ 1BC1,FILL-B-F2 1BC5 PUSH IX Point to start of data block 1BC7 POP DE workspace (i.e. RECFLG). 1BC8 LD HL,+0043 1BCB ADD HL,DE 1BCC CALL 1341,CHKS-HD-R Calculate DESCHK checksum. 1BCF LD DE,+000F Make HL point to the data buffer. 1BD2 ADD HL,DE 1BD3 CALL 1346,CHKS-BUFF Now this data block is written in all sectors with HDNUMB numbered from 254 to 1 1BD6 WR-F-TEST CALL 1312,DEC-SECT Decrease SECTOR. 1BD9 JR Z,1C0A,TEST-SCT Jump when SECTOR has reached zero. 1BDB LD (HDNUMB),C Take HDNUMB from SECTOR. 1BDE PUSH IX Make HL point to the start of the 1BE0 POP HL header workspace, i.e. HDFLAG. 1BE1 LD DE,+0028 1BE4 ADD HL,DE 1BE5 CALL 1341,CHKS-HD-R Calculate HDCHK checksum. 1BE8 LD DE,+FFF4 Make HL point to the header block 1BEB ADD HL,DE preamble. 1BEC CALL 1872,OUT-M-HD Write the header onto the cartridge. 1BEF LD BC,+01B2 Wait to create part of the first gap. 1BF2 CALL 18FA,DELAY-BC 1BF5 PUSH IX Make HL point to data block preamble. 1BF7 POP HL 1BF8 LD DE,+0037 1BFB ADD HL,DE 1BFC CALL 1878,OUT-M-BUF Write the data block. 1BFF LD BC,+033F Part of the second gap is created. 1C02 CALL 1BFA,DELAY-BC 1C05 CALL 18E9,TEST-BRK Give an error if BREAK has been pressed. 1C08 JR 18D6,WR-F-TEST Continue with next sector. 1C0A TEST-SCT LD A,+EE Stop writing. 1C0C OUT (+EF),A 1C0E LD A,(CHDRIV) Fetch drive number. 1C11 CALL 17F7,SEL-DRIVE Start motor. Now the sectors contain 'test data', and are to be read back to see if they are usable. If the checksums are correct, the appropriate map bit is reset to signal 'free for use' sectors. 1C14 LD BC,+00FF Pass through 255 sectors, 1C17 LD (SECTOR),BC 1C1B CHK-SCT CALL 12C4,GET-H-HD2 Fetch a header. 1C1E CALL 12DF,CHECK-MAP Check map bit and jump with 1C21 JR Z,1C3E,CHK-NSECT examined sectors. 1C23 PUSH IX Make HL point to start of data block 1C25 POP HL workspace (i.e. RECFLG). 1C26 LD DE,+0043 1C29 ADD HL,DE 1C2A CALL 18A9,GET-M-BF Fetch data block. 1C2D CALL 1341,CHKS-HD-R Calculate DESCHK checksum. 1C30 JR NZ,1C3E,CHK-NSECT Jump with faulty sectors. 1C32 LD DE,+000F Make HL point to the data buffer. 1C35 ADD HL,DE Start of data buffer. 1C36 CALL 1346,CHKS-BUFF Calculate DCHK checksum. 1C39 JR NZ,1C3E,CHK-NSECT Jump with faulty sectors. 1C3B CALL 12FE,RES-B-MAP Reset map bit with usable sectorS. 1C3E CHK-NSECT CALL 1312,DEC-SECT Decrease SECTOR. 1C41 JR NZ,1C1B,CHK-SCT Check all sectors. 1C43 CALL 1E3E,IN-CHK Initialise RECFLG, BECLEN, and DESCHK. At this point all sectors that have been found 'usable' (marked with a reset bit in the map) are written with RECFLG and RECLEN zeroed, as to mark them 'working' for future use. 1C46 MARK-FREE CALL 1264,CHK-FULL Jump until all bits in the map 1C49 JR NZ,1C53,MK-BLK are made set. 1C48 XOR A Turn off drive motors. 1C4C CALL 17F7,SEL-DRIVE 1C4F CALL 10C4,DEL-M-BUF Reclaim "m" channel and map. 1C52 RET Finished. 1C53 MK-BLK CALL 1275,SEND-BLK Write data block in the next 'free' sector. 1C56 JR 1C46,MARK-FREE Jump back. THE 'CAT' COMMAND ROUTINE This subroutine makes a CATalogue of the cartridge inserted in the drive whose number must be specified by D-STR1. S-STR1 must hold the stream to which the catalogue is to be directed. 1C58 CAT LD A,(S-STR1) Fetch stream number. 1C5B RST 10,CALBAS Call CHAN-OPEN to select the 1C5C DEFW +1601 specified stream. 1C5E CALL 0FE8,SET-T-MCH Set a temporary "m" channel. 1C61 LD A,(CHDRIV) Fetch drive number. 1C64 CALL 17F7,SEL-DRIVE Turn on drive motor. 1C67 LD BC,+00FF Pass through 255 sectors. 1C6A LD (SECTOR),BC 1C6E CAT-LP CALL 12C4,GET-M-HD2 Fetch a header. 1C71 CALL 1E53,G-RDES Fetch record descriptor. 1C74 JR NZ,1C6E,CAT-LP Repeat until data is correct. 1C76 LD A,(RECFLG) The sector is 'free for use' when 1C79 OR (RECLEN-hi) bit 1 of both RECFLG and RECLEN-hi 1C7C AND +02 are reset (see comment after 1C43). 1C7E JR NZ,1C85,IN-NAME Jump if not a 'free' sector. 1C80 CALL 12FE,RES-B-MAP Reset map bit if it is a 'free' sector. 1C83 JR 1CEE,F-N-SCT Continue with next sector. If the current sector is not 'free', then the name of the file held in it is to be collected and inserted in alphabetical order into the data buffer of the "m" channel. Names starting with CHR$ 0 are refused. 1C85 IN-NAME LD A,(RECNAM) Fetch first character of file name. 1C88 OR A Continue with next sector if this is 1C89 JR Z,1CEE,F-N-SCT CHR$ 0. 1C8B PUSH IX Make HL point to the data buffer. 1C8D POP HL 1C8E LD DE,+0052 1C91 ADD HL,DE 1C92 LD DE,+000A Length of filename. 1C95 LD B,+00 B is initiallly cleared. 1C97 LD C,(CHREC) Start with 'file count' cleared. The following loop tests to make sure that the name of the current record is not already stored in the buffer. 1C9A SE-NAME LD A,C Jump forward when all existing names 1C9B OR A have been examined. 1C9C JR Z,1CD4,INS-NAME 1C9E PUSH HL Save registers. 1C9F PUSH IX 1CA1 PUSH BC 1CA2 LD B,+0A Counts characters in a name. 1CA4 T-NA-1 LD A,(HL) Fetch a character from buffer. 1CA5 CF (RECNAM) Compare against RECNAM. 1CA8 JR NZ,1CAF,T-NA-2 Jump if they do not match. 1CAA INC HL Point to next character, 1CAB INC IX 1CAD DJNZ 1CA4,T-NA-1 Loop until all the names have been compared. 1CAF T-NA-2 POP BC Restore registers. 1CB1 POP IX 1CB2 POP HL 1CB3 JR Z,1CEE,F-N-SCT Continue with next sector if the name is already stored. 1CB5 JR NC,1CBB,ORD-NAM Jump if the name is surely not in the buffer (i.e. 'lower' than the current one). 1CB7 ADD HL,DE Otherwise point to next name. 1CB8 DEC C Decrease number of names to be examined. 1CB9 JR 1C9A,SE-NAME Loop back. The address at which the name is to be inserted has been calculated; the following names are moved down to create the space for storing the new name. 1CBB ORD-NAM PUSH HL Save registers. 1CBC PUSH DE 1CBD PUSH BC 1CBE PUSH HL 1CBF SLA C Multiply by two the number of names to be moved down. 1CC1 LD H,B Move result into HL (B holds 0). 1CC2 LD L,C 1CC3 ADD HL,BC Multiply this by 5, to get in HL the 1CC4 ADD HL,BC number of bytes to be moved down 1CC5 ADD HL,BC (i.e. number of names * 10). 1CC6 ADD HL,BC 1CC7 LD B,H Move into BC the length of the block 1CC8 LD C,L to be moved. 1CC9 POP HL Restore address where the current name is to be inserted. 1CCA DEC HL Make HL point to the last character 1CCB ADD HL,BC of the last name. 1CCC EX DE,HL Calculate into DE the address 'HL+10'. 1CCD ADD HL,DE 1CCE EX DE,HL 1CCF LDIR Move down the required names (leaving 10 bytes for the current name). 1CD1 POP BC Restore registers. 1CD2 POP DE 1CD3 POP HL 1CD4 INS-NAME PUSH IX Save channel start address. 1CD6 LD B,+0A Ten characters in a name. 1CD8 MOVE-NA LD A,(IX+RECNAM) Fetch a character from the name. 1CDB LD (HL),A Store in the buffer. 1CDC INC IX Point to next location. 1CDE INC HL 1CDF DJNZ 1CB8,MOVE-NA Loop until the whole name has been transferred. 1CE1 POP IX Restore channel start address. 1CE3 LD A,(CHREC) Fetch number of names in the buffer. 1CE6 INC A Include current name in the count. 1CE7 LD (CHREC),A Store new number. 1CEA CP +32 Jump if 50 names have been collected 1CEC JR Z,1CF4,BF-FILLED 1CEE F-N-SCT CALL 1312,BEC-SECT Decrease SECTOR. 1CF1 JP NZ,1C6E,CAT-LP Repeat for all 255 sectors. Now the file names are in the data buffer. CHREC holds the number of names stored. First the cartridge name is printed onto the selected stream. 1CF4 BF-FILLED PUSH IX Save channel base address. 1CF6 XOR A Switch off drive motor. 1CF7 CALL 17F7,SEL-DRIVE 1CFA PUSH IX Make HL point to HDNAME. 1CFC POP HL 1CFD LD DE,+002C 1D00 ADD HL,DE 1D01 CALL 1D50,PRNAME Print cartridge name. 1D04 LD A,+0D Print a carriage return. 1D06 CALL 1D66,PRCHAR 1D09 PUSH IX Make HL point to the data buffer. 1D0B POP HL 1D0C LD DE,+0052 1D0F ADD HL,DE 1D11 LD B,(CHREC) Fetch number of stored names. 1D13 LD A,B Jump forward if no names have been 1D14 OR A stored. 1D15 JR Z,1D1C,NONAMES 1D17 OT-NAMS CALL 1D53,PRNAME Print all filenames. 1D1A DJNZ 1D17,OT-NAMS 1D1C NONAMES CALL 1D38,FREESECT Calculate number of 'free' sectors 1D1F LD A,E into A. 1D20 SRL A Divide by two, giving the kilobytes left. 1D22 RST 10,CALBAS Call STACK-A to store this value on 1D23 DEFW +2D28 the calculator stack. 1D25 LD A,+0D Print a carriage return. 1D27 CALL 1D66,PRCHAR 1D2A RST 10,CALBAS Call PRINT-FP to print the number of 1D2B DEFW +2DE3 kilobytes left. 1D2D LD A,+0D Print the final carriage return. 1D2F CALL 1D66,PRCHAR 1D32 POP IX Restore channel start address. 1D34 CALL 10C4,DEL-M-BUF Reclaim the channel. 1D37 RET Finished. THE 'FREESECT' SUBROUTINE This subroutine is called to calculate the number of 'free sectors' (I...> bits reset in the map). The number is returned in the I register. 1D38 FREESECT LD L,(CHMAP-lo) Fetch address of map. 1D3B LD H,(CHMAP-hi) 1D3E LD E,+00 Start with E cleared. 1D40 LD C,+20 Length of map. 1D42 FR-SC-LP LD A,(HL) Fetch a byte from the map. 1D43 INC HL Advance the pointer. 1D44 LD B,+08 Loop for 8 bits. 1D46 FR-S-LPB RRA Jump if this bit is set, 1D47 JR C,14DA,FR-S-RES 1D49 INC E Otherwise increment counter. 1D4A FR-S-RES DJNZ 1D46,FR-S-LPB Repeat for all 8 bits. 1D4C DEC C Repeat for all bytes in the map. 1D4D JR NZ,1D42,FR-SC-LP 1D4F RET Finished. THE 'PRNAME' SUBROUTINE This is used from the CAT command routine to print a file-name starting from the address held into the HL register. 1D50 PRNAME PUSH BC Save BC register. 1D51 LD B,+0A Counts 10 characters. 1D53 PRNM-LP LD A,(HL) Fetch a character. 1D54 CALL 1D66,PRCHAR Print it. 1D57 INC HL Increment pointer. 1D58 DJNZ 1D53,PRNM-LP Loop until the whole name has been printed. 1D5A LD A,+0D Print a carriage return. 1D5C CALL 1D66,PRCHAR 1D5F PUSH HL Save the pointer. lD60 RST 10,CALBAS Call main ROM 'TEMPS' subroutine. 1D61 DEFW +0D4D 1D63 POP HL Restore registers. 1D64 POP BC 1D65 RET THE 'PRCHAR' SUBROUTINE The character whose code is held in the A register is sent over the currently selected stream. 1D66 PRCHAR PUSH IX Save channel base address. 1D68 RST 10,CALBAS Call restart 'PRINT-A' to print the 1D69 DEFW +0010 character. 1D6B POP IX Restore channel base address. 1D6D RET Finished. THE 'ERASE' COMMAND SUBROUTINE This is also called by using 'hook code' +24. The subroutine is entered with D-STR1 holding the drive number and N-STR1 holding the length and the start of the filename, Note that H'L' is corrupted. 1D6E ERASE CALL 0FE8,SET-T-MCH Set a temporary "m" channel. 1D71 LD A,(CHDRIV) Fetch drive number. 1D74 CALL 17F7,SEL-DRIVE Turn on drive motor. 1D77 IN A,(+EF) Continue only if the write-nrotect 1D79 AND +01 tab is present. 1D7B JR NZ,107F,ERASE-1 'Drive write protected' 1D7D RST 20,SH-ERR Call the error handling routine. 1D7E DEFB +0E 1D7F ERASE-1 PUSH IX Point to the data buffer. 1D81 POP HL 1D82 LD DE,+0052 1D85 ADD HL,DE 1D86 PUSH HL Copy this address into DE. 1D87 POP DE Now the first 32 locations in the data buffer are cleared. These locations act as a 'pseudo-map', used to mark the sectors to be erased, 1D88 INC DE Point to next location. 1D89 LD BC,+001F Gap length - 1. 1D8C XOR A Clear the first location. 1D8D LD (HL),A 1D8E LDIR Clear all locations. lD90 LD A,+FF CHREC is made holding 255. 1D92 CD (CHREC),A 1D95 LD BC,+04FB SECTOR is initialised to 'five passes 1D98 LD (SECTOR),BC of the tape'. The cartridge is searched for the sectors to be erased, and when any such sector is found, the relevant 'pseudo-map' bit is set. A 'normal' map is also set-up. 1D9C ERASE-LP CALL 1312,DEC-SECT Decrease SECTOR. 1D9F JR Z,1DF8,ERASE-MK Make the ERASE when it reaches 0. 1DA1 CALL 12C4,GET-M-HD2 Fetch a header. 1DA4 CALL 1E53,G-RDES Fetch record descriptor. 1DA7 JR NZ,1DDA,TST-NUM Jump with any error. 1DA9 LD A,(RECFLG) Jump it this record is not 'tree'. 1DAC OR (RECLEN-hi) lDAF AND +02 1DB1 JR NZ,1DB8,ERASE-2 1DB3 CALL 12FE,RES-B-MAP Otherwise reset map bit to indicate 'free sector'. 1DB6 JR 1DDA,TST-NUM Jump forward. The name of the current record is compared against that of the file to be erased. If the comparison is successful, the 'pseudo-map' bit is set to mark the sector. 1DB8 ERASE-2 PUSH IX MAke HL point to RECNAM. 1DBA POP HL 1DBB LD DE,+0047 1DBE ADD HL,DE 1DBF LD BC,+000A Counts ten characters in a name. 1DC2 CALL 131E,CHK-NAME Compare against CHNAME. 1DC5 JR NZ,1DDA,TST-NUM Jump if it does not equal. 1DC7 CALL 1306,TEST-PMAP Get position of pseudo-map bit. 1DCA LD A,B Fetch bit position. 1DCB OR (HL) Set the pseudo-map bit. 1DCC LD (HL),A 1DCD BIT 1,(RECFLG) Jump if this is not the EOF block. 1DD1 JR Z,1DDA,TST-NUN 1DD3 LD A,(RECNUM) Otherwise increment record number 1DD6 INC A and store it into CHMREC, giving the 1DD7 LD (CHREC),A number of sectors that composes the file. 1DDA TST-NUM PUSH IX Make HL point to the 'pseudo-map'. 1DDC POP HL 1DDD LD DE,+0052 1DE0 ADD HL,DE 1DE1 LD E,+00 Clear E register. 1DE3 LD C,+20 Length of the pseudo-map. IDE5 LP-P-MAP LD A,(HL) Fetch pseudo-map byte. 1DE6 INC HL Advance the pointer. 1DE7 LD B,+08 Counts 8 bits. 1DE9 LP-B-MAP RRA Jump if this bit is reset. 1DEA JR NC,1DED,NOINC-C 1DEC INC E Otherwise increment counter. 1DED NOINC-C DJNZ 1DE9,LP-B-MAP Loop for all 8 bits. 1DEF DEC C Decrement map length. 1DF0 JR NZ,1DE5,LP-P-MAP Loop until the whole map has been examined. 1DF2 LD A,(CHREC) Fetch number of records that composes the file. 1DF5 CP E Compare with number of records found. 1DF6 JR NZ,1D9C,ERASE-LP Continue until all records have been found (or five passes of the tape have been made). A 'free' sector descriptor is written in all records of the file to be erased. 1DF8 ERASE-MK CALL 1E3E,IN-CHK Set 'free record' attributes. 1DFB ERASE-MK2 CALL 12C4,GET-M-HD2 Fetch a header. 1DFE CALL 1306,TEST-PMAP Jump if this is not the header of a 1E01 JR Z,1E26,T-OTHER record to be erased. 1E03 PUSH HL Save map bit address and position. 1E04 PUSH BC 1E05 LD A,+E6 Start writing. 1E07 OUT (+EF),A 1E09 LD BC,0168 Wait to insert part of the first gap. 1E0C CALL 18FA,DELAY-BC 1E0F PUSH IX Make HL point to the data block 1E11 POP HL preamble. 1E12 LD DE,+0037 1E15 ADD HL,DE 1E16 CALL 1878,OUT-M-BUF Write the 'free record' descriptor. 1E19 LD A,+EE Stop writing. 1E1B OUT (+EF),A 1E1D CALL 12FE,RES-B-MAP Reset map bit. 1E20 POP BC Restore pseudo-map bit position and 1E21 POP HL address. 1E22 LD A,B Reset the appropriate bit. 1E23 CPL 1E24 AND (HL) 1E25 LD (HL),A If the pseudo-map contains at least one bit set, there are other records to be erased. 1E26 T-OTHER PUSH IX Make HL point to the pseudo-map. 1E28 POP HL 1E29 LD DE,+0052 1E2C ADD HL,DE 1E2D LD B,+20 Length of pseudo-map. 1E2F CHK-W-MAP LD A,(HL) Fetch a byte. 1E30 OR A Jump back if the byte is not zero 1E31 JR NZ,1DFB,ERASE-MK2 (i.e. there are other records to be erased). 1E33 INC HL Next location. 1E34 DJNZ 1E2F,CHK-W-MAP Loop for the whole map. 1E36 XOR A Switch off drive motor. 1E37 CALL 17F7,SEL-DRIVE 1E3A CALL 10C4,DEL-M-BUF Reclaim channel and map. 1E3D RET Finished. THE 'SIGNAL "FREE SECTOR"' SUBROUTINE This subroutine is called from the FORMAT and ERASE command routines to mark the current record descriptor as 'free sector' identifier. 1E3E IN-CHK XOR A Clear RECFLG and RECLEN. 1E3F LD (RECFLG),A 1E42 LD (RECLEN-lo),A 1E45 LD (RECLEN-hi),A 1E48 PUSH IX Make HL point to RECFLG. 1E4A POP HL 1E4B LD DE,+0043 1E4E ADD HL,DE 1E4F CALL 1341,CMKS-HD-R Restore DESCHK checksum. 1E52 RET Finished. THE 'OBTAIN A RECORD DESCRIPTOR' SUBROUTINE This subroutine is used from the FORMAT and ERASE coamnand routines to fetch from the current Microdrive unit the record descriptor held in the current sector (i.e. RECFLG...DESCHK). The zero flag is returned reset with any error. 1E53 G-RDES PUSH IX Make HL point to RECFLG. 1E55 POP HL 1E56 LD DE,+0043 1E59 ADD HL,DE 1E5A CALL 18A3,GET-M-HD Fetch record descriptor. 1E5D CALL 1341,CHKS-MD-R Calculate new checksum. 1E60 RET NZ Return if it is wrong. 1E61 BIT 0,(RECFLG) Return with zero flag reset if this 1E65 RET is a header. THE 'CALLS TO THE COMMAND ROUTINES' The six following calls are entered from the appropriate command syntax routine; on return from the command routine, the control returns to END1. 1E66 ERASE-RUN CALL 1D6E,ERASE 1E69 JR 1E84,ENDC 1E6B MOVE-RUN CALL 13F1,MOVE 1E6E JR 1E84,ENDC 1E70 CAT-RUN CALL 1C58,CAT 1E73 JR 1E84,ENDC 1E75 FOR-RUN CALL 1B6E,FORMAT 1E78 JR 1E84,ENDC 1E7A OP-RUN CALL 1AF0,OP-M-STRM 1E7D JR 1E84,ENDC 1E7F SAVE-RUN CALL 14DA,SA-DRIVE 1E82 JR 1E84,ENDC 1E84 ENDC JP 05Cl,END1 The 'not used' routines The following are four subroutines that are never called from the shadow ROM code; these routines are however described below as they may be useful to the programmer. THE 'DISP-HEX' SUBROUTINE The contents of the A register are displayed on the screen in hexadecimal. All registers are preserved, excluding A. 1E87 DISP-HEX PUSH AF Save A register. 1E88 RRA Shift left nibble to right. 1E89 RRA 1E8A RRA 1E8B RRA 1E8C CALL 1E90,DISP-NIB Print the first digit. 1E8F POP AF Restore value. 1E90 DISP-NIB AND +0F Clear left nibble. 1E92 CP +0A Jump if the value is lower than 9. 1E94 JR C,1E98,CONV-1 1E96 ADD A,+07 Otherwise add +07 to reach the code of A..F. 1E98 CONV-1 ADD A,+30 Add offset for ASCII code. 1E9A CALL 1EA9,DISP-CH Print the digit. 1E9D RET Finished. THE 'DISP-HEX2' SUBROUTINE This performs the same task as the preceding one, but the hex number is followed by a space. All registers are preserved. 1E9E DISP-HEX2 PUSH AF Save A register. 1E9F CALL 1E87,DISP-HEX Print the hex number. 1EA2 LD A,+20 Follow with a space. 1EA4 CALL 1EA9,DISP-CH 1EA7 POP AF Restore A. 1EA8 RET Finished. THE 'DISP-CH' SUBROUTINE This subroutine prints on the screen the character held in the accumulator. All registers are preserved. 1EA9 DISP-CH PUSH HL Save registers. 1EAA PUSH DE 1EAB PUSH BC 1EAC PUSH AF 1EAD EXX Save alternate registers. 1EAE PUSH HL 1EAF PUSH DE 1EB0 PUSH BC 1EB1 PUSH AF 1EB2 LD HL,(CURCHL) Save also current channel address. 1EB5 PUSH HL 1EB6 PUSH AF Save character to be printed. 1EB7 LD A,+02 Select stream 2 (screen). 1EB9 RST 10,CALBAS Call CHAN-OPEN to select the stream. 1EBA DEFW +1601 1EBC POP AF Restore character. 1EBD RST 10,CALBAS Call PRINT-A restart to print the 1EBE DEFW +0010 character. 1EC0 POP HL Restore old channel address. 1EC1 LD (CURCHL),A 1EC4 POP AF Restore alternate registers. 1EC5 POP BC 1EC6 POP DE 1EC7 POP HL 1EC8 EXX Restore normal registers. 1EC9 POP AF 1ECA POP BC 1ECB POP DE 1ECC POP HL 1ECD RET THE 'HEX-LINE' SUBROUTINE This subroutine displays the values of the ten bytes from the location passed in the HL register. Again all registers are preserved. 1ECE HEX-LINE PUSH HL Save registers. 1ECF PUSH BC 1ED0 PUSH AF 1ED1 LD B,+0A Counts 10 bytes. 1ED3 HEX-LINE2 LD A,(HL) Fetch a byte. 1ED4 CALL 1E9E,DISP-HEX2 Display it in hex and follow with a space. 1ED7 INC HL Point to next byte. 1ED8 DJNZ 1ED3,HEX-LINE2 Loop for all l0 bytes. 1EDA LD A,+0D Finally print a carriage return. 1EDC CALL 1EA9,DISP-CH 1EDF POP AF Restore registers. 1EE0 POP BC 1EEl POP HL 1EE2 RET Finished. 1EE3...1FFF Unused locations (all set to +FF). APPENDIX 1 Labels sorted by address value (For edition 1 Shadow ROM) 0000 MAIN-ROM 0008 ST-SHADOW 0010 CALBAS 0018 CHKSYNTAX 0020 SH-ERR 0028 ROMERR 0030 NEWVARS 0038 INT-SERV 003A TEST-SP 0040 RMERR-2 0066 NMINT-SRV 0068 ST-ERROR 0077 CHECK-SP 0081 CALBAS-2 009A START-2 00A5 START-3 00BC START-4 00E7 NREPORT-0 00E9 TEST-CODE 00FB COPYCHADD 011B RUNTIME 0130 PROG-LINE 0133 SC-L-LOOP 0139 NREPORT-1 013B TEST-LOW 0144 LINE-LEN 014E SKIP-NUN 0152 EACH-ST 015D CHKEND 0165 CHKEVEN 0169 CHKEND-L 016F S-STAT 0182 RCLM-NUM 01A3 NXT-1 01A5 NEXTNUM 01AA CL-WORK 01EC ERR-V 01F0 ERR-6 01F7 CRT-VARS 0224 DEFAULT 0235 VAR-EXIST 024D RES-VARS 0252 EACH-VAR 0258 REP-MSG 026E FETCH-ERR 029F PR-REP-LP 02AC END-PR-MS 0486 CAT-SYN 0494 MISSING-D 04A6 CAT-SCRN 04B2 OREPORT-1 04B4 FRTM-SYN 04BF NO-FOR-M 04CD FOR-B-T 04D3 NOT-FOR-B 04E7 FOR-M 04ED OPEN-SYN 0500 NOT-OP-M 051C OPEN-RS 051F NOT-OP-B 0529 OP-M-C 052F NREPORT-C 0531 ERASE-SYN 053D MOVE-SYN 0559 CLS#-SYN 057F CLR#-SYN 0584 NONSENSE 058E ALL-STRMS 059F EX-D-STR 05A7 ALL-BYTES 05B1 SEPARATOR 05B7 ST-END 05BF TEST-RET 05C1 END1 05DD RETAD-RUN 05E0 RETAD-SYN 05E2 BREAK-PGM 05E7 EXPT-STR 05F2 EXPT-SPEC 05F5 EXP-SPEC2 060C TEST-NEXT 061E EXPT-NUM 062D NREPORT-3 062F EXPT-NAME 064C NREPORT-4 064E EXPT-STRM 0663 NREPORT-2 0665 CHECK-H 066D CHECK-M-2 0681 NREPORT-5 0683 NREPORT-9 0685 TEST-MNAM 068F TEST-STAT 06A1 NREPORT-8 06A3 EXPT-EXPR 06B0 TEST-BAUD 06B9 EXPT-EXP1 06CC ENDHERE 0700 UNPAGE 0701 EXPT-PRMS 0716 NO-NAME 0722 NOT-NET 073C OREP-1-2 073E LINE 0750 END-EXPT 0753 PROC 0771 SCREEN$ 0789 CODE 079A DEFLT-0 079F PAR-1 07A7 TEST-SAVE 07B2 PAR-2 07B8 END-CODE 07D2 DATA 07DA NO-M-ARR 07F2 EXISTING 07F4 NONS-BSC 07F6 G-TYPE 0803 VR-DATA 080E LD-DATA 0819 NUM-ARR 081C END-DATA 082F SAVE-SYN 0849 SAVE-M 084F SA-HEADER 0854 HD-LOOP 086E SA-BLOCK 0872 SA-BLK-LP 087D S-BLK-END 0880 SA-BYTE 088E SA-NET 0891 SA-B-END 0894 LOAD-SYN 089E VERIF-SYN 08A8 MRG-SYN 08AF LD-VF-MR 08CD TS-L-NET 08D3 TS-L-RS 08D8 LD-HEADER 08E0 LD-HD-NET 08E7 LD-HD-RS 08EC LD-HDR-2 08F2 TEST-TYPE 0902 NREPORT-H 0904 TST-MERGE 0911 T-M-CODE 0919 LD-BLOCK 0930 NREPORT-L 0932 LD-BLK-2 0941 LD-BLK-3 0952 LD-BLK-4 0959 LD-BLK-5 0962 LD-NO-PGM 0967 MERGE-BLK 0973 NO-AUTOST 0988 TST-MR-M 0994 TST-MR-N 09A0 MERGE-END 09A3 LD-PR-AR 09B5 LD-PROG 09BE TST-SPACE 09C7 TST-TYPE 09DE T-LD-NET 09E8 RCLM-OLD 09F3 CRT-NEW 0A0F END-LD-PR 0A15 SET-PROG 0A4E NO-AUTO 0A5C LV-ANY 0A6A LV-BN 0A72 LV-N 0A79 LV-B 0A7E LV-BN-E 0A8A VR-BN 0A8F LVBN-END 0A95 LOAD-RUN 0AC9 SET-BAUD 0AD0 NXT-ENTRY 0AE4 END-SET 0813 OP-RS-CH 0B47 OP-RSCHAN 0B4A OP-STREAM 0B6F T-INPUT 0B75 B-INPUT 0B7B TCHAN-IN 0B81 BCHAN-IN 0B8E REC-BYTE 0B9A REC-PROC 0BB1 READ-RS 0BC5 TST-AGAIN 0BD1 START-BIT 0BD8 SERIAL-IN 0BDA BD-DELAY 0BF0 WAIT-1 0BF1 WAIT-2 0BF9 T-FURTHER 0C1D SER-IN-2 0C1F BD-DELAY2 0C36 END-RS-IN 0C3C TCHAN-OUT 0C46 NOT-TOKEN 0C4C NOT-GRAPH 0C57 NOT-CR 0C5A BCHAN-OUT 0C6F BD-DEL-1 0C74 TEST-DTR 0C88 SER-OUT-L 0C8E BD-DEL-2 0CA4 BD-DEL-3 0CA9 BORD-REST 0CB4 BRK-INOUT 0CBD CALL-INP 0CDB IN-AGAIN 0CE1 INPUT-END 0CE5 OREPORT-8 0CEA NO-READ 0CED ACC-CODE 0CF7 END-INPUT 0CFB INKEY$ 0D01 INK$-END 0D0C N-INPUT 0D12 NCHAN-IN 0D1E TEST-BUFF 0D38 TST-N-EOF 0D3F GET-N-BUF 0D45 TRY-AGAIN 0D5F TIME-OUT 0D6C NCHAN-OUT 0D7A TEST-OUT 0D88 ST-BF-LEN 0D93 OUT-BLK-N 0DAB S-PACK-1 0DB2 SEND-PACK 0DC5 CHKS1 0DD4 CHKS2 0DDA SENDSCOUT 0DF6 SP-DL-1 0DFD INC-BLKN 0E05 SP-N-END 0E0F BR-DELAY 0E12 DL-LOOP 0E18 GET-NBLK 0E27 CHKS3 0E40 BRCAST 0E45 TEST-BLKN 0E62 GETNB-END 0E65 GET-NBUFF 0E87 CHKS4 0E93 STORE-LEN 0EA1 GETNBF-END 0EA3 OPEN-N-ST 0EA9 OP-TEMP-N 0EB5 OP-PERN-N 0EF5 SEND-NEOF 0F03 NET-STATE 0F0E CHK-REST 0F15 MAKESURE 0F1E WT-SCOUT 0F21 CLAIMED 0F35 WT-SYNC 0F4D E-READ-N 0F56 SCOUT-END 0F58 LP-SCOUT 0F5D DELAY-SC 0F61 SEND-SC 0F72 ALL-BITS 0F7D S-SC-DEL 0F8F END-S-DEL 0F92 INPAK 0F94 N-ACTIVE 0F9D INPAK-2 0F9E INPAK-L 0FAE UNTIL-MK 0FBE SEND-RESP 0FC5 OUTPAK 0FCA DEL-D-1 0FCC OUTPAK-L 0FD2 UNT-MARK 0FE8 SET-T-MCH 0FF6 CHK-LOOP 102A NEXT-CHAN 1034 CHAN-SPC 1061 T-CH-NAME 106F TEST-MAP 108A ST-MAP-AD 1094 FILL-MAP 10C4 DEL-M-BUF 10F5 TEST-MCHL 110A NXTCHAN 1114 RCLM-MAP 1122 M-INPUT 112C MCHAN-IN 1132 RWF-ERR 1134 TEST-M-BF 1158 CHK-M-EOF 1162 NEW-BUFF 1177 GET-RECD 117D GET-R-2 1184 GET-R-LP 119E NXT-SCT 11A3 RS-SH2 11A5 G-HD-RC 11D6 G-REC-ERR 11D8 MCHAN-OUT 11E6 NOREAD 11FF WR-RECD 120D WRITE-PRC 121B NOFULL 121F CP-NAME 1264 CHK-FULL 126C NXT-B-MAP 1275 SEND-BLK 127D FAILED 128F NO-PRT 12A6 CLOSE-M 12A9 CLOSE-M2 12B6 NOEMP 12BE ERR-RS 12C4 GET-M-HD2 12DA CHK-MAP-2 12DF CHECK-MAP 12E2 ENTRY 12E8 ENTRY-2 12F8 ROTATE 12FE RES-B-MAP 1306 TEST-PMAP 1312 DEC-SECT 131E CHK-NAME 1322 ALL-CHARS 1333 ALLCHR-2 133E CHKNAM-END 1341 CHKS-HD-R 1346 CHKS-BUFF 1349 CHKS-ALL 134C NXT-BYTE 1354 STCHK 135F REST-STRM 1365 NXT-STRM 1377 NOTRIGHT 137E STO-DISP 1384 UPD-POINT 1391 REST-MAP 139D LCHAN 13C1 LPEND 13F1 MOVE 1414 M-AGAIN 141A I-AGAIN 1423 MOVE-OUT 142E MOVE-EOF 1455 OP-STRM 1466 OP-CHAN 147F CHECK-N 148B CHECK-R 1495 USE-R 14A4 CL-CHAN 14B8 CL-CHK-N 14C7 EX-DSTR2 14CF ALL-BYT-2 14DA SA-DRIVE 14E8 START-SA 14FC NEW-NAME 1530 SA-DRI-2 1538 SA-DRI-3 1552 SA-DRI-WR 155E SA-DRI-4 1579 END-SA-DR 1580 F-M-HEAD 1591 F-HD-2 1599 F-HD-3 15A9 LV-MCH 15DF USE-REC 15F9 LOOK-MAP 1613 SA-MAP 1620 SA-MAP-LP 162D RE-MAP 163D RE-MAP-LP 1648 LD-VE-M 1658 VE-M-E 1664 VE-FAIL 1666 F-REC1 166C F-REC2 1673 UNTILFIVE 168A F-ERROR 1691 REST-N-AD 16AC TST-PLACE 1708 CLOSE-CH 1718 CLOSE 1751 CL-RS-CH 175E CL-N-CH 176D CL-M-CN 177F RCLM-CH 1789 UPD-STRM 17A4 UPD-NXT-S 17B9 RCL-T-CH 17C2 EX-CHANS 17D2 CHK-TEMPM 17DE CHK-TEMPN 17ED PT-N-CHAN 17F7 SEL-DRIVE 1802 TURN-ON 1809 TON-DELAY 1811 REPTEST 1813 CHK-PRES 1820 NOPRES 182A SW-MOTOR 1835 ALL-MOTRS 184B OFF-MOTOR 185C NXT-MOTOR 1867 DEL-S-1 1872 OUT-M-HD 1878 OUT-M-BUF 187C OUT-M-BLK 1884 NOT-PROT 1895 OUT-M-BYT 18A3 GET-M-HD 18A9 GET-M-BUF 18AD GET-M-BLK 18B1 CHK-AGAIN 18B3 CHKLOOP 18BE CHK-AG-2 18C0 CHK-LP-2 18D2 DR-READY 18DE IN-M-BLK 18E9 TEST-ERR 1BFA DELAY-BC 18FB DELAY-BC1 1902 UNKN-1 191C UNKN-2 1929 UNKN-3 1952 UNKN-4 1959 UNKN-5 1961 UNKN-6 1968 UNKN-7 196C UNKN-8 1976 UNKN-9 1981 HOOK-CODE 1987 CLR-ERR 19A4 HOOK-32 19A8 HOOK-31 19D9 CONS-IN 19DE WTKEY 19EC CONS-OUT 19EF OUT-CODE 19FC PRT-OUT 1A01 KBD-TEST 1A09 READ-SEQ 1A14 INCREC 1A17 RD-RANDOM 1A24 CLOSE-NET 1A31 GET-PACK 1A46 GP-ERROR 1A4B RD-SECTOR 1A51 NO-GOOD 1A63 USE-C-RC 1A81 DEL-B-CT 1A86 RD-NEXT 1A91 WR-SECTOR 1AAD WR-S-1 1ABF WR-S-2 1AC5 RS-SH 1AC7 WR-S-3 1AE0 CLR-BUFF 1AF0 OP-M-STRM 1B0D MAKE-PERM 1B23 STORE-DSP 1B29 OP-TEMP-M 1B3A OP-F-1 1B57 OP-F-2 1B5C OP-F-3 1B5F OP-F-4 1B6C OP-F-5 1B6E FORMAT 1B86 FORMAT-1 1BBD FILL-B-F 1BC1 FILL-B-F2 1BD6 WR-F-TEST 1C0A TEST-SCT 1C1B CHK-SCT 1C3E CHK-NSECT 1C46 MARK-FREE 1C53 MK-BLK 1C58 CAT 1C6E CAT-LP 1C85 IN-NAME 1C9A SE-NAME 1CA4 T-NA-1 1CAF T-NA-2 1CBB ORD-NAM 1CD4 INS-NAME 1CD8 MOVE-NA 1CEE F-N-SCT 1CF4 BF-FILLED 1D17 OT-NAMS 1D1C NONAMES 1D38 FREESECT 1D42 FR-SC-LP 1D46 FR-S-LPB 1D4A FR-S-RES 1D50 PRNAME 1D53 PRNM-LP 1D66 PRCHAR 1D6E ERASE 1D7F ERASE-1 1D9C ERASE-LP 1DB8 ERASE-2 1DDA TST-NUM 1DE5 LP-P-MAP 1DE9 LP-B-MAP 1DED NOINC-C 1DF8 ERASE-MK 1DFB ERASE-MK2 1E26 T-OTHER 1E2F CHK-W-MAP 1E3E IN-CHK 1E53 G-RDES 1E66 ERASE-RUN 1E6B MOVE-RUN 1E70 CAT-RUN 1E75 FOR-RUN 1E7A OP-RUN 1E7F SAVE-RUN 1E84 ENDC 1E87 DISP-HEX 1E90 DISP-NIB 1E98 CONV-1 1E9E DISP-HEX2 1EA9 DISP-CH 1ECE HEX-LINE 1ED3 HEX-LINE2 APPENDIX 2 Labels sorted alphabetically (For edition 1 Shadow ROM) ACC-CODE 0CED ALL-BITS 0F72 ALL-BYT-2 14CF ALL-BYTES 05A7 ALL-CHARS 1322 ALL-MOTRS 1835 ALL-STRMS 058E ALLCHR-2 1333 B-INPUT 0B75 BCHAN-IN 0B81 BCHAN-OUT 0C5A BD-DEL-1 0C6F BD-DEL-2 0C8E BD-DEL-3 0CA4 BD-DELAY 0BDA BD-DELAY2 0C1F BF-FILLED 1CF4 BORD-REST 0CA9 BR-DELAY 0E0F BRCAST 0E40 BREAK-PGM 05E2 BRK-INOUT 0CB4 CALBAS 0010 CALBAS-2 0081 CALL-INP 0CBD CAT 1C58 CAT-LP 1C6E CAT-RUN 1E70 CAT-SCRN 04A6 CAT-SYN 0486 CHAN-SPC 1034 CHECK-H 0665 CHECK-M-2 066D CHECK-MAP 12DF CHECK-N 147F CHECK-R 148B CHECK-SP 0077 CHK-AG-2 18BE CHK-AGAIN 18B1 CHK-FULL 1264 CHK-LOOP 0FF6 CHK-LP-2 18C0 CHK-M-EOF 1158 CHK-MAP-2 12DA CHK-NAME 131E CHK-NSECT 1C3E CHK-PRES 1813 CHK-REST 0F0E CHK-SCT 1C1B CHK-TEMPM 17D2 CHK-TEMPN 17DE CHK-W-MAP 1E2F CHKEND 015D CHKEND-L 0169 CHKEVEN 0165 CHKLOOP 18B3 CHKNAM-END 133E CHKS-ALL 1349 CHKS-BUFF 1346 CHKS-HD-R 1341 CHKS1 0DC5 CHKS2 0DD4 CHKS3 0E27 CHKS4 0E87 CHKSYNTAX 0018 CL-CHAN 14A4 CL-CHK-N 14B8 CL-M-CN 176D CL-N-CH 175E CL-RS-CH 1751 CL-WORK 01AA CLAIMED 0F21 CLOSE 1718 CLOSE-CH 1708 CLOSE-M 12A6 CLOSE-M2 12A9 CLOSE-NET 1A24 CLR#-SYN 057F CLR-BUFF 1AE0 CLR-ERR 1987 CLS#-SYN 0559 CODE 0789 CONS-IN 19D9 CONS-OUT 19EC CONV-1 1E98 COPYCHADD 00FB CP-NAME 121F CRT-NEW 09F3 CRT-VARS 01F7 DATA 07D2 DEC-SECT 1312 DEFAULT 0224 DEFLT-0 079A DEL-B-CT 1A81 DEL-D-1 0FCA DEL-M-BUF 10C4 DEL-S-1 1867 DELAY-BC 1BFA DELAY-BC1 18FB DELAY-SC 0F5D DISP-CH 1EA9 DISP-HEX 1E87 DISP-HEX2 1E9E DISP-NIB 1E90 DL-LOOP 0E12 DR-READY 18D2 E-READ-N 0F4D EACH-ST 0152 EACH-VAR 0252 END-CODE 07B8 END-DATA 081C END-EXPT 0750 END-INPUT 0CF7 END-LD-PR 0A0F END-PR-MS 02AC END-RS-IN 0C36 END-S-DEL 0F8F END-SA-DR 1579 END-SET 0AE4 END1 05C1 ENDC 1E84 ENDHERE 06CC ENTRY 12E2 ENTRY-2 12E8 ERASE 1D6E ERASE-1 1D7F ERASE-2 1DB8 ERASE-LP 1D9C ERASE-MK 1DF8 ERASE-MK2 1DFB ERASE-RUN 1E66 ERASE-SYN 0531 ERR-6 01F0 ERR-RS 12BE ERR-V 01EC EX-CHANS 17C2 EX-D-STR 059F EX-DSTR2 14C7 EXISTING 07F2 EXP-SPEC2 05F5 EXPT-EXP1 06B9 EXPT-EXPR 06A3 EXPT-NAME 062F EXPT-NUM 061E EXPT-PRMS 0701 EXPT-SPEC 05F2 EXPT-STR 05E7 EXPT-STRM 064E F-ERROR 168A F-HD-2 1591 F-HD-3 1599 F-M-HEAD 1580 F-N-SCT 1CEE F-REC1 1666 F-REC2 166C FAILED 127D FETCH-ERR 026E FILL-B-F 1BBD FILL-B-F2 1BC1 FILL-MAP 1094 FOR-B-T 04CD FOR-M 04E7 FOR-RUN 1E75 FORMAT 1B6E FORMAT-1 1B86 FR-S-LPB 1D46 FR-S-RES 1D4A FR-SC-LP 1D42 FREESECT 1D38 FRTM-SYN 04B4 G-HD-RC 11A5 G-RDES 1E53 G-REC-ERR 11D6 G-TYPE 07F6 GET-M-BLK 18AD GET-M-BUF 18A9 GET-M-HD 18A3 GET-M-HD2 12C4 GET-N-BUF 0D3F GET-NBLK 0E18 GET-NBUFF 0E65 GET-PACK 1A31 GET-R-2 117D GET-R-LP 1184 GET-RECD 1177 GETNB-END 0E62 GETNBF-END 0EA1 GP-ERROR 1A46 HD-LOOP 0854 HEX-LINE 1ECE HEX-LINE2 1ED3 HOOK-31 19A8 HOOK-32 19A4 HOOK-CODE 1981 I-AGAIN 141A IN-AGAIN 0CDB IN-CHK 1E3E IN-M-BLK 18DE IN-NAME 1C85 INC-BLKN 0DFD INCREC 1A14 INK$-END 0D01 INKEY$ 0CFB INPAK 0F92 INPAK-2 0F9D INPAK-L 0F9E INPUT-END 0CE1 INS-NAME 1CD4 INT-SERV 0038 KBD-TEST 1A01 LCHAN 139D LD-BLK-2 0932 LD-BLK-3 0941 LD-BLK-4 0952 LD-BLK-5 0959 LD-BLOCK 0919 LD-DATA 080E LD-HD-NET 08E0 LD-HD-RS 08E7 LD-HDR-2 08EC LD-HEADER 08D8 LD-NO-PGM 0962 LD-PR-AR 09A3 LD-PROG 09B5 LD-VE-M 1648 LD-VF-MR 08AF LINE 073E LINE-LEN 0144 LOAD-RUN 0A95 LOAD-SYN 0894 LOOK-MAP 15F9 LP-B-MAP 1DE9 LP-P-MAP 1DE5 LP-SCOUT 0F58 LPEND 13C1 LV-ANY 0A5C LV-B 0A79 LV-BN 0A6A LV-BN-E 0A7E LV-MCH 15A9 LV-N 0A72 LVBN-END 0A8F M-AGAIN 1414 M-INPUT 1122 MAIN-ROM 0000 MAKE-PERM 1B0D MAKESURE 0F15 MARK-FREE 1C46 MCHAN-IN 112C MCHAN-OUT 11D8 MERGE-BLK 0967 MERGE-END 09A0 MISSING-D 0494 MK-BLK 1C53 MOVE 13F1 MOVE-EOF 142E MOVE-NA 1CD8 MOVE-OUT 1423 MOVE-RUN 1E6B MOVE-SYN 053D MRG-SYN 08A8 N-ACTIVE 0F94 N-INPUT 0D0C NCHAN-IN 0D12 NCHAN-OUT 0D6C NET-STATE 0F03 NEW-BUFF 1162 NEW-NAME 14FC NEWVARS 0030 NEXT-CHAN 102A NEXTNUM 01A5 NMINT-SRV 0066 NO-AUTO 0A4E NO-AUTOST 0973 NO-FOR-M 04BF NO-GOOD 1A51 NO-M-ARR 07DA NO-NAME 0716 NO-PRT 128F NO-READ 0CEA NOEMP 12B6 NOFULL 121B NOINC-C 1DED NONAMES 1D1C NONS-BSC 07F4 NONSENSE 0584 NOPRES 1820 NOREAD 11E6 NOT-CR 0C57 NOT-FOR-B 04D3 NOT-GRAPH 0C4C NOT-NET 0722 NOT-OP-B 051F NOT-OP-M 0500 NOT-PROT 1884 NOT-TOKEN 0C46 NOTRIGHT 1377 NREPORT-0 00E7 NREPORT-1 0139 NREPORT-2 0663 NREPORT-3 062D NREPORT-4 064C NREPORT-5 0681 NREPORT-8 06A1 NREPORT-9 0683 NREPORT-C 052F NREPORT-H 0902 NREPORT-L 0930 NUM-ARR 0819 NXT-1 01A3 NXT-B-MAP 126C NXT-BYTE 134C NXT-ENTRY 0AD0 NXT-MOTOR 185C NXT-SCT 119E NXT-STRM 1365 NXTCHAN 110A OFF-MOTOR 184B OP-CHAM 1466 OP-F-1 1B3A OP-F-2 1B57 OP-F-3 1B5C OP-F-4 1B5F OP-F-5 1B6C OP-M-C 0529 OP-M-STRM 1AF0 OP-PERN-N 0EB5 OP-RS-CH 0813 OP-RSCHAN 0B47 OP-RUN 1E7A OP-STREAM 0B4A OP-STRM 1455 OP-TEMP-M 1B29 OP-TEMP-N 0EA9 OPEN-N-ST 0EA3 OPEN-RS 051C OPEN-SYN 04ED ORD-NAM 1CBB OREP-1-2 073C OREPORT-1 04B2 OREPORT-8 0CE5 OT-NAMS 1D17 OUT-BLK-N 0D93 OUT-CODE 19EF OUT-M-BLK 187C OUT-M-BUF 1878 OUT-M-BYT 1895 OUT-M-HD 1872 OUTPAK 0FC5 OUTPAK-L 0FCC PAR-1 079F PAR-2 07B2 PR-REP-LP 029F PRCHAR 1D66 PRNAME 1D50 PRNM-LP 1D53 PROC 0753 PROG-LINE 0130 PRT-OUT 19FC PT-N-CHAN 17ED RCL-T-CH 17B9 RCLM-CH 177F RCLM-MAP 1114 RCLM-NUM 0182 RCLM-OLD 09E8 RD-NEXT 1A86 RD-RANDOM 1A17 RD-SECTOR 1A4B RE-MAP 162D RE-MAP-LP 163D READ-RS 0BB1 READ-SEQ 1A09 REC-BYTE 0B8E REC-PROC 0B9A REP-MSG 0258 REPTEST 1811 RES-B-MAP 12FE RES-VARS 024D REST-MAP 1391 REST-N-AD 1691 REST-STRM 135F RETAD-RUN 05DD RETAD-SYN 05E0 RMERR-2 0040 ROMERR 0028 ROTATE 12F8 RS-SH 1AC5 RS-SH2 11A3 RUNTIME 011B RWF-ERR 1132 S-BLK-END 087D S-PACK-1 0DAB S-SC-DEL 0F7D S-STAT 016F SA-B-END 0891 SA-BLK-LP 0872 SA-BLOCK 086E SA-BYTE 0880 SA-DRI-2 1530 SA-DRI-3 1538 SA-DRI-4 155E SA-DRI-WR 1552 SA-DRIVE 14DA SA-HEADER 084F SA-MAP 1613 SA-MAP-LP 1620 SA-NET 088E SAVE-M 0849 SAVE-RUN 1E7F SAVE-SYN 082F SC-L-LOOP 0133 SCOUT-END 0F56 SCREEN$ 0771 SE-NAME 1C9A SEL-DRIVE 17F7 SEND-BLK 1275 SEND-NEOF 0EF5 SEND-PACK 0DB2 SEND-RESP 0FBE SEND-SC 0F61 SENDSCOUT 0DDA SEPARATOR 05B1 SER-IN-2 0C1D SER-OUT-L 0C88 SERIAL-IN 0BD8 SET-BAUD 0AC9 SET-PROG 0A15 SET-T-MCH 0FE8 SH-ERR 0020 SKIP-NUN 014E SP-DL-1 0DF6 SP-N-END 0E05 ST-BF-LEN 0D88 ST-END 05B7 ST-ERROR 0068 ST-MAP-AD 108A ST-SHADOW 0008 START-2 009A START-3 00A5 START-4 00BC START-BIT 0BD1 START-SA 14E8 STCHK 1354 STO-DISP 137E STORE-DSP 1B23 STORE-LEN 0E93 SW-MOTOR 182A T-CH-NAME 1061 T-FURTHER 0BF9 T-INPUT 0B6F T-LD-NET 09DE T-M-CODE 0911 T-NA-1 1CA4 T-NA-2 1CAF T-OTHER 1E26 TCHAN-IN 0B7B TCHAN-OUT 0C3C TEST-BAUD 06B0 TEST-BLKN 0E45 TEST-BUFF 0D1E TEST-CODE 00E9 TEST-DTR 0C74 TEST-ERR 18E9 TEST-LOW 013B TEST-M-BF 1134 TEST-MAP 106F TEST-MCHL 10F5 TEST-MNAM 0685 TEST-NEXT 060C TEST-OUT 0D7A TEST-PMAP 1306 TEST-RET 05BF TEST-SAVE 07A7 TEST-SCT 1C0A TEST-SP 003A TEST-STAT 068F TEST-TYPE 08F2 TIME-OUT 0D5F TON-DELAY 1809 TRY-AGAIN 0D45 TS-L-NET 08CD TS-L-RS 08D3 TST-AGAIN 0BC5 TST-MERGE 0904 TST-MR-M 0988 TST-MR-N 0994 TST-N-EOF 0D38 TST-NUM 1DDA TST-PLACE 16AC TST-SPACE 09BE TST-TYPE 09C7 TURN-ON 1802 UNKN-1 1902 UNKN-2 191C UNKN-3 1929 UNKN-4 1952 UNKN-5 1959 UNKN-6 1961 UNKN-7 1968 UNKN-8 196C UNKN-9 1976 UNPAGE 0700 UNT-MARK 0FD2 UNTIL-MK 0FAE UNTILFIVE 1673 UPD-NXT-S 17A4 UPD-POINT 1384 UPD-STRM 1789 USE-C-RC 1A63 USE-R 1495 USE-REC 15DF VAR-EXIST 0235 VE-FAIL 1664 VE-M-E 1658 VERIF-SYN 089E VR-BN 0A8A VR-DATA 0803 WAIT-1 0BF0 WAIT-2 0BF1 WR-F-TEST 1BD6 WR-RECD 11FF WR-S-1 1AAD WR-S-2 1ABF WR-S-3 1AC7 WR-SECTOR 1A91 WRITE-PRC 120D WT-SCOUT 0F1E WT-SYNC 0F35 WTKEY 19DE APPENDIX 3 'Shadow' system variables Notes Address Name Contents X1 23734 5CB6 FLAGS3 Various flags: bit 0 - set during execution of 'new' commands. bit 1 - set during execution of CLEAR# command. On entry to the shadow ROM, it is set at the first 'paging' operation. bit 2 - set if the main ROM error handler is to be used. (Normally it is always reset). bit 3 - set if using the network. bit 4 - set during execution of LOAD and MOVE. bit 5 - set during execution of SAVE conwsand. bit 6 - set during execution of MERGE conmiand. bit 7 - set during execution of VERIFY cormnand. FLAGS3 may be addressed with (IY+124). X2 23735 5CB7 VECTOR Normally points to +01F0 (ERR-6). You may modify this address to point to a RAM routine. X10 23737 5CB9 SBRT ROM paging subroutine as follows: 5CB9 LD HL,nnnnn 5CBC CALL nnnnn 5CBF LD (H-L),HL 5CC2 RET H-L EQU +5CBA Used to save the value of HL while calling 'main' ROM routines. 2 23747 5CC3 BAUD Timing constant used during RS232 i/o. May be obtained with: (3500000/(26*baud rate))-2 1 23749 5CC5 NTSTAT Network own station number 1..64. 1 23759 5CC6 IOBORD Border colour used during I/O; normally 0 (black) N2 23751 5CC7 SER-FL Low byte may be 00 or 01; high byte holds a received byte if low byte is 01. N2 23753 5CC9 SECTOR Counter of sectors examined during Microdrive operations. N2 23755 5CCB CHADD- Temporary store for CH-ADD. 1 23757 5CCD NTRESP Store for network response code +01. 1 23758 5CCE NTDEST Start of network buffer; destination station number for the current packet (0..64). 1 23759 5CCF NTSRCE Station number of 'sending' Spectrum for the current packet. X2 23768 5CD0 NTNUMB Current packet block number (0..65535). N1 23762 5CD2 NTTYPE Packet type (00 for normal packets, 01 for EOF). X1 23763 5CD3 NTLEN Length of the data block being received, 1..255. N1 23764 5CD4 NTDCS Current data block checksum. N1 23765 5CD5 NTCHS Current header block checksum. N2 23766 5CD6 D-STR1 Start of first 8-byte file specifier; drive number 1..8, destination station number 0..64 or baud rate 75..19200. N1 23768 5CD8 S-STR1 Stream number 0..15. N1 23769 5CD9 L-STR1 Device specifier "m", "n", "t" or "b". N2 23770 5CDA N-STR1 Filename length N2 23772 5CDC Filename start address. N2 23774 5CDE D-STR2 Start of 2nd 8-byte file specifier, used by MOVE and LOAD commands. N1 23776 5CE0 S-STR2 See S-STR1. N1 23777 5CE1 L-STR2 See L-STR1. N2 23778 5CE2 N-STR2 See N-STR1. N2 23788 5CE4 N1 23782 5CE6 HD-00 Start of workspace used by LOAD, SAVE, VERIFY and MERGE commands. File type, may be: 00 - program 01 - numeric array 02 - string array 03 - bytes N2 23783 5CE7 HD-0B Data blocklength. N2 23785 5CE9 HD-0D Data block start address. N2 23787 5CEB HD-0F Program length (without variables), or array name. N2 23789 5CED HD-11 Autostart line number (+FFFF if no autostart), or address of the routine called by using 'hook code' +32. 1 23791 5CEF COPIES Number of copies made by SAVE. Reset to +01 after the SAVE. APPENDIX 4 Channels 1. MICRODRIVE CHANNEL This area is used to communicate with the Microdrive device; it is created in the CHANS area. The start address is pointed by the IX index register in the shadow ROM program. 0 +0008 Main ROM 'output' routine. 2 +0008 Main ROM 'input' routine. 4 'M' Channel specifier ('M'+80H denotes a 'temporary' channel, used by SAVE, MOVE, etc.). 5 +11D8 Shadow ROM 'output' routine. 7 +1122 Shadow ROM 'input' routine. 9 +0253 Channel length. 11 CHBYTE Position of the next byte to be received or stored in the buffer (0..512). 13 CHREC Record number 0..255. Also used as temporary store of sector number. 14 CHNAME 10-byte filename with trailing spaces. 24 CHFLAG Bit 0 set indicates a 'write' channel. Bit 0 reset indicates a 'read' channel. 25 CHDRIV Drive number 1..8. 26 CHMAP Address of microdrive map. 28 - 12 bytes of header preamble (ten zeros and two +FF). Used to mark the start of the header block. 40 HDFLAG Bit 0 set indicates that the received block is a header. 41 HDNUMB Sector number from which the header comes. 42 - Unused 44 HDNAME 10-byte cartridge name with trailing spaces. 54 HDCHK Checksum from HDFLAG to HDCHK-1. 55 - 12 bytes of data preamble, as for the header; used to mark the start of the record descriptor. 67 RECFLG Bit 0 reset indicates that the received block is a record descriptor. Bit 1 is set if the record is the EOF one. Bit 2 is reset if the record is part of a PRINT-type file. 68 RECNUM Record number 0..255. 69 RECLEN Number of bytes in the record (0..512). 71 RECNAM 10-byte record name with trailing spaces. 81 DESCHK Checksum from RECFLG to DESCHK-l. 82 CHDATA Start of 512-byte buffer. 594 DCHK Buffer checksum. Bytes 0..27 are used as 'channel descriptor' and are never transmitted; bytes 28..54 are the 'header block'; bytes 55..594 are the 'data block'. Bytes 55..91 may be collected (or written) as 'record descriptor', without affecting the data buffer starting from CHDATA. 2. NETWORK CHANNEL As with the Microdrive channel, this area is addressed by using the IX index register it is used to communicate through the Local Area Network. 0 +0008 Main ROM 'Output' routine, 2 +0008 Main ROM 'Input' routine. 4 'N' Channel specifier ('N'+80H denotes a 'temporary' channel). 5 +0D6C Shadow ROM 'Output' routine. 7 +0D9C Shadow ROM 'Input' routine. 9 +0114 Length of the channel. 11 NCIRIS Destination station number 0..64. 12 NCSELF Own station number 1..64. 13 NCNUMB Current block bumber 0..65535. 15 NCTYPE Packet type: 00 normal packet, 01 'end of file' packet. 16 NCOBL Number of bytes held in the buffer during 'output' (holds 0 if the channel is used for reading). 17 NCDCS Checksum of the 255-byte buffer. 18 NCHCS Checksum of block NCIRIS...NCDCS. 19 NCCUR Position of the currently received byte (in the buffer). 20 NCIBL Number of bytes in the buffer during 'output' (holds zero if the channel is used for writing). 21 NCB 255-byte data buffer. While 'sending', the bytes 11.18 form the 'header block' (to be stored into the system variables NTDEST...NTCHS of the receiving Spectrum). Bytes 21..275 form the 'data block'. 3. RS232 "T" CHANNEL This channel is created only when the RS232 link is to be attached to a stream. 'Temporary' RS232 channels are never created, because the RS232 I/O does not require a buffer to store the data to be sent or received (the only 'workspace' is made by the SER-FL system variable). 0 +0008 Main ROM 'output' routine. 2 +0008 Main ROM 'input' routine. 4 'T' Channel specifier. 5 +0C3C Shadow ROM 'output' routine. 7 +0B6F Shadow ROM 'input' routine. 9 +000B Channel length. 4. RS232 "B" CIANNEL 0 +0008 Main ROM 'output' routine. 2 +0008 Main ROM 'input' routine. 4 'B' Channel specifier. 5 +0C5A Shadow ROM 'output' routine. 7 +0B75 Shadow ROM 'input' routine. 9 +000B Channel length. APPENDIX 5 Bibliography S. Vickers, ZX SPECTRUM BASIC PROGRAMMING (Sinclair Research Ltd.) MICRODRIVE AND INTERFACE I MANUAL (Sinclair Research Ltd.) I. Logan, F. O'Hara, THE COMPLETE SPECTRUM ROM DISASSEMBLY (Melbourne House) I. Logan, SPECTRUM MICRODRIVE BOOK (Melbourne House) R. Zaks, PROGRAMMING THE Z80 (Sybex) APPENDIX 6 Index to routines (For edition 1 Shadow ROM) 0000 Return to main ROM 0008 Start 0010 Call a main ROM routine 0018 Test if syntax is being checked 0020 Shadow error 0028 Main ROM error restart 0030 Create new system variables restart 0038 Maskable interrupt 003A TEST-SP 0040 Main ROM error routine 0066 Non-maskable interrupt 0068 ST-ERROR 0077 CHECK-SP 0081 CALBAS-2 009A Control routine 01F7 Create new system variables routine 023A System variables default values 024D Reset new system variables 0258 Shadow report printing 0287 Shadow report messages 0486 CAT command syntax routine 04B4 FORMAT command syntax routine 04ED OPEN command syntax routine 0531 ERASE command syntax routine 053D MOVE command syntax routine 0559 CLS# command routine 057F CLEAR# command routine 059F Exchange file specifiers 05B1 SEPARATOR 05B7 End of statement 05Cl Return to the main interpreter 05E7 Evaluate string expression 05F2 Evaluate channel expression 061E Evaluate numeric expression 062F Evaluate filename 064E Evaluate stream number 0665 Check "m" parameters 0685 Check "m" parameters and filename 068F Check station number 06A3 Evaluate "x";n;"name" 06B0 Check baud rate 06B9 Evaluate stream or expression 0700 UNPAGE 0701 Evaluate parameters 082F SAVE command syntax routine 0880 Save a byte to network or RS232 link 0894 LOAD command syntax routine 089E VERIFY command syntax routine 08A8 MERGE command syntax routine 08AF LOAD-VERIFY-MERGE commands routine 0A5C LOAD or VERIFY 0A95 Load "run" program 0AC9 Set "BAUD" system variable 0AEF RS232 timing constants 0B13 Open RS232 channel in CHANS area 0B47 Attach channel to a stream 0B64 "T" channel data 0B6F "T" channel input 0B75 "B" channel input 0B7B "T" channel input service routine 0B81 "B" channel input service routine 0C3C "T" channel output 0C5A "B" channel output 0CA9 Border colour restore 0CB4 Break into I/O operation 0CBD CALL-INP 0D0C "N" channel input 0D12 "N" channel input service routine 0D6C "N" channel output 0D93 OUT-BLK-N 0DAB S-PACK-1 0DB2 SEND-PACK 0E0F BR-DELAY 0E18 Header and data block receiving 0EA3 OPEN "N" channel command routine 0EA9 Open temporary "n" channel 0EB5 Open permanent "n" channel 0EEA "N" channel data 0EF5 Send EOF block to network 0F03 Network state 0F0E Check-resting 0F1E Wait-scout 0F61 Send-scout 0F92 INPAK 0FBE Send response byte 0FC5 OUTPAK 0FE8 Set a temporary "m" channel 10C4 Reclaim "m" channel 1122 "M" channel input 112C "M" channel input service routine 1177 Get a record 11A5 Get header and data block 11D8 "M" channel output 11FF Write record onto Microdrive 1264 CHK-FULL 1275 SEND-BLK 12A6 Close file 12BE ERR-RS 12C4 Fetch header from Microdrive 12DA Check map bit state 12FF Reset bit in map area 1306 Check 'pseudo-map' bit state 1312 Decrease sector counter 131E CHECK-NAME 1341 Calculate/compare checksums 135F Restore stream data 1391 Restore map addresses 13CC "M" channel data 13E5 Preamble data 13F1 MOVE command 1455 Use stream or temporary channel 14A4 Close 'MOVE' channel 14C7 Exchange DSTR1 and STR2 contents 14DA Save data block into Mlcrodrive 1580 Get header information from Microdrive 15A9 Load or verify block from Microdrive 1613 Save Microdrive Map contents 162D Restore Microdrive Map contents 1648 LD-VE-M 1666 Fetch record from Microdrive. 1691 Restore address of filename 1708 CLOSE STREAM 1718 CLOSE command 17B9 Reclaim temporary channels 17F7 Select drive motor 1867 1 millisecond delay 1872 Send data block to Microdrive Head 18A3 Receive block from Microdrive Head 18E9 TEST-BRK 18FA DELAY-BC 1902 UNKN-1 196C UNKN-8 1981 HOOK-CODE 19A4 Hook code +32 19A8 Hook code +31 19A9 Hook code addresses 19D9 Console input 19EC Console output 19FC Printer output 1A01 Keyboard test 1A09 Read sequential 1A17 Read random 1A24 Close network channel 1A31 Get packet from network 1A4B Read sector 1A86 Read next sector 1A91 Write sector 1AE0 Clear buffer contents 1AF0 Open a permanent "m" channel 1B29 Open a temporary "m" channel 1B6E FORMAT "m" command 1C58 CAT command 1D38 FREESECT 1D59 PRNAME 1D66 PRCHAR 1D6E ERASE command 1E3E Signal 'free sector' 1E53 Obtain record descriptor 1E66 Calls to the command routines 1E87 DISP-HEX 1E9E DISP-HEX2 1EA9 DISP-CH 1ECE HEX-LINE APPENDIX 7 Shadow ROM issue 2 The new ZX Interface 1's with serial number greater than 87315 have been provided with a new shadow ROM, with some general improvements. The Spectrums fitted with the 'new' interface will print '80' in response to the command 'PRINT PEEK 23729'. The main changes may be summed up as follows: The TCHAN-OUT subroutine ("t" channel output routine) has been remarkably improved; the TAB function now is supported, as well as the 'comma' control code, and the 'leading space' bug has been corrected. The whole subroutine is listed below. 0C3A TCHAN-OUT CP +A5 Jump if the code is not a token 0C3C JR C,0C44,NOT-TOKEN code. 0C3E SUB +A5 Reduce range of token. 0C40 RST 10,CALBAS And detokenise it by calling 0C41 DEFW +0C18 recursively this routine via main 0C43 RET ROM 'PO-TOKENS' routine. 0C44 NOT-TOKEN LD HL,+5C3B This is FLAGS. 0C47 RES 0,(HL) Reset 'leading space' flag. 0C49 CP +20 Is the character a space? 0C4B JR NZ,0C4F,NOT-LEAD Jump if it is not. 0C4D SET 0,(HL) Otherwise set 'leading space' flag. 0C4F NOT-LEAD CP +7F Jump if the character is not 0C51 JR C,0C55,NOT-GRAPH a 'graphic' character. 0C53 LD A,+3F Otherwise print a '?' 0C55 NOT-GRAPH CP +20 Jump with codes lower than +20. 0C57 JR C,0C78,CTRL-CD 0C59 PUSH AF Save the character code. 0C5A INC (IY+118) Increment current print position. 0C5D LD A,(5CB1) Fetch line width. 0C60 CP (IY+118) Jump if the position is lower than 0C63 JR NC,0C6C,EMIT-CH or equal to the value of WIDTH. 0C65 CALL 0C74,NEWLINE Send CR and LF codes when pos>width. 0C68 LD (IY+118),+01 Reset 'print position' to +01. 0C6C ENIT-CH POP AF Restore character to be printed. 0C6D JP 0D07,BCHAN-OUT Print it. 0C70 CTRL-CD CP +0D Jump if the character is not 'CR'. 0C72 JR NZ,0C82,NOT-CR 0C74 LD (IY+118),+00 Clear print position. 0C78 LD A,+0D Print a CR code. 0C7A CALL 0D07,BCHAN-OUT 0C7D LD A,+0A Print a LF code. 0C7F JP 0D07,BCHAN-OUT 0C82 NOT-CR CP +06 Jump if the character is not the 0C84 JR NZ,0CA5,NOT-CMM 'comma' control code. 0C86 LD BC,(5CB0) Fetch width into B, and print position into C. 0C8A LD E,+00 0C8C SPC-COUNT INC E Increment space counter. 0C8D INC C Increment print position. 0C8E LD A,C Jump if 'position' reaches the 0C8F CP B right margin. 0C90 JR Z,0C9A,PRINT-SPC 0C92 CMM-LOOP SUB +08 Tabulate every 8 columns. 0C94 JR Z,0C9A,PRINT-SPC Jump when reached the right column. 0C96 JR NC,0C92,CMMLOOP Subtract again... 0C98 JR 0C8C,SPC-COUNT Column not reached, jump back. 0C9A PRINT-SPC PUSH DE Save space counter. 0C9B LD A,+20 Print the required number of spaces 0C9D CALL 0C3A,TCHAN-OUT by calling TCHAN-OUT recursively. 0CA0 POP DE Restore space counter. 0CA1 DEC E 0CA2 RET Z 0CA3 JR 0C9A,PRINT-SPC 0CA5 NOT-CNN CP +16 Jump with AT control code. 0CA7 JR Z,0CB5,TAB-PROC 0CA9 CP +17 Jump with TAB control code. 0CAB JR Z,0C5B,TAB-PROC 0CAD CP +19 Return with codes lower than 16d 0CAF RET C 0CB0 LD DE,+0CD0 Service routine for INK, PAPER 0CB3 JR 0CB8,STORE-COD ...control codes. 0CB5 TAB-PROC LD DE,+0CC8 Service routine for AT and TAB 0CB8 STORE-COD LD (TVDATA-lo),A Store first operand. 0CBB ALTER-OUT LD HL,(CURCHL) Fetch current channel address. 0CBE PUSH DE 0CBF LD DE,+0005 Point to 'output address' pointer. 0CC2 ADD HL,DE 0CC3 POP DE 0CC4 LD (HL),E Store new 'output' address. 0CC5 INC HL 0CC6 LD (HL),D 0CC? RET 0CC8 TAB-SERV LD DE,+0CD0 The new 'output' address. 0CCB LD (TVDATA-hi),A Store second operand. 0CCE JR 0CBB,ALTER-OUT Jump to change the 'output' address. 0CD0 LD DE,+0C3A Restore the normal 'output' address. 0CD3 CALL 0CBB,ALTER-OUT 0CD6 LD D,A Pass 'second operand' to D. 0CD7 LD A,(TVDATA-lo) Fetch first operand (code type). 0CDA CP +16 Jump with AT. 0CDC JR Z,0CE6,TST-WIDTH 0CDE CP +17 Return unless the code is TAB. 0CE0 CCF 0CE1 RET NZ 0CE2 LD A,(TVDATA-hi) Fetch TAB column. 0CE5 LD D,A Move it into D. 0CE6 TST-WIDTH LD A,(5CB1) Fetch line width. 0CE9 CP D 0CEA JR Z,0CEE,TAB-MOD Jump if TAB is at last column. 0CFC JR NC,0CF4,TABZERO Jump if TAB is within range. 0CEE TAB-MOD LD B,A Fetch column width. 0CEF LD A,D Fetch TAB column. 0CF0 SUB B A=TAB-WIDTH 0CF1 LD D,A The new position. 0CF2 JR 0CE6,TST-WIDTH Take (TAB pos.) MOD (width). 0CF4 TABZERO LD A,D Fetch TAB column. 0CF5 OR A New line with TAB 0. 0CF6 JP Z,0C74,NEWLINE 0CF9 TABLOOP LD A,(5CB0) Fetch current print position. 0CFC CP D Return if already at the.. 0CFD RET Z ..TAB position. 0CFE PUSH DE 0CFF LD A,+20 Print the TAB spaces. 0D01 CALL 0C3A,TCHAN-OUT 0D04 POP DE 0D05 JR 0CF9,TABLOOP You should note that variable line width is allowed by POKEing the required value into the location 23729; the default value is 80. Other important alterations concern with Microdrive reading operations (i.e. channel opening, CAT command); the number of sectors examined is not fixed to 255, but is given by 'maximum sector number + 3'; this prevents the routine from reading 'nonexistent' sectors, and reduces the time required in the command execution. The checking operation done by the FORMAT command routine is now made directly with OUT instructions, without using the Microdrive channel to send/receive the blocks containing 'test data'. Other minor changes are: - The OP-RS-CH routine stores the "B" specifier into (IX+4) when opening a RS232 "b" channel. - Most of the tests done to the BREAK key have been replaced by calls to the TEST-BRK subroutine at +163E. - The carry flag is preserved when calling the BORD-REST subroutine at +0D4D; thus, the 'hook code' +2F works correctly. - When a "m" or "n" channel is created in the CHANS area (OP-PERM-N and SET-T-MCH), a check is made to see if there is sufficient memory to insert the new space. - The GET-M-HD subroutine, returns (with bit 0 of HDFLAG or RECFLG inverted) when 'time-out' occurs during the reading operation. - An instruction 'SET 7,(HL)' has been inserted at location +1741 (i.e. the middle of the CLOSE routine), to correct the bug present in the 'old' shadow ROM (see comment to the CLOSE routine). - No CR code is sent when a RS232 'b" channel is closed. - The 'hook code' +2B calls the SET-T-MCH subroutine. - Two new 'hook codes', +33 and +34, are now available. Hook code +33 may be used to fetch a 'record descriptor' from the next sector; the microdrive motor must be turned on before calling the routine. The record descriptor is stored into the current microdrive channel (whose start address must be held into the IX index register), and the carry flag is returned set if any error occurs, or if the 'record descriptor' holds a filename starting wIth CHR$ 0. Hook code +34 opens a RS232 "b" channel by calling the OP-RS-CH subroutine. The channel base address is returned into the DE register pair. APPENDIX 8 How to tell which edition Interface 1 you have There are two different versions of the ZX Interface, each having a slightly different program in its ROM. It is important that you know which version of the ROM you have, and you can find this out in the fo5lowing manner: Run the following line of BASIC: CLOSE # 0: PRINT PEEK 23729 If this prints out a '0', then you have an edition 1 Interface 1. if it prints out '80', you have an edition 2 Interface 1. There is the possibility that Sinclair Research may release a third edition of the Shadow ROM, with a few more changes. If you should get one of these, the extended BASIC commands may not work properly with it. The 'PRINT PEEK 23729' test probably wont distinguish between the edition 2 and edition 3 Shadow ROMs, You can, however, upload the Shadow ROM into a higher area of RAM, disassemble it there, and compare the code to the listings given in this book. The following program will load the Shadow ROM into RAM from 32768 to 48968: ORG 34000 LD HL,LABEL LD (23789),HL RST 08 DEFB 32H LABEL POP HL POP HL LD HL,0 LD DE,32768 LD BC,8192 LDIR RST 0 RET To do the same thing from BASIC, use the following program: 10 CLEAR 26000 20 FOR X=54000 TO 54022 30 READ Y 40 POKE X,Y 50 NEXT X 60 RAND USR 54000 70 DATA 33,248,210,34,237,92,207,50,225,225 80 DATA 33,0,0,17,0,128,1,0,32,237,176,199,201 For information on how to make the extended BASIC commands work with edition 3 or later Shadow ROMs, refer to Appendix 11, page 165. APPENDIX 9 Basic loader program for edition 2 Shadow ROM (For owners of Interface 1s equipped with the edition 2 Shadow ROM.) Here is the new BASIC loader program, changed to run with the new shadow ROM. To enter the new BASIC commands into your Spectrum without using an assembler, enter the following BASIC loader program. 1 CLEAR 63743 10 FOR A=63744 TO 65951 STEP 12 20 PRINT "ADDRESS:";A' 30 LET C=0 40 FOR B=1 TO 12 50 LET Z=A+B-1: IF Z<=65051 THEN INPUT X: PRINT X: POKE Z,X: LET C=C+X 60 NEXT B 70 PRINT '"CHECKSUM=";C 80 INPUT "THIS IS WRONG ? (Y/N) "; LINE Y$: IF CODE Y$=80 OR CODE Y$=121 THEN PRINT "Retype from address ";A: PAUSE 100: CLS : GO TO 20 90 IF CODE Y$<>78 AND CODE Y$<>110 THEN GO TO 80 100 CLS: NEXT A 110 PRINT "Saving the program" 120 SAVE *"M";l;"SHADP" CODE 63744,1308 When you have finished typing this program into your Spectrum, you should 'RUN' it. You should then type from the listing on the next page, the 12 bytes from the address shown on the screen. When you have typed the first 12 bytes, a 'checksum' should be displayed on the screen; if it matches the one printed on the listing, at the right hand side of the line, then you have made no mistakes in typing the numbers, and you may enter 'N' or 'n' to continue with the next line. If the checksums do not match, you must enter 'Y' or 'y', and then retype the whole line. When all numbers have been entered, the program will automatically be saved on Microdrive cartridge (there must be a cartridge with at least 2K free in Microdrive 1). If you wish to save the program on tape, line 120 of the listing should be modified appropriately. When at some 1ater time you wish to use the routines, you have simply to place the cartridge in Microdrive 1, and then to enter the following direct commands: CLEAR 63743: LOAD *"M";1;"SHADP" CODE: RANDOMIZE USR 63744 and the new comnands should be available. Note that if you use the NEW command, you should then give the direct command 'RANDOMISE USR 63744' to reinitialise the VECTOR system variable. Here is the data for the new Shadow ROM: 63744: 207 49 33 9 249 34 183 92 201 215 24 0 1296 63756: 254 244 202 45 249 254 42 202 114 249 254 215 2384 63768: 202 11 250 254 227 202 188 251 254 229 202 12 2282 63780: 252 254 224 202 175 252 195 240 1 215 32 0 2042 63792: 254 42 194 75 249 215 121 28 205 183 5 215 1786 63804: 153 30 197 215 153 30 197 225 193 113 35 112 1653 63816: 195 193 5 215 130 28 254 44 194 240 1 215 1714 63828: 32 0 215 140 28 205 183 5 215 241 43 197 1504 63840: 213 215 153 30 80 89 223 193 120 177 202 193 1890 63852: 5 237 176 195 193 5 215 32 0 254 207 202 1721 63864: 102 250 246 32 254 108 194 197 249 215 32 0 1879 63876: 215 130 28 205 183 5 215 153 30 96 105 124 1489 63888: 205 214 20 125 205 214 20 62 32 205 248 20 1570 63900: 229 6 6 197 126 205 237 20 35 16 249 193 1519 63912: 225 126 230 127 254 32 56 6 254 128 48 2 1488 63924: 24 2 62 32 205 248 20 35 16 235 62 13 954 63936: 205 248 20 24 202 254 101 194 240 1 215 32 1736 63948: 0 215 130 28 205 183 5 215 153 30 253 203 1620 63960: 12 126 202 240 1 120 230 192 194 240 1 237 1795 63972: 67 73 92 237 123 61 92 33 7 250 229 42 1306 63984: 61 92 229 33 127 16 229 237 115 61 92 253 1545 63996: 54 0 255 215 169 15 33 56 15 229 199 225 1465 64008: 195 180 18 215 32 0 254 42 194 240 1 215 1586 64020: 121 28 254 44 194 240 1 215 121 28 205 183 1634 64032: 5 215 148 30 245 215 148 30 167 40 54 79 1376 64044: 6 0 197 215 148 30 167 40 44 79 6 0 932 64056: 197 215 153 30 197 205 0 7 225 209 193 241 1872 64068: 229 245 197 229 213 205 181 3 209 225 193 241 2370 64080: 167 237 66 48 240 61 225 32 235 33 193 5 1542 64092: 34 237 92 207 50 253 54 0 0 239 215 32 1413 64104: 0 205 30 6 205 183 5 205 109 6 62 2 1018 64116: 215 1 22 205 165 16 221 126 25 205 50 21 1272 64128: 205 169 19 33 9 251 17 24 0 205 5 251 1188 64140: 205 38 20 32 239 33 9 251 203 70 32 232 1364 64152: 58 9 251 33 12 251 182 230 2 194 169 250 1641 64164: 205 227 19 24 215 58 13 251 183 40 209 58 1502 64176: 10 251 183 32 203 221 126 41 221 190 13 40 1531 64188: 22 205 33 251 205 0 251 221 126 13 183 194 1704 64200: 128 250 221 126 41 221 119 13 195 128 250 221 1913 64212: 229 175 205 50 21 205 0 251 221 229 225 17 1828 64224: 44 0 25 205 178 251 205 0 251 205 67 29 1460 64236: 123 203 63 215 40 45 215 227 45 205 0 251 1632 64248: 221 225 205 159 17 195 193 5 62 13 195 113 1603 64260: 29 229 195 242 21 0 0 0 0 0 0 0 716 64272: 0 0 0 0 0 0 0 0 0 0 0 0 0 64284: 0 0 0 0 0 33 140 92 54 255 33 13 620 64296: 251 205 178 251 62 32 205 113 29 58 9 251 1644 64308: 203 87 194 62 251 62 245 195 113 29 33 24 1498 64320: 251 126 183 202 99 251 254 3 202 157 251 61 2040 64332: 245 62 228 205 113 29 58 29 251 230 31 198 1679 64344: 96 205 113 29 241 200 62 36 195 113 29 33 1352 64356: 32 251 126 230 192 192 43 62 202 205 113 29 1677 64368: 94 35 86 235 17 16 39 205 143 251 17 232 1370 64380: 3 205 143 251 17 100 0 205 143 251 17 10 1345 64392: 0 205 143 251 17 1 0 62 255 60 183 237 1414 64404: 82 48 250 25 246 48 195 113 29 62 175 205 1478 64416: 113 29 35 229 35 35 205 112 251 62 44 205 1355 64428: 113 29 225 195 112 251 6 10 126 205 113 29 1414 64440: 35 16 249 201 215 32 8 254 35 194 240 1 1472 64452: 215 121 28 205 183 5 215 148 30 245 215 148 1758 64464: 30 254 16 210 99 6 215 1 22 221 42 81 1197 64476: 92 221 126 4 254 77 194 45 6 221 203 24 1467 64488: 70 194 13 18 241 221 119 13 221 126 25 205 1466 64500: 50 21 33 255 0 34 201 92 205 95 18 175 1179 64512: 221 119 11 221 119 12 205 50 21 195 193 5 1372 64524: 215 32 0 215 130 28 205 183 5 215 148 30 1406 64536: 254 16 210 99 6 215 1 22 221 42 81 92 1259 64548: 221 126 4 254 77 194 45 6 221 203 24 70 1445 64560: 194 6 9 221 126 25 205 50 21 33 255 0 1145 64572: 34 201 92 205 128 18 56 19 40 14 221 203 1231 64584: 67 78 40 11 221 126 41 221 119 13 24 3 964 64596: 205 227 19 205 247 19 32 227 219 239 230 1 1870 64608: 202 185 31 205 63 31 218 126 18 221 110 69 1479 64620: 221 102 70 221 117 11 221 116 12 221 203 24 1539 64632: 198 205 73 30 205 169 19 221 126 13 221 190 1670 64644: 41 32 245 62 230 211 239 1 104 1 205 82 1453 64656: 22 221 229 225 17 55 0 25 205 179 21 62 1261 64668: 238 211 239 205 227 19 221 126 68 221 119 13 1907 64680: 175 205 50 21 195 193 5 215 32 0 254 33 1378 64692: 40 11 254 47 40 33 254 63 40 54 195 240 1271 64704: 1 215 121 28 205 183 5 215 148 30 167 202 1520 64716: 250 253 50 21 254 215 148 30 61 50 20 254 1606 64728: 195 193 5 215 121 28 205 183 5 215 148 30 1543 64740: 50 22 254 215 148 30 50 23 254 175 50 27 1298 64752: 254 195 193 5 215 32 0 215 130 28 205 183 1655 64764: 5 215 148 30 254 1 40 12 62 3 253 203 1226 64776: 124 142 205 24 23 195 193 5 62 3 215 39 1230 64788: 23 33 17 0 167 237 66 218 47 5 205 23 1041 64800: 11 213 33 5 0 25 17 53 253 115 35 114 874 64812: 62 3 50 216 92 209 195 81 11 254 165 211 1548 64824: 62 12 253 203 1 134 254 32 56 91 32 4 1134 64836: 253 203 1 198 245 62 1 50 24 254 241 254 1786 64848: 127 56 2 62 63 205 7 13 58 20 254 71 938 64860: 58 19 254 184 48 5 60 50 19 254 201 205 1357 64872: 111 253 175 50 24 254 201 62 1 50 24 254 1459 64884: 61 50 19 254 58 25 254 167 196 7 13 58 1162 64896: 26 254 167 196 7 13 58 23 254 71 58 27 1154 64908: 254 60 184 32 0 58 22 254 167 196 7 13 1255 64920: 175 50 27 254 201 254 13 32 12 58 24 254 1354 64932: 167 62 1 50 24 254 200 24 194 254 6 32 1268 64944: 33 42 19 254 58 21 254 71 14 0 12 44 822 64956: 125 188 48 167 144 40 4 48 251 24 243 197 1479 64968: 62 32 205 53 253 193 13 32 246 201 254 23 1567 64980: 192 17 226 253 42 81 92 6 5 9 115 35 1073 64992: 114 201 50 15 92 17 234 253 24 238 17 53 1308 65004: 253 205 216 253 58 15 92 71 58 20 254 184 1679 65016: 48 5 253 54 0 10 239 58 19 254 144 200 1284 65028: 48 5 237 68 79 24 188 197 205 111 253 193 1608 65040: 72 24 180 0 80 20 12 60 1 13 10 0 472 APPENDIX 10 Extended BASIC commands from assembler for edition 2 Shadow ROM (For owners of Interface 1s equipped with the edition 2 Shadow ROM.) To add the extended BASIC commands to your Spectrum, if you own an edition 2 Shadow ROM and an assembler, first enter the assembly program on pages 12 to 32 into your Spectrum. Do not enter the table of EQU statements that follows on page 33. These labels all refer to the edition 1 Shadow ROM, and are not relevant to edition 2. Instead, for each label given on page 33, enter the value given in the alphabetical list of Shadow ROM 2 labels which follow. When you have entered this program and assembled it, save it onto Microdrive or tape. To use the new BASIC commands, load the machine code file you have made into your Spectrum at 63744 (F900 Hex), and give the direct command 'RANDOMISE USR 63744'. The new commands should then be available. Below is an alphabetical list of the labels related to the edition 2 shadow ROM. ACC-CODE 0D8A ALL-BITS 102F ALL-BYTES 05A7 ALL-CHARS 1407 ALL-MOTRS 1570 ALL-STRMS 058E ALLCHR-2 1418 ALTER-OUT 0CBB B-INPUT 0B7C BCHAN-IN 0B88 BCHAN-OUT 0D07 BD-DEL-1 0D1C BD-DEL-2 0D32 BD-DEL-3 0D48 BD-DELAY 0BD8 BD-DELAY2 0C1D BF-FILLED 1CFF BORD-REST 0D4D BR-DELAY 0EAC BRCAST 0EDD BREAK-PGM 05E2 CALBAS 0010 CALBAS-2 0081 CALL-INP 0D5A CAT 1C52 CAT-LP 1C68 CAT-LP-E 1C77 CAT-RUN 1AB5 CAT-SCRN 04A6 CAT-SYN 0486 CHAN-SPC 10F1 CHECK-M 0665 CHECK-M-2 066D CHECK-MAP 13C4 CHECK-N 1883 CHECK-R 188F CHECK-SP 0077 CHK-AG-2 1608 CHK-AGAIN 15F6 CHK-FULL 1349 CHK-LOOP 10B3 CHK-LP-2 160F CHK-M-EOF 1233 CHK-MAP-2 13BF CHK-NAME 1403 CHK-NSECT 1C1E CHK-PRES 154E CHK-REST 0FC7 CHK-SCT 1BF6 CHK-SCT2 1C05 CHK-TEMPM 17D0 CHK-TEMPN 17DC CHK-W-MAP 1E3A CHKEND 015D CHKEND-L 0169 CHKEVEN 0165 CHKLOOP 15FD CHKS-ALL 142E CHKS-BUFF 142B CHKS-HD-R 1426 CHKS1 0E62 CHKS2 0E71 CHKS3 0EC4 CHKS4 0F24 CHKSYNTAX 0018 CKNAM-END 1423 CL-CHAN 18A8 CL-CHK-N 18BC CL-M-CH 176B CL-N-CH 175C CL-WORK 01AA CLAIMED 0FD9 CLOSE 1718 CLOSE-CH 1708 CLOSE-M 138B CLOSE-M2 138E CLOSE-NET 1F18 CLR#-SYN 057F CLR-BUFF 1FD4 CLR-ERR 1E77 CLS#-SYN 0559 CMM-LOOP 0C92 CODE 0789 CONS-IN 1ECD CONS-OUT 1EE0 CONV-1 14E7 COPYCHADD 00FB CP-NAME 1300 CRT-NEW 09F7 CRT-VARS 01F7 CTRL-CD 0C70 DATA 07D2 DEC-SECT 13F7 DEFAULT 0224 DEFLT-0 079A DEL-B-CT 1F75 DEL-M-BUF 119F DEL-O-1 1087 DEL-S-1 15A2 DELAY-BC 1652 DELAY-BC1 1653 DELAY-SC 101A DISP-CH 14F8 DISP-HEX 14D6 DISP-HEX2 14ED DISP-NIB 14DF DL-LOOP 0EAF DR-READY 1620 E-READ-N 100A EACH-ST 0152 EACH-VAR 025A EMIT-CH 0C6C END-CODE 07B8 END-DATA 081C END-EXPT 0750 END-INPUT 0D94 END-LD-PR 0A13 END-PR-MS 02B4 END-RS-IN 0C34 END-S-DEL 104C END-SA-DR 196A END-SET 0AE8 END1 05C1 ENDC 1AC9 ENDHERE 06CC ENDRD 16AD ENTRY 13C7 ENTRY-2 17C0 ERASE 1D79 ERASE-1 1D8A ERASE-2 1DC3 ERASE-LP 1DA7 ERASE-MK 1E03 ERASE-MK2 1E06 ERASE-RUN 1AAB ERASE-SYN 0531 ERR-6 01F0 ERR-RS 13A3 ERR-V 01EC EX-CHANS 17C0 EX-D-STR 059F EXISTING 07F2 EXPT-EXP1 06B9 EXPT-EXPR 06A3 EXPT-NAME 062F EXPT-NUM 061E EXPT-PRMS 0701 EXPT-SPEC 05F2 EXPT-STR 05E7 EXPT-STRM 064E F-ERROR 1A7B F-HD-2 1982 F-HD-3 198A F-M-HEAD 1971 F-N-SCT 1CF4 F-REC1 1A57 F-REC2 1A5D FAILED 1362 FETCH-ERR 0276 FILL-MAP 1163 FOR-B-T 04CD FOR-M 04E7 FOR-RUN 1ABA FORMAT 185D FORMAT-1 1B75 FR-S-LPB 1D51 FR-S-RES 1D55 FR-SC-LP 1D4D FREESECT 1D43 FRMT-SYN 04B4 G-HD-RC 1280 G-RDES 1E5E G-REC-ERR 12B1 G-TYPE 07F6 GET-DESC 1FE4 GET-M-BLK 15F2 GET-M-BUF 15EB GET-M-HD 15E2 GET-M-HD2 13A9 GET-N-BUF 0DDC GET-NBLK 0EB5 GET-NBUFF 0F02 GET-PACK 1F25 GET-R-2 1258 GET-R-LP 125F GET-RECD 1252 GETBF-END 0F3E GETNB-END 0EFF GP-ERROR 1F3A HD-LOOP 0854 HEX-LINE 151D HEX-LINE2 1522 HOOK-31 1E98 HOOK-32 1E94 HOOK-CODE 1E71 I-AGAIN 181E IN-AGAIN 0D78 IN-CHK 1E49 IN-M-BLK 1633 IN-NAME 1C8B INC-BLKN 0E9A INCREC 1F08 INKEY$ 0D98 INPAK 104F INPAK-2 105A INPAK-L 105B INS-NAME 1CDA INT-SERV 0038 KBD-TEST 1EF5 LCHAN 1482 LD-BLK-2 0936 LD-BLK-3 0945 LD-BLK-4 0956 LD-BLK-5 095D LD-BLOCK 091D LD-DATA 080E LD-HD-NET 08E4 LD-HD-RS 08EB LD-HDR-2 08F0 LD-HEADER 08DC LD-NO-PGM 0966 LD-PR-AR 09A7 LD-PROG 09B9 LD-VE-M 1A39 LD-VF-MR 08B3 LINE 073E LINE-LEN 0144 LOAD-RUN 0A99 LOAD-SYN 0898 LOOK-MAP 19EA LP-B-MAP 1DF4 LP-P-MAP 1DF0 LP-SCOUT 1015 LPEND 14A6 LV-ANY 0A60 LV-B 0A7D LV-BN 0A6E LV-BN-E 0A82 LV-MCH 199A LV-N 0A76 LVBN-END 0A93 M-AGAIN 1818 M-INPUT 11FD MAIN-ROM 0000 MAKE-PERM 1AE9 MAKESURE 0FCA MARK-FREE 1C40 MCHAN-IN 1207 MCHAN-OUT 12B3 MERGE-BLK 096B MERGE-END 09A4 MISSING-D 0494 MK-BLK 1C4D MOVE 17F5 MOVE-EOF 1832 MOVE-NA 1CDE MOVE-OUT 1827 MOVE-RUN 1AB0 MOVE-SYN 053D MRG-SYN 08AC N-ACTIVE 1051 N-INPUT 0DA9 NCHAN-IN 0DAF NCHAN-OUT 0E09 NET-STATE 0FBC NEW-BUFF 123D NEW-NAME 18ED NEWVARS 0030 NEXT-CHAN 10E7 NEXTNUM 01A5 NMINT-SRV 0660 NO-AUTO 0A52 NO-AUTOST 0977 NO-FOR-M 04BF NO-GOOD 1F45 NO-M-ARR 07DA NO-NAME 0716 NO-PRT 1374 NO-READ 0D87 NOEMP 139B NOFULL 12FC NOINC-C 1DF8 NONAMES 1D27 NONS-BSC 07F4 NONSENSE 0584 NOPRES 155B NOREAD 12C1 NOT-CMM 0CA5 NOT-CR 0C82 NOT-FOR-B 04D3 NOT-GRAPH 0C55 NOT-LEAD 0C4F NOT-NET 0722 NOT-OP-B 051F NOT-OP-M 0500 NOT-PROT 15BF NOT-RECV 1FF1 NOT-TOKEN 0C44 NOTRIGHT 145C NREPORT-1 0139 NREPORT-2 0663 NREPORT-3 062D NREPORT-4 064C NREPORT-5 0681 NREPORT-8 06A1 NREPORT-9 0683 NREPORT-L 0934 NREPORT-N 0906 NUM-ARR 0819 NXT-1 01A3 NXT-B-MAP 1351 NXT-BYTE 1431 NXT-ENTRY 0AD4 NXT-MOTOR 1597 NXT-SCT 1279 NXT-STRM 144A NXTCHAN 11E5 OFF-MOTOR 1586 OP-B-CHAN 1FF6 OP-CHAN 186A OP-F-1 1B16 OP-F-2 1B41 OP-F-3 1B46 OP-F-4 1B49 OP-F-5 1B5B OP-F-X 1B26 OP-M-C 0529 OP-M-STRM 1ACC OP-PERM-N 0F52 OP-RS-CH 0B17 OP-RSCHAN 0B4E OP-RUN 1ABF OP-STREAM 0B51 OP-STRM 1859 OP-TEMP-M 1B05 OP-TEMP-N 0F46 OPEN-N-ST 0F40 OPEN-RS 051C OPEN-SYN 04ED ORD-NAM 1CC1 OREP-1-2 073C OREPORT-1 04B2 OREPORT-8 0D82 OT-NAMS 1D22 OUT-BLK-N 0E30 OUT-CODE 1EE3 OUT-M-BLK 15B7 OUT-M-BUF 15B3 OUT-M-BYT 15D0 OUT-M-HD 15AD OUTMEM 0F9E OUTMEM2 119A OUTPAK 1082 OUTPAK-L 1089 PAR-1 079F PAR-2 07B2 PR-REP-LP 02A7 PRCHAR 1D71 PREP-MARK 1C35 PRINT-SPC 0C9A PRNAME 1D5B PRNM-LP 1D5E PROG 0753 PROG-LINE 0130 PRT-OUT 1EF0 PT-N-CHAN 17EB RCL-T-CH 17B7 RCLM-CH 177D RCLM-MAP 11EF RCLM-NUM 0182 RCLM-OLD 09EC RD-BYT-1 1696 RD-BYT-2 169D RD-BYT-3 16A5 RD-NEXT 1F7A RD-RANDOM 1F0B RD-SECTOR 1F3F RDLOOP1 165C RDLOOP2 165E RDLOOP3 1669 RDLOOP4 166B RE-MAP 1A1E RE-MAP-LP 1A2E READ-BLK 165A READ-RS 0BAF READ-SEQ 1EFD READY-R2 1686 READY-RE 162A REC-BYTE 0B95 REC-PROC 0B98 REP-MSG 0260 REPTEST 154C RES-B-MAP 13E3 RES-VARS 0255 REST-MAP 1476 REST-N-AD 1A82 REST-STRM 1444 RETAD-RUN 05DD RETAD-SYN 05E0 RMERR-2 0040 ROMERR 0028 ROTATE 13DD RS-SH 1AC5 RS-SH2 11A3 RUNTIME 011B RWF-ERR 1132 S-BLK-END 0881 S-PACK-1 0E48 S-SC-DEL 103A S-STAT 016F SA-B-END 0895 SA-BLK-LP 0872 SA-BLOCK 086E SA-BYTE 0884 SA-DRI-2 1921 SA-DRI-3 1929 SA-DRI-4 194F SA-DRI-WR 1943 SA-DRIVE 18CB SA-HEADER 084F SA-MAP 1A04 SA-MAP-LP 1A11 SA-NET 0892 SAVE-M 0849 SAVE-RUN 1AC4 SAVE-SYN 082F SC-L-LOOP 0133 SCOUT-END 1013 SCREEN$ 0771 SE-NAME 1CA0 SEL-DRIVE 1532 SEND-BLK 135A SEND-NEOF 0FAE SEND-PACK 0E4F SEND-RESP 107B SEND-SC 101E SENDSCOUT 0E77 SEPARATOR 05B1 SER-IN2 0C1B SER-OUT-L 0D2C SERIAL-IN 0BD6 SET-BAUD 0ACD SET-PROG 0A19 SET-T-MCH 10A5 SH-ERR 0020 SIGN-ERR 15DE SKIP-NUM 014E SP-DL-1 0E93 SP-N-END 0EA2 SPC-COUNT 0C8C ST-BF-LEN 0E25 ST-END 05B7 ST-ERROR 0068 ST-MAP-AD 1168 ST-SHADOW 0008 START-2 009A START-3 00A5 START-4 00BC START-BIT 0BCF STAR-SA 18D9 STCHK 1439 STO-DISP 1463 STORE-COD 0CB8 STORE-DSP 1AFF STORE-LEN 0F30 SW-MOTOR 1565 SYNC-RD 167C T-CH-NAME 1135 T-FURTHER 0BF7 T-INPUT 0B76 T-LD-NET 09E2 T-M-COOE 0915 T-NA-1 1CAA T-NA-2 1CB5 T-OTHER 1E31 TAB-MOD 0CEE TAB-PROC 0CB5 TAB-SERV 0CC8 TABLOOP 0CF9 TABZERO 0CF4 TCHAN-IN 0B82 TCHAN-OUT 0C3A TEST-BAUD 06B0 TEST-BLKN 0EE2 TEST-BRK 163E TEST-BUFF 0DBB TEST-CODE 00E9 TEST-DTR 0D21 TEST-LOW 013B TEST-N-BF 120F TEST-MAP 1143 TEST-MCHL 11D0 TEST-MNAM 0685 TEST-NEXT 060C TEST-OUT 0E17 TEST-PMAP 13E8 TEST-RET 05BF TEST-SAVE 07A7 TEST-SCT 1BDF TEST-SP 003A TEST-STAT 068F TEST-TYPE 08F6 TIME-OUT 0DFC TON-DELAY 1344 TRY-AGAIN 0DE2 TS-L-NET 08D1 TS-L-RS 08D7 TST-AGAIN 0BC3 TST-MERGE 0908 TST-MR-M 098C TST-MR-N 0998 TST-N-EOF 0DD5 TST-NUM 1DE5 TST-PLACE 1A9D TST-SPACE 09C2 TST-TYPE 09CB TST-WIDTH 0CE6 TURN-ON 153D UNPAGE 0700 UNT-MARK 108F UNTIL-MK 106B UNTILFIVE 1A64 UPD-NXT-S 17A2 UPD-POINT 1469 UPD-STRM 1787 USE-C-RC 1F57 USE-R 1899 USE-REC 19D0 VAR~EXIST 023D VE-FAIL 1A55 VE-M-E 1A49 VERIFSYN 08A2 VR-BN 0A8E VR-DATA 0803 WAIT-1 0BEE WAIT-2 0BEF WR-BLK 16AF WR-BYT-1 16C4 WR-BYT-2 16C8 WR-BYT-3 16CD WR-F-TEST 1BAB WR-RECD 12DA WR-S-1 1FA1 WR-S-2 1FB3 WR-S-3 1FBB WR-SECTOR 1F85 WRITE-PRC 12EE WT-SC-E 0FD3 WT-SCOUT 0FD6 WT-SYNC 0FED WTKEY 1ED2 APPENDIX 11 What to do if you have an unknown ROM If you should find that your Interface 1 contains a ROM which differs from both the edition 1 and the edition 2 Shadow ROM, then the code to implement the extended BASIC commands that is given in this book will not work. This is because the code that we have given contains a number of calls to routines in the Shadow ROM, which perform a number of useful tasks, such as selecting Microdrives, reading a sector of tape, displaying hexadecimal numbers on the screen, etc. Many of these routines are at different locations in the first two editions of the ROM, and presumably they would be different again in any future ROMs. This does not, however mean that it is not possible for you to add the expanded BASIC commands to your machine. The code that we have given is still quite correct, but the calls it makes to the ROM are no longer accurate. The solution, then is to add to the extended BASIC commands routines of your own which have the same names as the ROM routines, and will perform the same functions. This doesn't mean that you'll have to write all these routines - all the code you need is contained in the Shadow ROM disassembly given earlier in this book. Simply find the routine you need in the Shadow ROM disassembly, and copy it into your program. Consider the following example: The extended BASIC command '*L n' includes the following code: LD H,B ;move it into HL LD L,C AGAIN LD A,H ;display high byte of address in hex CALL DISP-HEX LD A,L ;display low byte This wont work as it stands, as it includes a call to the Shadow ROM routine DISP-HEX, and the address given for DISP-HEX in the table of EQU statements will not be correct. What you should do to make this work is to remove the entry for DISP-HEX from the EQU table, and then look up the entry for DISP-HEX in the alphabetical list of labels (Appendix 2.). According to this, the DISP-HEX routine is at 1E87H. Look this up in the disassembly, and add the routine you find (shown below) to the end of your program. DISP-HEX PUSH AF RRA RRA RRA RRA CALL DISP-NIB POP AF DISP-NIB AND 0FH CP 0AH JR C,CONV-1 ADD A,7 CONV-1 ADD A,30H CALL DISP-CH RET Note, however, that this routine makes its own call to another Shadow ROM routine, DISP-CH, which you will also have to add to your code. DISP-CH is located at 1EA9 in the disassembly, and is as follows: DISP-CH PUSH HL PUSH DE PUSH BC PUSH AF EXX PUSH HL PUSH DE PUSH BC PUSH AF LD HL,(CURCHL) PUSH HL PUSH AF LD A,2 RST CALBAS DEFW 1601H POP AF RST CALBAS DEFW 10H POP HL LD (CURCHL),A POP AF POP BC POP DE POP HL EXX POP AF POP BC POP DE POP HL RET Doing the same thing with all the other Shadow ROM calls should make it possible for you to run all the extended BASIC commands. Note that the program, as it stands, fits into the very highest part of memory, with no room above it to spare. The code you will be adding will make the extended commands somewhat longer. Because of this, you will have to ORG your program to an earlier location, in order for it to fit into memory. Remember that when you initialise the new commands from BASIC, you should no longer use RANDOMISE USR 63744 but instead use RANDOMISE USR x where x is the location at which your assembler program is ORGed.