.The +D system variables and tables THE 'SYSTEM VARIABLES' These variables hold various settings for drives etc. The variables starting at address #2000 can be accessed from BASIC with POKE @p,n. Where p is 0 for RBCC at #2000. 2000 RBCC DEFB #07 Flashing borders. 2001 TRAKS1 DEFB 80+128 Drive 1 80 tracks double sided. 2002 TRAKS2 DEFB 80+128 Drive 2 80 tracks double sided. 2003 STPRAT DEFB 0 "Steprate" 0 msec. 2004 NSTAT DEFB 1 Network on? 2005 WIDTH DEFB 80 Printer right margin. 2006 PCODE DEFB 0 Expand tokens, etc. before printing. 2007 LSPCE DEFB 12 Line spacing 12/72 inch. 2008 LFEED DEFB 1 Number of line feeds after CR 1. 2009 LMARG DEFB 0 Left margin at 0. 200A GRAPH DEFB 0 Print special graphics off. 200B ZXPNT DEFB 0 +D printer port on. 200C RESERVED DEFW #0000 200E ONERR DEFW #0000 Address of routine called after an error has occurred. 2010 EVERY_INT DEFW #208F Address of routine called at every interrupt. THE 'PRINTER CODES' TABLE Here the printer control codes are stored. 2012 INIT_PRT DEFB 27,"@",#80,#80 2016 DEFB #80,#80,#80,#80 201A CHAR_PITCH DEFB #80,#80,#80,#80 201E DEFB #80,#80,#80,#80 2022 N/72_LSPC DEFB 27,"A",#80,#80 2026 DEFB #80,#80,#80,#80 202A GRAPH_DPI DEFB 27,"*",5,#80 202E DEFB #80,#80,#80,#80 2032 INIT_PRT2 DEFB #80,#80,#80,#80 2036 DEFB #80,#80,#80,#80 THE 'GRAPHIC REPRESENTATION' TABLE This table consists of the graphic representations of the £, # and © signs. The 'GRAPH' system variable (@10) determines whether the normal code or the graphic representation is outputted to the printer. 203A £_SIGN DEFB %00011000 203B DEFB %00100000 203C DEFB %00100000 203D DEFB %01111000 203E DEFB %00100000 203F DEFB %00100000 2040 DEFB %01111100 2041 DEFB %00000000 2042 #_SIGN DEFB %00000000 2043 DEFB %00100100 2044 DEFB %01111110 2045 DEFB %00100100 2046 DEFB %00100100 2047 DEFB %01111110 2048 DEFB %00100100 2049 DEFB %00000000 204A ©-SIGN DEFB %01111110 204B DEFB %10000001 204C DEFB %10111101 204D DEFB %10100001 204E DEFB %10100001 204F DEFB %10111101 2050 DEFB %10000001 2051 DEFB %01111110 THE 'GREYSCALE' PRINTER CONTROL CODE This code is outputted to the printer if a 'SCREEN$ 2' screendump is wanted. 2052 GREY_BITIM DEFB 27,"*",5,#40 2056 DEFB #02,#80,#80,#80 THE 'GREYSCALE' TABLE This table consists of three times three bytes of greyscale info. Each screen pixel is converted into 3x3 printer dots during greyscale printing. The printer dots are ordered as follows: The first dot row is produced from the first three bytes by taking the bit, which number is corresponding with the colour number, from each of the three bytes. E.g. for colour 2 (=red) bit 2 is used. In the same way the second and third dot rows are produced from the second and third three bytes respectively. The following eight 3x3 matrices are produced: White Yellow Cyan Green Magenta Red Blue Black 000 000 100 000 100 010 110 111 000 010 010 101 111 111 111 111 000 000 001 000 001 010 011 111 Note that some greytones aren't right. E.g. cyan is darker than green, which isn't so on the screen. colour 76543210 205A GREYSCALE DEFB %00101011 205B DEFB %00011111 first row 205C DEFB %00000001 205D DEFB %00000111 205E DEFB %01101111 second row 205F DEFB %00000111 2060 DEFB %00000001 2061 DEFB %00011111 third row 2062 DEFB %00101011 2063 DEFW #1429,P_ALL Address of 'output' routine for "P". 2065 DEFB #00 The 'ENTER' flag. 2066 DEFW #0000 D_ERR_SP 2067 DEFB #00 THE 'SNAPSHOT-FILE' UFIA The following bytes are the last 20 bytes of a snapshot file UFIA. 2068 SNAP_UFIA DEFB 0 Directory description. 2069 DEFM "Snap " File name. 2073 DEFB 3 File type. 2074 DEFW #0000 File length. 2076 DEFW #0000 File address. 2078 DEFW #0000 Not used with Snap's. 207A DEFW #FFFF Not used with Snap's. SOME 'LOST' ASSEMBLER TEXT Miles-Gordon seem to have lost some of their assembler text. 207C DEFM "JP" 207E DEFB #07 207F DEFB "Z" THE 'RAM JUMPS' These 13 'jumps' are used from the ROM to call +D System routines present in RAM (after the System file has been loaded). 2080 JCOPS NOP The small dump isn't patched. 2081 NOP 2082 RET 2083 JCOPS2 NOP Neither is the greyscale dump. 2084 NOP 2085 RET 2086 JPCHAN NOP Nor the PCHAN_OUT routine. 2087 NOP 2088 RET 2089 JPOKE NOP Nor the POKE routine. 208A NOP 208B RET 208C JPRTR NOP Even the TAKE_PRTR routine isn't 208D NOP patched. 208E RET 208F JJIFFY NOP Called EVERY_INT. 2090 NOP 2091 RET 2092 JLOAD JP #28EE,LD_VF_MR1 Load the file. 2095 JHXFER JP #2F8B,HXFER Transfer UFIA to DFCA. 2098 JKSCAN JP #2245,JIFFY Called every interrupt. 209B JMSG3 JP #3090,MSG_3 Give the copyright message. 209E JHOOK JP #228E,HOOK_CODE Execute the hook or command code. 20A1 JSNAP JP #2115,SNAP Continue with the Snapshot routine. 20A4 JCTRL JP #20A7,CTRL Continue with the control routine. THE 'CONTROL ROUTINE' CONTINUED The final part of the control routine determines which command failed the Spectrum syntax. If it is a +D command then the apropriate routine is executed. 20A7 CTRL PUSH AF 20A8 LD HL,#3DF4 20AB LD BC,60 20AE RESET_VARS LD (HL),255 Reset +D work areas, including UFIA1 20B0 INC HL and UFIA2. 20B1 DEC BC 20B2 LD A,B 20B3 OR C 20B4 JR NZ,#20AE,RESET_VARS 20B6 LD (#3ACF),A Clear FLAGS3. 20B9 LD IX,#3AC3 Point to +D system variables. 20BD POP AF Fetch the command. 20BE LD (#3DFF),A Store it. 20C1 CP 207 Is the command 'CAT' ? 20C3 JP Z,#245B,CAT Jump to the CAT routine if so. 20C6 CP 208 Also for 'FORMAT',... 20C8 JP Z,#2AB9,FORMAT 20CB CP 209 ...'MOVE',... 20CD JP Z,#2B03,MOVE 20D0 CP 210 ...'ERASE',... 20D2 JP Z,#250C,ERASE 20D5 CP 211 ...'OPEN #',... 20D7 JP Z,#2C68,OPEN 20DA CP 212 ...'CLOSE #',... 20DC JP Z,#2E16,CLOSE 20DF CP 213 ...'MERGE',... 20E1 JP Z,#28E4,MERGE 20E4 CP 214 ...'VERIFY',... 20E6 JP Z,#28DF,VERIFY 20E9 CP 239 ...'LOAD',... 20EB JP Z,#28DA,LOAD 20EE CP 248 ...'SAVE',... 20F0 JP Z,#288B,SAVE 20F3 CP 251 ...'CLS',... 20F5 JP Z,#2EB9,CLS 20F8 CP 253 ...'CLEAR',... 20FA JP Z,#2E39,CLEAR 20FD CP 255 ...'COPY',... 20FF JP Z,#3020,COPY 2102 LD HL,(#200E) Fetch ONERR address. 2105 LD A,H 2106 OR L 2107 RET Z Return if no ON ERROR address. 2108 LD (#2110),HL Store it so it can be CALBASsed. 210B POP HL Drop return address. 210C LD A,(#3DFF) Fetch command which has to be examined 210F RST #10,CALBAS by user-routine (BASIC extensions). 2110 DEFW #0000 CALL the extend BASIC routine(s). 2112 JP #047C,END Test end of command and exit. THE 'SNAPSHOT ROUTINE' CONTINUED Here the snapshot routine continues with the disk related functions, keys 3-5. 2115 SNAP LD HL,16384 start of RAM (also start of SCR$). 2118 BIT 2,E 211A JR NZ,#2123,NO_SCR 3: Save SCREEN$. 211C LD A,7 type=SCR$. 211E LD DE,6912 length of SCR$. 2121 JR #2139,SNAP_SAVE 2123 NO_SCR BIT 3,E 2125 JR NZ,#212E,NO_SNP48 4: 48K Snapshot. 2127 LD A,5 type=48K Snap. 2129 LD DE,49152 length of 48K RAM. 212C JR #2139,SNAP_SAVE 212E NO_SNP48 BIT 4,E 2130 RET NZ Exit if not 5: 128K Snapshot. 2131 LD A,9 Type=128K Snap. 2133 LD DE,16384 Length of a RAM-page. 2136 LD HL,49152 Start of a RAM-page. 2139 SNAP_SAVE LD (#2068),A Store type in snapshot UFIA. 213C LD (#2074),DE Store length in UFIA. 2140 LD (#2076),HL And the start-address. 2143 POP AF Drop return addres. 2144 LD B,#FE Key CAPS-V I/O address. 2146 IN A,(C) 2148 BIT 0,A 214A JR NZ,#2154,SNAP_NAME If CAPS is pressed the Snap goes to 214C LD A,(#3ACE) the other drive. 214F XOR #03 2151 LD (#3ACE),A 2154 SNAP_NAME LD A,%01000000 2156 CALL #09A5,SCAN_CAT Search first free catalogue entry. 2159 RET NZ Exit if catalogue full. 215A LD A,D Track to A. 215B AND #07 Jump if CAT-entry will be located 215D JR Z,#2164,SNAP_N1 on track 0. The name a snapshot-file is given, depends on the position it's going to occupy in the directory. When the entry will be located on the first track the names range from 'Snap A' to 'Snap T', if however the entry will be located on track 1 to 3 the character after 'Snap' will be the track number. I.e. 'Snap1A' to 'Snap1T' for track 1, etc. Notice that the character after 'Snap' is never set to a ' '. 215F ADD A,48 ASCII offset for '0'. 2161 LD (#206D),A Store a 1, 2 or 3 in name-part of UFIA. 2164 SNAP_N1 LD L,E Store sector in L. 2165 SLA L Two entries per sector. 2167 DEC L 2168 LD A,(IX+14) Is it the first or second entry in the 216B ADD A,L CAT-sector. 216C ADD A,64 Add ASCII 'A' offset. 216E LD (#206E),A Store 'A' to 'T' in name-part of UFIA. 2171 LD HL,#2068,SNAP_UFIA Copy UFIA to DFCA. 2174 LD DE,#3E05 2177 LD BC,20 217A LDIR 217C CALL #0AD9,OFSM_2 Open the file. 217F LD HL,#3FEA Copy snap registers to catalogue entry. 2182 LD DE,#3BB2 2185 LD BC,22 2188 LDIR 218A LD A,(#2068) Get directory description. 218D CP 9 218F JP NZ,#222D,NO_SNP128 Jump if not a 128K Snapshot. 2192 LD HL,49152 Now the 5 first bytes of the current 2195 LD DE,#3BD6 RAM-page are saved in the +D RAM 2198 LD BC,5 and replaced by the "BRUCE" message. 219B LDIR This is done to determine the currently 219D LD HL,#2228,BRUCE paged in RAM-page. 21A0 LD DE,49152 21A3 LD BC,5 21A6 LDIR 21A8 XOR A Signal '128K ROM bank active'. 21A9 LD (#3E19),A 21AC CALL #011D,?_ROMBANK Determine current 'main' ROM bank. 21AF JR NZ,#21B6,SNP128_1 Jump if 128K ROM bank. 21B1 LD A,#10 Signal '48K ROM bank active'. 21B3 LD (#3E19),A 21B6 SNP128_1 CALL #0511,REST_PBUF Restore printer buffer contents. 21B9 LD A,(#3E19) 21BC CALL #223F,RAMPAGE_A Page in current ROM bank & RAM page 0. The code now tests which screen is active. Because it isn't possible to detect which is the active screen, the user is consulted. By making nice border stripes the user is signalled that 'Y' (meaning: yes, screen changed) or 'N' (meaning: no, screen hasn't changed) has to be pressed. 21BF SNP128_2 LD BC,#DFFE Keyboard port and I/O address for Y-P. 21C2 IN E,(C) 21C4 BIT 4,E 21C6 JR Z,#21D7,CHANGED_$ Jump if 'Y' was pressed, screen changed 21C8 LD B,#7F I/O address for B-SPACE. 21CA IN E,(C) 21CC BIT 3,E 21CE JR Z,#21E2,SAME_$ Jump if 'N' was pressed, same screen. 21D0 INC A 21D1 AND #07 21D3 OUT (C),A Make nice stripes in border again. 21D5 JR #21BF,SNP128_2 Only 'Y' or 'N' is accepted. 21D7 CHANGED_$ LD A,(#3E19) 21DA OR #08 Signal 'screen 1'. 21DC ?_RAMBANK LD (#3E19),A 21DF CALL #223F,RAMPAGE_A Page in active ROM bank and screen. Now the 'which RAM bank' test is executed. The active RAM bank is determined by searching which bank has been given the "BRUCE" message. 21E2 SAME_$ LD DE,49152 Here the message has been placed. 21E5 LD HL,#2228,BRUCE Message to be found. 21E8 LD B,5 There are five bytes in the message. 21EA BRUCE_1 LD A,(DE) 21EB CP (HL) 21EC JR Z,#21F4,BRUCE_2 Jump if characters match. 21EE LD A,(#3E19) Otherwise it has to be one of the other 21F1 INC A banks. 21F2 JR ?_RAMBANK 21F4 BRUCE_2 INC DE 21F5 INC HL 21F6 DJNZ #21EA,BRUCE_1 All five characters have to match. 21F8 LD HL,#3BD6 The active RAM bank has been found, 21FB LD DE,49152 restore the original five bytes. 21FE LD BC,5 2201 LDIR 2203 LD A,(#3E19) 2206 PUSH AF Save the page-configuration byte in the 2207 CALL #0761,SBYT snapshot file. 220A AND #F8 Mask RAM bank, start with 0. 220C LD B,8 There are eight RAM banks 220E SAVE_BANK PUSH AF 220F PUSH BC 2210 CALL #223F,RAMPAGE_A Page in RAM bank. 2213 LD HL,(#2076) 2216 LD DE,(#2074) 221A CALL #0850,HSVBK_2 Save DE bytes starting at address HL. 221D POP BC 221E POP AF 221F INC A Next RAM bank. 2220 DJNZ #220E,SAVE_BANK Loop for all eight 16K RAM banks. 2222 POP AF 2223 CALL #223F,RAMPAGE_A Page in original RAM bank. 2226 JR #223C,SNAP_CLOSE 2228 BRUCE DEFM "BRUCE" 222D NO_SNP128 CP 7 Copy the 9 header bytes to the file if 222F CALL Z,#2879,SAVE_HEAD1 it is a SCREEN$. 2232 LD HL,(#2076) 2235 LD DE,(#2074) 2239 CALL #0850,HSVBK_2 Save DE bytes starting at address HL. 223C SNAP_CLOSE JP #0B89,CFSM Close the file. THE 'PAGE 128K RAM' ROUTINE The 128K RAM-bank contained in the A register is paged-in. 223F RAMPAGE_A LD BC,#7FFD 128K bank-switch port address. 2242 OUT (C),A Select RAM bank. 2244 RET THE 'JIFFY' CALL This routine is executed whenever KEY-SCAN in the Spectrum ROM is reached at #028E. It can be used to executed a routine with every interrupt. 2245 JIFFY LD HL,(#2010) Call routine which has to be called 2248 JP (HL) every 'interrupt'. (Normal #208F) THE 'MOUSE' ROUTINE This routine is also present in the DISCiPLE and tests a mouse-like device. Pointers which seem to keep track of screen coordinates are updated when necessary. 2249 TEST_MOUSE LD BC,#03FF The MGT mouse port? 224C IN A,(C) 224E BIT 7,A 2250 RET NZ Return if no activity. 2251 CPL 2252 AND #05 Return if there was no horizontal or 2254 RET Z vertical movement. 2255 LD HL,#228B,SIGN_MOUSE 2258 PUSH HL 2259 LD HL,#2275,MOVE_VERT 225C PUSH HL 225D IN D,(C) Read mouse bits again. 225F LD HL,#3DF1 Mouses x-coordinate. 2262 BIT 0,D 2264 RET NZ Return to vertical movement test. 2265 BIT 1,D 2267 JR Z,#226F,MOVE_RIGHT Jump if mouse was moved right. 2269 LD A,0 Left side of screen. 226B CP (HL) 226C RET Z Return if left movement isn't possible. 226D DEC (HL) Otherwise decrement x-coordinate. 226E RET 226F MOVE_RIGHT LD A,255 Right side of screen. 2271 CP (HL) 2272 RET Z Return if right movement impossible. 2273 INC (HL) Otherwise increment x. 2274 RET 2275 MOVE_VERT LD HL,#3DF2 Y-coordinate of mouse. 2278 BIT 2,D 227A RET NZ Return to signal mouse. 227B BIT 3,D 227D JR NZ,#2285,MOVE_UP Jump if mouse was moved up. 227F LD A,0 Bottom side of screen. 2281 CP (HL) 2282 RET Z Return if bottom has been reached. 2283 DEC (HL) Otherwise move towards it. 2284 RET 2285 MOVE_UP LD A,175 Top side of screen. 2287 CP (HL) 2288 RET Z Return if top was reached. 2289 INC (HL) Otherwise increment y-coordinate. 228A RET 228B SIGN_MOUSE OUT (C),D Give original signal to mouse. 228D RET .The Hook and Command code routine & The Command code table This routine is entered with the A register holding an 'IF1 hook code', a '+D command code' or an invalid error code. The routine calls a set of subroutines in the +D system, and is intended to help machine-code access to the drives. There are two tables containing addresses of the routines, the first is located in ROM (at #0DD7) and consists of the addresses of the routines for the IF1 hookcodes. The second table is located at address #22DE and consists of the addresses of the +D command code routines. 228E HOOK_CODE LD (#3AC5),DE 2292 CP 24 2294 JR NC,#22BC,COMM_CODE Jump if code isn't a hook code. 2296 LD DE,#0DD7,IF1_HOOK Address of hook (IF1) code table. 2299 CODE_CONT LD (IY+0),#FF Clear error. 229D SET 2,(IY+1) What's the purpose of this? 22A1 INC HL Advance return address past the code. 22A2 PUSH HL 22A3 ADD A,A Table is made of two byte addresses, so 22A4 LD L,A double code. 22A5 LD H,0 22A7 ADD HL,DE Point codes entry in table. 22A8 LD E,(HL) Fetch the address of the routine. 22A9 INC HL 22AA LD D,(HL) 22AB LD HL,#22C8,HOOK_RET Return address after completion of 22AE PUSH HL code. 22AF LD (#2066),SP Set D_ERR_SP. 22B3 EX DE,HL 22B4 LD DE,(#3AC5) Restore DE and A. 22B8 LD A,( #3E4F) 22BB JP (HL) Jump to the routine. 22BC COMM_CODE SUB 24 Adjust range for command codes (0..20). 22BE CP 21 22C0 JP NC,#1666,REP_17 Give error if not a command code. 22C3 LD DE,#22DE,MGT_HOOK Address of command code table. 22C6 JR #2299,CODE_CONT Continue with command codes. THE 'HOOK_RET' ROUTINE This routine is entered whenever a hook or command code is finished. 22C8 HOOK_RET PUSH HL 22C9 LD HL,#0000 22CC LD (#2066),HL Clear D_ERR_SP. 22CF POP HL 22D0 CALL #168E,BORD_REST Return to the calling routine with the 22D3 JP #0050,UNPAGE_1 'main' ROM paged in. THE 'PAGE-IN +D' SUBROUTINE This is called by using 'command code' 71. On return the +D is paged-in and the HL register contains 0, to indicate that this is a +D (with a DISCiPLE HL holds 1). 22D6 PATCH POP HL Drop 'HOOK_RET' return address. 22D7 LD HL,#0000 Clear 'D_ERR_SP'. 22DA LD (#2066),HL 22DD RET HL=0, meaning 'this is a +D'. THE 'COMMAND CODE ADRESSES' TABLE This jump table consists of the 21 addresses of the routines called by using the various 'command codes'. 22DE MGT_HOOK DEFW #2F8B,HXFER Command code #33, 51. 22E0 DEFW #2F9E,OFSM Command code #34, 52. 22E2 DEFW #2FA4,HOFLE Command code #35, 53. 22E4 DEFW #0761,SBYT Command code #36, 54. 22E6 DEFW #2FAB,HSVBK Command code #37, 55. 22E8 DEFW #0B89,CFSM Command code #38, 56. 22EA DEFW #15C9,PNTP Command code #39, 57. 22EC DEFW #12D2,COPS Command code #3A, 58. 22EE DEFW #2FB1,HGFLE Command code #3B, 59. 22F0 DEFW #077F,LBYT Command code #3C, 60. 22F2 DEFW #2FB7,HLDBK Command code #3D, 61. 22F4 DEFW #3016,JWSAD Command code #3E, 62. 22F6 DEFW #300F,JRSAD Command code #3F, 63. 22F8 DEFW #06B6,REST Command code #40, 64. 22FA DEFW #2FBD,HERAZ Command code #41, 65. 22FC DEFW #133E,COPS2 Command code #42, 66. 22FE DEFW #3154,PCAT Command code #43, 67. 2300 DEFW #2FD4,HRSAD Command code #44, 68. 2302 DEFW #2FF2,HWSAD Command code #45, 69. 2304 DEFW #3110,OTFOC Command code #46, 70. 2305 DEFW #22D6,PATCH Command code #47, 71. .The BASIC command execution routines I THE 'COPY FILE(S)' ROUTINE This routine handles the copying of files. It is executed as soon as the 'EXPT_PARMS' routine at #2665 finds a 'TO' keyword. The return address to the routine which called 'EXPT_PARMS' is dropped at #230E. 2308 TO CALL #3108,TEST_SAVE 230B JP Z,#1644,REP_0 Give error if not SAVEing. 230E POP HL Drop return address to SAVE routine. 230F CALL #2626,SWAP_UFIAS Swap the UFIAS. 2312 RST #28,NEXT_C 2313 AND #DF Drop lower case bit. 2315 CP 68,"D" 2317 JP NZ,#1644,REP_0 Jump if 2nd device isn't "D". 231A LD (#3E04),A Store it in DEV_TYPE1. 231D CALL #25E2,EXPT_DEVN Evaluate drive num., store it in UFIA1. 2320 CALL #25A2,SEPARATOR Test for a separator, jump if one 2323 JR Z,#2328,TO_1 found, i.e. a 2nd name is given. 2325 CALL #1608,SIGN_4 Used here to signal 'use source filename for destination file'. 2328 TO_1 CALL Z,#2640,EXPT_FNAME Evaluate filename if there was a separator. 232B CALL #2626,SWAP_UFIAS Swap the UFIAS again. 232E CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 2331 LD HL,#3E1E Copy the second filename and directory 2334 LD DE,#3E32 description. 2337 LD BC,11 233A LDIR 233C LD HL,#0001 Track 0 sector 1. 233F LD (#3DED),HL 2342 LD HL,#0000 Disk buffer offset #0000. 2345 LD (#3DEB),HL 2348 TO_2 CALL #0702,TEST_DRV Is the drive defined? 234B CALL #23EC,TO_SEARCH Search for a file to be copied. 234E JP NZ,#23BF,TO_EXIT Jump if there are no files left. 2351 CALL #0C04,LOAD_1ST Copy file description (directory description and filename) to UFIA2 and load the first sector of the file into the disk buffer. 2354 LD A,(#3E1E) Get directory description. 2357 CP 5 2359 JR Z,#2348,TO_2 Jump with 'Snapshot 48K'. 235B CP 6 235D JR Z,#2348,TO_2 Jump with 'Microdrive file'. 235F CP 9 2361 JR Z,#2348,TO_2 Jump with 'Snapshot 128K'. 2363 CP 10 2365 JR Z,#2348,TO_2 Jump with 'Opentype file'. 2367 CP 11 2369 JR Z,#2348,TO_2 Jump with 'Execute file'. These five file types can't be copied with the 'SAVE .. TO ..' command. Now the file is going to be copied. NOTE: The file to be copied will destroy everything above 'start of BASIC'+256 and no checks are made if the file fits in memory and if the stack isn't overwritten. 236B CALL #28CD,LOAD_HEAD2 Copy the file header (the 9 bytes consisting of filetype, length, etc.) to UFIA2. 236E LD HL,(23635) Fetch start of BASIC program (PROG). 2371 INC H Add 256 to it. 2372 LD DE,(#3E2A) Fetch length of file (LENGTH2_1). 2376 CALL #079E,LOAD_FILE Load DE bytes, starting at address HL. 2379 CALL #23CB,TO_MSG Print the message "CHANGE disc ...." if source drive is destination drive. 237C CALL #2626,SWAP_UFIAS Swap the UFIA's again. The header of the loaded file is now held in UFIA1. 237F CALL #1630,TEST_4 Used here to test whether a 2nd 2382 JR NZ,#239A,TO_5 filename was given. Jump if not. 2384 LD HL,#3E33 Here the 2nd filename was stored. 2387 LD DE,#3E06 Start of filename of loaded file. 238A LD B,10 Filename length. Now the characters from the filename of the loaded file are replaced by the characters of the 2nd filename. Except when the wildcard characters '*' and '?' were used in the 2nd name. With '*' all next characters are left unchanged, with '?' the current character isn't changed. 238C TO_3 LD A,(HL) 238D CP 42,"*" With a '*' don't replace the remaining 238F JR Z,#239A,TO_5 characters. 2391 CP 63,"?" With a '?' in name 2 don't replace this 2393 JR Z,#2396,TO_4 character. 2395 LD (DE),A Store this character. 2396 TO_4 INC HL 2397 INC DE 2398 DJNZ #238C,TO_3 Repeat for all 'normal' characters. 239A TO_5 CALL #0702,TEST_DRV 239D CALL #0AD9,OFSM_2 Open the file for SAVEing. 23A0 JR NZ,#23B3,TO_6 Jump if file existed already and the user didn't want to overwrite it. 23A2 CALL #2879,SAVE_HEAD1 SAVE the 9 header bytes to the file. 23A5 LD HL,(23635) Fetch start of BASIC (PROG), and add 23A8 INC H 256 to it. (here the file was loaded) 23A9 LD DE,(#3E11) Length of file. 23AD CALL #0850,HSVBK_2 Save the file. 23B0 CALL #0B89,CFSM Close the file. 23B3 TO_6 CALL #2626,SWAP_UFIAS Swap the UFIA's again. 23B6 CALL #15F4,SIGN_0 Signal 'at least one file has been copied' 23B9 CALL #23CB,TO_MSG Print message "Input ..." if necessary 23BC JP #2348,TO_2 Repeat until no more files have to be copied. 23BF TO_EXIT CALL #161C,TEST_0 Give error if there isn't one file 23C2 JP Z,#1678,REP_26 copied. 23C5 LD HL,#11B7,NEW Otherwise jump to the appropriate 'NEW' 23C8 JP #3137,TO_NEW routine (128K or 48K). THE 'PRINT "CHANGE DISC"' SUBROUTINE This subroutine tests whether source and destination drives are equal. If they are the messages "Insert SOURCE disc - press SPACE" and "Insert TARGET disc - press SPACE" are printed in turn. 23CB TO_MSG LD A,(#3E01) Fetch source drive. 23CE LD B,A 23CF LD A,(#3E1A) Fetch destination drive. 23D2 CP B 23D3 RET NZ Return if they aren't equal. 23D4 RST #10,CALBAS Otherwise clear lower screen area. 23D5 DEFW #0D6E,CLS_LOWER 23D7 SET 5,(IY+2) Signal 'lower screen has to be cleared' 23DB CALL #30B5,TO_MSG1 Print "Input ... disc" message. 23DE CALL #0B75,BEEP Give a beep. 23E1 TO_WSPC LD A,#7F Keyboard row B-SPACE address. 23E3 IN A,(254) 23E5 RRA 23E6 JR C,#23E1,TO_WSPC Jump unless the SPACE key is pressed. 23E8 RST #10,CALBAS Clear lower screen. 23E9 DEFW #0D6E,CLS_LOWER 23EB RET Finished. THE 'SEARCH FILES' SUBROUTINE This subroutine searches for files which have to be copied. It returns with the Zero flag set if the current file is to be copied, if the complete directory is searched the routine returns with Zero reset. 23EC TO_SEARCH LD DE,(#3DED) Track & sector to DE. 23F0 LD A,D 23F1 CP 4 Jump if not reached track 4, i.e. 23F3 JR NZ,#23F8,TO_SEARCH1 directory hasn't been read completely. 23F5 CP 0 Reset Zero flag. 23F7 RET The directory isn't finished yet, so read sector and test the file(s). 23F8 TO_SEARCH1 CALL #05CC,RSAD Read sector E from track D. 23FB TO_SEARCH2 CALL #2433,TO_COPY Check if this file is to be copied. 23FE PUSH AF Store result (Zero flag). 23FF LD HL,(#3DEB) Disk buffer offset to HL. 2402 LD A,H 2403 CP 1 2405 JR Z,#2418,TO_NXTSEC Jump if second entry. 2407 LD A,(#3DDA) Fetch current control port status. 240A AND #04 240C JR NZ,#2418,TO_NXTSEC Jump with single density. 240E LD HL,256 Otherwise offset is for second entry. 2411 LD (#3DEB),HL 2414 POP AF Restore Zero flag. 2415 RET Z Return if this file is to be copied. 2416 JR #23FB,TO_SEARCH2 Otherwise next file. The file entries of the current sector have been tested so point to the next sector. 2418 TO_NXTSEC LD HL,0 Offset is for first entry. 241B LD DE,(#3DED) Fetch track and sector. 241F INC E Next sector. 2420 LD A,E 2421 CP 11 2423 JR NZ,#2428,TO_NXT1 Jump if not last sector on this track. 2425 LD E,1 Start with sector 1. 2427 INC D Next track. 2428 TO_NXT1 LD (#3DED),DE Store track & sector. 242C LD (#3DEB),HL Store disk buffer offset. 242F POP AF Restore Zero flag. 2430 RET Z Return if previous file is to be 2431 JR #23F8,TO_SEARCH copied. Otherwise jump. THE 'COPY THIS FILE ?' SUBROUTINE This subroutine checks if the 'current' filename is to be copied. The routine returns with the Zero flag set to signal yes and RPT pointing to the directory description of the file to be copied. 2433 TO_COPY LD HL,#3BD6 Point to start of sector. 2436 LD DE,(#3DEB) Offset to DE. 243A LD (IX+14),D Update RPT (RAM PoinTer (?)). 243D ADD HL,DE Update HL. 243E LD A,(HL) Fetch directory description. 243F AND A 2440 JR NZ,#2444,TO_COPY1 Jump if the file isn't ERASEd. 2442 INC A Reset Zero flag to signal 'do not copy 2443 RET this file' and exit. 2444 TO_COPY1 INC HL Step past directory descriptor. 2445 LD DE,#3E06 DE now points to FILE_NAME1. 2448 LD B,10 A filename is 10 characters long. 244A TO_COPY2 LD A,(DE) Fetch character. 244B CP 42,"*" If it was a '*' all other characters 244D RET Z don't matter. Signal 'copy this one'. 244E CP 63,"?" If it was a '?' this character doesn't 2450 JR Z,#2456,TO_COPY3 matter. 2452 XOR (HL) 2453 AND #DF Upper and lower case? don't bother. 2455 RET NZ Exit if characters are unequal. 2456 TO_COPY3 INC DE Check next character. 2457 INC HL 2458 DJNZ #244A,TO_COPY2 245A RET Finished. THE 'CAT' COMMAND SYNTAX ROUTINE This routine checks that the command is in the form CAT <#s;>d<<;>n$>. 245B CAT LD IX,#3AC3 Point to the +D workspace. 245F LD HL,#3E06 "*" is the default name of the files 2462 LD (HL),42,"*" being CATted. 2464 LD HL,#3E03 Just like #2 is the default output 2467 LD (HL),2 stream. 2469 RST #28,NEXT_C Get next character. 246A CP 13 Give an error if an 'end of line' (CR) 246C JP Z,#1648,REP_2 is found right after "CAT". 246F CP 58,":" 2471 JP Z,#1648,REP_2 Same error for ":". 2474 CP 35,"#" Jump if no stream specified, use 2476 JR NZ,#2481,CAT_DRV default stream #2. 2478 CALL #2AEF,EXPT_#NR Evaluate stream number. 247B CALL #25A2,SEPARATOR Check if there is a separator. 247E JP NZ,#1644,REP_0 Give an error if no separator found. 2481 CAT_DRV CALL #25FA,EXPT_DEVN2 Evaluate drive number. 2484 CALL #25A2,SEPARATOR Evaluate filename if there is a 2487 CALL Z,#2640,EXPT_FNAME separator. 248A CP 33,"!" If there is no "!" then an extended 248C JR NZ,#2499,EXT_CAT catalogue is given. 248E RST #28,NEXT_C Next character. 248F CALL #3148,ST_END_RAM Confirm end of statement and exit when syntax checking. 2492 CALL #0702,TEST_DRV See if drive is defined. 2495 LD A,%00000010 Signal 'small' CAT. 2497 JR #24A4,DO_CAT1 2499 EXT_CAT CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax time. 249C RST #10,CALBAS Clear the screen by calling 'main' ROM 249D DEFW #0DAF,CL_ALL routine. 249F DO_CAT CALL #0702,TEST_DRV See if drive is defined. 24A2 LD A,%00000100 Signal extended CAT. 24A4 DO_CAT1 CALL #24B5,CAT_RUN Give the CAT. 24A7 JP #047C,END Finished. THE 'CAT' COMMAND ROUTINE This routine makes a catalogue of the disk inserted in the specified drive, by calling the +D ROM routine 'SCAN_CAT'. 24AA CAT_1 LD HL,#3E06 Point to name. 24AD LD (HL),42,"*" All files. 24AF LD HL,#3E03 Point to stream number. 24B2 LD A,2 Make it stream 2. 24B4 LD (HL),A 24B5 CAT_RUN PUSH AF 24B6 LD A,(#3E03) 24B9 RST #10,CALBAS Open the desired stream by calling 24BA DEFW #1601,CHAN_OPEN 'CHAN_OPEN' in the 'main' ROM. 24BC LD A,13 24BE CALL #1799,PRT_A Printing starts on the next line. 24C1 CALL #304B,MSG_0 Print the 1st part of "DIR"-message. 24C4 LD A,(#3ACE) Fetch current drive. 24C7 AND #03 Only bits 0&1. 24C9 OR #30 Make ASCII "1" or "2". 24CB CALL #1799,PRT_A Print drive number. 24CE CALL #3061,MSG_1 Print the 2nd part of "DIR"-message. 24D1 LD HL,0 Reset 'total number of sectors' 24D4 LD (#3DD8),HL occupied. 24D7 POP AF Restore 'CAT' type. 24D8 CALL #09A5,SCAN_CAT Print the CAT entries. 24DB CALL #3072,MSG_2 Print "Free ..." message. 24DE CALL #0985,DRV_CAP Get drive capacity in A register. 24E1 PUSH BC 24E2 BIT 7,A 24E4 JR Z,#24E7,CAT_RUN1 Jump if drive is single sided. 24E6 ADD A,A Otherwise double the number of tracks and get rid of the side bit. 24E7 CAT_RUN1 SUB 4 Subtract number of catalogue tracks. 24E9 LD HL,0 24EC LD B,10 Each track has 10 sectors. 24EE LD D,0 Number of tracks to DE. 24F0 LD E,A 24F1 CAT_RUN2 ADD HL,DE Calculate total number of sectors. 24F2 DJNZ #24F1,CAT_RUN2 24F4 POP BC 24F5 NOP New code is two bytes shorter. 24F6 NOP 24F7 LD DE,(#3DD8) Get number of used sectors. 24FB XOR A Clear carry. 24FC SBC HL,DE Calculate number of free sectors. 24FE SRL H Divide it by two to get number of free 2500 RR L K-bytes. 2502 XOR A 2503 CALL #174C,PRT_N1000 Print the number. 2506 LD A,13 2508 CALL #1799,PRT_A Print a newline. 250B RET THE 'ERASE' COMMAND SYNTAX ROUTINE This routine checks that the command is in the form ERASE *n$ to erase a file or ERASE *n1$ TO n2$ to rename a file. The '*' stands for +D syntax ('d'd<;>) or Microdrive syntax ('"m"';d;). 250C ERASE RST #28,NEXT_C Get next character. 250D LD (#3E04),A Store the device descriptor. 2510 CP 34,""" Test for Microdrive syntax if it was a 2512 CALL Z,#25C2,MD_SYN1 quote. 2515 CALL #25E2,EXPT_DEVN Evaluate the drive number. 2518 CALL #25A2,SEPARATOR Test for a separator. 251B JP NZ,#1644,REP_0 Give error if none found. 251E CALL #2640,EXPT_FNAME Evaluate filename. 2521 CP 204,"TO" Is the filename followed by "TO"? 2523 JR Z,#2561,RENAME Jump if so, rename is wanted. 2525 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 2528 LD A,(#3E04) Fetch device descriptor. 252B AND #DF Drop lower case bit. 252D CP 68,"D" 252F JR Z,#2536,ERASE_RUN Jump if it was "D". 2531 CP 77,"M" 2533 JP NZ,#1658,REP_10 Give error if it wasn't "M". THE 'ERASE A FILE' ROUTINE This routine deletes the specified file(s) on the specified drive. First it calls the routine 'FIND_FILE' to find a matching name, then it marks the file ERASEd by setting the directory description to 0, the dir. entry is then SAVEd back to disc. 2536 ERASE_RUN CALL #0702,TEST_DRV See if drive is defined. 2539 ERASE_LOOP CALL #2559,FIND_FILE Find the file. 253C JR NZ,#2548,NOT_FOUND Jump if not found. 253E LD (HL),0 Directory description 0 means ERASEd. 2540 CALL #0584,WSAD Write sector DE. 2543 CALL #15F4,SIGN_0 Signal 'at least one file ERASEd'. 2546 JR #2539,ERASE_LOOP ERASE all files with this filename. 2548 NOT_FOUND CALL #161C,TEST_0 Give an error if there wasn't at least 254B JP Z,#1678,REP_26 one file ERASEd. 254E ERASE_EXIT LD A,(#3E04) 2551 CP 68,"D" If the device descriptor was a 2553 CALL Z,#24AA,CAT_1 (capital) "D", then give a CATalogue. 2556 JP #047C,END Finished. THE 'FIND A FILE' SUBROUTINE This routine searches the directory for a matching filename by calling the +D ROM routine 'SCAN_CAT', it returns with HL pointing to the directory description of the matching file. This routine is also called by command code 65 routine. 2559 FIND_FILE LD A,%00010000 Scan the CATalogue for a matching 255B CALL #09A5,SCAN_CAT filename. 255E JP #0D93,RPT_HL Make HL point to the start of the dir. entry buffer and exit. THE 'RENAME A FILE' ROUTINE This routine renames a file by replacing its filename, given first, by the filename given second. It first tests whether the 'new' name isn't used already. If not, a check is made whether the file to be renamed exists. 2561 RENAME RST #28,NEXT_C Get next character. 2562 CALL #25A2,SEPARATOR Check if there is a separator. 2565 JP NZ,#1644,REP_0 Give an error if none found. 2568 CALL #2620,EXPT_2FNAM Evaluate 2nd filename. 256B CALL #3148,ST_END_RAM Confirm end of statement and exit when syntax checking. 256E LD A,(#3E04) Fetch device descriptor. 2571 AND #DF Drop lower case bit. 2573 CP 68,"D" 2575 JR Z,#257C,RENAME_RUN Jump if it was a "D". 2577 CP 77,"M" 2579 JP NZ,#1658,REP_10 Give error if it wasn't a "M". 257C RENAME_RUN CALL #0702,TEST_DRV See if the drive is defined. 257F CALL #2626,SWAP_UFIAS Swap UFIA 1 & 2 in the DFCA. 2582 CALL #2559,FIND_FILE Give an error if the 2nd filename 2585 JP Z,#167C,REP_28 already exists. 2588 CALL #2626,SWAP_UFIAS Swap UFIA 1 & 2 in the DFCA. 258B CALL #2559,FIND_FILE Give an error if the 1st filename 258E JP NZ,#1678,REP_26 doesn't exist. 2591 INC HL 2592 PUSH DE 2593 LD DE,#3E1F Rename the file by copying the 2nd to 2596 EX DE,HL the 1st name. 2597 LD BC,10 259A LDIR 259C POP DE 259D CALL #0584,WSAD Write the CATalogue sector. 25A0 JR #254E,ERASE_EXIT Exit via 'ERASE_EXIT'. .The syntax checking routines THE 'SEPARATOR' SUBROUTINE This small subroutine tests whether the current character is a separator or a quote. It returns with Zero flag set if it was a ";", "," or a """, with the first two A holds the next character. 25A2 SEPARATOR CP 44,"," 25A4 JR Z,#25AD,SEPAR_1 Jump if current character is a comma. 25A6 CP 59,";" 25A8 JR Z,#25AD,SEPAR_1 Jump if it is a semicolon. 25AA CP 34,""" 25AC RET Return with Zero set if it's a quote. 25AD SEPAR_1 RST #28,NEXT_C Get next character. 25AE LD (#3DEA),A 25B1 XOR A Set Zero flag. 25B2 LD A,(#3DEA) 25B5 RET THE 'EVALUATE STRING EXPR.' SUBROUTINE A call is made to the 'main' ROM 'EXPT_EXP' (class-0A) subroutine, to evaluate a string expression. During runtime, the parameters of the string (start and length) are returned in the DE and BC register pairs. 25B6 EXPT_STR RST #10,CALBAS Evaluate the string expression. 25B7 DEFW #1C8C,EXPT_EXP 25B9 RST #30,SYNTAX_Z 25BA RET Z Return if syntax is being checked. 25BB PUSH AF Save the character following the string 25BC RST #10,CALBAS and the zero flag. 25BD DEFW #2BF1,STK_FETCH Fetch the string parameters. 25BF POP AF 25C0 RET THE 'EVAL. MICRODRIVE SYNTAX' SUBROUTINE This subroutine is entered at 'MD_SYNTAX' or 'MD_SYNTAX1' depending upon whether or not the character pointer is to be updated to the next character. A single character string is evaluated, and its ASCII value is stored during runtime. If a separator isn't present after the single character string, an error is given. 25C1 MD_SYNTAX RST #28,NEXT_C Next character. 25C2 MD_SYN1 CALL #25B6,EXPT_STR 25C5 JR Z,#25D9,MD_SYN2 Jump if syntax is being checked. 25C7 PUSH AF Save the character following the 25C8 LD A,C string. A holds string length low byte. 25C9 DEC A 25CA OR B Give an error if there isn't exactly 25CB JP NZ,#1658,REP_10 one character in the string. 25CE LD A,(DE) Fetch the channel specifier. 25CF RST #10,CALBAS Call 'ALPHA' to see if it's a valid 25D0 DEFW #2C8D,ALPHA letter. 25D2 JP NC,#1658,REP_10 Give error if not a valid letter. 25D5 LD (#3E04),A Store the specifier in the UFIA. 25D8 POP AF Restore next character. 25D9 MD_SYN2 CP 59,";" 25DB RET Z Return if it's a semicolon. 25DC CP 44,"," 25DE RET Z Return if it's a comma. 25DF JP #1644,REP_0 Otherwise give error. THE 'EVALUATE DEVICE NUMBER' SUBROUTINE This subroutine is used to evaluate the device number. 25E2 EXPT_DEVN AND #DF Make upper case. 25E4 CP 80,"P" 25E6 JR NZ,#25F9,EXPT_DEVN1 Jump if the device wasn't "P". 25E8 RST #28,NEXT_C Next character. 25E9 CALL #2611,EXPT_NUM Get the program number. 25EC RET Z Return if syntax checking. 25ED PUSH AF 25EE LD A,(#3E01) Store program number. 25F1 LD (#3E02),A 25F4 CALL #2604,LAST_DRV Drive is last drive. 25F7 POP AF 25F8 RET Now a check is made whether the last used device is wanted. 25F9 EXPT_DEVN1 RST #28,NEXT_C Get next character. 25FA EXPT_DEVN2 CP 42,"*" 25FC JR NZ,EXPT_NUM Jump if it wasn't a "*". 25FE RST #30,SYNTAX_Z 25FF CALL NZ,#2604,LAST_DRV Store last drive number during runtime. 2602 RST #28,NEXT_C Next character. 2603 RET THE 'SET LAST DRIVE' SUBROUTINE This subroutine is used whenever the last used drive is to be used again. 2604 LAST_DRV LD A,(#3DDA) Fetch current control port status. 2607 AND #01 Keep only drive select. 2609 ADD A,#01 A holds 1 for drive 2, 2 for drive 1. 260B XOR #03 1 becomes 2, 2 becomes 1. 260D LD (#3E01),A Store drive number. 2610 RET THE 'EVALUATE NUMERIC EXPR.' SUBROUTINE This subroutine is used to evaluate a single numeric expression. The result is returned during runtime into the BC register pair and into UFIA1. 2611 EXPT_NUM RST #10,CALBAS Evaluate the expression by calling 2612 DEFW #1C82,EXPT_1NUM 'EXPT_1NUM' in the 'main' ROM. 2614 RST #30,SYNTAX_Z 2615 RET Z Return if syntax is being checked. 2616 PUSH AF 2617 RST #10,CALBAS Fetch the value from the calculator 2618 DEFW #1E99,FIND_INT2 stack. 261A LD A,C 261B LD (#3E01),A Store it in UFIA1. 261E POP AF 261F RET THE 'EVALUATE 2ND FILENAME' SUBROUTINE This routine evaluates the second filename of a BASIC command. Because 'EXP_F_NAME' stores the filename in UFIA1, both UFIAS are swapped first, then 'EXP_F_NAME' is called and an exit is made via 'SWAP_UFIAS' to get the UFIA's in the right place again. 2620 EXPT_2FNAM CALL #2626,SWAP_UFIAS Swap UFIA1 and 2. 2623 CALL #2640,EXPT_FNAME Evaluate filename. Exit via 'SWAP_UFIAS'. THE 'SWAP UFIAS' SUBROUTINE This subroutine swaps the contents of UFIA1 and UFIA2 in DFCA. 2626 SWAP_UFIAS PUSH AF 2627 PUSH BC 2628 PUSH DE 2629 PUSH HL 262A LD B,24 An UFIA is 24 bytes long. 262C LD DE,#3E01 Start of UFIA1. 262F LD HL,#3E1A Start of UFIA2. 2632 SWAP_LOOP LD A,(DE) Exchange the contents. 2633 LD C,(HL) 2634 EX DE,HL 2635 LD (DE),A 2636 LD (HL),C 2637 INC DE 2638 INC HL 2639 DJNZ #2632,SWAP_LOOP Repeat for all 24 bytes. 263B POP HL 263C POP DE 263D POP BC 263E POP AF 263F RET THE 'EVALUATE A FILENAME' SUBROUTINE A string expression is evaluated and, provided that the length is within the range 1..10 characters, is stored in UFIA1. 2640 EXPT_FNAME CALL #25B6,EXPT_STR Evaluate the string. 2643 RET Z Return if checking syntax. 2644 PUSH AF 2645 LD A,C 2646 OR B 2647 JP Z,#1654,REP_8 Give error with null string. 264A LD HL,10 264D SBC HL,BC 264F JP C,#1654,REP_8 Give error with string length > 10. 2652 LD HL,#3E05 Clear the filename and the directory 2655 LD A,11 description of UFIA1. 2657 CLR_FNAME LD (HL),32 2659 INC HL 265A DEC A 265B JR NZ,#2657,CLR_FNAME Repeat for all 11 bytes. 265D LD HL,#3E06 Copy the filename into UFIA1. 2660 EX DE,HL 2661 LDIR 2663 POP AF 2664 RET THE 'EVALUATE PARAMETERS' SUBROUTINE This very important subroutine is called to evaluate the syntax of the +D 'SAVE', 'LOAD', 'MERGE' and 'VERIFY' commands. The routine is entered with CH_ADD pointing to the command; on exit during runtime UFIA1 is filled with the proper values. 2665 EXPT_PARMS RST #28,NEXT_C Get next character from BASIC line. 2666 CP 32," " Give an error with character codes 2668 JP C,#1644,REP_0 below 32, i.e. colour codes, etc. 266B CP 170,"SCREEN$" 266D JP Z,#301D,DUMP_SCR$ Jump with 'SCREEN$'. 2670 LD (#3E04),A Otherwise store it in DEV_TYPE1. 2673 CP 64,"@" 2675 JR NZ,#26AE,NOT_@ Jump if not a '@'. Now deal with @. 2677 CALL #25E2,EXPT_DEVN Evaluate drive number. 267A CALL #25A2,SEPARATOR 267D JP NZ,#1648,REP_2 Give error if no separator was found. 2680 RST #10,CALBAS Call 'EXPT_1NUM' to evaluate the track 2681 DEFW #1C82,EXPT_1NUM number. 2683 CALL #25A2,SEPARATOR Test for another separator and give an 2686 JP NZ,#1648,REP_2 error if none found. 2689 RST #10,CALBAS Evaluate sector number. 268A DEFW #1C82,EXPT_1NUM 268C CALL #25A2,SEPARATOR Again a separator has to be found. 268F JP NZ,#1648,REP_2 2692 RST #10,CALBAS Evaluate address. 2693 DEFW #1C82,EXPT_1NUM 2695 CALL #3148,ST_END_RAM Confirm end of statement, and exit during syntax checking. 2698 RST #10,CALBAS Fetch the address from the calculator 2699 DEFW #1E99,FIND_INT2 stack. 269B LD (#3E15),BC Store it in LENGTH1_2 269F RST #10,CALBAS Fetch sector. 26A0 DEFW #1E99,FIND_INT2 26A2 LD (#3E13),BC Store it in FILE_ADDR1 26A6 RST #10,CALBAS Fetch track. 26A7 DEFW #1E99,_FIND_INT2 26A9 LD (#3E11),BC Store it in LENGTH1_1 26AD RET Exit. 26AE NOT_@ CP 42,"*" Call 'MD_SYNTAX' if it was a "*". 26B0 CALL Z,#25C1,MD_SYNTAX 26B3 CALL #25E2,EXPT_DEVN Fetch device or program number. 26B6 CALL #25A2,SEPARATOR Test for a separator. 26B9 PUSH AF 26BA RST #30,SYNTAX_Z 26BB JR Z,#26D6,FILENAME Jump if syntax checking. 26BD LD A,(#3E04) Fetch device descriptor. 26C0 AND #DF Only capitals. 26C2 CP 68,"D" 26C4 JR Z,#26D1,NOT_@1 Jump if device is disk. 26C6 CP 77,"M" 26C8 JR Z,#26D1,NOT_@1 Or disk with Microdrive syntax. 26CA CP 80,"P" 26CC JR Z,#26DB,PARAMS Jump with program. 26CE JP NZ,#1658,REP_10 Give error with unknown device. 26D1 NOT_@1 POP AF Give error if no separator or quote 26D2 JP NZ,#1644,REP_0 found with devices "D" and "M". 26D5 PUSH AF Balance 'POP AF' below. 26D6 FILENAME POP AF 26D7 CALL Z,#2640,EXPT_FNAME Evaluate filename if necessary. 26DA PUSH AF Balance next instruction. 26DB PARAMS POP AF 26DC CP 13 26DE JP Z,#276F,NO_PARAMS Jump with ENTER. 26E1 CP 58,":" 26E3 JP Z,#276F,NO_PARAMS Jump with colon. 26E6 CP 204,"TO" 26E8 JP Z,#2308,TO Jump with 'TO'. 26EB CP 170,"SCREEN$" 26ED JP Z,#27A5,SCREEN$ Jump with 'SCREEN$'. 26F0 CP 175,"CODE" 26F2 JP Z,#27C0,CODE Jump with 'CODE'. 26F5 CP 228,"DATA" 26F7 JP Z,#281A,DATA Jump with 'DATA'. 26FA CP 202,"LINE" 26FC JP Z,#275F,LINE Jump with 'LINE'. 26FF AND #DF Only capitals. 2701 CP 83,"S" 2703 JR NZ,#270F,NOT_S Jump with other than 'S'. 2705 RST #28,NEXT_C Next character. 2706 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 2709 LD A,5 Signal '48K Snapshot'. 270B LD (#3E05),A 270E RET Finished. 270F NOT_S CP 75,"K" 2711 JR NZ,#271D,NOT_K Jump with other than 'K'. 2713 RST #28,NEXT_C Next character. 2714 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 2717 LD A,9 Signal '128K Snapshot'. 2719 LD (#3E05),A 271C RET Finished. 271D NOT_K CP 88,"X" 271F JP NZ,#1644,REP_0 Give error with other than 'X'. 2722 RST #28,NEXT_C Next character. 2723 CALL #25A2,SEPARATOR Jump if a separator found, there is 2726 JR Z,#2736,XFILE_1 more. 2728 CALL #1635,TEST_5 There must follow a address if SAVEing. 272B JP NZ,#1648,REP_2 Give error if SAVEing. 272E CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 2731 LD BC,#3BD6 Load address of execute file. 2734 JR #273F,XFILE_2 Jump forward. A separator has been found, so there should follow an address. 2736 XFILE_1 RST #10,CALBAS Evaluate address. 2737 DEFW #1C82,EXPT_1NUM 2739 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 273C RST #10,CALBAS Fetch the address. 273D DEFW #1E99,FIND_INT2 273F XFILE_2 LD (#3E13),BC Store it in FILE_ADDR1 2743 LD BC,510 Length of execute file on double 2746 LD A,(#3DDA) density disks. 2749 AND #04 274B JR Z,#2750,XFILE_3 Jump if double density selected. 274D LD BC,254 Otherwise this is the length of the execute file. 2750 XFILE_3 LD (#3E11),BC Store length in LENGTH1_1. 2754 LD A,3 File type is 'CODE'. 2756 LD (#3E10),A Store it in FILE_TYPE1. 2759 LD A,11 Signal 'Execute file'. 275B LD (#3E05),A Store in DIR_DESCR1 275E RET Finished. Now deal with LINE. The +D allows LOAD, VERIFY and MERGE .. LINE to be entered as a command but the LINE is completely ignored. 275F LINE RST #28,NEXT_C Advance CH_ADD. 2760 RST #10,CALBAS Evaluate autostart line number by 2761 DEFW #1C82,EXPT_1NUM calling 'EXPT_1NUM' in the 'main' ROM. 2763 CALL #3148,ST_END_RAM Confirm end of statement, and exit during syntax checking. 2766 RST #10,CALBAS Fetch the autostart line number. 2767 DEFW #1E99,FIND_INT2 2769 LD (#3E17),BC Store it in AUTOSTART1. 276D JR #2772,PROG If there are no parameters, as with a BASIC program, the syntax checking ends here. 276F NO_PARAMS CALL #3148,ST_END_RAM Confirm end of statement, exit when syntax checking. 2772 PROG LD A,(#3E04) 2775 AND #DF Only capitals. 2777 CP 80,"P" Jump if the device wasn't "P", i.e. no 2779 JR NZ,#2782,PROG_1 program number was specified. 277B CALL #1635,TEST_5 'SAVE pn' is not supported, so give an 277E RET Z error if saving, otherwise return. 277F JP #1644,REP_0 2782 PROG_1 XOR A File type is 'BASIC'. 2783 LD (#3E10),A 2786 LD A,1 Signal 'BASIC file'. 2788 LD (#3E05),A 278B LD HL,(23641) Fetch (E_LINE), the first location past the variables area. 278E LD DE,(23635) Fetch (PROG), the 'start' of the BASIC 2792 LD (#3E13),DE program and store it in FILE_ADDR1 2796 SCF Calculate ((E_LINE)-(PROG)-1), i.e. the 2797 SBC HL,DE length of the program and its 2799 LD (#3E11),HL variables. Store it in LENGTH1_1. 279C LD HL,(23627) Fetch (VARS) and calculate 279F SBC HL,DE (VARS)-(PROG), i.e. the length of the program without its variables. 27A1 LD (#3E15),HL Store it into LENGTH1_2. 27A4 RET Finished. If the token is SCREEN$, the parameters are entered directly into the file header. 27A5 SCREEN$ RST #28,NEXT_C Get the next character. 27A6 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 27A9 LD HL,6912 The size of the display file is stored 27AC LD (#3E11),HL into LENGTH1_1. 27AF LD HL,16384 The startaddress is stored into 27B2 LD (#3E13),HL FILE_ADDR1 27B5 LD A,3 File type is 'CODE'. 27B7 LD (#3E10),A 27BA LD A,7 Signal 'SCREEN$'. 27BC LD (#3E05),A 27BF RET Now deal with CODE, three parameters are needed: "start", "length" and "execute address". With LOAD there may be none, one, two or three parameters, but with SAVE at least two parameters must be present. 27C0 CODE RST #28,NEXT_C Update CH_ADD. 27C1 CP 13 If there are no further parameters, 27C3 JR Z,#27C9,CODE_1 jump to use '0' as default value. 27C5 CP 58,":" Jump if there are parameters to be 27C7 JR NZ,#27D4,CODE_2 evaluated (i.e. the next character is not a colon). 27C9 CODE_1 CALL #1635,TEST_5 'SAVE .. CODE' has to be followed by at 27CC JP NZ,#1648,REP_2 least two numbers, so give an error if none present. 27CF RST #10,CALBAS A call to the 'main' ROM routine 27D0 DEFW #1CE6,USE_ZERO 'USE_ZERO' is made to use a value of 27D2 JR #27DC,CODE_3 zero as default. It's likely that an address follows. 27D4 CODE_2 RST #10,CALBAS Use the 'main' ROM routine to evaluate 27D5 DEFW #1C82,EXPT_1NUM the first parameter. 27D7 CALL #25A2,SEPARATOR 27DA JR Z,#27E7,CODE_4 Jump if a separator is present. 27DC CODE_3 CALL #1635,TEST_5 Give an error if there isn't a second 27DF JP NZ,#1648,REP_2 number with 'SAVE .. CODE'. 27E2 RST #10,CALBAS Otherwise use zero as default. 27E3 DEFW #1CE6,USE_ZERO 27E5 JR #27EF,CODE_5 The length seems to be present also. 27E7 CODE_4 RST #10,CALBAS Evaluate the second parameter. 27E8 DEFW #1C82,EXPT_1NUM 27EA CALL #25A2,SEPARATOR Jump if a second separator is found. 27ED JR Z,#27F4,CODE_6 27EF CODE_5 RST #10,CALBAS Otherwise zero is default. 27F0 DEFW #1CE6,USE_ZERO 27F2 JR #27F7,CODE_7 There's even an execute address. 27F4 CODE_6 RST #10,CALBAS Evaluate the third parameter. 27F5 DEFW #1C82,EXPT_1NUM 27F7 CODE_7 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 27FA RST #10,CALBAS Fetch the "autoexecute" address from 27FB DEFW #1E99,FIND_INT2 the calculator stack and store it into 27FD LD (#3E17),BC AUTOSTART1 2801 RST #10,CALBAS Fetch the "length". 2802 DEFW #1E99,FIND_INT2 2804 LD (#3E11),BC Store it into LENGTH1_1 2808 RST #10,CALBAS Fetch the "start". 2809 DEFW #1E99,FIND_INT2 280B LD (#3E13),BC Store it into FILE_ADDR1 280E LD A,3 File type is 'CODE'. 2811 LD (#3E10),A 2814 LD A,4 Signal 'CODE file'. 2816 LD (#3E05),A 2819 RET Finished. Finally the routine to evaluate DATA parameters. 281A DATA CALL #163A,TEST_6 Give an error if attempting to MERGE an 281D JP NZ,#1660,REP_14 array. 2820 RST #28,NEXT_C Next character. 2821 RST #10,CALBAS Call LOOK_VARS to look for the array 2822 DEFW #28B2,LOOK_VARS name. 2824 SET 7,C 2826 JR NC,#2833,DATA_1 Jump if handling an existing array or if syntax checking. 2828 LD HL,#0000 Signal 'using a new array'. 282B CALL #1630,TEST_4 282E JR NZ,#284E,DATA_3 Jump if LOADing the array. 2830 JP #165A,REP_11 Otherwise give error 'Variable not found'. 2833 DATA_1 JP NZ,#1644,REP_0 Give error if not an array variable. NOTE: This test fails to exclude simple strings, but the 'bug' (present in the 'main' ROM) is corrected at #283E. 2836 RST #30,SYNTAX_Z 2837 JR Z,#2860,DATA_5 Jump if syntax is being checked. 2839 CALL #1635,TEST_5 283C JR Z,#2843,DATA_2 Jump if LOADing. 283E BIT 7,(HL) Give an error if trying to SAVE a 2840 JP Z,#1644,REP_0 simple string. 2843 DATA_2 INC HL Point to the 'length' of the array. 2844 LD A,(HL) Store the length into LENGTH1_1. 2845 LD (#3E11),A 2848 INC HL 2849 LD A,(HL) 284A LD (#3E12),A 284D INC HL Advance to the start of the array. 284E DATA_3 LD A,C Store array name into LSB of LENGTH1_2. 284F LD (#3E15),A 2852 LD A,1 File type is 'NUM ARRAY'. 2854 BIT 6,C 2856 JR Z,#2859,DATA_4 Jump if really a numeric array. 2858 INC A File type is 'STR ARRAY'. 2859 DATA_4 LD (#3E10),A Store file type into FILE_TYPE1. 285C INC A Signal: (A=2) 'Numeric array', 285D LD (#3E05),A (A=3) 'String array'. 2860 DATA_5 EX DE,HL DE holds 'start' of the array (or #0000 with a 'new' array to be LOADed). 2861 RST #28,NEXT_C Next character. 2862 CP 41,")" Check that the ')' does exist. 2864 JP NZ,#1648,REP_2 Report an error if not. 2867 RST #28,NEXT_C Next character. 2868 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 286B LD (#3E13),DE Store "start" of the array into 286F RET FILE_ADDR1 and exit. .The BASIC command execution routines II THE 'GET TRACK AND SECTOR' SUBROUTINE This routine loads DE with track and sector number from the file header, where they were stored by the 'EXPT_PARMS' subroutine. Used with LOAD/SAVE @. 2870 GET_TR&SE LD A,(#3E11) Get track from LSB of LENGTH1_1. 2873 LD D,A 2874 LD A,(#3E13) Get sector from LSB of FILE_ADDR1. 2877 LD E,A 2878 RET THE 'SAVE HEADER 1' SUBROUTINE This subroutine SAVEs the 9 bytes header from UFIA 1 to the file and to the catalogue entry which is build up in the DFCA. 2879 SAVE_HEAD1 LD HL,#3E10 Start of header 1. 287C LD DE,#3BA9 Address of header area of a catalogue entry 287F LD B,9 The headers length. 2881 SAVE_H11 LD A,(HL) 2882 LD (DE),A 2883 CALL #0761,SBYT Save the byte to the file. 2886 INC HL 2887 INC DE 2888 DJNZ #2881,SAVE_H11 Repeat for all nine bytes. 288A RET Finished. THE 'SAVE' COMMAND SYNTAX ROUTINE This routine checks that the SAVE command has the appropriate syntax. 288B SAVE LD IX,#3AC3 Pointer to the DFCA. 288F CALL #160D,SIGN_5 Signal 'SAVEing'. 2892 CALL #2665,EXPT_PARMS Evaluate & store all parameters. 2895 CALL #0702,TEST_DRV See if the drive is defined. 2898 LD A,(#3E04) 289B CP 64,"@" 289D JR NZ,#28AF,SAVE_RUN Jump if the command wasn't 'SAVE @'. 289F LD IX,(#3E15) Get address where sector is to be saved 28A3 CALL #2870,GET_TR&SE from. Get track and sector number. 28A6 LD A,(#3E01) Get drive number. 28A9 CALL #2FF2,HWSAD Write the sector. 28AC JP #047C,END Finished. THE 'SAVE A FILE' ROUTINE This routine SAVEs the specified file on the specified drive. 28AF SAVE_RUN CALL #0AD9,OFSM_2 Open the file for 'SAVE'. 28B2 JP NZ,#254E,ERASE_EXIT Exit if the file isn't to be overwritten. 28B5 LD A,(#3E05) 28B8 CP 11 Pass the header to the file unless it's 28BA CALL NZ,#2879,SAVE_HEAD1 an 'execute' file. 28BD LD HL,(#3E13) Fetch the start address. 28C0 LD DE,(#3E11) Fetch the length. 28C4 CALL #0850,HSVBK_2 Save the block. 28C7 CALL #0B89,CFSM Close the file. 28CA JP #254E,ERASE_EXIT Exit via 'ERASE_EXIT'. THE 'LOAD HEADER INTO UFIA 2' SUBROUTINE This subroutine LOADs a 9 bytes header into UFIA 2. 28CD LOAD_HEAD2 LD HL,#3E29 Start of HEADER 2. 28D0 LD B,9 Length of a header. 28D2 LOAD_H21 CALL #077F,LBYT Load a byte. 28D5 LD (HL),A Store it into UFIA 2. 28D6 INC HL 28D7 DJNZ #28D2,LOAD_H21 Repeat for all header bytes. 28D9 RET THE 'LOAD' COMMAND SYNTAX ROUTINE The 'LOAD' flag is set and the routine continues into the 'LOAD_VERIFY_MERGE' routine below. 28DA LOAD CALL #1608,SIGN_4 Signal 'LOADing'. 28DD JR #28E7,LD_VF_MR THE 'VERIFY' COMMAND SYNTAX ROUTINE The 'VERIFY' flag is set and again the 'LOAD_VERIFY_MERGE' routine handles the rest. 28DF VERIFY CALL #1617,SIGN_7 Signal 'VERIFYing'. 28E2 JR #28E7,LD_VF_MR THE 'MERGE' COMMAND SYNTAX ROUTINE The 'MERGE' flag is set and 'LOAD_VERIFY_MERGE' continues the syntax checking. 28E4 MERGE CALL #1612,SIGN_6 Signal 'MERGEing'. THE 'LOAD_VERIFY_MERGE' COMMAND ROUTINE This routine checks the syntax of the LOAD, VERIFY and MERGE commands and executes it. 28E7 LD_VF_MR LD IX,#3AC3 Pointer to DFCA. 28EB CALL #2665,EXPT_PARMS Evaluate & store all parameters. 28EE LD_VF_MR1 CALL #0702,TEST_DRV See if the drive is defined. 28F1 LD A,(#3E04) 28F4 CP 64,"@" 28F6 JR NZ,#2908,LD_ETC_RUN Jump if it wasn't a '@' command. 28F8 LD IX,(#3E15) Get address where sector is to be 28FC CALL #2870,GET_TR&SE loaded. Get track and sector number. 28FF LD A,(#3E01) Get drive number. 2902 CALL #2FD4,HRSAD Load the sector. 2905 JP #047C,END Finished. The routine continues here when a file is to be LOADed from disk. 2908 LD_ETC_RUN CALL #0BCF,HGFLE_2 Open the file for loading. 290B LD A,(#3E05) 290E CP 5 2910 JR NZ,#2921,LD_ETC_R1 Jump if it isn't a 'Snapshot 48K'. 2912 LD SP,#3FEA Use internal stack. 2915 LD HL,16384 Start address and length of a 48K Snap. 2918 LD DE,49152 291B CALL #079E,LOAD_FILE Load the file. 291E JP #00B1,SNAP_EXIT Exit via 'SNAP_EXIT'. 2921 LD_ETC_R1 CP 9 2923 JR NZ,#294A,LD_ETC_R3 Jump if it isn't a 'Snapshot 128K'. 2925 LD SP,#3FEA Use internal stack. 2928 CALL #077F,LBYT Get the page configuration byte. 292B PUSH AF 292C AND #F8 Keep the RAM page bits only. 292E LD B,#08 LOAD the eight RAM-pages. 2930 LD_ETC_R2 PUSH AF 2931 PUSH BC 2932 CALL #223F,RAMPAGE_A Page in RAM bank. 2935 LD HL,49152 Start address and length of each RAM 2938 LD DE,16384 bank. 293B CALL #079E,LOAD_FILE 'LOAD DE bytes to HL'. 293E POP BC 293F POP AF 2940 INC A Next RAM bank. 2941 DJNZ #2930,LD_ETC_R2 Repeat for each RAM bank. 2943 POP AF Retrieve page configuration. 2944 CALL #223F,RAMPAGE_A Page in the right RAM, ROM and SCR$ 2947 JP #00B1,SNAP_EXIT bank, exit via 'SNAP_EXIT'. 294A LD_ETC_R3 CP 11 294C JR NZ,#2954,LD_ETC_R4 Jump if it isn't a 'Execute' file. 294E CALL #3BD6 Execute (this is the address of the 2951 JP #047C,END disk buffer). Finished. 2954 LD_ETC_R4 CALL #28CD,LOAD_HEAD2 Load the header into UFIA2. 2957 LD A,(#3E10) Fetch type of program to be LOADed. 295A LD B,A 295B LD A,(#3E29) Fetch type of program found. 295E CP B 295F JP NZ,#1654,REP_8 Give an error if they aren't equal. NOTE: The error 'Invalid FILE NAME' is given, maybe MGT have made a typing error. 'Wrong FILE type' is the right message. 2962 CP 3 2964 JR Z,#2974,LD_ETC_R5 Jump if it's a 'CODE' file. 2966 JP NC,#1654,REP_8 Give error if file type >= 4. 2969 CALL #163A,TEST_6 296C JR NZ,#29DF,MERGE_CTRL Jump if 'MERGEing'. 296E CALL #163F,TEST_7 Jump if not 'VERIFYing' (i.e. doing a 2971 JP Z,#29FB,LOAD_CTRL LOAD). Now deal with loading of all files with type 3, like 'CODE' and 'SCREEN$', or verifying of all file types. 2974 LD_ETC_R5 CALL #163A,TEST_6 2977 JP NZ,#1660,REP_14 Give error if 'MERGE .. CODE' was used. 297A LD HL,(#3E11) Fetch length of requested file. 297D LD DE,(#3E2A) Fetch length of file found. 2981 LD A,H 2982 OR L 2983 JR Z,#2992,LD_ETC_R6 Jump if length unspecified. 2985 SBC HL,DE Jump if file to be LOADed is shorter 2987 JR NC,#2992,LD_ETC_R6 than or of equal length as the requested file. 2989 CALL #1630,TEST_4 298C JP Z,#165C,REP_12 'VERIFY failed' if not LOADing. 298F JP #1662,REP_15 'CODE error' otherwise. 2992 LD_ETC_R6 LD HL,(#3E13) Fetch start address from FILE_ADDR1 2995 LD A,H 2996 OR L 2997 JR NZ,#299C,LD_ETC_R7 Jump if a start address was specified. 2999 LD HL,(#3E2C) Otherwise use the start address of the found file. 299C LD_ETC_R7 LD A,(#3E29) But if the file is a BASIC program the 299F AND A start address is held in (PROG). 29A0 JR NZ,#29A5,LD_ETC_R8 29A2 LD HL,(23635) Fetch 'start' from (PROG). 29A5 LD_ETC_R8 CALL #2A9A,LV_ANY Load the file. 29A8 CALL #163F,TEST_7 29AB JP NZ,#047C,END Exit when 'VERIFYing'. 29AE LD HL,(#3E17) Fetch execute address. 29B1 CALL #29BD,EXEC_CODE Use it if it was specified. 29B4 LD HL,(#3E30) Otherwise use the files execute 29B7 CALL #29BD,EXEC_CODE address. 29BA JP #047C,END But if it hasn't one either, exit here. THE 'EXECUTE CODE FILE' SUBROUTINE This routine jumps to the address in the HL register pair (if it is valid) after pushing the addresses of 'STMT_R_1' and 'STACK_BC'. 29BD EXEC_CODE LD A,H 29BE OR L 29BF RET Z Return if the execute address is zero. 29C0 LD A,H 29C1 CP #FF 29C3 JR NZ,#29C9,EXEC_C1 29C5 LD A,L Also return when the execute address is 29C6 CP #FF #FFFF. 29C8 RET Z 29C9 EXEC_C1 LD SP,(23613) Clear the stack. (ERR_SP) 29CD LD (IY+0),#FF Clear the error. 29D1 CALL #168E,BORD_REST Restore the border colour. 29D4 LD BC,#1B7D,STMT_R_1 Return to 'STMT_R_1' in the 'main' ROM 29D7 PUSH BC when finished. 29D8 LD BC,#2D2B,STACK_BC Return to 'STMT_R_1' via 'STACK_BC' 29DB PUSH BC also in the 'main' ROM. 29DC JP #004F,UNPAGE_HL Jump to the execute address while unpaging the +D. THE 'MERGE CONTROL' ROUTINE This routine handles the MERGEing of a (BASIC) file. No test is made if the file is an array when using the MERGE 'p'n syntax (see NOTE at 'LOAD CONTROL'). 29DF MERGE_CTRL LD BC,(#3E2A) Fetch the length of the program to be 29E3 PUSH BC MERGEd. 29E4 INC BC Extra location for the 'end marker'. 29E5 RST #10,CALBAS Call 'BC_SPACES' in the 'main' ROM to 29E6 DEFW #0030,BC_SPACES make the required room in workspace. 29E8 LD (HL),128 Mark the end. 29EA EX DE,HL Move start pointer to HL. 29EB POP DE Length to DE. 29EC PUSH HL 29ED CALL #2A9A,LV_ANY Load the file. 29F0 POP HL Fetch 'start' of new program. 29F1 LD DE,(23635) Fetch 'start' of old program (PROG). 29F5 RST #10,CALBAS Do the MERGEing by calling the 'main' 29F6 DEFW #08D2,ME_NEW_LP ROM 'MERGE' routine. 29F8 JP #047C,END Finished. THE 'LOAD CONTROL' ROUTINE This routine handles the LOADing of a BASIC program or an array. NOTE: The Spectrum will crash when trying to LOAD or MERGE 'p' an array. The problem starts in the 'HGFLE_2' ('OPEN A FILE FOR LOAD') subroutine in ROM (#0BCF) which is called from the 'LD_ETC_RUN' routine at #2908. Normally UFIA1 holds the parameters of the existing array (if present), and UFIA2 holds the parameters of the array to be loaded. But when the 'p' syntax is used, the 'HGFLE_2' routine makes the contents of UFIA1 equal to UFIA2. The reclaiming at address #2A32 then fails, trying to reclaim something which isn't there. 29FB LOAD_CTRL LD DE,(#3E2A) Fetch 'new' length. 29FF LD HL,(#3E13) Fetch 'old' start (=0 when loading a 2A02 PUSH HL 'new' array'). 2A03 LD A,H 2A04 OR L 2A05 JR NZ,#2A0D,LOAD_C1 Jump if not a 'new' array. 2A07 INC DE Increment 'length' by 3, i.e. allows 2A08 INC DE for the insertion of array name and 2A09 INC DE two-byte length. 2A0A EX DE,HL Move 'length' to HL. 2A0B JR #2A16,LOAD_C2 Jump forward. The array to be loaded replaces an existing array. 2A0D LOAD_C1 LD HL,(#3E11) Fetch 'old' length (i.e. length of existing program or array) from UFIA1. 2A10 EX DE,HL Move 'new' length to HL. 2A11 SCF Jump if the program or array to be 2A12 SBC HL,DE loaded isn't longer than the existing 2A14 JR C,#2A1F,LOAD_C3 one. 2A16 LOAD_C2 LD DE,5 Otherwise a check must be made to 2A19 ADD HL,DE ensure that there is sufficient space 2A1A LD B,H in memory for the program (or array) to 2A1B LD C,L be loaded. 2A1C RST #10,CALBAS Make the check by calling the 'main' 2A1D DEFW #1F05,TEST_ROOM ROM 'TEST_ROOM' subroutine. 2A1F LOAD_C3 POP HL Restore 'old' start (=0 when handling 2A20 LD A,(#3E29) a 'new' array). 2A23 AND A 2A24 JR Z,#2A57,LD_PROG Jump if it's a BASIC program. 2A26 LD A,H 2A27 OR L Jump unless an 'old' array is to be 2A28 JR Z,#2A35,LOAD_C4 erased before loading the 'new' one. 2A2A DEC HL Points to high byte of 'array length'. 2A2B LD B,(HL) Fetch the 'length'. 2A2C DEC HL 2A2D LD C,(HL) 2A2E DEC HL Now points to the 'array name'. 2A2F INC BC Include 'length' and 'name' in the 2A30 INC BC array length. 2A31 INC BC 2A32 RST #10,CALBAS Call 'RECLAIM_2' in the 'main' ROM to 2A33 DEFW #19E8,RECLAIM_2 delete the array. 2A35 LOAD_C4 LD HL,(23641) (E_LINE) points to the end of variables 2A38 DEC HL area+1. 2A39 LD BC,(#3E2A) Fetch length of array to be loaded. 2A3D PUSH BC 2A3E INC BC Include in the length one byte for the 2A3F INC BC 'array name' and two bytes for the 2A40 INC BC 'array length'. 2A41 LD A,(#3E15) Fetch the array name from 'LENGTH1_2'. 2A44 PUSH AF 2A45 RST #10,CALBAS Call 'MAKE_ROOM' to create the space 2A46 DEFW #1655,MAKE_ROOM for the array. 2A48 INC HL Point to first 'new' location inserted. 2A49 POP AF 2A4A LD (HL),A Store array name into first location. 2A4B POP DE 2A4C INC HL Store array length into the following 2A4D LD (HL),E two locations. 2A4E INC HL 2A4F LD (HL),D 2A50 INC HL 2A51 CALL #2A9A,LV_ANY Load the file. 2A54 JP #047C,END Finished. Now deal with the LOADing of a BASIC program and its variables. 2A57 LD_PROG LD DE,(23635) Fetch start of existing program. (PROG) 2A5B LD HL,(23641) Fetch end of existing program. I.e. 2A5E DEC HL (E_LINE)-1. 2A5F RST #10,CALBAS Delete the program by calling 2A60 DEFW #19E5,RECLAIM_1 'RECLAIM_1' in the 'main' ROM. 2A62 LD BC,(#3E2A) Fetch length of program and variables. 2A66 LD HL,(23635) Fetch (PROG), start of a BASIC program. 2A69 RST #10,CALBAS Create the required space by calling 2A6A DEFW #1655,MAKE_ROOM 'MAKE_ROOM'. 2A6C INC HL Point to the first location. 2A6D LD BC,(#3E2E) Fetch length without variables. 2A71 ADD HL,BC Calculate and store the start of the 2A72 LD (23627),HL variables area. 2A75 LD A,(#3E31) When no autostart is known this 2A78 LD H,A ('AUTOSTART2-hi') holds #FF. 2A79 AND #C0 2A7B JR NZ,#2A88,LD_PROG1 Jump with no autostart. 2A7D LD A,(#3E30) Otherwise store the autostart line 2A80 LD L,A number into 'NEWPPC' and clear 'NSPPC'. 2A81 LD (23618),HL These hold the line and the statement 2A84 LD (IY+10),#00 to be executed respectively. 2A88 LD_PROG1 LD HL,(23635) Fetch the start of the BASIC program. 2A8B LD DE,(#3E2A) Fetch the length + variables. 2A8F DEC HL Reset the DATA pointer 'DATADD' to the 2A90 LD (23639),HL beginning of the program. 2A93 INC HL Balance the 'DEC HL'. 2A94 CALL #2A9A,LV_ANY Load the file. 2A97 JP #047C,END Finished. THE 'LOAD OR VERIFY' SUBROUTINE This subroutine is used to LOAD or VERIFY (signalled by FLAGS3) a block of bytes. It must be entered with HL and DE holding 'start' and 'length'. 2A9A LV_ANY LD A,D 2A9B OR E 2A9C RET Z Return if 'length' is zero. 2A9D CALL #163F,TEST_7 2AA0 JR NZ,#2AAE,LV_ANY3 Jump if 'VERIFYing'. 2AA2 JP #079E,LOAD_FILE Otherwise load the file. 2AA5 LV_ANY1 CP (HL) The actual VERIFY, i.e. compare the fetched byte with that held in memory. 2AA6 JP NZ,#165C,REP_12 Give an error if they don't match. 2AA9 LV_ANY2 INC HL Next memory address. 2AAA DEC DE One byte less to go. 2AAB LD A,D 2AAC OR E 2AAD RET Z Exit if no more bytes left. 2AAE LV_ANY3 CALL #077F,LBYT Load one byte. 2AB1 CALL #163F,TEST_7 2AB4 JR NZ,#2AA5,LV_ANY1 Jump if VERIFYing. 2AB6 LD (HL),A Otherwise store the byte. 2AB7 JR #2AA9,LV_ANY2 Repeat for all bytes. THE 'FORMAT' COMMAND SYNTAX ROUTINE This routine tests if the command has the appropriate syntax. 2AB9 FORMAT RST #28,NEXT_C Advance CH_ADD to next character. 2ABA AND #DF Only capitals. 2ABC CP 68,"D" 2ABE JP NZ,#1644,REP_0 Give an error if not a "D". 2AC1 RST #28,NEXT_C Next character. 2AC2 CALL #25FA,EXPT_DEVN2 Evaluate the drive number. 2AC5 CP 204,"TO" Jump if the current character isn't 2AC7 JR NZ,#2AD3,FORMAT_1 'TO'. 2AC9 CALL #2626,SWAP_UFIAS Exchange UFIA1 and UFIA2. 2ACC RST #28,NEXT_C Update CH_ADD. 2ACD CALL #25FA,EXPT_DEVN2 Evaluate 2nd drive number. 2AD0 CALL #2626,SWAP_UFIAS Exchange UFIA's again. 2AD3 FORMAT_1 CALL #3148,ST_END_RAM Confirm end of statement and exit when syntax checking. 2AD6 CALL #0702,TEST_DRV Check if the drive is defined. 2AD9 RST #10,CALBAS 2ADA DEFW #0D6E,CLS_LOWER Clear lower screen area. 2ADC SET 5,(IY+2) Signal 'lower screen has to be cleared'. 2AE0 CALL #180C,MESG_2 Print 'Are you SURE ? (y/n)' message. 2AE3 CALL #0B60,TEST_Y Wait for a key, Zero set means 'Y' 2AE6 JP NZ,#047C,END pressed. Finished when not sure. 2AE9 CALL #0C2B,FORMAT_RUN Otherwise FORMAT the disk. 2AEC JP #047C,END Finished. .The stream handling routines THE 'EVALUATE STREAM NUMBER' SUBROUTINE A single numeric expression is evaluated and the result, in the range 0..15 is stored into 'STRM_NUM1'. 2AEF EXPT_#NR RST #28,NEXT_C Advance CH_ADD. 2AF0 EXPT_#NR1 RST #10,CALBAS Evaluate stream number. 2AF1 DEFW #1C82,EXPT_1NUM 2AF3 RST #30,SYNTAX_Z Return if syntax is being checked. 2AF4 RET Z 2AF5 PUSH AF 2AF6 RST #10,CALBAS Fetch the number. 2AF7 DEFW #1E94,FIND_INT1 2AF9 CP 16 Give an error if it isn't in the range 2AFB JP NC,#1656,REP_9 0..15. ('Invalid station' ?) 2AFE LD (#3E03),A Store stream number into 'STRM_NUM1'. 2B01 POP AF 2B02 RET 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 into the UFIA's. 2B03 MOVE CALL #2BAD,EXPT_EXP1 Evaluate stream or channel expression. 2B06 CP 204,"TO" The keyword 'TO' must be present, 2B08 JP NZ,#1644,REP_0 give an error if 'TO' is missing. 2B0B CALL #2626,SWAP_UFIAS Exchange the UFIA's. 2B0E CALL #2BAD,EXPT_EXP1 Evaluate second stream or channel expression. 2B11 CALL #2626,SWAP_UFIAS Exchange the UFIA's again. 2B14 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax check. The actual 'MOVE' command reads a byte from the source channel or stream, and then writes it to the destination channel or stream. This is repeated until the first channel or stream reports 'End Of File'. 'SIGN_2' is called to signal to the 'D_INPUT' routine at #2EDC that the 'END of file' error isn't to be generated. 2B17 CALL #15FE,SIGN_2 See above. 2B1A LD A,191,"IN" This is the keyword 'IN', it is used to 2B1C LD (#3E02),A signal 'READ channel'. 2B1F CALL #2BDA,OP_MOVE Open the source channel/stream. 2B22 LD HL,(23631) Save (CHANS). 2B25 PUSH HL 2B26 LD A,(#3E02) Save 'DIR_DESCR1' into 'DIR_DESCR2'. 2B29 LD (#3E1E),A 2B2C CALL #2626,SWAP_UFIAS Exchange the UFIA's. 2B2F LD A,223,"OUT" This is the keyword 'OUT'. 2B31 LD (#3E02),A Signal 'WRITE channel'. 2B34 LD IX,#3AC3 Pointer to DFCA. 2B38 CALL #2BDA,OP_MOVE Open the destination channel/stream. 2B3B JR NC,#2B49,MOVE_RUN1 Jump if opening was successfull. I.e. file was 'new' or 'old' file was overwritten. 2B3D LD IX,(#3E1E) Otherwise reclaim first channel (Second 2B41 CALL #2B9E,RECL_CHAN wasn't opened so nothing to reclaim). 2B44 POP HL Drop (CHANS) address. 2B45 POP HL ?? Drop what? 2B46 JP #047C,END Finished. 2B49 MOVE_RUN1 CALL #2626,SWAP_UFIAS Exchange UFIA's again. To my knowledge the instructions at #2B22, #2B25, #2B44 and from #2B4C to #2B58 aren't needed with the +D. With IF1 the Microdrive maps are situated between 23734 (end of Spectrum system variables) and (CHANS). The consequence of opening a new channel could be the creating of a new map. I.e. the channel information could move up and then the source channels address is to be recalculated. With the +D, however, nothing is situated between 23734 and (CHANS). 2B4C POP DE Retrieve 'old' (CHANS). 2B4D LD HL,(23631) Fetch 'new' (CHANS). 2B50 OR A Calculate the space which was inserted 2B51 SBC HL,DE under (CHANS). 2B53 LD DE,(#3E05) Adjust first channels address. 2B57 ADD HL,DE 2B58 LD (#3E05),HL 2B5B MOVE_RUN2 LD HL,(#3E05) Make 'current' the first channel. 2B5E LD (23633),HL (CURCHL) 2B61 MOVE_RUN3 RST #10,CALBAS Call 'INPUT_A' in the 'main' ROM to 2B62 DEFW #15E6,INPUT_A read a byte. 2B64 JR C,#2B6A,MOVE_RUN4 Jump with acceptable codes. 2B66 JR Z,#2B61,MOVE_RUN3 Repeat if no byte read. 2B68 JR #2B75,MOVE_RUN5 Jump if EOF has been reached. An acceptable code has been found. 2B6A MOVE_RUN4 LD HL,(#3E1E) Make 'current' the 2nd channel. 2B6D LD (23633),HL (CURCHL) 2B70 RST #10,CALBAS Use 'main' ROM 'PRINT_A_2' to send the 2B71 DEFW #15F2,PRINT_A_2 byte to the 2nd channel. 2B73 JR #2B5B,MOVE_RUN2 Repeat until EOF. EOF has been reached. 2B75 MOVE_RUN5 XOR A Clear FLAGS3. 2B76 LD (#3ACF),A 2B79 LD HL,(23631) Store current (CHANS). 2B7C PUSH HL 2B7D CALL #2626,SWAP_UFIAS Exchange the UFIA's. 2B80 CALL #2C12,CL_MOVE Close the destination channel. 2B83 CALL #2626,SWAP_UFIAS Exchange the UFIA's again. Again the instructions at address #2B79, #2B7C and from #2B86 to #2B92 aren't needed with the +D. 2B86 POP DE Restore initial address of CHANS. 2B87 LD HL,(23631) Fetch current (CHANS). 2B8A OR A Calculate the amount of bytes reclaimed 2B8B SBC HL,DE after the deletion of the second channel. 2B8D LD DE,(#3E05) Calculate the new start address of the 2B91 ADD HL,DE first channel. 2B92 LD (#3E05),HL And store it. 2B95 CALL #2C12,CL_MOVE Close the source channel. 2B98 CALL #2C28,RECL_TEMP Reclaim temporary channels. 2B9B JP #047C,END Finished. THE 'RECLAIM CHANNEL' SUBROUTINE This subroutine is used to reclaim the channel pointed to by IX. 2B9E RECL_CHAN LD C,(IX+9) Fetch channel length. 2BA1 LD B,(IX+10) 2BA4 PUSH BC 2BA5 PUSH IX Channel start to HL. 2BA7 POP HL 2BA8 RST #10,CALBAS Call 'RECLAIM_2' in the 'main' ROM to 2BA9 DEFW #19E8,RECLAIM_2 reclaim the channel. 2BAB POP BC 2BAC RET THE 'EVALUATE STRM. OR EXPR.' SUBROUTINE This subroutine is used to check the syntax of the 'MOVE' command. If the 'current' character is a hash sign (#), then a stream number is evaluated. Otherwise a device expression is evaluated. 2BAD EXPT_EXP1 RST #28,NEXT_C Advance CH_ADD. 2BAE CP 35,"#" Jump to 'EXPT_#_NR' to evaluate stream 2BB0 JP Z,#2AEF,EXPT_#NR number if character is a '#'. 2BB3 EXPT_EXP2 LD (#3E04),A Otherwise store device letter. 2BB6 AND #DF Only capitals. 2BB8 CP 68,"D" If device letter isn't "D" then 2BBA CALL NZ,#25C2,MD_SYN1 evaluate microdrive syntax. 2BBD CALL #25E2,EXPT_DEVN Evaluate device number. 2BC0 CALL #25A2,SEPARATOR If there is a separator exit via 2BC3 JP Z,#2640,EXPT_FNAME 'EXP_F_NAME' to evaluate a filename. 2BC6 RST #30,SYNTAX_Z 2BC7 RET Z Return if checking syntax. 2BC8 PUSH AF 2BC9 LD A,(#3E04) Fetch device letter. 2BCC AND #DF Only capitals. 2BCE CP 68,"D" If the device is "D" or "M" then there 2BD0 JP Z,#1648,REP_2 must be a name present. Give an error 2BD3 CP 77,"M" if no name specified. 2BD5 JP Z,#1648,REP_2 2BD8 POP AF 2BD9 RET THE 'USE STREAM OR CHANNEL' SUBROUTINE This subroutine is used from the 'MOVE' command routine above to fetch the start address of the channel attached to a stream, or to open a channel and fetch its start address. 2BDA OP_MOVE LD A,(#3E03) Fetch stream number. 2BDD INC A Jump to open a temporary channel, i.e. 2BDE JR Z,#2BEB,OP_MOVE1 if the stream was nonexistent. 2BE0 DEC A 2BE1 RST #10,CALBAS Open the channel attached to stream A. 2BE2 DEFW #1601,CHAN_OPEN 2BE4 LD HL,(23633) Store the channels address (CURCHL) 2BE7 LD (#3E05),HL into UFIA1. 2BEA RET Return. 2BEB OP_MOVE1 LD A,(#3E04) Fetch device letter. 2BEE AND #DF Capitals only. 2BF0 CP 77,"M" 2BF2 JR Z,#2BF8,OP_MOVE2 Jump if it's a "M". 2BF4 CP 68,"D" 2BF6 JR NZ,#2C09,OP_MOVE3 Jump if it isn't a "D". 2BF8 OP_MOVE2 CALL #0702,TEST_DRV Check if the drive is defined. 2BFB CALL #2CDF,OP_TEMP_D Open a temporary "D" channel. 2BFE LD A,(#3E05) Save 'DIR_DESCR1' into 'PROG_NUM1'. 2C01 LD (#3E02),A 2C04 LD (#3E05),IX Store channels address. 2C08 RET 2C09 OP_MOVE3 CP 78,"N" 2C0B JP NZ,#1644,REP_0 Give an error if device isn't "N". 2C0E CALL #1603,SIGN_3 Otherwise signal 'using network'. 2C11 RET THE 'CLOSE "MOVE" CHANNEL' SUBROUTINE This is the opposite subroutine of the preceeding one, and is used to CLOSE the channel used by the 'MOVE' command routine. If 'STRM_NUM1' denotes that a stream was used, nothing is done. 2C12 CL_MOVE LD A,(#3E03) Fetch stream number. 2C15 INC A 2C16 RET NZ Return if a stream has been used. 2C17 LD A,(#3E04) Otherwise fetch device letter. 2C1A AND #DF Only capitals. 2C1C CP 78,"N" 2C1E JR Z,#2C27,CL_MOVE1 Jump if it was "N". 2C20 LD IX,(#3E05) Fetch channel address. 2C24 JP #2C57,CLOSE_CHAN Close the channel and exit. 2C27 CL_MOVE1 RET THE 'RECLAIM TEMP. CHANNELS' SUBROUTINE This subroutine is called to reclaim from the CHANS all 'temporary' channels (i.e. with bit 7 of the channel specifier set). 2C28 RECL_TEMP LD IX,(23631) Point to the start of the channel area. 2C2C LD DE,20 IX now points to the first 2C2F ADD IX,DE 'non-standard' channel. 2C31 RECL_T1 LD A,(IX+0) 2C34 CP 128 Return if the end marker was found, 2C36 RET Z i.e. there are no more channels. 2C37 LD A,(IX+4) Fetch channel specifier. 2C3A CP 196,"D"+128 2C3C JR NZ,#2C43,RECL_T2 Jump if not a temporary "D" channel. 2C3E CALL #2C57,CLOSE_CHAN 2C41 JR #2C28,RECL_TEMP Permanent "D" channels mustn't be closed, except when 'CLEAR #' was given. 2C43 RECL_T2 CALL #1621,TEST_1 2C46 JR Z,#2C4D,RECL_T3 Jump if not 'CLEAR # executing'. 2C48 CALL #2B9E,RECL_CHAN Otherwise reclaim the channel. 2C4B JR #2C28,RECL_TEMP Skip this channel. 2C4D RECL_T3 LD E,(IX+9) Fetch channel length. 2C50 LD D,(IX+10) 2C53 ADD IX,DE Point to the next channel. 2C55 JR #2C31,RECL_T1 Repeat for all channels. THE 'CLOSE CHANNEL' SUBROUTINE This subroutine closes the channel pointed to by IX. 2C57 CLOSE_CHAN PUSH IX 2C59 POP HL 2C5A LD DE,(23631) (CHANS). 2C5E OR A 2C5F SBC HL,DE Calculate channel offset. 2C61 INC HL 2C62 LD (#3DED),HL The channel is CLOSEd by jumping into 2C65 JP #2E80,CLOSE_0 the 'CLOSE' routine THE 'OPEN' COMMAND SYNTAX ROUTINE This routine deals with the 'OPEN #' command concerning +D channels, Spectrum channels are handled by the 'main' ROM. 2C68 OPEN CALL #2AEF,EXPT_#NR Evaluate stream number. 2C6B CALL #25A2,SEPARATOR 2C6E JP NZ,#1644,REP_0 Give an error if no separator found. 2C71 CALL #2BB3,EXPT_EXP2 Evaluate channel specifier. 2C74 CP 13 2C76 JR Z,#2C85,OPEN_2 Jump if no more parameters. 2C78 CP 191,"IN" 2C7A JR Z,#2C81,OPEN_1 Jump if 'IN' specified. 2C7C CP 223,"OUT" 2C7E JP NZ,#1648,REP_2 Give error if no 'OUT' specified. 2C81 OPEN_1 LD (#3E02),A Store the channel type (IN or OUT) in 'PROG_NUM1'. 2C84 RST #28,NEXT_C Advance CH_ADD. 2C85 OPEN_2 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 2C88 LD A,(#3E03) Fetch stream number. 2C8B RST #10,CALBAS Call 'main' ROM 'STR_DATA1' routine; on 2C8C DEFW #1727,STR_DATA1 exit, BC holds 'stream data'. 2C8E LD HL,17 2C91 AND A 2C92 SBC HL,BC Give an error if the current stream was 2C94 JP C,#1680,REP_30 already used by the +D. 2C97 LD A,(#3E04) Fetch channel specifier. 2C9A AND #DF Only capitals. 2C9C CP 68,"D" 2C9E JR Z,#2CA5,OPEN_3 Jump if opening a "D" channel. 2CA0 CP 77,"M" Give an error if not opening a "M" 2CA2 JP NZ,#1644,REP_0 channel. 2CA5 OPEN_3 CALL #0702,TEST_DRV See if the drive is defined. 2CA8 LD A,#0A Signal 'OPENTYPE file'. 2CAA LD (#3E05),A 2CAD CALL #2CB3,OPEN_CHAN Open the channel. 2CB0 JP #047C,END Finished. THE 'OPEN "D" CHANNEL' SUBROUTINE This is the actual OPEN routine referred to the "D" channel. 2CB3 OPEN_CHAN LD A,(#3E03) Fetch stream number. 2CB6 ADD A,A The streams area entries are two bytes each. 2CB7 LD HL,23574 Address of data for stream 0. 2CBA LD E,A 2CBB LD D,0 2CBD ADD HL,DE Index into STRMS area. 2CBE PUSH HL 2CBF CALL #2CDF,OP_TEMP_D Open a temporary "D" channel. On return 2CC2 POP DE HL holds new channel offset. 2CC3 RET C Return when an error occurred. 2CC4 BIT 0,(IX+12) 2CC8 JR Z,#2CD6,MAKE_PERM Jump if this is a 'read' file. 2CCA IN A,(227) Read Floppy Disk Controller status. 2CCC BIT 6,A Test the 'write protect' bit. 2CCE JR Z,#2CD6,MAKE_PERM Jump if disk isn't write protected. NOTE: This doesn't work, the write protect bit of the FDC's status register is not adjusted with read commands. So the jump is always made. 2CD0 CALL #2B9E,RECL_CHAN Otherwise reclaim the channel. 2CD3 JP #1672,REP_23 And give an error. 2CD6 MAKE_PERM RES 7,(IX+4) Make the channel permanent by resetting bit 7 of the channel specifier. 2CDA EX DE,HL DE holds new channel offset. 2CDB LD (HL),E Store it into the STRMS area. 2CDC INC HL 2CDD LD (HL),D 2CDE RET Finished. THE 'OPEN TEMP. "D" CHANNEL' SUBROUTINE This subroutine is used to open a temporary "D" channel in the CHANS area. 2CDF OP_TEMP_D LD IX,(23631) Start of channel area (CHANS). 2CE3 LD DE,20 Point to the first 'non-standard' 2CE6 ADD IX,DE channel. 2CE8 OP_TEMP1 LD A,(IX+0) 2CEB CP 128 2CED JR Z,#2D24,OP_TEMP4 Jump if end of CHANS area is reached. 2CEF LD A,(IX+4) Otherwise fetch channel specifier. 2CF2 AND #5F Clear bit 7 and make capital. 2CF4 CP 68,"D" 2CF6 JR NZ,#2D1A,OP_TEMP3 Jump if this isn't a "D" channel. 2CF8 LD A,(#3E01) Fetch drive number. 2CFB CP (IX+11) Jump if this channel uses a different 2CFE JR NZ,#2D1A,OP_TEMP3 drive. 2D00 PUSH IX 2D02 POP HL Start of channel to HL. 2D03 LD DE,20 Filename offset. 2D06 ADD HL,DE 2D07 EX DE,HL DE points to the name of this channel. 2D08 LD HL,#3E06 HL points to the name of the channel to 2D0B LD B,10 be opened. 2D0D OP_TEMP2 LD A,(DE) 2D0E XOR (HL) 2D0F AND #DF Capitalize. 2D11 JR NZ,#2D1A,OP_TEMP3 Jump if not the same file. 2D13 INC HL 2D14 INC DE 2D15 DJNZ #2D0D,OP_TEMP2 Repeat for all 10 characters. 2D17 JP #1682,REP_31 Give an error if the channel already exists. 2D1A OP_TEMP3 LD E,(IX+9) Fetch the length of the channel. 2D1D LD D,(IX+10) 2D20 ADD IX,DE Point to the next channel. 2D22 JR #2CE8,OP_TEMP1 Repeat for all channels. The channel wasn't already present in memory so it can be opened. 2D24 OP_TEMP4 PUSH IX 2D26 LD A,%0001000 Scan the CATalogue for a matching 2D28 CALL #09A5,SCAN_CAT filename. 2D2B LD A,(#3E02) Get channel type (read/write). 2D2E JP NZ,#2D8A,OP_TEMP5 Jump if file not found. 2D31 CP 223,"OUT" 2D33 JP Z,#312A,OP_T_PATCH Jump if OUTput channel. 2D36 LD BC,551 Length of INput channel. 2D39 CALL #2DF3,CHAN_SPC Create the room for the channel. 2D3C CALL #0D93,RPT_HL Make HL point to the CAT entry. 2D3F POP IX 2D41 CALL #0702,TEST_DRV See if the drive is defined. 2D44 NOP 2D45 NOP 2D46 NOP 2D47 LD A,0 Signal 'READing'. 2D49 LD (IX+12),A 2D4C LD BC,39 Offset of buffer from start of channel. 2D4F LD (IX+15),C 2D52 LD (IX+16),B 2D55 PUSH HL HL points to the CATalogue entry. 2D56 PUSH IX IX points to the start of the channel. 2D58 POP HL 2D59 LD DE,19 Offset of directory description. 2D5C ADD HL,DE 2D5D EX DE,HL 2D5E POP HL Pointer to CAT entry. 2D5F LD BC,11 Move the directory description and the 2D62 LD A,(HL) filename to the channel. 2D63 LD (#3E05),A Store dir. descr. in UFIA1. 2D66 LDIR 2D68 INC HL Skip length in sectors, i.e. point to 2D69 INC HL track and sector bytes. 2D6A LD B,(HL) Fetch first track and sector. 2D6B INC HL 2D6C LD C,(HL) 2D6D PUSH BC 2D6E LD BC,196 2D71 ADD HL,BC HL points to file header - 1 in CAT 2D72 LD A,(HL) entry. That is the MSB of the file 2D73 LD (IX+18),A length (number of 64K blocks). 2D76 INC HL 2D77 LD BC,9 2D7A LDIR Copy the file header to the channel. 2D7C LD DE,#3FEA 2D7F LD BC,22 Copy the SNAP registers (?). 2D82 LDIR 2D84 POP DE Get track and sector in DE. 2D85 CALL #05CC,RSAD Load the sector at DE. 2D88 JR #2DDC,OP_TEMP8 The file was not found, so if the channel isn't for OUTput give an error. 2D8A OP_TEMP5 CP 191,"IN" 2D8C JP Z,#1678,REP_26 Give error if it is an INput channel. 2D8F OP_TEMP6 LD BC,787 Length of OUTput channel. 2D92 CALL #2DF3,CHAN_SPC Create the room for the channel. 2D95 POP IX 2D97 CALL #0702,TEST_DRV See if the drive is defined. 2D9A NOP 2D9B NOP 2D9C NOP 2D9D LD A,1 Signal 'WRITEing'. 2D9F LD (IX+12),A 2DA2 LD BC,275 Offset of databuffer from the start of 2DA5 LD (IX+15),C the channel. 2DA8 LD (IX+16),B 2DAB CALL #0AD9,OFSM_2 Open the file. 2DAE JR Z,#2DBB,OP_TEMP7 Jump if file doesn't exist (anymore). 2DB0 LD BC,787 Length of an OUTput channel. 2DB3 PUSH IX Start of the channel to HL. 2DB5 POP HL 2DB6 RST #10,CALBAS Reclaim the channel. 2DB7 DEFW #19E8,RECLAIM_2 2DB9 SCF Signal 'error'. 2DBA RET Finished. 2DBB OP_TEMP7 JP #2DDC,OP_TEMP8 Jump forward. Before the routine continues there are first some 'leftovers' from a earlier system version. 2DBE JR Z,#2DDC,OP_TEMP8 2DC0 PUSH IX 2DC2 POP HL 2DC3 LD DE,230 2DC6 ADD HL,DE 2DC7 EX DE,HL 2DC8 LD HL,(#3E1E) 2DCB LD BC,30 2DCE ADD HL,BC 2DCF LD BC,9 2DD2 LDIR 2DD4 LD HL,#3FEA 2DD7 LD BC,20 2DDA LDIR Now continue with the 'OPEN a temporary "D" channel' routine. 2DDC OP_TEMP8 PUSH IX 2DDE POP DE Start of channel to DE. 2DDF LD HL,#2E0B,D_CH_DATA Start of the "D" channel data. 2DE2 LD BC,11 Copy the 11 bytes channel data to the 2DE5 LDIR channel area. 2DE7 PUSH IX Start of channel to HL. 2DE9 POP HL 2DEA LD DE,(23631) HL-(CHANS)+1 gives the required 'stream 2DEE OR A offset'. 2DEF SBC HL,DE 2DF1 INC HL 2DF2 RET Finished. THE 'MAKE ROOM FOR CHANNEL' SUBROUTINE This small subroutine creates room for a channel at the end of the CHANS area (i.e. just before the BASIC program). 2DF3 CHAN_SPC LD (#2E14),BC Store the length of the channel into the "D" channel data table. 2DF7 LD HL,(23635) Fetch the start address of the channel 2DFA DEC HL ((PROG)-1). 2DFB PUSH HL 2DFC PUSH BC 2DFD RST #10,CALBAS Create the required space by calling 2DFE DEFW #1655,MAKE_ROOM 'main' ROM 'MAKE_ROOM'. 2E00 POP BC 2E01 POP HL Clear the created space. 2E02 CHAN_SPC1 LD (HL),0 2E04 INC HL 2E05 DEC BC 2E06 LD A,B 2E07 OR C 2E08 JR NZ,#2E02,CHAN_SPC1 2E0A RET THE '"D" CHANNEL DATA' TABLE The '11' bytes that compose the initial part of a "D" channel are as follows: 2E0B D_CH_DATA DEFW #0008 Main ROM 'output' routine. 2E0D DEFW #0008 Main ROM 'input' routine. 2E0F DEFB "D"+128 Channel specifier. 2E10 DEFW #2F5F,DCHAN_OUT +D system 'output' routine. 2E12 DEFW #2EDC,D_INPUT +D system 'input' routine. 2E14 DEFW #0000 Length of a channel. THE 'CLOSE #' COMMAND SYNTAX ROUTINE Unlike the Interface 1 and the Opus Discovery, the +D doesn't page-in in the middle of the 'main' ROM 'CLOSE' routine. But because the 'main' ROM routine can't cope with +D channels a 'CLOSE' for those channels has to be available. In order to fail the normal syntax, 'CLOSE #*s' has to be used. The 'CLOSE #*' command closes all streams. 2E16 CLOSE RST #28,NEXT_C Next character. 2E17 CP 42,"*" 2E19 JP NZ,#1644,REP_0 Give an error if it isn't a '*'. 2E1C RST #28,NEXT_C Next character. 2E1D CP 13 2E1F JR Z,#2E34,CLOSE_ALL Jump if statement ended with ENTER. 2E21 CP 58,":" 2E23 JR Z,#2E34,CLOSE_ALL Also if statement ended with a ':'. 2E25 CALL #2AF0,EXPT_#NR1 Evaluate stream number. 2E28 CALL #3148,ST_END_RAM Confirm end of statement and exit when syntax checking. 2E2B LD A,(#3E03) Fetch stream number. 2E2E CALL #2E5E,CLOSE_STRM Close the stream. 2E31 JP #047C,END Finished. 2E34 CLOSE_ALL CALL #3148,ST_END_RAM Confirm end of statement and exit if 2E37 JR #2E46,CLEAR_1 syntax checking. Jump into the CLEAR# routine. THE 'CLEAR #' COMMAND ROUTINE All streams are closed in turn, with bit 1 of FLAGS3 set to signal that the remaining buffer contents are to be erased (with the 'CLOSE #*' command all buffers are emptied, i.e. their contents are sent to the corresponding device). 2E39 CLEAR RST #28,NEXT_C Advance CH_ADD. 2E3A CP 35,"#" 2E3C JP NZ,#1644,REP_0 Give an error if it isn't a '#'. 2E3F RST #28,NEXT_C 2E40 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 2E43 CALL #15F9,SIGN_1 Signal 'CLEAR #'. 2E46 CLEAR_1 XOR A Start with stream 0. 2E47 CLEAR_2 PUSH AF 2E48 CALL #2E5E,CLOSE_STRM Close this stream. 2E4B POP AF 2E4C INC A Next stream. 2E4D CP 16 Repeat until all streams 0..15 have 2E4F JR C,#2E47,CLEAR_2 been CLOSEd. 2E51 CALL #2C28,RECL_TEMP Reclaim temporary channels. 2E54 XOR A 2E55 LD (#3DEF),A Clear 'MAP_USED' (=POKE @7663,0). 2E58 LD (#3ACF),A Clear FLAGS3. 2E5B JP #047C,END Finished. THE 'CLOSE A STREAM' SUBROUTINE Any stream 0 to 15 may be CLOSEd by loading the stream number into A and then calling this subroutine. The unsent bytes in 'OUTput' 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. 2E5E CLOSE_STRM RST #10,CALBAS Call 'STR_DATA1'. 2E5F DEFW #1727,STR_DATA1 2E61 LD A,C 2E62 OR B Return if the stream is already CLOSEd 2E63 RET Z (i.e. stream data = 0). 2E64 LD (#3DED),BC Store stream data. 2E68 PUSH HL 2E69 LD HL,(23631) Make HL point to the start of the 2E6C DEC HL channel attached to the stream to be 2E6D ADD HL,BC CLOSEd ((CHANS)+'stream data'). 2E6E EX (SP),HL HL now holds the address of the stream data. 2E6F RST #10,CALBAS A call in the middle of the 'main' ROM 2E70 DEFW #16EB,CLOSE_0 'CLOSE' routine is made to update STRMS contents. 2E72 POP IX IX points to the start of the channel 2E74 LD A,B to be removed. 2E75 OR C 2E76 RET NZ Exit if the stream is one of 0 to 3. NOTE: Because this test tests for streams a disk channel attached to one of the streams 0..3 can never be CLOSEd. If the test was made for 'standard' channels it had been possible to use streams 0..3 with "D" channels. 2E77 LD A,(IX+4) Fetch channel specifier. 2E7A AND #5F Clear bit 7 (temporary) and make capital. 2E7C CP 68,"D" 2E7E JR NZ,#2E8E,CLOSE_1 Jump if it isn't a "D" channel. 2E80 CLOSE_0 BIT 0,(IX+12) 2E84 JR Z,#2E8E,CLOSE_1 Jump if it is an 'INput' channel. 2E86 CALL #1621,TEST_1 Jump if doing a 'CLEAR #', i.e. just 2E89 JR NZ,#2E8E,CLOSE_1 remove the channel. 2E8B CALL #3117,CL_PATCH Empty the buffer. 2E8E CLOSE_1 CALL #2B9E,RECL_CHAN Reclaim the channel. Now all data refering to the stream attached to the channels moved down are updated. 2E91 XOR A Start with stream 0. 2E92 LD HL,23574 Address of data for stream 0. 2E95 CLOSE_2 LD (#3AC8),HL Use 'FILE_ADDR' as a temporary storage. 2E98 LD E,(HL) Fetch stream data. 2E99 INC HL 2E9A LD D,(HL) 2E9B LD HL,(#3DED) Fetch stream data for CLOSEd stream. 2E9E AND A Jump if the stream data found is lower 2E9F SBC HL,DE than that of the CLOSEd stream (i.e. 2EA1 JR NC,#2EAE,CLOSE_3 channel has not been moved). 2EA3 EX DE,HL Fetched stream data to HL. 2EA4 AND A 2EA5 SBC HL,BC Calculate the new stream data. 2EA7 EX DE,HL New stream data to DE. 2EA8 LD HL,(#3AC8) Restore stream data address. 2EAB LD (HL),E Store new stream data. 2EAC INC HL 2EAD LD (HL),D 2EAE CLOSE_3 LD HL,(#3AC8) Make HL point to next stream data. 2EB1 INC HL 2EB2 INC HL 2EB3 INC A Increment stream number. 2EB4 CP 16 2EB6 JR C,#2E95,CLOSE_2 Repeat for all streams 0..15. 2EB8 RET Finished. THE 'CLS #' COMMAND ROUTINE The 'CLS #' command resets during runtime the Spectrum system variables ATTR_P, ATTR_T, MASK_P, MASK_T, P_FLAG and BORDCR. I.e. all these variables are filled with their 'initial' values (paper 7, ink 0, flash 0 and bright 0). 2EB9 CLS RST #28,NEXT_C Next character. 2EBA CP 35,"#" 2EBC JP NZ,#1644,REP_0 Give error if it isn't a '#'. 2EBF RST #28,NEXT_C Next character. 2EC0 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 2EC3 LD HL,56 The 'initial' attribute value. 2EC6 LD (23693),HL Store 56 into ATTR_P, clear MASK_P. 2EC9 LD (23695),HL Store 56 into ATTR_T, clear MASK_T. 2ECC LD (IY+14),L Store 56 also for lower screen attribute. 2ECF LD (IY+87),H Clear P_FLAG. 2ED2 LD A,7 Set white border. 2ED4 OUT (254),A 2ED6 RST #10,CALBAS Call 'main' ROM 'CLS' routine. 2ED7 DEFW #0D6B,CLS 2ED9 JP #047C,END Finished. THE '"D" CHANNEL INPUT' ROUTINE This is a peculiar routine, although the +D supports only one type of channel (the "D" channel), this routine can handle all kinds of channels by loading HL with the address of the 'service' input routine and entering at address #2EE3. From that address on it's largely the same as the Interface 1 'CALL_INP' routine, which routine handles all the IF1's channels. 2EDC D_INPUT LD IX,(23633) IX points to the start of the current channel (CURCHL). 2EE0 LD HL,#2F2E,DCHAN_IN Address of "D" input service routine. 2EE3 RES 3,(IY+2) Signal 'the mode is to be considered as being unchanged'. 2EE7 PUSH HL Store address of service routine. 2EE8 LD HL,(23613) HL points to error address (ERR_SP). 2EEB LD E,(HL) Fetch the error address. 2EEC INC HL 2EED LD D,(HL) 2EEE AND A 2EEF LD HL,#107F,ED_ERROR If the error address is 'ED_ERROR' 2EF2 SBC HL,DE ('main' ROM) then an INPUT command was 2EF4 JR NZ,#2F1D,D_INKEY$ used. Jump if unequal to 'ED_ERROR'. Now deal with an 'INPUT #' command referred to a "D" channel. 2EF6 POP HL Restore address of service routine. 2EF7 LD SP,(23613) Clear the machine stack (ERR_SP). 2EFB POP DE Remove 'ED_ERROR'. 2EFC POP DE 2EFD LD (23613),DE Restore the old value of ERR_SP. 2F01 D_INPUT1 PUSH HL Store address of service routine. 2F02 LD DE,#2F07,D_INP_END Return address is 'D_INP_END' below. 2F05 PUSH DE 2F06 JP (HL) Jump to the service routine. When the byte has been read from the required channel, a return is made here to add the byte to the INPUT line, or to return if the byte is equal to CHR$ 13, i.e. ENTER. 2F07 D_INP_END JR C,#2F0F,D_INP_ACC Jump with acceptable codes. 2F09 JP NZ,#167A,REP_27 Give the 'END of file' error when the Zero flag is reset. 2F0C POP HL Otherwise restore address of service 2F0D JR #2F01,D_INPUT1 routine and try again. 2F0F D_INP_ACC CP 13 2F11 JR Z,#2F19,D_INPUT2 Jump if the code is ENTER. 2F13 RST #10,CALBAS Otherwise the byte is to be added to 2F14 DEFW #0F85,ADD_CHAR0 the INPUT line. This is done by calling into the 'ADD_CHAR' subroutine. 2F16 POP HL Restore address of service routine and 2F17 JR #2F01,D_INPUT1 read the next byte. 2F19 D_INPUT2 POP HL Drop the address of the service routine 2F1A JP #0050,UNPAGE_1 and page-out the +D system. Now deal with the reading of a single byte. 2F1D D_INKEY$ POP HL Restore address of the servce routine. 2F1E LD DE,#2F23,D_INK$_END Return address is 'D_INK$_END' below. 2F21 PUSH DE 2F22 JP (HL) Jump to the service routine. 2F23 D_INK$_END RET C Return with acceptable codes or 2F24 RET Z with no byte read. 2F25 CALL #1626,TEST_2 Give the 'END of file' error if not 2F28 JP Z,#167A,REP_27 executing a 'MOVE' command. 2F2B OR 1 Otherwise return with Zero and Carry 2F2D RET flags both reset. THE '"D" CHANNEL INPUT' SERVICE ROUTINE This is the actual input a byte from disk routine. The byte is read from the data buffer in the channel, when it is empty the next sector is read from disk (provided that the 'current' data block is not the EOF one) before reading the byte. 2F2E DCHAN_IN BIT 0,(IX+12) Give 'Reading a WRITE file' error if 2F32 JP NZ,#1668,REP_18 it's an OUTput channel. 2F35 LD A,(IX+31) Decrease LSB of file length. 2F38 SUB 1 2F3A LD (IX+31),A 2F3D JR NC,#2F57,DCHAN_IN1 Jump if more bytes left. 2F3F LD A,(IX+32) Decrease MID byte of file length. 2F42 SUB 1 2F44 LD (IX+32),A 2F47 JR NC,#2F57,DCHAN_IN1 Jump if more bytes left. 2F49 LD A,(IX+18) Decrease MSB of file length. 2F4C SUB 1 2F4E LD (IX+18),A 2F51 JR NC,#2F57,DCHAN_IN1 Jump if more bytes left. 2F53 XOR A Otherwise EOF has been reached, so reset Zero and Carry flag to signal 'End Of File'. 2F54 ADD A,13 The return byte is 13. 2F56 RET Finished. NOTE: This 'end of file' test works only once, if an attempt is made to read more bytes after the 'End of FILE' message has been given a crash will almost certainly follow. 2F57 D_CHANIN1 CALL #077F,LBYT Load one byte, read a new sector from disk when the buffer is empty. 2F5A CALL #168E,BORD_REST Restore border colour. 2F5D SCF Signal 'acceptable code'. 2F5E RET THE '"D" CHANNEL OUTPUT' ROUTINE The routine which handles "D" channel output is quite short. It SAVEs the byte in the A register to disk by calling the ROM 'SBYT' routine, which handles the saving of the byte. The only thing done here is incrementing the file length bytes. 2F5F DCHAN_OUT LD IX,(23633) IX point to current channel (CURCHL). 2F63 BIT 0,(IX+12) Give 'Writing a READ file' error if 2F67 JP Z,#166A,REP_19 it's an INput channel. 2F6A CALL #0761,SBYT Save the byte in the A register. 2F6D CALL #168E,BORD_REST Restore the border colour. 2F70 NOP 2F71 NOP 2F72 NOP 2F73 NOP 2F74 PUSH IX 2F76 LD BC,229 2F79 ADD IX,BC IX now points to the file header. 2F7B INC (IX+2) Update file length, skip higher bytes 2F7E JR NZ,#2F88,DCHAN_OUT1 if it isn't necessary to update them. 2F80 INC (IX+3) 2F83 JR NZ,#2F88,DCHAN_OUT1 2F85 INC (IX+0) 2F88 DCHAN_OUT1 POP IX 2F8A RET Finished. .The Command code routines THE 'TRANSFER UFIA TO DFCA' SUBROUTINE This subroutine is called by using command code 51 (#33), it transfers the file description and header (UFIA) to the Disk File Channel Area (DFCA). On entry IX must point to the start of the User's File Information Area (UFIA). 2F8B HXFER PUSH IX 2F8D POP HL 2F8E LD DE,#3E01 Start of 'UFIA1'. 2F91 LD BC,24 2F94 LDIR Transfer the UFIA to 'UFIA1'. 2F96 LD IX,#3AC3 IX points to the DFCA. 2F9A CALL #0702,TEST_DRV Check if the specified drive is 2F9D RET defined. THE 'OPEN FILE SECTOR MAP' SUBROUTINE This subroutine is called by using command code 52 (#34), it Opens a File Sector Map with the information contained in the DFCA. On entry IX must point to the UFIA, a call to 'HXFER' above transfers the UFIA to the DFCA. A return is made with the disk buffer pointer (RPT) set to the start of the disk buffer in the +D RAM. 'OFSM' should be used for files which don't contain a 9 byte header at the start of the file. 2F9E OFSM CALL #2F8B,HXFER Transfer UFIA to DFCA. 2FA1 JP #0AD9,OFSM_2 Open the file sector map. THE 'OPEN A FILE' SUBROUTINE This subroutine is called by using command code 53 (#35), it opens a file for SAVEing. As with the preceeding subroutines IX must point to the UFIA. By calling 'OFSM' above the UFIA is transferred to the DFCA and the file sector map is opened. Finally 'SAVE_HEAD1' is called to transfer the 9 bytes file header to the file. 'HOFLE' can be used for files which contain the 9 byte header. 2FA4 HOFLE CALL #2F9E,OFSM Transfer UFIA to DFCA and open the file sector map. 2FA7 CALL #2879,SAVE_HEAD1 Transfer the 9 byte file header to the 2FAA RET file and exit. THE 'SAVE BLOCK TO DISK' SUBROUTINE This is called by using command code 55 (#37). The data block starting at address DE with length BC is SAVEd to disk. NOTE: A file has to be opened for SAVEing before writing bytes. Use 'HOFLE' or 'OFSM' to do this. 2FAB HSVBK CALL #2FCB,BCDE_DEHL Transfer BC to DE and DE to HL. 2FAE JP #0850,HSVBK_2 Save the block. THE 'GET A FILE FROM DISK' SUBROUTINE This is called by using command code 59 (#3B), it opens a file for LOADing. The IX register must point to the start of the UFIA. The return is made with the first sector of the file loaded into the disk buffer and RPT pointing to the first byte (usually the start of the 9 byte file header). 2FB1 HGFLE CALL #2F8B,HXFER Transfer the UFIA to the DFCA. 2FB4 JP #0BCF,HGFLE_2 Open the file and load the first sector in the disk buffer. THE 'LOAD BLOCK FROM DISK' SUBROUTINE This subroutine is called by using command code 61 (#3D), it does the opposite of 'HSVBK' above. The data block starting at address DE with length BC is LOADed from disk. NOTE: The file has to be opened by using 'HGFLE' before an attempt can be made to LOAD bytes. Don't try to LOAD more bytes than available. 2FB7 HLDBK CALL #2FCB,BCDE_DEHL Transfer BC to DE and DE to HL. 2FBA JP #079E,LOAD_FILE Load the block. THE 'ERASE A FILE' SUBROUTINE This is called by using command code 65 (#41). It ERASEs one file on the disk (even when wildcards were used), using the information contained in the UFIA, so make sure that IX points to the start of it. 2FBD HERAZ CALL #2F8B,HXFER Transfer the UFIA to the DFCA. 2FC0 CALL #2559,FIND_FILE Find the file, HL points to the directory entry of the file (contained in the disk buffer). 2FC3 JP NZ,#1678,REP_26 Give error if file not found. 2FC6 LD (HL),0 Directory description 0 means ERASEd. 2FC8 JP #0584,WSAD Write sector DE. THE 'BC TO DE AND DE TO HL' SUBROUTINE This routine transfers the contents of BC to DE and that of DE to HL, it also sets IX to the start of the DFCA. 2FCB BCDE_DEHL PUSH DE 2FCC PUSH BC 2FCD POP DE 2FCE POP HL 2FCF LD IX,#3AC3 2FD3 RET THE 'READ SECTOR TO ADDRESS' SUBROUTINE This routine is called by using command code 68 (#44). It reads sector DE from drive A to the address held in the IX register. 2FD4 HRSAD PUSH BC 2FD5 PUSH IX 2FD7 LD IX,#3AC3 2FDB CALL #0705,TEST_DRV See if the drive held in the A register is defined. 2FDE CALL #05CC,RSAD Load the sector into the disk buffer. 2FE1 POP HL 2FE2 PUSH DE 2FE3 LD DE,#3BD6 Start of disk buffer. 2FE6 EX DE,HL 2FE7 LD BC,512 Sector length. 2FEA LDIR Move sector to specified address. 2FEC PUSH DE 2FED POP IX Update IX. 2FEF POP DE Restore DE and BC. 2FF0 POP BC 2FF1 RET THE 'WRITE SECTOR FROM ADDR.' SUBROUTINE This is called using command code 69 (#45), it writes sector DE to drive A starting from address IX. 2FF2 HWSAD PUSH BC 2FF3 PUSH IX 2FF5 POP HL 2FF6 LD IX,#3AC3 2FFA CALL #0705,TEST_DRV See if the drive held in the A register 2FFD PUSH DE is defined. 2FFE LD DE,#3BD6 3001 LD BC,512 Sector length. 3004 LDIR Move BC bytes to the disk buffer. 3006 POP DE 3007 PUSH HL 3008 CALL #0584,WSAD Write sector DE to disk. 300B POP IX 300D POP BC 300E RET Finished. THE 'READ SECTOR DE' SUBROUTINE This routine is called using command code 63 (#3F), it loads sector DE from the current drive into the disk buffer. 300F JRSAD LD IX,#3AC3 3013 JP #05CC,RSAD Load the sector. THE 'WRITE SECTOR DE' SUBROUTINE This is called using command code 62 (#3E), it saves the contents of the disk buffer into sector DE on the current drive. 3016 JWSAD LD IX,#3AC3 301A JP #0584,WSAD Save the sector. .Miscalleneous routines III THE 'COPY SCREEN' ROUTINE This routine has two entry points. The first one, #301D, is used with the BASIC commands 'SAVE/LOAD/VERIFY/MERGE SCREEN$'. The second entry point (#3020) is used for the 'COPY' command itself. Depending on the parameter following the 'SCREEN$', the normal or the grey scale screen dump is used. 301D DUMP_SCR$ POP HL Drop the return address (within the routine which called 'EXPT_PARMS'). 301E JR #3026,COPY_1 Jump forward. 3020 COPY RST #28,NEXT_C Advance CH_ADD. 3021 CP 170,"SCREEN$" Give 'Nonsense in G+DOS' error if 3023 JP NZ,#1644,REP_0 command isn't followed by 'SCREEN$'. 3026 COPY_1 LD A,49,"1" Default is '1' for 'normal' dump. 3028 LD (#3E00),A 302B RST #28,NEXT_C Advance CH_ADD 302C CP 13 302E JR Z,#3038,COPY_2 Jump with ENTER. 3030 CP 58,":" 3032 JR Z,#3038,COPY_2 Also jump with ':'. 3034 LD (#3E00),A Otherwise store character. 3037 RST #28,NEXT_C Update CH_ADD again. 3038 COPY_2 CALL #3148,ST_END_RAM Confirm end of statement and exit during syntax checking. 303B LD A,(#3E00) 303E CP 49,"1" Normal screendump if '1' followed the 3040 CALL Z,#12D2,COPS 'SCREEN$'. 3043 CP 50,"2" Grey scale in case of a '2'. 3045 CALL Z,#133E,COPS2 Ignore other values. 3048 JP #047C,END Finished. .The system message routines Finally there follow some messages. A message follows directly after the CALL to the ROM print routine. 304B MSG_0 CALL #178A,PO_MSG1 304E DEFM "* MGT PLUS D DISC" 3060 DEFB " "+128 3061 MSG_1 CALL #178A,PO_MSG1 3064 DEFM " CATALOGUE *" 3070 DEFB 13,13+128 3072 MSG_2 CALL #178A,PO_MSG1 3075 DEFB 13,13 3077 DEFB "Number of Free K-Bytes =" 308F DEFB " "+128 3090 MSG_3 CALL #177E,PO_MSG 3093 DEFM "©Miles Gordon Technology G+DOS2a" 30B3 DEFB 13,13+128 This routine makes sure the 'SOURCE' and 'TARGET' messages are printed in turn. 30B5 TO_MSG1 LD A,(#3107) 30B8 XOR #01 30BA LD (#3107),A 30BD JR NZ,#30E3,MSG_5 30BF MSG_4 CALL #178A,PO_MSG1 30C2 DEFB 13 30C3 DEFM "Insert SOURCE disc - press SPAC" 30E2 DEFB "E"+128 30E3 MSG_5 CALL #178A,PO_MSG1 30E6 DEFB 13 30E7 DEFM "Insert TARGET disc - press SPAC" 3106 DEFB "E"+128 3107 DEFB #00 THE 'CLEAR MESSAGE FLAG' SUBROUTINE 3108 TEST_SAVE XOR A Clear the flag used in printing 3109 LD (#3107),A 'SOURCE' and 'TARGET' message. 310C CALL #1635,TEST_5 310F RET .The patches THE 'OPENTYPE FILE OPEN/CLOSE' ROUTINE This routine opens or closes an opentype file according to the contents of the A register. When it holds 0 a "D" channel is attached to the stream given in the DFCA. A non zero value closes the corresponding stream. 3110 OTFOC AND A 3111 JP Z,#2CB3,OPEN_CHAN Open a channel if A holds zero. 3114 JP #2E5E,CLOSE_STRM Otherwise close the stream. THE 'CLOSE #' PATCH This patch cures the bug related to CLOSEing 'OPENTYPE' files. Before the file is CLOSEd first the correct drive settings are send to the FDC. 3117 CL_PATCH LD E,(IX+17) Fetch sector and track. 311A LD D,(IX+18) 311D LD A,(IX+11) Fetch drive number. 3120 LD (#3ACE),A 3123 CALL #071C,SET_DRVSD Select track, sector, side and drive. 3126 CALL #0B89,CFSM Close the file sector map. 3129 RET Finished. THE 'OPEN TEMPORARY OUTPUT' PATCH This patch gives an error report when an attempt is made to open an existing OUTput file using a command code. A jump back to the 'open a temporary channel' routine is made if not using a command code. 312A OP_T_PATCH PUSH HL 312B LD HL,(#2066) 312E LD A,H 312F OR L Jump back to the 'OP_TEMP' routine if 3130 POP HL 'D_ERR_SP' is zero (this isn't the case 3131 JP Z,#2D8F,OP_TEMP6 during command code execution). 3134 JP #167C,REP_28 Otherwise give 'File NAME used' error. THE 'NEW' PATCH When the file copy command is finished the +D jumps to the 'NEW' routine. With System 2a a selection is made for 48K or 128K 'NEW' 3137 TO_NEW BIT 4,(IY+1) Jump if not in 128K mode HL contains 313B JP Z,#004F,UNPAGE_HL #11B7, the address of 48K 'NEW'. 313E CALL #5B00,SWAP Call the paging subroutine of the 128. 3141 DI 3142 LD BC,#00C7 Address of 128 'NEW' routine. 3145 JP #0046,UNPAGE_BC THE 'END OF STATEMENT' ROUTINE It isn't clear why IX should point to #000C during syntax checking. 3148 ST_END_RAM LD IX,#000C 314C CALL #046E,ST_END 314F LD IX,#3AC3 3153 RET THE 'PCAT' ROUTINE This routine is called by using command code 67, in System 2a the command code works. 3154 PCAT CALL #0702,TEST_DRV Drive defined? 3157 LD A,(#3E10) Get 'CAT' type. 315A JP #24B5,CAT_RUN Do the CAT. 315D - 39FF Unused locations (all set to #00).