The restart routines THE 'USR 0' RESTART When address #0001 (NOT #0000!) is reached the DISCiPLE hardware pages in the DISCiPLE RAM/ROM. (RAM at #0000) NOTE: On power up or when the reset button is pressed the ROM is paged in at address #0000. 0000 USR_0 DI Disable the 'keyboard interrupt'. 0001 XOR A #00 for 'USR 0' (#FF for 'NEW'). 0002 OUT (31),A Reset control lines. 0004 JP #04BA,USR_0_1 Continue with the 'USR_0' routine. 0007 DEFB #00 Unused location. THE 'USE GDOS' RESTART This is the main entry point to the DISCiPLE system; it is paged in when the Z80 reaches address #0008, that is, the address of the 'main' ROM 'ERROR' routine. 0008 START LD HL,(23645) The address reached by the interpreter 000B LD (23647),HL (CH_ADD) is copied to the error pointer 000E JR #003A,START_2 (X_PTR) before proceeding. THE 'CALL A MAIN ROM ROUTINE' RESTART This routine allows for a subroutine in the 'main' ROM to be called from the DISCiPLE system. It can be called by using a RST #10 instruction, followed by the address of the 'main' ROM subroutine. 0010 CALBAS JP #0499,CALBAS_2 Jump forward. THE 'INITIALIZE SYSTEM' ROUTINE This is part of the boot routine, after loading the system file (using the ROM routine) control is transferred to this address. 0013 INIT_SYS OUT (123),A Resets boot, i.e. ROM at #2000. 0015 JP #0550,LOAD_AUTO Jump forward. THE 'FLAGS ADDRESS' RESTART This routine is used by the -BIT- routines at address #09CE, the original HL is saved and the flags address is loaded into HL. 0018 F_ADDR_RAM EX (SP),HL Exchange RETurn address and HL. 0019 PUSH HL Re-stack RETurn address. 001A LD HL,#1ACF Address of FLAGS3. 001D RET 001E DEFB #00,#00 Unused locations. THE 'DISCiPLE ERROR' RESTART A RST #20 followed by an one-byte error code will print the appropriate message, when the error occurred during the execution of a command code however, the error code will be returned in the A register with the Carry flag set. 0020 DISC_ERR LD HL,(23645) The address reached by the interpreter 0023 LD (23647),HL is copied to the error pointer before 0026 JR #0035,DISC_ERR2 proceeding. THE 'NEXT CHAR' RESTART This routine gets the next character from a BASIC line, it does this by calling the RST #20 routine in the 'main' ROM. 0028 NEXT_C_RAM RST 16,CALBAS Call 'main' ROM 'NEXT_CHAR'. 0029 DEFW #0020,NEXT_CHAR 002B RET THE 'GET CHAR' ROUTINE Get character by calling the 'main' ROM restart. 002C GET_C_RAM RST 16,CALBAS Call 'main' ROM 'GET_CHAR'. 002D DEFW #0018,GET_CHAR 002F RET THE 'SYNTAX-Z' RESTART This corresponds to the 'main' ROM 'SYNTAX-Z' subroutine. A test of bit 7 of FLAGS will give the Zero flag set during syntax checking, and reset during execution. 0030 SYNTAX_Z BIT 7,(IY+1) Test the runtime flag. 0034 RET THE 'DISC_ERR2' ROUTINE 0035 DISC_ERR2 JP #2990,JD_ERROR Continue with the DISCiPLE error routine. THE 'MASKABLE INTERRUPT' RESTART While the DISCiPLE system is paged in, 'nothing' is done during a interrupt. 0038 INT_RAM EI Enable interrupts before RETurning. 0039 RET THE 'START_2' ROUTINE 003A START_2 JP #0597,START_3 Continue with the DISCiPLE systems main entry routine. The page in/out routines THE 'PAGE 128K RAM' ROUTINE The 128K RAM-bank contained in the A register is paged-in. 003D RAMPAGE_A LD BC,#7FFD 128K bank-switch port address. 0040 OUT (C),A Select RAM bank. 0042 RET THE 'SECRET VERSION NUMBER' 0043 DEFM "6.8" THE 'UNPAGE 128 ROM' SUBROUTINE This routine pages out the DISCiPLE system and returns to the 128K ROM at address #0049. That address contains a RET instruction so the effect is a jump to BC with the 128K ROM paged in. 0046 UNPAGE_BC PUSH BC Stack return address. 0047 UNPAGE_0 OUT (187),A Page out DISCiPLE system. 0049 RET ? This statement is not reached from above. 004A DEFB #00,#00,#00,#00,#00 Unused locations. THE 'UNPAGE' SUBROUTINE This routine pages out the DISCiPLE system and returns to the 'main' ROM at address #0052. That address contains a RET instruction so the effect is a jump to HL with the 'main' ROM paged in. 004F UNPAGE_HL PUSH HL Stack return address. 0050 UNPAGE_1 OUT (187),A Page out DISCiPLE system. The Snapshot routines THE 'SNAPSHOT-FILE' UFIA The following bytes are the last 20 bytes of a snapshot file UFIA. 0052 SNAP_UFIA DEFB 0 Directory description. 0053 DEFM "Snap " File name. 005D DEFB 3 File type. 005E DEFW #0000 File length. 0060 DEFW #0000 File address. 0062 DEFW #0000 Not used with Snap's. 0064 DEFW #FFFF Not used with Snap's. THE 'NON-MASKABLE INTERRUPT' ROUTINE This is the third point, from address #0000, at which the DISCiPLE system is paged in. It is reached either by pressing the 'snapshot' button or when returning from a CALBAS. 0066 NMI_RAM PUSH AF Save A register. 0067 LD A,(#1DE5) 006A CP #47 Check if returning from a CALBAS. 006C JR NZ,#0074,SNAPSHOT Jump if not returning from a CALBAS. 006E XOR A 006F LD (#1DE5),A Clear CALBAS executing. 0072 POP AF Restore A register and return to the 0073 RET calling routine. THE 'SNAPSHOT' ROUTINE When the 'snapshot' button is pressed this routine is executed. By pressing the keys 1 to 5 a choice between the following options can be made: dump the screen to the printer small or grey-scale, save the screen to disk, or to save the complete RAM contents to disk both for the 48K and 128K Spectrums. 0074 SNAPSHOT LD A,R 0076 PUSH AF Save R register and interrupt status. 0077 LD (#1FFE),SP Use 'internal' stack. 007B LD SP,#1FFE 007E LD A,I 0080 PUSH AF Save all registers, starting with I. 0081 PUSH HL 0082 PUSH BC 0083 PUSH DE 0084 EXX Save alternative registerset. 0085 PUSH AF Note, AF is PUSHed again! 0086 PUSH HL So in effect AF' is completely 0087 PUSH BC forgotten. 0088 PUSH DE 0089 PUSH IX Save the index registers. 008B PUSH IY 008D DI This is not necessary, interrupts are disabled already. 008E LD HL,#01EE,SNAP_EXIT 0091 PUSH HL RETurn address from snapshot. 0092 LD (#0296),SP Store current stackpointer at D_ERR_SP so an error will activate SNAP_EXIT. 0096 LD BC,#FEFE Keyboard port and CAPS-V I/O address. 0099 IN A,(C) 009B BIT 0,A 009D RET NZ Test for CAPS, RETurn if not pressed. 009E LD B,#F7 Key 1-5 I/O address. 00A0 SNAP_KEYS IN E,(C) 00A2 BIT 0,E CASE key OF 00A4 JP Z,#164C,COPS 1: jump to the smallcopy routine. 00A7 BIT 1,E 00A9 JP Z,#16B2,COPS2 2: jump to the greyscale routine. 00AC LD HL,16384 start of RAM (also start of SCR$). 00AF BIT 2,E 00B1 JR NZ,#00BA,NO_SCREEN 3: Save SCREEN$. 00B3 LD A,7 type=SCR$. 00B5 LD DE,6912 length of SCR$. 00B8 JR #00D8,SNAP_SAVE 00BA NO_SCREEN BIT 3,E 00BC JR NZ,#00C5,NO_SNAP_48 4: 48K Snapshot. 00BE LD A,5 type=48K Snap. 00C0 LD DE,49152 length of 48K RAM. 00C3 JR #00D8,SNAP_SAVE 00C5 NO_SNAP_48 BIT 4,E 00C7 JR Z,#00D0,SNAP_128 5: 128K Snapshot. 00C9 INC A END. 00CA AND #07 00CC OUT (C),A Nice stripes in border. 00CE JR #00A0,SNAP_KEYS Wrong key pressed, try again. 00D0 SNAP_128 LD A,9 Type=128K Snap. 00D2 LD DE,16384 Length of a RAM-page. 00D5 LD HL,49152 Start of a RAM-page. 00D8 SNAP_SAVE LD (#0052),A Store type in snapshot UFIA. 00DB LD (#005E),DE Store length in UFIA. 00DF LD (#0060),HL And the start-address. 00E2 LD B,#FE Key CAPS-V I/O address. 00E4 IN A,(C) 00E6 BIT 0,A 00E8 JR NZ,#00F2,NO_DRV_CHG If CAPS is pressed the Snap goes to 00EA LD A,(#1ACE) the other drive. 00ED XOR #01 00EF LD (#1ACE),A 00F2 NO_DRV_CHG LD A,#40 00F4 CALL #2993,JSCAN_CAT Search first free catalogue entry. 00F7 RET NZ Exit if catalogue full. 00F8 LD A,D Track to A. 00F9 AND #07 Jump if CAT-entry will be located 00FB JR Z,#0102,SNAP_NAME1 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 ' '. 00FD ADD A,48 ASCII offset for '0'. 00FF LD (#0057),A Store a 1, 2 or 3 in name-part of UFIA. 0102 SNAP_NAME1 LD L,E Store sector in L. 0103 LD A,(#1DDA) Fetch current control port state. 0106 AND #04 0108 JR NZ,#010D,SNAP_NAME2 Jump if Single Density. 010A SLA L Two entries per sector. 010C DEC L 010D SNAP_NAME2 LD A,(IX+14) Is it the first or second entry in the 0110 ADD A,L CAT-sector. 0111 ADD A,64 Add ASCII 'A' offset. 0113 LD (#0058),A Store 'A' to 'T' in name-part of UFIA. 0116 LD HL,#0052 Copy UFIA to DFCA. 0119 LD DE,#1E05 011C LD BC,20 011F LDIR 0121 CALL #29A8,JOFSM_2 Open the file. 0124 LD HL,#1FEA Copy snap registers to catalogue entry. 0127 LD DE,#1BB2 012A LD BC,22 012D LDIR 012F LD A,(#0052) Get directory description. 0132 CP 9 0134 JP NZ,#01DC,NO_SNAP128 Jump if not a 128K Snapshot. 0137 LD HL,49152 Now the 5 first bytes of the current 013A LD DE,#1BD6 RAM-page are saved in the DISCiPLE RAM 013D LD BC,5 and replaced by the "BRUCE" message. 0140 LDIR This is done to determine the currently 0142 LD HL,#01D7,BRUCE paged in RAM-page. 0145 LD DE,49152 0148 LD BC,5 014B LDIR 014D XOR A Signal '128K ROM bank active'. 014E LD (#1E19),A 0151 CALL #0258,?_ROMBANK Determine current 'main' ROM bank. 0154 JR NZ,#015B,SNAP128_1 Jump if 128K ROM bank. 0156 LD A,#10 Signal '48K ROM bank active'. 0158 LD (#1E19),A 015B SNAP128_1 CALL #027B,REST_PBUF Restore printer buffer contents. 015E LD A,(#1E19) 0161 JR #016B,SNAP128_2 0163 DEFB #00,#00 Unused locations. THE 'UNUSED EXIT' ROUTINE This routine returns to the 'main' ROM statement loop. Only one ROM routine seems to use it, but the jump is never taken, see #3D00. 0165 UNUSED_X LD HL,#1B7D,STMT_R_1 Return to 'STMT_R_1' in 'main' ROM. 0168 JP #004F,UNPAGE_HL THE 'SNAPSHOT ROUTINE' CONTINUED 016B SNAP128_2 CALL #003D,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. 016E SNAP128_3 LD BC,#DFFE Keyboard port and I/O address for Y-P. 0171 IN E,(C) 0173 BIT 4,E 0175 JR Z,#0186,CHANGED_$ Jump if 'Y' was pressed, screen changed. 0177 LD B,#7F I/O address for B-SPACE. 0179 IN E,(C) 017B BIT 3,E 017D JR Z,#0191,SAME_$ Jump if 'N' was pressed, same screen. 017F INC A 0180 AND #07 0182 OUT (C),A Make nice stripes in border again. 0184 JR #016E,SNAP128_3 Only 'Y' or 'N' is accepted. 0186 CHANGED_$ LD A,(#1E19) 0189 OR #08 Signal 'screen 1'. 018B ?_RAMBANK LD (#1E19),A 018E CALL #003D,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. 0191 SAME_$ LD DE,49152 Here the message has been placed. 0194 LD HL,#01D7,BRUCE Message to be found. 0197 LD B,5 There are five bytes in the message. 0199 BRUCE?_1 LD A,(DE) 019A CP (HL) 019B JR Z,#01A3,BRUCE?_2 Jump if characters match. 019D LD A,(#1E19) Otherwise it has to be one of the other 01A0 INC A banks. 01A1 JR #018B,?_RAMBANK 01A3 BRUCE?_2 INC DE 01A4 INC HL 01A5 DJNZ #0199,BRUCE?_1 All five characters have to match. 01A7 LD HL,#1BD6 The active RAM bank has been found, 01AA LD DE,49152 restore the original five bytes. 01AD LD BC,5 01B0 LDIR 01B2 LD A,(#1E19) 01B5 PUSH AF Save the page-configuration byte in the 01B6 CALL #29C3,JSBYT snapshot file. 01B9 AND #F8 Mask RAM bank, start with 0. 01BB LD B,#08 There are eight RAM banks 01BD SAVE_BANK PUSH AF 01BE PUSH BC 01BF CALL #003D,RAMPAGE_A Page in RAM bank. 01C2 LD HL,(#0060) 01C5 LD DE,(#005E) 01C9 CALL #29C9,JHSVBK_2 Save DE bytes starting at address HL. 01CC POP BC 01CD POP AF 01CE INC A Next RAM bank. 01CF DJNZ #01BD,SAVE_BANK Loop for all eight 16K RAM banks. 01D1 POP AF 01D2 CALL #003D,RAMPAGE_A Page in original RAM bank. 01D5 JR #01EB,CLOSE_SNAP 01D7 BRUCE DEFM "BRUCE" 01DC NO_SNAP128 CP 7 Copy the 9 header bytes to the file if 01DE CALL Z,#0D2F,SAVE_HEAD1 it is a SCREEN$. 01E1 LD HL,(#0060) 01E4 LD DE,(#005E) 01E8 CALL #29C9,JHSVBK_2 Save DE bytes starting at address HL. 01EB CLOSE_SNAP JP #2981,JCFSM Close the file. THE 'SNAP_EXIT' ROUTINE This routine is used to return to the snapshotted program, whether it has been loaded, a snapshot was saved or an error occurred. 01EE SNAP_EXIT LD HL,#0000 Clear D_ERR_SP. 01F1 LD (#0296),HL 01F4 DI 01F5 NOP 01F6 NOP 01F7 LD SP,#1FEA 01FA POP IY Restore the index registers. 01FC POP IX 01FE POP DE Restore the alternate registerset. 01FF POP BC 0200 POP HL 0201 POP AF 0202 EXX 0203 CALL #0258,?_ROMBANK Determine current 'main' ROM bank. 0206 JR NZ,#0230,SNAP_EX_3 Jump if 128K ROM bank. 0208 CALL #027B,REST_PBUF 020B POP DE Restore the registerset. 020C POP BC 020D POP HL 020E POP AF 020F LD I,A 0211 CP #00 0213 JR Z,#021B,SNAP_EX_1 0215 CP #3F When the I register doesn't contain #00 0217 JR Z,#021B,SNAP_EX_1 or #3F, it is most likely that the 0219 IM 2 interrupt mode is 2. 021B SNAP_EX_1 LD SP,(#1FFE) Restore stack pointer. 021F POP AF 0220 LD R,A Jump if the interupts were disabled 0222 JP PO,#022C,SNAP_EX_2 when 'SNAPSHOT' was entered. 0225 PUSH HL 0226 LD HL,#004F Otherwise return to snapshotted program 0229 JP #004F,UNPAGE_HL via 'main' ROM "POP HL", "POP AF" and "EI". 022C SNAP_EX_2 POP AF Return to the instruction before which 022D JP #0050,UNPAGE_1 the snapshot occurred. This piece of code does almost the same as the above. The only difference is that it returns to the 128 'main' ROM at a somewhat different address. 0230 SNAP_EX_3 CALL #027B,REST_PBUF 0233 POP DE 0234 POP BC 0235 POP HL 0236 POP AF 0237 LD I,A 0239 CP #00 023B JR Z,#0243,SNAP_EX_4 023D CP #3F 023F JR Z,#0243,SNAP_EX_4 0241 IM 2 0243 SNAP_EX_4 LD SP,(#1FFE) 0247 POP AF 0248 LD R,A 024A JP PO,#0254,SNAP_EX_5 024D PUSH BC 024E LD BC,#007B 0251 JP #0046,UNPAGE_BC 0254 SNAP_EX_5 POP AF 0255 JP #0047,UNPAGE_0 THE 'DETERMINE 128K ROM BANK' SUBROUTINE This routine determines, by examining the byte at address #0001, which bank of the 128K ROM is selected. Because the DISCiPLE system is currently paged in the 'main' ROM can't be accessed directly. So a routine, which pages out the DISCiPLE, is copied to the printer buffer. But first the first 10 bytes of the printer buffer are saved. 0258 ?_ROMBANK LD HL,23296 Save the 10 bytes needed by the 025B LD DE,#1BE6 subroutine in DISCiPLE RAM. 025E LD BC,10 0261 LDIR 0263 LD HL,#0271,DET_ROM Copy the subroutine to the freed bytes. 0266 LD DE,23296,DET_ROM' 0269 LD BC,10 026C LDIR 026E JP 23296,DET_ROM' Exit via DET_ROM. This small routine is copied to 23296, it returns with the Zero flag set if address #0001 in the 'main' ROM contains 175, that is when the 48K ROM bank is paged in. 0271 DET_ROM OUT (187),A Page DISCiPLE out. 0273 LD A,(#0001) 0276 CP 175 0278 IN A,(187) Page DISCiPLE in. 027A RET THE 'RESTORE PRINTER BUFFER' SUBROUTINE This subroutine restores the printer buffers 10 bytes which were destroyed by the '?_ROMBANK' subroutine. 027B REST_PBUF LD HL,#1BE6 027E LD DE,23296 0281 LD BC,10 0284 LDIR 0286 RET The OTFOC patch 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. This routine was added in System 3d. 0287 OTFOC AND A 0288 JP Z,#1261,OPEN_CHAN Open a channel if A holds zero. 028B JP #140C,CLOSE_STRM Otherwise close the stream. The periodic routines & The DISCiPLE system variables and tables THE 'KEY-SCAN' ROUTINE This is another entry point to the DISCiPLE system; it is paged in when the Z80 reaches address #028E, that is, the Spectrum 'KEY-SCAN' routine. So whenever the Spectrum tries to scan the keyboard by calling this routine the DISCiPLE is paged in first. This routine tests for some sort of pointing device (the non-existent MGT mouse?) and when the network is enabled a check is made for network activity. 028E KSCAN_RAM LD L,#2F 0290 JP #02FB,KSCAN_RAM1 0293 NOP An unused location. 0294 KSCAN_RET OUT (187),A Page out to continue in 'main' ROM 'KEY-SCAN'. THE 'SYSTEM VARIABLES' These variables hold various settings for drives etc. The variables starting at address #0298 can be accessed from BASIC with POKE @p,n. Where p is 0 for RBCC at #0298. 0296 D_ERR_SP DEFW #0000 0298 RBCC DEFB #00 @0 No flashing borders. 0299 TRAKS1 DEFB 80+128 @1 Drive 1 80 tracks double sided. 029A TRAKS2 DEFB 80+128 @2 Drive 2 80 tracks double sided. 029B STPRAT DEFB 0 @3 "Steprate" 0 msec. 029C NSTAT DEFB 0 @4 Network off. 029D WIDTH DEFB 80 @5 Printer right margin. 029E PCODE DEFB 0 @6 Expand tokens, etc. before printing. 029F LSPCE DEFB 12 @7 Line spacing 12/72 inch. 02A0 LFEED DEFB 1 @8 Number of line feeds after CR 1. 02A1 LMARG DEFB 0 @9 Left margin at 0. 02A2 GRAPH DEFB 1 @10 Give graphic representation of some chars. 02A3 ZXPNT DEFB 1 @11 DISCiPLE printer port not used. 02A4 RESERVED DEFW #0000 @12 02A6 ONERR DEFW #0000 @14 Address of routine called after an error has occurred. 02A8 EVERY_INT DEFW #03B0 @16 Address of routine called at every interrupt. THE 'PRINTER CODES' TABLE Here the printer control codes are stored. 02AA INIT_PRT DEFB 27,"@",#80,#80 02AE DEFB #80,#80,#80,#80 02B2 CHAR_PITCH DEFB 27,"M",#80,#80 02B6 DEFB #80,#80,#80,#80 02BA N/72_LSPC DEFB 27,"A",#80,#80 02BE DEFB #80,#80,#80,#80 02C2 60_DPI DEFB 27,"K",#80,#80 02C6 DEFB #80,#80,#80,#80 02CA INIT_PRT2 DEFB #80,#80,#80,#80 02CF DEFB #80,#80,#80,#80 THE 'GRAPHIC REPRESENTATION' TABLE This table consists of the graphic representations of the £, # and (c) signs. The 'GRAPH' system variable (@10) determines whether the normal code or the graphic representation is outputted to the printer. 02D2 £-SIGN DEFB %00011000 02D3 DEFB %00100000 02D4 DEFB %00100000 02D5 DEFB %01111000 02D6 DEFB %00100000 02D7 DEFB %00100000 02D8 DEFB %01111100 02D9 DEFB %00000000 02DA #-SIGN DEFB %00000000 02DB DEFB %00100100 02DC DEFB %01111110 02DD DEFB %00100100 02DE DEFB %00100100 02DF DEFB %01111110 02E0 DEFB %00100100 02E1 DEFB %00000000 02E2 (c)-SIGN DEFB %01111110 02E3 DEFB %10000001 02E4 DEFB %10111101 02E5 DEFB %10100001 02E6 DEFB %10100001 02E7 DEFB %10111101 02E8 DEFB %10000001 02E9 DEFB %01111110 THE 'GREYSCALE' PRINTER CONTROL CODE This code is outputted to the printer if a 'SCREEN$ 2' screendump is wanted. 02EA GREY_BITIM DEFB 27,"*",5,#40 02EE 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. System 3d can't print a greyscale dump anymore (see #1751). colour 76543210 02F2 DEFB %00101011 02F3 DEFB %00011111 first row 02F4 DEFB %00000001 02F5 DEFB %00000111 02F6 DEFB %01101111 second row 02F7 DEFB %00000111 02F8 DEFB %00000001 02F9 DEFB %00011111 third row 02FA DEFB %00101011 THE 'KSCAN_RAM' ROUTINE CONTINUED 02FB KSCAN_RAM1 NOP The following call was removed for 02FC NOP Sys 3d: CALL #03B1,TEST_MOUSE 02FD NOP 02FE LD A,(#1DE5) 0301 CP #47 If a CALBAS was under execution return 0303 JR Z,#031A,KSCAN_EXIT immediately to 'main' ROM 'KEY-SCAN'. 0305 LD A,(#029C) 0308 CP 0 Jump if network is on, that is when a 030A JR NZ,#0325,NET_SERVER station number is specified. 030C KSCAN_RAM2 LD A,(#1DDA) Make network inactive, select current 030F OUT (31),A drive. 0311 CALL #0460,TAKE_PRTR Refresh 'P'-channel if necessary. 0314 LD HL,(#02A8) Call routine which has to be called 0317 CALL #04F0,JP_HL every 'interrupt'. (Normal #03B0) 031A KSCAN_EXIT LD L,#2F Restore registers for 'main' ROM 031C LD DE,#FFFF 'KEY-SCAN' 031F LD BC,#FEFE 0322 JP #0294,KSCAN_RET THE 'NETWORK SERVER' ROUTINE This routine checks if a "command block" is send over the network. In a master/ pupil network (Shared Access Network) a pupil has no drive or printer. When a pupil gives a command like "CAT 1" the command is send over the network to the master or an assistent station, which executes the command and sends the result back to the pupil which gave the command. Before a command block can be received the network has to be active for about 10400 T cycles and then has to go inactive in less than 52000 T states. Then a check is made if the command block is for this station, and if so the command is executed. 0325 NET_SERVER LD HL,200 This counter allows the network to be tested for 10395 T cycles. 0328 TST_N_ACT IN A,(31) Read network port. 032A BIT 7,A 032C JR NZ,#030C,KSCAN_RAM2 Exit if the network is inactive. 032E DEC HL Decrease the counter. 032F LD A,H 0330 OR L 0331 JR NZ,#0328,TST_N_ACT Repeat test until finished. Now the network has to go inactive within about 52000 T cycles otherwise this routine will be left. 0333 LD HL,1000 0336 TST_N_INA DEC HL Decrease the counter. 0337 LD A,H 0338 OR L Exit if network isn't inactive within 0339 JR Z,#030C,KSCAN_RAM2 the right time. 033B IN A,(31) 033D BIT 7,A Now the command block is fetched from the network. 033F JR Z,#0336,TST_N_INA Repeat until network is inactive. 0341 LD HL,#031A,KSCAN_EXIT Return address. 0344 PUSH HL 0345 LD HL,#1DFD Point to the data buffer. 0348 LD E,29 034A CALL #2969,JINPAK Read 29 bytes from the network. 034D RET NZ Return when no bytes received. 034E LD HL,#1DFD Restore the pointer. 0351 XOR A Clear checksum. 0352 LD B,28 Calculate checksum for 28 bytes. 0354 TST_N_CHKS ADD A,(HL) Add this byte. 0355 INC HL Next byte. 0356 DJNZ #0354,TST_N_CHKS Repeat for all bytes. 0358 CP (HL) Compare with received checksum. 0359 RET NZ Return if they don't match. 035A LD HL,#1DFD Restore pointer. 035D LD A,(#029C) Fetch own station number (NSTAT). 0360 CP (HL) Return if the message isn't for this 0361 RET NZ Spectrum. 0362 CALL #2972,JSEND_RESP Otherwise send response code. 0365 LD HL,#1DFF Point to the command. 0368 LD A,(HL) Fetch it. 0369 CP 210 A pupil station cannot ERASE a file, so 036B RET Z return if the command was "ERASE". Now follows an undocumented feature of the Shared Access Network. When a pupil prints something to a "P"-channel (normally attached to #3), it is send directly to the master station. Please note that printer output gets garbled when more users try to use the printer at the same time. 036C CP 245 036E JR NZ,#0375,SERVE_PUP Jump if it wasn't "PRINT". 0370 INC HL Otherwise send one byte to the printer. 0371 LD A,(HL) 0372 JP #1944,PNTP 0375 SERVE_PUP CALL #09D3,SIGN_SERV Signal 'serving pupil'. 0378 PUSH AF Store command. 0379 LD HL,(23633) Store CURCHL. 037C LD (#1E32),HL 037F LD HL,#1E34 0382 LD A,(23611) Store FLAGS. 0385 LD (HL),A 0386 INC HL 0387 LD A,(23612) Store TVFLAG. 038A LD (HL),A 038B INC HL 038C LD A,(23658) Store FLAGS2. 038F LD (HL),A 0390 POP AF 0391 CALL #0674,EXEC_COMM Execute command. 0394 LD HL,(#1E32) Restore CURCHL. 0397 LD (23633),HL 039A LD HL,#1E34 Restore FLAGS. 039D LD A,(HL) 039E LD (23611),A 03A1 INC HL 03A2 LD A,(HL) Restore TVFLAG. 03A3 LD (23612),A 03A6 INC HL 03A7 LD A,(HL) Restore FLAGS2. 03A8 LD (23658),A 03AB XOR A 03AC LD (#1ACF),A Reset FLAGS3 and exit. 03AF RET THE 'DEFAULT EVERY_INT' ROUTINE 03B0 RET THE 'MOUSE' ROUTINE This routine tests a mouse-like device. Pointers which seem to keep track of screen coordinates are updated when necessary. 03B1 TEST_MOUSE LD BC,#03FF The MGT mouse port? 03B4 IN A,(C) 03B6 BIT 7,A 03B8 RET NZ Return if no activity. 03B9 CPL 03BA AND #05 Return if there was no horizontal or 03BC RET Z vertical movement. 03BD LD HL,#03F3,SIGN_MOUSE 03C0 PUSH HL 03C1 LD HL,#03DD,MOVE_VERT 03C4 PUSH HL 03C5 IN D,(C) Read mouse bits again. 03C7 LD HL,23681,X_POS_M Mouses x-coordinate. 03CA BIT 0,D 03CC RET NZ Return to vertical movement test. 03CD BIT 1,D 03CF JR Z,#03D7,MOVE_RIGHT Jump if mouse was moved right. 03D1 LD A,0 Left side of screen. 03D3 CP (HL) 03D4 RET Z Return if left movement isn't possible. 03D5 DEC (HL) Otherwise decrement x-coordinate. 03D6 RET 03D7 MOVE_RIGHT LD A,255 Right side of screen. 03D9 CP (HL) 03DA RET Z Return if right movement impossible. 03DB INC (HL) Otherwise increment x. 03DC RET 03DD MOVE_VERT LD HL,23729,Y_POS_M Y-coordinate of mouse. 03E0 BIT 2,D 03E2 RET NZ Return to signal mouse. 03E3 BIT 3,D 03E5 JR NZ,#03ED,MOVE_UP Jump if mouse was moved up. 03E7 LD A,0 Bottom side of screen. 03E9 CP (HL) 03EA RET Z Return if bottom has been reached. 03EB DEC (HL) Otherwise move towards it. 03EC RET 03ED MOVE_UP LD A,175 Top side of screen. 03EF CP (HL) 03F0 RET Z Return if top was reached. 03F1 INC (HL) Otherwise increment y-coordinate. 03F2 RET 03F3 SIGN_MOUSE OUT (C),D Give original signal to mouse. 03F5 RET 03F6 DEFB #00,#00,#00,#00 Unused locations. Miscalleneous routines I THE 'TEST_BREAK' SUBROUTINE The BREAK key is checked and the appropriate error is given if it is pressed. This routine is also present in ROM at address #2181. 03FA TEST_BREAK LD A,#7F 03FC IN A,(254) 03FE RRA 03FF RET C Return if SPACE wasn't pressed. 0400 LD A,#FE 0402 IN A,(254) 0404 RRA 0405 RET C Return if CAPS wasn't pressed. 0406 JP #2926,REP_3 THE 'END OF STATEMENT' ROUTINE After the syntax of the 'new' commands has been checked, a jump is made here to confirm that the statement is finished. An error report is given if it isn't finished. A return to the calling routine is made only during runtime, otherwise the control returns to the 'main' ROM interpreter. This routine is also present in ROM (#2155). 0409 ST_END_RAM CALL #002C,GET_C_RAM Get current character. 040C CP 13 040E JR Z,#0415,TEST_RET Jump if the statement ends with ENTER. 0410 CP ":" Give an error if statement doesn't end 0412 JP NZ,#2924,REP_2 with a colon. 0415 TEST_RET RST #30,SYNTAX_Z 0416 RET NZ Return during runtime. 0417 JR #0420,END1 THE 'RETURN TO THE INTERPRETER' ROUTINE The control is returned to the BASIC interpreter for interpretation of the next statement. Except when the network was served, then a return is made to #0394 in 'SERVE_PUP'. 0419 END CALL #297B,JBORD_REST Restore border color. 041C CALL #09FB,TEST_SERV 041F RET NZ Exit if serving a pupil. 0420 END1 LD SP,(23613) Clear machine stack. (ERR_SP) 0424 LD (IY+0),#FF Clear error code. (ERR_NR) 0428 LD HL,#1BF4 Return address to 'main' ROM is 042B RST #30,SYNTAX_Z 'STMT_NEXT' if syntax is being checked. 042C JP Z,#004F,UNPAGE_HL 042F EI 0430 NOP 0431 NOP 0432 LD HL,#1B76 Return address during runtime is 0435 JP #004F,UNPAGE_HL 'STMT_RET'. THE 'POKE @' COMMAND ROUTINE The POKE @ command allows a value between 0 and 255 to be stored in the DISCiPLE system variables. But if the value is between 256 and 65535 the POKE @ behaves as a DPOKE. Because the DISCiPLE system vars have a offset of #0298 (or 664) this value has to be subtracted if the POKE @ is to be made directly to the given address. So POKE @60000-664,1000 to DPOKE 60000,1000. 0438 POKE@ RST #28,NEXT_C_RAM Get next character. 0439 CP "@" 043B JP NZ,#2920,REP_0 If it isn't "@" give error. 043E RST #10,CALBAS Evaluate the two following numeric 043F DEFW #1C79,NEXT_2NUM expressions. 0441 CALL #0409,ST_END_RAM Confirm end of statement and exit 0444 RST #10,CALBAS during syntax checking. 0445 DEFW #1E99,FIND_INT2 Fetch value to be POKEd in BC. 0447 PUSH BC 0448 RST #10,CALBAS 0449 DEFW #1E99,FIND_INT2 Fetch POKE address. 044B LD HL,#0298 Offset for DISCiPLE system variables. 044E ADD HL,BC 044F POP BC 0450 LD (HL),C POKE address,low byte. 0451 LD A,B 0452 AND A 0453 JP Z,#0419,END Exit if 8 bit value. 0456 INC HL Otherwise POKE address+1,high byte 0457 LD (HL),B before exiting. 0458 JP #0419,END THE '"P" CHANNEL DATA' TABLE Here follow the 5 bytes that compose a DISCiPLE "P" channel. 045B P_CHANNEL DEFW #0008 Main ROM 'output' routine. 045D DEFW #0008 Main ROM 'input' routine. 045F DEFB "P" Channel "P" identifier. THE 'TAKEOVER PRINTER' SUBROUTINE If the printer is to be controlled by the DISCiPLE system, the following subroutine copies the "P" channel data into the channel. 0460 TAKE_PRTR LD A,(#02A3) (ZXPNT) 0463 AND A Return if the printer isn't to be handled 0464 RET NZ by the DISCiPLE. 0465 LD HL,(23631) Get address of channel data. (CHANS) 0468 LD BC,15 Offset for channel "P". 046B ADD HL,BC 046C EX DE,HL 046D LD HL,#045B,P_CHANNEL 0470 LD BC,5 0473 LDIR Copy the "P" channel data. 0475 RET THE 'INIT PRINTER' SUBROUTINE This subroutine initialises the printer, if it's to be handled by the DISCIPLE and if it's attached, by sending the initialisation codes and the permanent setting codes as mentioned in the 'Setup' program. 0476 INIT_PRTR CALL #15E0,TEST_PRTR 0479 RET C Exit if no printer connected or printer 047A NOP not to be handled by DISCiPLE. 047B LD DE,#02AA Send initialisation codes to printer. 047E CALL #1779,PO_ESC_SEQ 0481 LD DE,#02B2 Set character pitch. 0484 CALL #1779,PO_ESC_SEQ 0487 LD DE,#02BA Set line spacing to (#029F)/72 inch. 048A CALL #1779,PO_ESC_SEQ 048D LD A,(#029F) 0490 CALL #1944,PNTP 0493 LD DE,#02CA Set other permanent printer settings. 0496 JP #1779,PO_ESC_SEQ THE 'CALBAS_2' ROUTINE This routine calls the required 'main' ROM routine. It is an exact copy of the ROM routine at #2190. 0499 CALBAS_2 LD (#1AC5),DE Free DE and HL. 049D LD (#1AC8),HL 04A0 POP HL Get return address, points to address 04A1 LD E,(HL) of 'main' ROM routine to be called. 04A2 INC HL Fetch address of routine to be called. 04A3 LD D,(HL) 04A4 INC HL 04A5 PUSH HL Restack return address. 04A6 LD HL,#1DE5 04A9 LD (HL),#47 Signal 'CALBAS executing'. 04AB LD HL,#0066 Return address to DISCiPLE system is 04AE PUSH HL 'NMI_RAM'. 04AF PUSH DE Push address of routine to be called. 04B0 LD HL,(#1AC8) Restore HL and DE. 04B3 LD DE,(#1AC5) 04B7 JP #0050,UNPAGE_1 Do the CALBAS. THE 'USR_0' ROUTINE CONTINUED A jump is made to the RAM test and initialisation routine in the 'main' ROM. These three instructions can also be found in ROM at #230C. 04BA USR_0_1 LD DE,#FFFF Top of possible RAM. 04BD LD HL,#11CB,START/NEW The 'START/NEW' routine in 'main' ROM. 04C0 JP #004F,UNPAGE_HL Continue with USR 0 in 'main' ROM. The Hook and Command code routine & The Command code table This routine is entered with the A register holding an 'IF1 hook code', a 'DISCiPLE command code' or an invalid error code. The routine calls a set of subroutines in the DISCiPLE 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 and consists of the addresses of the routines for the IF1 hookcodes. The second table is located at address #050B and consists of the addresses of the DISCiPLE command code routines. 04C3 HOOK_CODE LD (#1AC5),DE 04C7 CP 24 04C9 JR NC,#04F1,COMM_CODE Jump if code isn't a hook code. 04CB LD DE,#29D2 Address of hook (IF1) code table. 04CE CODE_CONT LD (IY+0),#FF Clear error. 04D2 SET 2,(IY+1) What's the purpose of this? 04D6 INC HL Advance return address past the code. 04D7 PUSH HL 04D8 ADD A,A Table is made of two byte addresses, so 04D9 LD L,A double code. 04DA LD H,0 04DC ADD HL,DE Point codes entry in table. 04DD LD E,(HL) Fetch the address of the routine. 04DE INC HL 04DF LD D,(HL) 04E0 LD HL,#04FD,HOOK_RET Return address after completion of 04E3 PUSH HL code. 04E4 LD (#0296),SP Set D_ERR_SP. 04E8 EX DE,HL 04E9 LD DE,(#1AC5) Restore DE and A. 04ED LD A,(#1DEA) 04F0 JP_HL JP (HL) Jump to the routine. 04F1 COMM_CODE SUB 24 Adjust range for command codes (0..20). 04F3 CP 21 04F5 JP NC,#2942,REP_17 Give error if not a command code. 04F8 LD DE,#050B Address of command code table. 04FB JR #04CE,CODE_CONT Continue with command codes. THE 'HOOK_RET' ROUTINE This routine is entered whenever a hook or command code is finished. 04FD HOOK_RET PUSH HL 04FE LD HL,#0000 0501 LD (#0296),HL Clear D_ERR_SP. 0504 POP HL 0505 CALL #297B,JBORD_REST Return to the calling routine with the 0508 JP #0050,UNPAGE_1 'main' ROM paged in. THE 'COMMAND CODE ADRESSES' TABLE This jump table consists of the 21 addresses of the routines called by using the various 'command codes'. Command code 70 and 71 were added in system 3d. 050B DEFW #1539,HXFER Command code #33, 51. 050D DEFW #154C,OFSM Command code #34, 52. 050F DEFW #1552,HOFLE Command code #35, 53. 0511 DEFW #29C3,JSBYT Command code #36, 54. 0513 DEFW #1559,HSVBK Command code #37, 55. 0515 DEFW #2981,JCFSM Command code #38, 56. 0517 DEFW #1944,PNTP Command code #39, 57. 0519 DEFW #164C,COPS Command code #3A, 58. 051B DEFW #155F,HGFLE Command code #3B, 59. 051D DEFW #29A2,JLBYT Command code #3C, 60. 051F DEFW #1565,HLDBK Command code #3D, 61. 0521 DEFW #15C4,WSAD Command code #3E, 62. 0523 DEFW #15BD,RSAD Command code #3F, 63. 0525 DEFW #29BA,JREST Command code #40, 64. 0527 DEFW #156B,HERAZ Command code #41, 65. 0529 DEFW #16B2,COPS2 Command code #42, 66. 052B DEFW #08AA,PCAT Command code #43, 67. 052D DEFW #1582,HRSAD Command code #44, 68. 052F DEFW #15A0,HWSAD Command code #45, 69. 0531 DEFW #0287,OTFOC Command code #46, 70. 0533 DEFW #136B,PATCH Command code #47, 71. 0535 UNDEFINED RET This RET was used in older systemfiles for undefined command codes. The initialise system routine THE '"AUTO*" FILE' UFIA The following 22 bytes form the UFIA of the autoload file, which is loaded right after the system file, except when "RUN boot" was given. 0536 AUTO_UFIA DEFB 1 Drive 1 0537 DEFB 0 0538 DEFB 0 0539 DEFB "D" Device "D" 053A DEFB 1 Dir. entry for BASIC file. 053B DEFM "AUTO* " Name of autoload file. 0545 DEFB 0 File type is BASIC. 0546 DEFW 65535 Max. length. 0548 DEFW 65535 054A DEFW 65535 THE 'DO NOT LOAD AUTOLOAD FILE' EXTENSION When the system file was loaded by giving "RUN boot" the autoload file isn't loaded. 054C BOOT DEFM "BOOT" THE 'LOAD AUTOLOAD FILE' ROUTINE This routine loads the autoload file, if wanted, after loading the system file. 0550 LOAD_AUTO LD A,%00010001 Drive 1 and DISCiPLE active. 0552 OUT (31),A Activate. 0554 LD (#1DDA),A Set current control port state. 0557 LD A,#44 Signal 'System loaded'. 0559 LD (#1DE4),A 055C XOR A 055D LD (#1ACF),A Clear FLAGS3. 0560 LD IX,#054C Point to "BOOT". 0564 LD B,4 Four characters. 0566 RUN_BOOT? RST #28,NEXT_C_RAM Fetch next character. 0567 AND #DF Drop lower case bit. 0569 CP (IX+0) Compare it to "BOOT". Jump if one of 056C JR NZ,#0576,JUST_RUN the characters doesn't match. 056E INC IX Next character of "BOOT". 0570 DJNZ #0566,RUN_BOOT? Repeat for the next character. 0572 RST #28,NEXT_C_RAM All characters match, so don't load 0573 JP #0419,END autoload file. Just return to Spectrum. 0576 JUST_RUN RST #10,CALBAS Clear the whole display. 0577 DEFW #0DAF,CL_ALL 0579 CALL #0460,TAKE_PRTR If necessary takeover the "P" channel. 057C CALL #19BE,MSG_3 Print DOS copyright message. 057F CALL #0476,INIT_PRTR If necessary initialize printer. 0582 LD IX,#0536 Point to autoload file ufia. 0586 CALL #1539,HXFER Transfer UFIA to DFCA. 0589 LD A,#08 Search for a file with specified name and 058B CALL #2993,JSCAN_CAT type. 058E JP NZ,#2948,REP_20 "O.K. GDOS 3" if no autoload file found. 0591 CALL #09E2,SIGN_LOAD Signal 'loading'. 0594 JP #0E28,LD_VF_MR1 Load the file. The control routine This routine is called from 'START' at #0008, when the DISCiPLE system is paged in. It has three main tasks: - If a disc channel has been requested, it jumps to the required 'input' or 'output' routine. - If a hook/command code is used, it jumps to the required routine. - If an error occurred in the 'main' ROM, it checks whether a DISCiPLE command was used. If so the corresponding routine is called, otherwise a return is made to the 'main' ROM, except when the DISCiPLE variable ONERR holds a non zero address. In that case a CALBAS to that address is made. 0597 START_3 LD (#1DD6),HL DISCiPLE's CH_ADD (D_CH_ADD). 059A LD (#1DEA),A 059D POP HL Get RETurn address (usually points to 059E PUSH HL the error code). 059F PUSH DE Now see if a DISCiPLE channel has been requested. 05A0 AND A 05A1 LD DE,#15FE If a channel has been requested, this is the RETurn address stored by the CALL #162C in the 'CALL-SUB' subroutine in the Spectrum ROM. 05A4 SBC HL,DE 05A6 POP DE 05A7 JR NZ,#05C7,START_4 Jump if no channels have been requested. 05A9 LD HL,#0050,UNPAGE_1 Make UNPAGE_1 RETurn address 05AC PUSH HL Now see if the channel requested is the "P" channel. The DISCiPLE "P" channel differs only from the Spectrum's in the 'input' and 'output' addresses. For the DISCiPLE they both are #0008. There is no information in the channel on what the DISCiPLE system's in/output addresses are (as with "D" channels). So it has to be handled separately. 05AD PUSH BC 05AE LD HL,(23631) Fetch CHANS. 05B1 LD BC,16 Point to "P" channel. 05B4 ADD HL,BC 05B5 SBC HL,DE DE holds address of requested channel. 05B7 POP BC 05B8 LD A,(#1DEA) Restore A register. 05BB JP Z,#1783,PCHAN_OUT Jump if DISCiPLE "P" channel was used. 05BE LD HL,4 DE holds address of routine pointer-4. See #15EF in 'main' ROM. 05C1 ADD HL,DE HL now holds address of routine pointer. 05C2 LD E,(HL) 05C3 INC HL Fetch routine address. 05C4 LD D,(HL) 05C5 EX DE,HL HL now points to the routine. 05C6 JP (HL) Jump to the appropriate 'input' or 'output' routine. At this point, the DISCiPLE has been paged-in by an error in the 'main' ROM or by a hook/command code. When an error occurred during a CALBAS and D_ERR_SP isn't zero, the error has to be handled by the 'main' ROM. If D_ERR_SP is zero, the error is reported to the routine which executed a CALBAS. 05C7 START_4 LD A,(#1DE5) Check if the DISCiPLE CALLed a Spectrum 05CA CP #47 ROM routine. 05CC JR NZ,#05EC,START_5 Jump if it didn't. 05CE XOR A 05CF LD (#1DE5),A Clear CALBAS executing. 05D2 LD (#1ACF),A Clear FLAGS3. 05D5 POP HL Fetch RETurn address. 05D6 RST #10,CALBAS This CALL's a LD A,(HL) in the Spectrum 05D7 DEFW #007B ROM, so the error code is fetched. 05D9 LD (23610),A Store the error code in ERR_NR. 05DC LD HL,(#0296) Fetch D_ERR_SP. 05DF LD A,H 05E0 OR L Jump if D_ERR_SP was zero, that is when 05E1 JP Z,#06D6,SPEC_ERR2 the 'main' ROM has to handle the error. 05E4 LD A,(23610) Copy error code in A register. 05E7 SET 7,A Signal 'Spectrum error'. 05E9 LD SP,HL Clear stack. 05EA SCF Signal 'error and exit', someone else has 05EB RET to handle the error. Now it is most likely that the DISCiPLE has to handle the problem which the 'main' ROM couldn't. So see if it is an error or a hook/command code. 05EC START_5 POP HL Fetch address of error or hook/command code (the byte after RST #08). 05ED RST #10,CALBAS Fetch the byte. 05EE DEFW #007B 05F0 LD (IY+0),A Store it in ERR_NR. 05F3 CP 255 Check if the error is 'OK'. 05F5 JP Z,#2948,REP_20 Give 'OK GDOS' message if so. 05F8 SUB 27 Adjust range, hookcodes start at 0 now. 05FA JP NC,#04C3,HOOK_CODE Jump if it is a hook or command code. 05FD CP 240 Jump if the error is 05FF JR Z,#060E,TEST_INPUT 'Nonsense in BASIC'. 0601 CP 243 0603 JR Z,#060E,TEST_INPUT Also if it is 'Invalid filename'. 0605 CP 252 0607 JR Z,#060E,TEST_INPUT Or 'Invalid stream'. 0609 CP 230 060B JP NZ,#06CD,SPEC_ERR Jump to the 'main' ROM error handler if it isn't 'Variable not found'. 060E TEST_INPUT BIT 5,(IY+55) Use 'main' ROM error handler also if in 0612 JP NZ,#06CD,SPEC_ERR INPUT mode. Now a loop is entered to find the BASIC command which produced the error. The way in which this is done is very simple, a backward search is made until a byte value >= 206 (value of first BASIC command 'DEF FN') is found. There are a few cases in which this algorithm fails, e.g.: -When a number in a BASIC line is followed by its hidden representation (starts with a CHR$ 14 number marker), this could contain a byte >= 206. -If the line the error occurred on doesn't contain a BASIC command the searching continues until a byte value >= 206 is found. So line length, line number and even previous lines could be searched. 0615 LD HL,(23645) Fetch CH_ADD. 0618 FIND_COM DEC HL 0619 LD A,(HL) 061A CP 206 Test for DEF FN (first BASIC command). 061C JR C,#0618,FIND_COM Loop until a byte >= 206 is found. 061E LD (23645),HL Update CH_ADD. 0621 RST 48,SYNTAX_Z 0622 JR NZ,#0651,RUNTIME Jump during RUNtime. The following loop removes all number representations from the line. 0624 DEC HL Balance "INC HL" below. 0625 LD C,0 ???? C isn't used. 0627 RCLM_NUM INC HL 0628 LD A,(HL) Next character. 0629 CP 14 Is it a 'number' marker ? 062B JR NZ,#064C,NO_NUM Jump if not. 062D PUSH BC 062E PUSH HL 062F LD BC,6 0632 RST #10,CALBAS Reclaim the 6 bytes forming a number 0633 DEFW #19E8,RECLAIM_2 and the 'number marker'. 0635 POP HL 0636 PUSH HL 0637 LD DE,(#1DD6) Fetch D_CH_ADD. 063B AND A Jump if the number bytes reclaimed were 063C SBC HL,DE after the character pointed to by 063E JR NC,#064A,NXT_1 D_CH_ADD. 0640 EX DE,HL Otherwise D_CH_ADD has to be updated. 0641 LD BC,6 0644 AND A The character pointed by D_CH_ADD has 0645 SBC HL,BC been moved '6' bytes down. 0647 LD (#1DD6),HL Update D_CH_ADD. 064A NXT_1 POP HL 064B POP BC 064C NO_NUM LD A,(HL) 064D CP 13 064F JR NZ,#0627,RCLM_NUM Repeat until 'end of line' is found. Now the work areas and some DISCiPLE variables are cleared. 0651 RUNTIME RST #10,CALBAS Clear Spectrum work areas by calling 0652 DEFW #16BF,SET_WORK 'SET_WORK' in 'main' ROM. 0654 LD HL,#1DF4 0657 LD BC,60 065A RESET_VARS LD (HL),255 Reset DISCiPLE work areas, including 065C INC HL UFIA1 and UFIA2. 065D DEC BC 065E LD A,B 065F OR C 0660 JR NZ,#065A,RESET_VARS 0662 LD (#1ACF),A Clear FLAGS3. 0665 LD A,#44 Signal 'System loaded'. 0667 LD (#1DE4),A 066A LD IX,#1AC3 Point to DISCiPLE system variables. Finally the command is fetched from the line, and if its a 'new' command the appropriate routine is called. 066E CALL #002C,GET_C_RAM Fetch the command. 0671 LD (#1DFF),A Store it. This part is also called from the network server routine at #0325. 0674 EXEC_COMM CP 207 Is the command 'CAT' ? 0676 JP Z,#0855,CAT Jump to the CAT routine if so. 0679 CP 208 Also for 'FORMAT',... 067B JP Z,#102C,FORMAT 067E CP 209 ...'MOVE',... 0680 JP Z,#10B1,MOVE 0683 CP 210 ...'ERASE',... 0685 JP Z,#0932,ERASE 0688 CP 211 ...'OPEN #',... 068A JP Z,#1216,OPEN# 068D CP 212 ...'CLOSE #',... 068F JP Z,#13C4,CLOSE# 0692 CP 213 ...'MERGE',... 0694 JP Z,#0DF8,MERGE 0697 CP 214 ...'VERIFY',... 0699 JP Z,#0DF3,VERIFY 069C CP 239 ...'LOAD',... 069E JP Z,#0DEE,LOAD 06A1 CP 244 ...'POKE',... 06A3 JP Z,#0438,POKE@ 06A6 CP 248 ...'SAVE',... 06A8 JP Z,#0D41,SAVE 06AB CP 251 ...'CLS',... 06AD JP Z,#1467,CLS# 06B0 CP 253 ...'CLEAR',... 06B2 JP Z,#13E7,CLEAR# 06B5 CP 255 ...'COPY',... 06B7 JP Z,#1621,COPY 06BA LD HL,(#02A6) Fetch ONERR address. 06BD LD A,H 06BE OR L 06BF JR Z,#06CD,SPEC_ERR Jump if no ON ERROR address. 06C1 LD (#06C8),HL Store it so it can be CALBASsed. 06C4 LD A,(#1DFF) Fetch command which has to be examined 06C7 RST #10,CALBAS by user-routine (BASIC extensions). 06C8 DEFW #0000,EXT_BASIC CALL the extend BASIC routine(s). 06CA JP #0419,END Test end of command and exit. THE 'SPECTRUM ERROR' ROUTINE This routine must be entered with the error code in (ERR_NR), and does the same as the 'main' ROM 'ERROR' restart, except when error messages are to be supressed. This is indicated by a non zero value in 23728. 06CD SPEC_ERR LD HL,(#1DD6) Fetch D_CH_ADD. 06D0 LD (23645),HL Restore CH_ADD. 06D3 LD (23647),HL Restore X_PTR. 06D6 SPEC_ERR2 LD HL,#0058 06D9 RST #30,SYNTAX_Z RETurn to #58, which is in ERROR_2, in 06DA JP Z,#004F,UNPAGE_HL the Spectrum ROM when checking syntax. 06DD LD A,(23728) 06E0 AND A Also RETurn to #58 in 'main' ROM when 06E1 JP Z,#004F,UNPAGE_HL error messages aren't to be supressed. 06E4 LD A,(23610) Otherwise signal 'Spectrum error'. 06E7 SET 7,A 06E9 LD (23610),A 06EC LD HL,#1B7D,STMT_R_1 And RETurn to STMT_R_1 in the Spectrum 06EF JP #004F,UNPAGE_HL ROM. THE 'LOAD A BYTE FROM NETWORK' ROUTINE This routine loads one byte from the network. 06F2 N_LBYT PUSH IX 06F4 CALL #2963,JN_INPUT Call the ROM routine. 06F7 POP IX 06F9 RET THE 'SAVE A BYTE TO NETWORK' ROUTINE This routine saves one byte to the network. 06FA N_SBYT PUSH IX 06FC CALL #2966,JN_OUTPUT Call the ROM routine. 06FF POP IX 0701 RET 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 #AEF finds a 'TO' keyword. The return address to the routine which called 'EXPT_PARMS' is dropped at #0708. 0702 TO CALL #0A0F,TEST_SAVE 0705 JP Z,#2920,REP_0 Give error if not SAVEing. 0708 POP HL Drop return address to SAVE routine. 0709 CALL #0AA2,SWAP_UFIAS Swap the UFIAS. 070C RST #28,NEXT_C_RAM 070D AND #DF Drop lower case bit. 070F CP "D" 0711 JP NZ,#2920,REP_0 Jump if 2nd device isn't "D". 0714 LD (#1E04),A Store it in DEV_TYPE1. 0717 CALL #0A5E,EXPT_DEVN Evaluate drive number, store it in UFIA1. 071A CALL #0A1E,SEPARATOR Test for a separator, jump if one 071D JR Z,#0722,TO_1 found, i.e. a 2nd name is given. 071F CALL #09E2,SIGN_LOAD Used here to signal 'use source filename for destination file'. 0722 TO_1 CALL Z,#0ABC,EXP_F_NAME Evaluate filename if there was a separator. 0725 CALL #0AA2,SWAP_UFIAS Swap the UFIAS again. 0728 CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 072B LD HL,#1E1E Copy the second filename and directory 072E LD DE,#1E32 description. 0731 LD BC,11 0734 LDIR 0736 LD HL,#0001 Track 0 sector 1. 0739 LD (#1DED),HL 073C LD HL,#0000 Disk buffer offset #0000. 073F LD (#1DEB),HL 0742 TO_2 CALL #2984,JTEST_DRV Is the drive defined? 0745 CALL #07E6,TO_SEARCH Search for a file to be copied. 0748 JP NZ,#07B9,TO_EXIT Jump if there are no files left. 074B CALL #299F,JLOAD_1ST Copy file description (directory description and filename) to UFIA2 and load the first sector of the file into the disk buffer. 074E LD A,(#1E1E) Get directory description. 0751 CP 5 0753 JR Z,#0742,TO_2 Jump with 'Snapshot 48K'. 0755 CP 6 0757 JR Z,#0742,TO_2 Jump with 'Microdrive file'. 0759 CP 9 075B JR Z,#0742,TO_2 Jump with 'Snapshot 128K'. 075D CP 10 075F JR Z,#0742,TO_2 Jump with 'Opentype file'. 0761 CP 11 0763 JR Z,#0742,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. 0765 CALL #0DE1,LOAD_HEAD2 Copy the file header (the 9 bytes consisting of filetype, length, etc.) to UFIA2. 0768 LD HL,(23635) Fetch start of BASIC program (PROG). 076B INC H Add 256 to it. 076C LD DE,(#1E2A) Fetch length of file (LENGTH2_1). 0770 CALL #29A5,JLOAD_FILE Load DE bytes, starting at address HL. 0773 CALL #07C5,TO_MSG Print the message "CHANGE disc ...." if source drive is destination drive. 0776 CALL #0AA2,SWAP_UFIAS Swap the UFIA's again. The header of the loaded file is now held in UFIA1. 0779 CALL #0A0A,TEST_LOAD Used here to test whether a 2nd 077C JR NZ,#0794,TO_5 filename was given. Jump if not. 077E LD HL,#1E33 Here the 2nd filename was stored. 0781 LD DE,#1E06 Start of filename of loaded file. 0784 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. 0786 TO_3 LD A,(HL) 0787 CP "*" With a '*' don't replace the remaining 0789 JR Z,#0794,TO_5 characters. 078B CP "?" With a '?' in name 2 don't replace this 078D JR Z,#0790,TO_4 character. 078F LD (DE),A Store this character. 0790 TO_4 INC HL 0791 INC DE 0792 DJNZ #0786,TO_3 Repeat for all 'normal' characters. 0794 TO_5 CALL #2984,JTEST_DRV 0797 CALL #29A8,JOFSM_2 Open the file for SAVEing. 079A JR NZ,#07AD,TO_6 Jump if file existed already and the user didn't want to overwrite it. 079C CALL #0D2F,SAVE_HEAD1 SAVE the 9 header bytes to the file. 079F LD HL,(23635) Fetch start of BASIC (PROG), and add 07A2 INC H 256 to it. (here the file was loaded) 07A3 LD DE,(#1E11) Length of file. 07A7 CALL #29C9,JHSVBK_2 Save the file. 07AA CALL #2981,JCFSM Close the file. 07AD TO_6 CALL #0AA2,SWAP_UFIAS Swap the UFIA's again. 07B0 CALL #09CE,SIGN_1HAND Signal 'at least one file has been copied' 07B3 CALL #07C5,TO_MSG Print message "CHANGE ..." if necessary. 07B6 JP #0742,TO_2 Repeat until no more files have to be copied. 07B9 TO_EXIT CALL #09F6,TEST_1HAND Give error if there isn't one file 07BC JP Z,#2954,REP_26 copied. 07BF LD HL,#11B7 Otherwise jump to the appropriate 'NEW' 07C2 JP #160D,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 message "CHANGE disc ..press SPACE" is printed. 07C5 TO_MSG LD A,(#1E01) Fetch source drive. 07C8 LD B,A 07C9 LD A,(#1E1A) Fetch destination drive. 07CC CP B 07CD RET NZ Return if they aren't equal. 07CE RST #10,CALBAS Otherwise clear lower screen area. 07CF DEFW #0D6E,CLS_LOWER 07D1 SET 5,(IY+2) Signal 'lower screen has to be cleared'. 07D5 CALL #19E3,MSG_4 Print "CHANGE disc ..." message. 07D8 CALL #297E,JDISC_BEEP Give a beep. 07DB TO_SPC_KEY LD A,#7F Keyboard row B-SPACE address. 07DD IN A,(254) 07DF RRA 07E0 JR C,#07DB,TO_SPC_KEY Jump unless the SPACE key is pressed. 07E2 RST #10,CALBAS Clear lower screen. 07E3 DEFW #0D6E,CLS_LOWER 07E5 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. 07E6 TO_SEARCH LD DE,(#1DED) Track & sector to DE. 07EA LD A,D 07EB CP 4 Jump if not reached track 4, i.e. 07ED JR NZ,#07F2,TO_SEARCH1 directory hasn't been read completely. 07EF CP 0 Reset Zero flag. 07F1 RET The directory isn't finished yet, so read sector and test the file(s). 07F2 TO_SEARCH1 CALL #29BD,JRSAD Read sector E from track D. 07F5 TO_SEARCH2 CALL #082D,TO_COPY Check if this file is to be copied. 07F8 PUSH AF Store result (Zero flag). 07F9 LD HL,(#1DEB) Disk buffer offset to HL. 07FC LD A,H 07FD CP 1 07FF JR Z,#0812,TO_NXT_SEC Jump if second entry. 0801 LD A,(#1DDA) Fetch current control port status. 0804 AND #04 0806 JR NZ,#0812,TO_NXT_SEC Jump with single density. 0808 LD HL,256 Otherwise offset is for second entry. 080B LD (#1DEB),HL 080E POP AF Restore Zero flag. 080F RET Z Return if this file is to be copied. 0810 JR #07F5,TO_SEARCH2 Otherwise next file. The file entries of the current sector have been tested so point to the next sector. 0812 TO_NXT_SEC LD HL,0 Offset is for first entry. 0815 LD DE,(#1DED) Fetch track and sector. 0819 INC E Next sector. 081A LD A,E 081B CP 11 081D JR NZ,#0822,TO_NXT1 Jump if not last sector on this track. 081F LD E,1 Start with sector 1. 0821 INC D Next track. 0822 TO_NXT1 LD (#1DED),DE Store track & sector. 0826 LD (#1DEB),HL Store disk buffer offset. 0829 POP AF Restore Zero flag. 082A RET Z Return if previous file is to be 082B JR #07E6,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. 082D TO_COPY LD HL,#1BD6 Point to start of sector. 0830 LD DE,(#1DEB) Offset to DE. 0834 LD (IX+14),D Update RPT (RAM PoinTer (?)). 0837 ADD HL,DE Update HL. 0838 LD A,(HL) Fetch directory description. 0839 AND A 083A JR NZ,#083E,TO_FILE Jump if the file isn't ERASEd. 083C INC A Reset Zero flag to signal 'do not copy 083D RET this file' and exit. 083E TO_FILE INC HL Step past directory descriptor. 083F LD DE,#1E06 DE now points to FILE_NAME1. 0842 LD B,10 A filename is 10 characters long. 0844 TO_COPY_L LD A,(DE) Fetch character. 0845 CP "*" If it was a '*' all other characters 0847 RET Z don't matter. Signal 'copy this one'. 0848 CP "?" If it was a '?' this character doesn't 084A JR Z,#0850,TO_COPY1 matter. 084C XOR (HL) 084D AND #DF Upper and lower case? don't bother. 084F RET NZ Exit if characters are unequal. 0850 TO_COPY1 INC DE Check next character. 0851 INC HL 0852 DJNZ #0844,TO_COPY_L 0854 RET Finished. THE 'CAT' COMMAND SYNTAX ROUTINE This routine checks that the command is in the form CAT <#s;>d<<;>n$>. 0855 CAT LD IX,#1AC3 Point to the DISCiPLE workspace. 0859 CALL #09FB,TEST_SERV Check if a 'pupil' requested a CAT. 085C JP NZ,#089F,DO_CAT Jump if serving a 'pupil'. 085F LD HL,#1E06 "*" is the default name of the files 0862 LD (HL),#2A being CATted. 0864 LD HL,#1E03 Just like #2 is the default output 0867 LD (HL),#02 stream. 0869 RST #28,NEXT_C_RAM Get next character. 086A CP 13 Give an error if an 'end of line' (CR) 086C JP Z,#2924,REP_2 is found right after "CAT". 086F CP ":" 0871 JP Z,#2924,REP_2 Same error for ":". 0874 CP "#" Jump if no stream specified, use 0876 JR NZ,#0881,CAT_DRV default stream #2. 0878 CALL #109D,EXPT_#_NR Evaluate stream number. 087B CALL #0A1E,SEPARATOR Check if there is a separator. 087E JP NZ,#2920,REP_0 Give an error if no separator found. 0881 CAT_DRV CALL #0A76,EXPT_DEVN2 Evaluate drive number. 0884 CALL #0A1E,SEPARATOR Evaluate filename if there is a 0887 CALL Z,#0ABC,EXP_F_NAME separator. 088A CP "!" If there is no "!" then an extended 088C JR NZ,#0899,EXT_CAT catalogue is given. 088E RST #28,NEXT_C_RAM Next character. 088F CALL #0409,ST_END_RAM Confirm end of statement and exit when syntax checking. 0892 CALL #2984,JTEST_DRV See if drive is defined. 0895 LD A,#02 Signal 'small' CAT. 0897 JR #08A4,DO_CAT1 0899 EXT_CAT CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax time. 089C RST #10,CALBAS Clear the screen by calling 'main' ROM 089D DEFW #0DAF,CL_ALL routine. 089F DO_CAT CALL #2984,JTEST_DRV See if drive is defined. 08A2 LD A,#04 Signal extended CAT. 08A4 DO_CAT1 CALL #08B5,CAT_RUN Give the CAT. 08A7 JP #0419,END Finished. THE 'CAT' COMMAND ROUTINE This routine makes a catalogue of the disk inserted in the specified drive, by calling the DISCiPLE ROM routine 'SCAN_CAT'. It has two entry points: #08AA for the command code 67, and #08B5 for the BASIC 'CAT' command. The first entry point was somewhat changed in 'Sys 3d' to make the command code work. 08AA PCAT CALL #2984,JTEST_DRV Drive defined? 08AD LD A,(#1E10) Get 'CAT' type. 08B0 NOP 08B1 NOP 08B2 NOP 08B3 NOP 08B4 NOP 08B5 CAT_RUN PUSH AF 08B6 CALL #09FB,TEST_SERV Serving the network? 08B9 CALL NZ,#0924,OPEN_N_CH Open the "N" channel if so. 08BC LD A,(#1E03) 08BF RST #10,CALBAS Open the desired stream by calling 08C0 DEFW #1601,CHAN_OPEN 'CHAN_OPEN' in the 'main' ROM. 08C2 LD A,13 08C4 CALL #29AE,JPRT_A Printing starts on the next line. 08C7 CALL #1979,MSG_0 Print the 1st part of "DIR"-message. 08CA LD A,(#1ACE) Fetch current drive, 0=2, 1=1. 08CD AND #01 Only bit0. 08CF XOR 49 Make ASCII "1" or "2". 08D1 INC A 08D2 CALL #29AE,JPRT_A Print drive number. 08D5 CALL #198F,MSG_1 Print the 2nd part of "DIR"-message. 08D8 LD HL,#0000 Reset 'total number of sectors' 08DB LD (#1DD8),HL occupied. 08DE POP AF Restore 'CAT' type. 08DF CALL #2993,JSCAN_CAT Print the CAT entries. 08E2 CALL #19A0,MSG_2 Print "Free ..." message. 08E5 CALL #29CC,JDRV_CAP Get drive capacity in A register. The 'Sys 3b' system couldn't cope with non 40, 80 tracks drives (both single and double sided), the amount of free space was calculated as if it was an 80 tracks double sided drive. In 'Sys 3c' this was cured. 08E8 PUSH BC 08E9 BIT 7,A 08EB JR Z,#08EE,CAT_RUN1 Jump if drive is single sided. 08ED ADD A,A Otherwise double the number of tracks and get rid of the side bit. 08EE CAT_RUN1 SUB 4 Subtract number of catalogue tracks. 08F0 LD HL,0 08F3 LD B,10 Each track has 10 sectors. 08F5 LD D,0 Number of tracks to DE. 08F7 LD E,A 08F8 NO_SECTORS ADD HL,DE Calculate total number of sectors. 08F9 DJNZ #08F8,NO_SECTORS 08FB POP BC 08FC NOP New code is two bytes shorter. 08FD NOP 08FE LD DE,(#1DD8) Get number of used sectors. 0902 XOR A Clear carry. 0903 SBC HL,DE Calculate number of free sectors. 0905 SRL H Divide it by two to get number of free 0907 RR L K-bytes. 0909 LD A,(#1DDA) Fetch current control port status. 090C AND #04 090E JR Z,#0914,CAT_RUN2 Jump with double density drive. 0910 SRL H Otherwise divide by two, SD sectors contain 256 bytes. 0912 RR L 0914 CAT_RUN2 XOR A 0915 CALL #29B1,JPRT_NUM Print the number. 0918 LD A,13 091A CALL #29AE,JPRT_A Print a newline. 091D CALL #09FB,TEST_SERV 0920 RET Z Return if not serving. 0921 JP #2975,JSEND_NEOF Otherwise send the EOF block over the network. THE 'OPEN A NETWORK CHANNEL' ROUTINE This subroutine is used to send the data, requested by a pupil, over the network. 0924 OPEN_N_CH PUSH IX 0926 LD A,(#1DFE) Fetch pupil's station number. 0929 LD (#1E01),A 092C CALL #2960,JOPEN_N Open the "n" channel. 092F POP IX 0931 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 DISCiPLE syntax ('d'd<;>) or Microdrive syntax ('"m"';d;). NOTE: The routine starts with testing if it was a pupil requested ERASE command, the 'NET_SERVER' routine (at #0369) however doesn't allow pupils ERASEing files. 0932 ERASE CALL #09FB,TEST_SERV 0935 JP NZ,#0954,ERASE1 Jump if serving. 0938 RST #28,NEXT_C_RAM Get next character. 0939 LD (#1E04),A Store the device descriptor. 093C CP """ Test for Microdrive syntax if it was a 093E CALL Z,#0A3E,MD_SYNTAX1 quote. 0941 CALL #0A5E,EXPT_DEVN Evaluate the drive number. 0944 CALL #0A1E,SEPARATOR Test for a separator. 0947 JP NZ,#2920,REP_0 Give error if none found. 094A CALL #0ABC,EXPT_F_NAME Evaluate filename. 094D CP 204 Is the filename followed by "TO"? 094F JR Z,#098D,RENAME Jump if so, rename is wanted. 0951 CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 0954 ERASE1 LD A,(#1E04) Fetch device descriptor. 0957 AND #DF Drop lower case bit. 0959 CP "D" 095B JR Z,#0962,ERASE_RUN Jump if it was "D". 095D CP "M" 095F JP NZ,#2934,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. 0962 ERASE_RUN CALL #2984,JTEST_DRV See if drive is defined. 0965 ERASE_LOOP CALL #0985,FIND_FILE Find the file. 0968 JR NZ,#0974,NOT_FOUND Jump if not found. 096A LD (HL),0 Directory description 0 means ERASEd. 096C CALL #29CF,JWSAD Write sector DE. 096F CALL #09CE,SIGN_1HAND Signal 'at least one file ERASEd'. 0972 JR #0965,ERASE_LOOP ERASE all files with this filename. The file wasn't found, an error is given if no file was ERASEd at all. 0974 NOT_FOUND CALL #09F6,TEST_1HAND Give an error if there wasn't at least 0977 JP Z,#2954,REP_26 one file ERASEd. 097A EXIT_ERASE LD A,(#1E04) 097D CP "D" If the device descriptor was a (capital) 097F CALL Z,#08AA,PCAT "D", then give a CATalogue. Note: This doesn't work anymore because 'CAT'-type, filename and stream don't make sense. This option was lost when the routine for command code 67 was repaired. The following happens: 'STRM_NUM1' holds stream number -1 (=#FF, see #065A), which is attached to the Spectrum "R"-channel (the "R"-channel is used to print characters into Spectrum workspaces). When the CAT routine is called, the output is stored at the address held in the Spectrum system variable 'K_CUR', which points to the edit line. Because the filename is that of the just ERASEd file, the CAT consists only of the 'DISC .. DIRECTORY' message and the 'Free K-bytes' message. 0982 JP #0419,END Finished. THE 'FIND A FILE' SUBROUTINE This routine searches the directory for a matching filename by calling the DISCiPLE 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. 0985 FIND_FILE LD A,#10 Scan the CATalogue for a matching 0987 CALL #2993,JSCAN_CAT filename. 098A JP #29B4,JRPT_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. 098D RENAME RST #28,NEXT_C_RAM Get next character. 098E CALL #0A1E,SEPARATOR Check if there is a separator. 0991 JP NZ,#2920,REP_0 Give an error if none found. 0994 CALL #0A9C,EXP_F_NAM2 Evaluate 2nd filename. 0997 CALL #0409,ST_END_RAM Confirm end of statement and exit when synatx checking. 099A LD A,(#1E04) Fetch device descriptor. 099D AND #DF Drop lower case bit. 099F CP "D" 09A1 JR Z,#09A8,RENAME_RUN Jump if it was a "D". 09A3 CP "M" 09A5 JP NZ,#2934,REP_10 Give error if it wasn't a "M". 09A8 RENAME_RUN CALL #2984,JTEST_DRV See if the drive is defined. 09AB CALL #0AA2,SWAP_UFIAS Swap UFIA 1 & 2 in the DFCA. 09AE CALL #0985,FIND_FILE Give an error if the 2nd filename 09B1 JP Z,#2958,REP_28 already exists. 09B4 CALL #0AA2,SWAP_UFIAS Swap UFIA 1 & 2 in the DFCA. 09B7 CALL #0985,FIND_FILE Give an error if the 1st filename 09BA JP NZ,#2954,REP_26 doesn't exist. 09BD INC HL 09BE PUSH DE 09BF LD DE,#1E1F Rename the file by copying the 2nd to 09C2 EX DE,HL the 1st name. 09C3 LD BC,10 09C6 LDIR 09C8 POP DE 09C9 CALL #29CF,JWSAD Write the CATalogue sector. 09CC JR #097A,EXIT_ERASE Exit via 'EXIT_ERASE'. The flag set and test routines THE 'SIGNAL ..' SUBROUTINES These subroutines are used to signal various states of the DISCiPLE system. The corresponding test routines are located from #09F6 and onwards. Clearing is done by loading 0 into FLASG3, resetting all flags at once. It seems that the flags aren't used during hook/command code execution. 09CE SIGN_1HAND RST #18,F_ADDR_RAM Signal 'there has at least one file 09CF SET 0,(HL) been handled'. 09D1 POP HL 09D2 RET 09D3 SIGN_SERV RST #18,F_ADDR_RAM Signal 'serving the network'. 09D4 SET 1,(HL) 09D6 POP HL 09D7 RET 09D8 SIGN_STEAL RST #18,F_ADDR_RAM Signal 'stealing from or forcing to a 09D9 SET 2,(HL) pupil'. 09DB POP HL 09DC RET 09DD SIGN_NET RST #18,F_ADDR_RAM Signal 'networking'. 09DE SET 3,(HL) 09E0 POP HL 09E1 RET 09E2 SIGN_LOAD RST #18,F_ADDR_RAM Signal 'LOADing'. 09E3 SET 4,(HL) 09E5 POP HL 09E6 RET 09E7 SIGN_SAVE RST #18,F_ADDR_RAM Signal 'SAVEing'. 09E8 SET 5,(HL) 09EA POP HL 09EB RET 09EC SIGN_MERGE RST #18,F_ADDR_RAM Signal 'MERGEing'. 09ED SET 6,(HL) 09EF POP HL 09F0 RET 09F1 SIGN_VERIF RST #18,F_ADDR_RAM Signal 'VERIFYing'. 09F2 SET 7,(HL) 09F4 POP HL 09F5 RET THE 'TEST ..' SUBROUTINES These subroutines are used to test various states of the DISCiPLE system. 09F6 TEST_1HAND RST #18,F_ADDR_RAM 09F7 BIT 0,(HL) 09F9 POP HL 09FA RET 09FB TEST_SERV RST #18,F_ADDR_RAM 09FC BIT 1,(HL) 09FE POP HL 09FF RET 0A00 TEST_STEAL RST #18,F_ADDR_RAM 0A01 BIT 2,(HL) 0A03 POP HL 0A04 RET 0A05 TEST_NET RST #18,F_ADDR_RAM 0A06 BIT 3,(HL) 0A08 POP HL 0A09 RET 0A0A TEST_LOAD RST #18,F_ADDR_RAM 0A0B BIT 4,(HL) 0A0D POP HL 0A0E RET 0A0F TEST_SAVE RST #18,F_ADDR_RAM 0A10 BIT 5,(HL) 0A12 POP HL 0A13 RET 0A14 TEST_MERGE RST #18,F_ADDR_RAM 0A15 BIT 6,(HL) 0A17 POP HL 0A18 RET 0A19 TEST_VERIF RST #18,F_ADDR_RAM 0A1A BIT 7,(HL) 0A1C POP HL 0A1D RET 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. 0A1E SEPARATOR CP "," 0A20 JR Z,#0A29,SEPAR_1 Jump if current character is a comma. 0A22 CP ";" 0A24 JR Z,#0A29,SEPAR_1 Jump if it is a semicolon. 0A26 CP """ 0A28 RET Return with Zero set if it's a quote. 0A29 SEPAR_1 RST #28,NEXT_C_RAM Get next character. 0A2A LD (#1DEA),A 0A2D XOR A Set Zero flag. 0A2E LD A,(#1DEA) 0A31 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. 0A32 EXPT_STR RST #10,CALBAS Evaluate the string expression. 0A33 DEFW #1C8C,EXPT_EXP 0A35 RST #30,SYNTAX_Z 0A36 RET Z Return if syntax is being checked. 0A37 PUSH AF Save the character following the string 0A38 RST #10,CALBAS and the zero flag. 0A39 DEFW #2BF1,STK_FETCH Fetch the string parameters. 0A3B POP AF 0A3C 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. 0A3D MD_SYNTAX RST #28,NEXT_C_RAM Next character. 0A3E MD_SYNTAX1 CALL #0A32,EXPT_STR 0A41 JR Z,#0A55,MD_SYNT_1 Jump if syntax is being checked. 0A43 PUSH AF Save the character following the 0A44 LD A,C string. A holds string length low byte. 0A45 DEC A 0A46 OR B Give an error if there isn't exactly 0A47 JP NZ,#2934,REP_10 one character in the string. 0A4A LD A,(DE) Fetch the channel specifier. 0A4B RST #10,CALBAS Call 'ALPHA' to see if it's a valid 0A4C DEFW #2C8D,ALPHA letter. 0A4E JP NC,#2934,REP_10 Give error if not a valid letter. 0A51 LD (#1E04),A Store the specifier in the UFIA. 0A54 POP AF Restore next character. 0A55 MD_SYNT_1 CP ";" 0A57 RET Z Return if it's a semicolon. 0A58 CP "," 0A5A RET Z Return if it's a comma. 0A5B JP #2920,REP_0 Otherwise give error. THE 'EVALUATE DEVICE NUMBER' SUBROUTINE This subroutine is used to evaluate the device number. 0A5E EXPT_DEVN AND #DF Make upper case. 0A60 CP "P" 0A62 JR NZ,#0A75,EXPT_DEVN1 Jump if the device wasn't "P". 0A64 RST #28,NEXT_C_RAM Next character. 0A65 CALL #0A8D,EXPT_NUM Get the program number. 0A68 RET Z Return if syntax checking. 0A69 PUSH AF 0A6A LD A,(#1E01) Store program number. 0A6D LD (#1E02),A 0A70 CALL #0A80,LAST_DRV Drive is last drive. 0A73 POP AF 0A74 RET Now a check is made whether the last used device is wanted. 0A75 EXPT_DEVN1 RST #28,NEXT_C_RAM Get next character. 0A76 EXPT_DEVN2 CP "*" 0A78 JR NZ,#0A8D,EXPT_NUM Jump if it wasn't a "*". 0A7A RST #30,SYNTAX_Z 0A7B CALL NZ,#0A80,LAST_DRV Store last drive number during runtime. 0A7E RST #28,NEXT_C_RAM Next character. 0A7F RET THE 'SET LAST DRIVE' SUBROUTINE This subroutine is used whenever the last used drive is to be used again. 0A80 LAST_DRV LD A,(#1DDA) Fetch current control port status. 0A83 AND #01 Keep only drive select. 0A85 ADD A,1 A holds 1 for drive 2, 2 for drive 1. 0A87 XOR #03 1 becomes 2, 2 becomes 1. 0A89 LD (#1E01),A Store drive number. 0A8C 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. 0A8D EXPT_NUM RST #10,CALBAS Evaluate the expression by calling 0A8E DEFW #1C82,EXPT_1NUM 'EXPT_1NUM' in the 'main' ROM. 0A90 RST #30,SYNTAX_Z 0A91 RET Z Return if syntax is being checked. 0A92 PUSH AF 0A93 RST #10,CALBAS Fetch the value from the calculator 0A94 DEFW #1E99,FIND_INT2 stack. 0A96 LD A,C 0A97 LD (#1E01),A Store it in UFIA1. 0A9A POP AF 0A9B 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. 0A9C EXP_F_NAM2 CALL #0AA2,SWAP_UFIAS Swap UFIA1 and 2. 0A9F CALL #0ABC,EXP_F_NAME Evaluate filename. Exit via 'SWAP_UFIAS'. THE 'SWAP UFIAS' SUBROUTINE This subroutine swaps the contents of UFIA1 and UFIA2 in DFCA. 0AA2 SWAP_UFIAS PUSH AF 0AA3 PUSH BC 0AA4 PUSH DE 0AA5 PUSH HL 0AA6 LD B,24 An UFIA is 24 bytes long. 0AA8 LD DE,#1E01 Start of UFIA1. 0AAB LD HL,#1E1A Start of UFIA2. 0AAE SWAP_LOOP LD A,(DE) Exchange the contents. 0AAF LD C,(HL) 0AB0 EX DE,HL 0AB1 LD (DE),A 0AB2 LD (HL),C 0AB3 INC DE 0AB4 INC HL 0AB5 DJNZ #0AAE,SWAP_LOOP Repeat for all 24 bytes. 0AB7 POP HL 0AB8 POP DE 0AB9 POP BC 0ABA POP AF 0ABB 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. 0ABC EXP_F_NAME CALL #0A32,EXPT_STR Evaluate the string. 0ABF RET Z Return if checking syntax. 0AC0 PUSH AF 0AC1 LD A,C 0AC2 OR B 0AC3 JP Z,#2930,REP_8 Give error with null string. 0AC6 LD HL,10 0AC9 SBC HL,BC 0ACB JP C,#2930,REP_8 Give error with string length > 10. 0ACE LD HL,#1E05 Clear the filename and the directory 0AD1 LD A,11 description of UFIA1. 0AD3 CLR_FNAME LD (HL)," " 0AD5 INC HL 0AD6 DEC A 0AD7 JR NZ,#0AD3,CLR_FNAME Repeat for all 11 bytes. 0AD9 LD HL,#1E06 Copy the filename into UFIA1. 0ADC EX DE,HL 0ADD LDIR 0ADF POP AF 0AE0 RET THE 'CHECK STATION NUMBER' SUBROUTINE A return to the calling routine is made only if DEV_NUM1 holds a valid station number, i.e. in the range 0..63. 0AE1 TEST_STAT LD A,(#1E01) Fetch DEV_NUM1. 0AE4 INC A Give an error if it holds #FF, no 0AE5 JP Z,#2932,REP_9 station number has been evaluated. 0AE8 DEC A Balance the 'INC'. 0AE9 SUB 64 Return only if the value isn't greater 0AEB RET C than 63. 0AEC JP #2932,REP_9 Give error. THE 'EVALUATE PARAMETERS' SUBROUTINE This very important subroutine is called to evaluate the syntax of the DISCiPLE's '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. 0AEF EXPT_PARMS CALL #09FB,TEST_SERV Return when serving the network, the 0AF2 RET NZ parameters have been evaluated already by the station requesting service. 0AF3 RST #28,NEXT_C_RAM Get next character from BASIC line. 0AF4 CP " " Give an error with character codes 0AF6 JP C,#2920,REP_0 below 32, i.e. colour codes, etc. 0AF9 CP 170 0AFB JP Z,#161E,DUMP_SCR$ Jump with 'SCREEN$'. 0AFE LD (#1E04),A Otherwise store it in DEV_TYPE1. 0B01 CP "@" 0B03 JR NZ,#0B3C,NOT_@ Jump if not a '@'. Now deal with @. 0B05 CALL #0A5E,EXPT_DEVN Evaluate drive number. 0B08 CALL #0A1E,SEPARATOR 0B0B JP NZ,#2924,REP_2 Give error if no separator was found. 0B0E RST #10,CALBAS Call 'EXPT_1NUM' to evaluate the track 0B0F DEFW #1C82,EXPT_1NUM number. 0B11 CALL #0A1E,SEPARATOR Test for another separator and give an 0B14 JP NZ,#2924,REP_2 error if none found. 0B17 RST #10,CALBAS Evaluate sector number. 0B18 DEFW #1C82,EXPT_1NUM 0B1A CALL #0A1E,SEPARATOR Again a separator has to be found. 0B1D JP NZ,#2924,REP_2 0B20 RST #10,CALBAS Evaluate address. 0B21 DEFW #1C82,EXPT_1NUM 0B23 CALL #0409,ST_END_RAM Confirm end of statement, and exit during syntax checking. 0B26 RST #10,CALBAS Fetch the address from the calculator 0B27 DEFW #1E99,FIND_INT2 stack. 0B29 LD (#1E15),BC Store it in LENGTH1_2 0B2D RST #10,CALBAS Fetch sector. 0B2E DEFW #1E99,FIND_INT2 0B30 LD (#1E13),BC Store it in FILE_ADDR1 0B34 RST #10,CALBAS Fetch track. 0B35 DEFW #1E99,FIND_INT2 0B37 LD (#1E11),BC Store it in LENGTH1_1 0B3A RET Exit. 0B3C NOT_@ CP "*" Call 'MD_SYNTAX' if it was a "*". 0B3E CALL Z,#0A3D,MD_SYNTAX 0B41 CALL #0A5E,EXPT_DEVN Fetch device or program number. 0B44 CALL #0A1E,SEPARATOR Test for a separator. 0B47 PUSH AF 0B48 RST #30,SYNTAX_Z 0B49 JR Z,#0B7F,FILENAME Jump if syntax checking. 0B4B LD A,(#1E04) Fetch device descriptor. 0B4E AND #DF Only capitals. 0B50 CP "D" 0B52 JR Z,#0B7A,NOT_NET Jump if device is disk. 0B54 CP "M" 0B56 JR Z,#0B7A,NOT_NET Or disk with Microdrive syntax. 0B58 CP "P" 0B5A JR Z,#0B84,PARAMS Jump with program. 0B5C CP "F" 0B5E JR NZ,#0B68,NETWORKING Jump if not stealing or forcing. 0B60 CALL #09D8,SIGN_STEAL Signal 'stealing from or forcing to a 0B63 LD A,"N" pupil'. Device is network. 0B65 LD (#1E04),A 0B68 NETWORKING CP "N" 0B6A JP NZ,#2934,REP_10 Give error with unknown device. 0B6D LD A,(#029C) 0B70 CP 0 0B72 JP Z,#294A,REP_21 Give error if network is off. 0B75 CALL #09DD,SIGN_NET Signal 'networking'. 0B78 JR #0B84,PARAMS Evaluate parameters. 0B7A NOT_NET POP AF Give error if no separator or quote 0B7B JP NZ,#2920,REP_0 found with devices "D" and "M". 0B7E PUSH AF Balance 'POP AF' below. 0B7F FILENAME POP AF 0B80 CALL Z,#0ABC,EXP_F_NAME Evaluate filename if necessary. 0B83 PUSH AF Balance next instruction. 0B84 PARAMS POP AF 0B85 CP 13 0B87 JP Z,#0C18,NO_PARAMS Jump with ENTER. 0B8A CP ":" 0B8C JP Z,#0C18,NO_PARAMS Jump with colon. 0B8F CP 204 0B91 JP Z,#0702,TO Jump with 'TO'. 0B94 CP 170 0B96 JP Z,#0C4E,SCREEN$ Jump with 'SCREEN$'. 0B99 CP 175 0B9B JP Z,#0C69,CODE Jump with 'CODE'. 0B9E CP 228 0BA0 JP Z,#0CC3,DATA Jump with 'DATA'. 0BA3 CP 202 0BA5 JP Z,#0C08,LINE Jump with 'LINE'. 0BA8 AND #DF Only capitals. 0BAA CP "S" 0BAC JR NZ,#0BB8,NOT_S Jump with other than 'S'. 0BAE RST #28,NEXT_C_RAM Next character. 0BAF CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 0BB2 LD A,5 Signal '48K Snapshot'. 0BB4 LD (#1E05),A 0BB7 RET Finished. 0BB8 NOT_S CP "K" 0BBA JR NZ,#0BC6,NOT_K Jump with other than 'K'. 0BBC RST #28,NEXT_C_RAM Next character. 0BBD CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 0BC0 LD A,9 Signal '128K Snapshot'. 0BC2 LD (#1E05),A 0BC5 RET Finished. 0BC6 NOT_K CP "X" 0BC8 JP NZ,#2920,REP_0 Give error with other than 'X'. 0BCB RST #28,NEXT_C_RAM Next character. 0BCC CALL #0A1E,SEPARATOR Jump if a separator found, there is 0BCF JR Z,#0BDF,X_FILE_1 more. 0BD1 CALL #0A0F,TEST_SAVE There must follow a address if SAVEing. 0BD4 JP NZ,#2924,REP_2 Give error if SAVEing. 0BD7 CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 0BDA LD BC,#1BD6 Load address of execute file. 0BDD JR #0BE8,X_FILE_2 Jump forward. A separator has been found, so there should follow an address. 0BDF X_FILE_1 RST #10,CALBAS Evaluate address. 0BE0 DEFW #1C82,EXPT_1NUM 0BE2 CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 0BE5 RST #10,CALBAS Fetch the address. 0BE6 DEFW #1E99,FIND_INT2 0BE8 X_FILE_2 LD (#1E13),BC Store it in FILE_ADDR1 0BEC LD BC,510 Length of execute file on double 0BEF LD A,(#1DDA) density disks. 0BF2 AND #04 0BF4 JR Z,#0BF9,X_FILE_3 Jump if double density selected. 0BF6 LD BC,254 Otherwise this is the length of the execute file. 0BF9 X_FILE_3 LD (#1E11),BC Store length in LENGTH1_1. 0BFD LD A,3 File type is 'CODE'. 0BFF LD (#1E10),A Store it in FILE_TYPE1. 0C02 LD A,11 Signal 'Execute file'. 0C04 LD (#1E05),A Store in DIR_DESCR1 0C07 RET Finished. Now deal with LINE. The DISCiPLE allows LOAD, VERIFY and MERGE .. LINE to be entered as a command but the LINE is completely ignored. 0C08 LINE RST #28,NEXT_C_RAM Advance CH_ADD. 0C09 RST #10,CALBAS Evaluate autostart line number by 0C0A DEFW #1C82,EXPT_1NUM calling 'EXPT_1NUM' in the 'main' ROM. 0C0C CALL #0409,ST_END_RAM Confirm end of statement, and exit during syntax checking. 0C0F RST #10,CALBAS Fetch the autostart line number. 0C10 DEFW #1E99,FIND_INT2 0C12 LD (#1E17),BC Store it in AUTOSTART1. 0C16 JR #0C1B,PROG If there are no parameters, as with a BASIC program, the syntax checking ends here. 0C18 NO_PARAMS CALL #0409,ST_END_RAM Confirm end of statement, exit when syntax checking. 0C1B PROG LD A,(#1E04) 0C1E AND #DF Only capitals. 0C20 CP "P" Jump if the device wasn't "P", i.e. no 0C22 JR NZ,#0C2B,PROG_1 program number was specified. 0C24 CALL #0A0F,TEST_SAVE 'SAVE pn' is not supported, so give an 0C27 RET Z error if saving, otherwise return. 0C28 JP #2920,REP_0 0C2B PROG_1 XOR A File type is 'BASIC'. 0C2C LD (#1E10),A 0C2F LD A,1 Signal 'BASIC file'. 0C31 LD (#1E05),A 0C34 LD HL,(23641) Fetch (E_LINE), the first location past the variables area. 0C37 LD DE,(23635) Fetch (PROG), the 'start' of the BASIC 0C3B LD (#1E13),DE program and store it in FILE_ADDR1 0C3F SCF Calculate ((E_LINE)-(PROG)-1), i.e. the 0C40 SBC HL,DE length of the program and its 0C42 LD (#1E11),HL variables. Store it in LENGTH1_1. 0C45 LD HL,(23627) Fetch (VARS) and calculate 0C48 SBC HL,DE (VARS)-(PROG), i.e. the length of the program without its variables. 0C4A LD (#1E15),HL Store it into LENGTH1_2. 0C4D RET Finished. If the token is SCREEN$, the parameters are entered directly into the file header. 0C4E SCREEN$ RST #28,NEXT_C_RAM Get the next character. 0C4F CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 0C52 LD HL,6912 The size of the display file is stored 0C55 LD (#1E11),HL into LENGTH1_1. 0C58 LD HL,16384 The startaddress is stored into 0C5B LD (#1E13),HL FILE_ADDR1 0C5E LD A,3 File type is 'CODE'. 0C60 LD (#1E10),A 0C63 LD A,7 Signal 'SCREEN$'. 0C65 LD (#1E05),A 0C68 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. 0C69 CODE RST #28,NEXT_C_RAM Update CH_ADD. 0C6A CP 13 If there are no further parameters, 0C6C JR Z,#0C72,CODE_1 jump to use '0' as default value. 0C6E CP ":" Jump if there are parameters to be 0C70 JR NZ,#0C7D,CODE_2 evaluated (i.e. the next character is not a colon). 0C72 CODE_1 CALL #0A0F,TEST_SAVE 'SAVE .. CODE' has to be followed by at 0C75 JP NZ,#2924,REP_2 least two numbers, so give an error if none present. 0C78 RST #10,CALBAS A call to the 'main' ROM routine 0C79 DEFW #1CE6,USE_ZERO 'USE_ZERO' is made to use a value of 0C7B JR #0C85,CODE_3 zero as default. It's likely that an address follows. 0C7D CODE_2 RST #10,CALBAS Use the 'main' ROM routine to evaluate 0C7E DEFW #1C82,EXPT_1NUM the first parameter. 0C80 CALL #0A1E,SEPARATOR 0C83 JR Z,#0C90,CODE_4 Jump if a separator is present. 0C85 CODE_3 CALL #0A0F,TEST_SAVE Give an error if there isn't a second 0C88 JP NZ,#2924,REP_2 number with 'SAVE .. CODE'. 0C8B RST #10,CALBAS Otherwise use zero as default. 0C8C DEFW #1CE6,USE_ZERO 0C8E JR #0C98,CODE_5 The length seems to be present also. 0C90 CODE_4 RST #10,CALBAS Evaluate the second parameter. 0C91 DEFW #1C82,EXPT_1NUM 0C93 CALL #0A1E,SEPARATOR Jump if a second separator is found. 0C96 JR Z,#0C9D,CODE_6 0C98 CODE_5 RST #10,CALBAS Otherwise zero is default. 0C99 DEFW #1CE6,USE_ZERO 0C9B JR #0CA0,CODE_7 There's even an execute address. 0C9D CODE_6 RST #10,CALBAS Evaluate the third parameter. 0C9E DEFW #1C82,EXPT_1NUM 0CA0 CODE_7 CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 0CA3 RST #10,CALBAS Fetch the "autoexecute" address from 0CA4 DEFW #1E99,FIND_INT2 the calculator stack and store it into 0CA6 LD (#1E17),BC AUTOSTART1 0CAA RST #10,CALBAS Fetch the "length". 0CAB DEFW #1E99,FIND_INT2 0CAD LD (#1E11),BC Store it into LENGTH1_1 0CB1 RST #10,CALBAS Fetch the "start". 0CB2 DEFW #1E99,FIND_INT2 0CB4 LD (#1E13),BC Store it into FILE_ADDR1 0CB8 LD A,3 File type is 'CODE'. 0CBA LD (#1E10),A 0CBD LD A,4 Signal 'CODE file'. 0CBF LD (#1E05),A 0CC2 RET Finished. Finally the routine to evaluate DATA parameters. 0CC3 DATA CALL #0A14,TEST_MERGE Give an error if attempting to MERGE an 0CC6 JP NZ,#293C,REP_14 array. 0CC9 RST #28,NEXT_C_RAM Next character. 0CCA RST #10,CALBAS Call LOOK_VARS to look for the array 0CCB DEFW #28B2,LOOK_VARS name. 0CCD SET 7,C 0CCF JR NC,#0CDC,DATA_1 Jump if handling an existing array or if syntax checking. 0CD1 LD HL,#0000 Signal 'using a new array'. 0CD4 CALL #0A0A,TEST_LOAD 0CD7 JR NZ,#0CF7,DATA_3 Jump if LOADing the array. 0CD9 JP #2936,REP_11 Otherwise give error 'Variable not found'. 0CDC DATA_1 JP NZ,#2920,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 #0CE7. 0CDF RST #30,SYNTAX_Z 0CE0 JR Z,#0D09,DATA_5 Jump if syntax is being checked. 0CE2 CALL #0A0F,TEST_SAVE 0CE5 JR Z,#0CEC,DATA_2 Jump if LOADing. 0CE7 BIT 7,(HL) Give an error if trying to SAVE a 0CE9 JP Z,#2920,REP_0 simple string. 0CEC DATA_2 INC HL Point to the 'length' of the array. 0CED LD A,(HL) Store the length into LENGTH1_1. 0CEE LD (#1E11),A 0CF1 INC HL 0CF2 LD A,(HL) 0CF3 LD (#1E12),A 0CF6 INC HL Advance to the start of the array. 0CF7 DATA_3 LD A,C Store array name into LSB of LENGTH1_2. 0CF8 LD (#1E15),A 0CFB LD A,1 File type is 'NUM ARRAY'. 0CFD BIT 6,C 0CFF JR Z,#0D02,DATA_4 Jump if really a numeric array. 0D01 INC A File type is 'STR ARRAY'. 0D02 DATA_4 LD (#1E10),A Store file type into FILE_TYPE1. 0D05 INC A Signal: (A=2) 'Numeric array', 0D06 LD (#1E05),A (A=3) 'String array'. 0D09 DATA_5 EX DE,HL DE holds 'start' of the array (or #0000 with a 'new' array to be LOADed). 0D0A RST #28,NEXT_C_RAM Next character. 0D0B CP ")" Check that the ')' does exist. 0D0D JP NZ,#2924,REP_2 Report an error if not. 0D10 RST #28,NEXT_C_RAM Next character. 0D11 CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 0D14 LD (#1E13),DE Store "start" of the array into 0D18 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 @. 0D19 GET_TR&SE LD A,(#1E11) Get track from LSB of LENGTH1_1. 0D1C LD D,A 0D1D LD A,(#1E13) Get sector from LSB of FILE_ADDR1. 0D20 LD E,A 0D21 RET THE 'GET SECTOR LENGTH' SUBROUTINE This subroutine returns with BC holding the length of a sector in bytes. With double density this is 512, with single density 256. This routine is also present in ROM (at #36B3). 0D22 GET_SECLEN LD BC,512 Length of DD sector. 0D25 LD A,(#1DDA) 0D28 AND 4 0D2A RET Z Return if using double density. 0D2B LD BC,256 Length of SD sector. 0D2E 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. 0D2F SAVE_HEAD1 LD HL,#1E10 Start of header 1. 0D32 LD DE,#1BA9 Address of header area of a catalogue entry 0D35 LD B,9 The headers length. 0D37 SA_HD1 LD A,(HL) 0D38 LD (DE),A 0D39 CALL #29C3,JSBYT Save the byte to the file. 0D3C INC HL 0D3D INC DE 0D3E DJNZ #0D37,SA_HD1 Repeat for all nine bytes. 0D40 RET Finished. THE 'SAVE' COMMAND SYNTAX ROUTINE This routine checks that the SAVE command has the appropriate syntax. 0D41 SAVE LD IX,#1AC3 Pointer to the DFCA. 0D45 CALL #09E7,SIGN_SAVE Signal 'SAVEing'. 0D48 CALL #0AEF,EXPT_PARMS Evaluate & store all parameters. 0D4B CALL #0A00,TEST_STEAL If 'forcing' a file to a pupil, send 0D4E CALL NZ,#15CB,SEND_BLOCK the command block over the network. 0D51 CALL #0A05,TEST_NET 0D54 JR Z,#0D5C,SAVE_1 Jump if not a SAVE to the network. 0D56 CALL #0DBA,SAVE_NET 0D59 JP #0419,END Finished. Now deal with saving to disk. 0D5C SAVE_1 CALL #2984,JTEST_DRV See if the drive is defined. 0D5F LD A,(#1E04) 0D62 CP "@" 0D64 JR NZ,#0D76,SAVE_RUN Jump if the command wasn't 'SAVE @'. 0D66 LD IX,(#1E15) Get address where sector is to be saved 0D6A CALL #0D19,GET_TR&SE from. Get track and sector number. 0D6D LD A,(#1E01) Get drive number. 0D70 CALL #15A0,HWSAD Write the sector. 0D73 JP #0419,END Finished. THE 'SAVE A FILE' ROUTINE This routine SAVEs the specified file on the specified drive. 0D76 SAVE_RUN CALL #29A8,JOFSM_2 Open the file for 'SAVE'. 0D79 JP NZ,#097A,EXIT_ERASE Exit if the file isn't to be overwritten. 0D7C LD A,(#1E05) 0D7F CP 11 Pass the header to the file unless it's 0D81 CALL NZ,#0D2F,SAVE_HEAD1 an 'execute' file. 0D84 CALL #09FB,TEST_SERV 0D87 JR Z,#0DAA,SAVE_R1 Jump if not serving the network. 0D89 CALL #0924,OPEN_N_CH Otherwise open the "n" channel. 0D8C LD B,9 Length of a header. 0D8E SAVE_R_N1 CALL #06F2,JN_INPUT LOAD a byte from the network. 0D91 DJNZ #0D8E,SAVE_R_N1 Repeat for all header bytes. 0D93 LD DE,(#1E11) Get the file length. 0D97 SAVE_R_N2 LD A,D 0D98 OR E 0D99 JR Z,#0DA4,SAVE_R_N3 Jump if no more bytes left. 0D9B CALL #06F2,JN_INPUT Otherwise LOAD a byte from the network. 0D9E CALL #29C3,JSBYT And SAVE it to disk. 0DA1 DEC DE One less to go. 0DA2 JR #0D97,SAVE_R_N2 Repeat for all bytes. There are no more bytes left, the file can be closed. 0DA4 SAVE_R_N3 CALL #2981,JCFSM Close the file. 0DA7 JP #0419,END Finished. Save the whole block of bytes to disk. 0DAA SAVE_R1 LD HL,(#1E13) Fetch the start address. 0DAD LD DE,(#1E11) Fetch the length. 0DB1 CALL #29C9,JHSVBK_2 Save the block. 0DB4 CALL #2981,JCFSM Close the file. 0DB7 JP #097A,EXIT_ERASE Exit via 'EXIT_ERASE'. THE 'SEND FILE OVER NETWORK' SUBROUTINE This subroutine sends a file and its header over the network. 0DBA SAVE_NET CALL #0AE1,TEST_STAT Check the station number. 0DBD CALL #2960,JOPEN_N Open the "N" channel. 0DC0 CALL #0DC6,SAVE_NET1 Save the file and its header over the network. 0DC3 JP #2975,JSEND_NEOF Send the EOF block and exit. THE 'SEND HEADER AND FILE' SUBROUTINE This subroutine sends the header of a file and the file itself over the network. The End Of File block isn't send. 0DC6 SAVE_NET1 LD DE,9 Length of the header. 0DC9 LD HL,#1E10 Address of the header. 0DCC CALL #0DD6,SAVE_NET2 Send the header over the network. 0DCF LD DE,(#1E11) Fetch file length. 0DD3 LD HL,(#1E13) Fetch address. 0DD6 SAVE_NET2 LD A,D 0DD7 OR E 0DD8 RET Z Return if no bytes left. 0DD9 LD A,(HL) Fetch the byte. 0DDA CALL #06FA,JN_OUTPUT Send the byte over the network. 0DDD INC HL Point to the next byte. 0DDE DEC DE One less. 0DDF JR #0DD6,SAVE_NET2 Repeat for all bytes. THE 'LOAD HEADER INTO UFIA 2' SUBROUTINE This subroutine LOADs a 9 bytes header into UFIA 2. 0DE1 LOAD_HEAD2 LD HL,#1E29 Start of HEADER 2. 0DE4 LD B,9 Length of a header. 0DE6 LOAD_H1 CALL #29A2,JLBYT Load a byte. 0DE9 LD (HL),A Store it into UFIA 2. 0DEA INC HL 0DEB DJNZ #0DE6,LOAD_H1 Repeat for all header bytes. 0DED RET THE 'LOAD' COMMAND SYNTAX ROUTINE The 'LOAD' flag is set and the routine continues into the 'LOAD_VERIFY_MERGE' routine below. 0DEE LOAD CALL #09E2,SIGN_LOAD Signal 'LOADing'. 0DF1 JR #0DFB,LD_VF_MR THE 'VERIFY' COMMAND SYNTAX ROUTINE The 'VERIFY' flag is set and again the 'LOAD_VERIFY_MERGE' routine handles the rest. 0DF3 VERIFY CALL #09F1,SIGN_VERIF Signal 'VERIFYing'. 0DF6 JR #0DFB,LD_VF_MR THE 'MERGE' COMMAND SYNTAX ROUTINE The 'MERGE' flag is set and 'LOAD_VERIFY_MERGE' continues the syntax checking. 0DF8 MERGE CALL #09EC,SIGN_MERGE Signal 'MERGEing'. THE 'LOAD_VERIFY_MERGE' COMMAND ROUTINE This routine checks the syntax of the LOAD, VERIFY and MERGE commands and executes it. 0DFB LD_VF_MR LD IX,#1AC3 Pointer to DFCA. 0DFF CALL #0AEF,EXPT_PARMS Evaluate & store all parameters. 0E02 CALL #0A00,TEST_STEAL If 'stealing' a file from a pupil, send 0E05 CALL NZ,#15CB,SEND_BLOCK the command block over the network. 0E08 CALL #0A05,TEST_NET 0E0B JR Z,#0E28,LD_VF_MR1 Jump if not using the network. 0E0D CALL #0AE1,TEST_STAT Check station number. 0E10 CALL #2960,JOPEN_N Open the "N" channel. 0E13 LD B,9 Length of a header. 0E15 LD HL,#1E29 Start of HEADER 2. 0E18 LD_ETC_N CALL #06F2,JN_INPUT LOAD a byte from the network. 0E1B LD (HL),A Store it into UFIA 2. 0E1C INC HL 0E1D DJNZ #0E18,LD_ETC_N Repeat for all header bytes. 0E1F LD HL,#06F2,JN_INPUT Store address of LOAD byte routine. 0E22 LD (#1DE8),HL 0E25 JP #0EBD,LD_ETC_R6 The routine continues here if the network isn't used. 0E28 LD_VF_MR1 CALL #2984,JTEST_DRV See if the drive is defined. 0E2B LD A,(#1E04) 0E2E CP "@" 0E30 JR NZ,#0E42,LD_ETC_RUN Jump if it wasn't a '@' command. 0E32 LD IX,(#1E15) Get address where sector is to be 0E36 CALL #0D19,GET_TR&SE loaded. Get track and sector number. 0E39 LD A,(#1E01) Get drive number. 0E3C CALL #1582,HRSAD Load the sector. 0E3F JP #0419,END Finished. The routine continues here when a file is to be LOADed from disk. 0E42 LD_ETC_RUN CALL #299C,JHGFLE_2 Open the file for loading. 0E45 LD A,(#1E05) 0E48 CP 5 0E4A JR NZ,#0E5B,LD_ETC_R1 Jump if it isn't a 'Snapshot 48K'. 0E4C LD SP,#1FEA Use internal stack. 0E4F LD HL,16384 Start address and length of a 48K Snap. 0E52 LD DE,49152 0E55 CALL #29A5,JLOAD_FILE Load the file. 0E58 JP #01EE,SNAP_EXIT Exit via 'SNAP_EXIT'. 0E5B LD_ETC_R1 CP 9 0E5D JR NZ,#0E84,LD_ETC_R3 Jump if it isn't a 'Snapshot 128K'. 0E5F LD SP,#1FEA Use internal stack. 0E62 CALL #29A2,JLBYT Get the page configuration byte. 0E65 PUSH AF 0E66 AND #F8 Keep the RAM page bits only. 0E68 LD B,8 LOAD the eight RAM-pages. 0E6A LD_ETC_R2 PUSH AF 0E6B PUSH BC 0E6C CALL #003D,RAMPAGE_A Page in RAM bank. 0E6F LD HL,49152 Start address and length of each RAM 0E72 LD DE,16384 bank. 0E75 CALL #29A5,JLOAD_FILE 'LOAD DE bytes to HL'. 0E78 POP BC 0E79 POP AF 0E7A INC A Next RAM bank. 0E7B DJNZ #0E6A,LD_ETC_R2 Repeat for each RAM bank. 0E7D POP AF Retrieve page configuration. 0E7E CALL #003D,RAMPAGE_A Page in the right RAM, ROM and SCR$ 0E81 JP #01EE,SNAP_EXIT bank, exit via 'SNAP_EXIT'. 0E84 LD_ETC_R3 CP 11 0E86 JR NZ,#0E8E,LD_ETC_R4 Jump if it isn't a 'Execute' file. 0E88 CALL #1BD6 Execute (this is the address of the 0E8B JP #0419,END disk buffer). Finished. 0E8E LD_ETC_R4 CALL #0DE1,LOAD_HEAD2 Load the header into UFIA2. 0E91 CALL #09FB,TEST_SERV 0E94 JR Z,#0EB7,LD_ETC_R5 Jump if not serving the network. 0E96 CALL #0924,OPEN_N_CH Open the "N" channel. 0E99 LD HL,#1E29 Point to the header info of UFIA2. 0E9C LD B,9 Nine header bytes. 0E9E LD_ETC_N1 LD A,(HL) 0E9F CALL #06FA,JN_OUTPUT Send a byte over the network. 0EA2 INC HL 0EA3 DJNZ #0E9E,LD_ETC_N1 Repeat for all header bytes. 0EA5 LD DE,(#1E2A) Fetch the length of the file. 0EA9 LD_ETC_N2 LD A,D 0EAA OR E Send the EOF block over the network and 0EAB JP Z,#2975,JSEND_NEOF exit when there are no more bytes left. 0EAE CALL #29A2,JLBYT LOAD a byte from disk. 0EB1 CALL #06FA,JN_OUTPUT And SAVE it over the network. 0EB4 DEC DE One byte less. 0EB5 JR #0EA9,LD_ETC_N2 Repeat for all bytes in the file. 0EB7 LD_ETC_R5 LD HL,#29A2,JLBYT Store address of LOAD byte routine. 0EBA LD (#1DE8),HL 0EBD LD_ETC_R6 LD A,(#1E10) Fetch type of program to be LOADed. Enter 0EC0 LD B,A here when LOADing from network. 0EC1 LD A,(#1E29) Fetch type of program found. 0EC4 CP B 0EC5 JP NZ,#2930,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. 0EC8 CP 3 0ECA JR Z,#0EDA,LD_ETC_R7 Jump if it's a 'CODE' file. 0ECC JP NC,#2930,REP_8 Give error if file type >= 4. 0ECF CALL #0A14,TEST_MERGE 0ED2 JR NZ,#0F45,MERGE_CTRL Jump if 'MERGEing'. 0ED4 CALL #0A19,TEST_VERIF Jump if not 'VERIFYing' (i.e. doing a 0ED7 JP Z,#0F61,LOAD_CTRL LOAD). Now deal with loading of all files with type 3, like 'CODE' and 'SCREEN$', or verifying of all file types. 0EDA LD_ETC_R7 CALL #0A14,TEST_MERGE 0EDD JP NZ,#293C,REP_14 Give error if 'MERGE .. CODE' was used. 0EE0 LD HL,(#1E11) Fetch length of requested file. 0EE3 LD DE,(#1E2A) Fetch length of file found. 0EE7 LD A,H 0EE8 OR L 0EE9 JR Z,#0EF8,LD_ETC_R8 Jump if length unspecified. 0EEB SBC HL,DE Jump if file to be LOADed is shorter 0EED JR NC,#0EF8,LD_ETC_R8 than or of equal length as the requested file. 0EEF CALL #0A0A,TEST_LOAD 0EF2 JP Z,#2938,REP_12 'VERIFY failed' if not LOADing. 0EF5 JP #293E,REP_15 'CODE error' otherwise. 0EF8 LD_ETC_R8 LD HL,(#1E13) Fetch start address from FILE_ADDR1 0EFB LD A,H 0EFC OR L 0EFD JR NZ,#0F02,LD_ETC_R9 Jump if a start address was specified. 0EFF LD HL,(#1E2C) Otherwise use the start address of the found file. 0F02 LD_ETC_R9 LD A,(#1E29) But if the file is a BASIC program the 0F05 AND A start address is held in (PROG). 0F06 JR NZ,#0F0B,LD_ETC_R10 0F08 LD HL,(23635) Fetch 'start' from (PROG). 0F0B LD_ETC_R10 CALL #1000,LV_ANY Load the file. 0F0E CALL #0A19,TEST_VERIF 0F11 JP NZ,#0419,END Exit when 'VERIFYing'. 0F14 LD HL,(#1E17) Fetch execute address. 0F17 CALL #0F23,EXEC_CODE Use it if it was specified. 0F1A LD HL,(#1E30) Otherwise use the files execute 0F1D CALL #0F23,EXEC_CODE address. 0F20 JP #0419,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'. 0F23 EXEC_CODE LD A,H 0F24 OR L 0F25 RET Z Return if the execute address is zero. 0F26 LD A,H 0F27 CP #FF 0F29 JR NZ,#0F2F,EXEC_CODE1 0F2B LD A,L Also return when the execute address is 0F2C CP #FF #FFFF. 0F2E RET Z 0F2F EXEC_CODE1 LD SP,(23613) Clear the stack. (ERR_SP) 0F33 LD (IY+0),255 Clear the error. 0F37 CALL #297B,JBORD_REST Restore the border colour. 0F3A LD BC,#1B7D,STMT_R_1 Return to 'STMT_R_1' in the 'main' ROM 0F3D PUSH BC when finished. 0F3E LD BC,#2D2B,STACK_BC Return to 'STMT_R_1' via 'STACK_BC' 0F41 PUSH BC also in the 'main' ROM. 0F42 JP #004F,UNPAGE_HL Jump to the execute address while unpaging the DISCiPLE. 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'). 0F45 MERGE_CTRL LD BC,(#1E2A) Fetch the length of the program to be 0F49 PUSH BC MERGEd. 0F4A INC BC Extra location for the 'end marker'. 0F4B RST #10,CALBAS Call 'BC_SPACES' in the 'main' ROM to 0F4C DEFW #0030,BC_SPACES make the required room in workspace. 0F4E LD (HL),128 Mark the end. 0F50 EX DE,HL Move start pointer to HL. 0F51 POP DE Length to DE. 0F52 PUSH HL 0F53 CALL #1000,LV_ANY Load the file. 0F56 POP HL Fetch 'start' of new program. 0F57 LD DE,(23635) Fetch 'start' of old program (PROG). 0F5B RST #10,CALBAS Do the MERGEing by calling the 'main' 0F5C DEFW #08D2,ME_NEW_LP ROM 'MERGE' routine. 0F5E JP #0419,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 (#358D) which is called from the 'LD_ETC_RUN' routine at #0E42. 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 #0F99 then fails, trying to reclaim something which isn't there. 0F61 LOAD_CTRL LD DE,(#1E2A) Fetch 'new' length. 0F65 LD HL,(#1E13) Fetch 'old' start (=0 when loading a 0F68 PUSH HL 'new' array'). 0F69 LD A,H 0F6A OR L 0F6B JR NZ,#0F73,LD_CTRL1 Jump if not a 'new' array. 0F6D INC DE Increment 'length' by 3, i.e. allows 0F6E INC DE for the insertion of array name and 0F6F INC DE two-byte length. 0F70 EX DE,HL Move 'length' to HL. 0F71 JR #0F7C,LD_CTRL2 Jump forward. The array to be loaded replaces an existing array. 0F73 LD_CTRL1 LD HL,(#1E11) Fetch 'old' length (i.e. length of existing program or array) from UFIA1. 0F76 EX DE,HL Move 'new' length to HL. 0F77 SCF Jump if the program or array to be 0F78 SBC HL,DE loaded isn't longer than the existing 0F7A JR C,#0F85,LD_CTRL3 one. 0F7C LD_CTRL2 LD DE,5 Otherwise a check must be made to 0F7F ADD HL,DE ensure that there is sufficient space 0F80 LD B,H in memory for the program (or array) to 0F81 LD C,L be loaded. 0F82 RST #10,CALBAS Make the check by calling the 'main' 0F83 DEFW #1F05,TEST_ROOM ROM 'TEST_ROOM' subroutine. 0F85 LD_CTRL3 POP HL Restore 'old' start (=0 when handling 0F86 LD A,(#1E29) a 'new' array). 0F89 AND A 0F8A JR Z,#0FBD,LD_PROG Jump if it's a BASIC program. 0F8C LD A,H 0F8D OR L Jump unless an 'old' array is to be 0F8E JR Z,#0F9B,LD_CTRL4 erased before loading the 'new' one. 0F90 DEC HL Points to high byte of 'array length'. 0F91 LD B,(HL) Fetch the 'length'. 0F92 DEC HL 0F93 LD C,(HL) 0F94 DEC HL Now points to the 'array name'. 0F95 INC BC Include 'length' and 'name' in the 0F96 INC BC array length. 0F97 INC BC 0F98 RST #10,CALBAS Call 'RECLAIM_2' in the 'main' ROM to 0F99 DEFW #19E8,RECLAIM_2 delete the array. 0F9B LD_CTRL4 LD HL,(23641) (E_LINE) points to the end of variables 0F9E DEC HL area+1. 0F9F LD BC,(#1E2A) Fetch length of array to be loaded. 0FA3 PUSH BC 0FA4 INC BC Include in the length one byte for the 0FA5 INC BC 'array name' and two bytes for the 0FA6 INC BC 'array length'. 0FA7 LD A,(#1E15) Fetch the array name from 'LENGTH1_2'. 0FAA PUSH AF 0FAB RST #10,CALBAS Call 'MAKE_ROOM' to create the space 0FAC DEFW #1655,MAKE_ROOM for the array. 0FAE INC HL Point to first 'new' location inserted. 0FAF POP AF 0FB0 LD (HL),A Store array name into first location. 0FB1 POP DE 0FB2 INC HL Store array length into the following 0FB3 LD (HL),E two locations. 0FB4 INC HL 0FB5 LD (HL),D 0FB6 INC HL 0FB7 CALL #1000,LV_ANY Load the file. 0FBA JP #0419,END Finished. Now deal with the LOADing of a BASIC program and its variables. 0FBD LD_PROG LD DE,(23635) Fetch start of existing program. (PROG) 0FC1 LD HL,(23641) Fetch end of existing program. I.e. 0FC4 DEC HL (E_LINE)-1. 0FC5 RST #10,CALBAS Delete the program by calling 0FC6 DEFW #19E5,RECLAIM_1 'RECLAIM_1' in the 'main' ROM. 0FC8 LD BC,(#1E2A) Fetch length of program and variables. 0FCC LD HL,(23635) Fetch (PROG), start of a BASIC program. 0FCF RST #10,CALBAS Create the required space by calling 0FD0 DEFW #1655,MAKE_ROOM 'MAKE_ROOM'. 0FD2 INC HL Point to the first location. 0FD3 LD BC,(#1E2E) Fetch length without variables. 0FD7 ADD HL,BC Calculate and store the start of the 0FD8 LD (23627),HL variables area. 0FDB LD A,(#1E31) When no autostart is known this 0FDE LD H,A ('AUTOSTART2-hi') holds #FF. 0FDF AND #C0 0FE1 JR NZ,#0FEE,LD_PROG1 Jump with no autostart. 0FE3 LD A,(#1E30) Otherwise store the autostart line 0FE6 LD L,A number into 'NEWPPC' and clear 'NSPPC'. 0FE7 LD (23618),HL These hold the line and the statement 0FEA LD (IY+10),0 to be executed respectively. 0FEE LD_PROG1 LD HL,(23635) Fetch the start of the BASIC program. 0FF1 LD DE,(#1E2A) Fetch the length + variables. 0FF5 DEC HL Reset the DATA pointer 'DATADD' to the 0FF6 LD (23639),HL beginning of the program. 0FF9 INC HL Balance the 'DEC HL'. 0FFA CALL #1000,LV_ANY Load the file. 0FFD JP #0419,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'. 1000 LV_ANY LD A,D 1001 OR E 1002 RET Z Return if 'length' is zero. 1003 CALL #0A19,TEST_VERIF 1006 JR NZ,#1019,LV_ANY3 Jump if 'VERIFYing'. 1008 CALL #0A05,TEST_NET 100B JR NZ,#1019,LV_ANY3 Jump if 'using the network'. 100D JP #29A5,JLOAD_FILE Otherwise load the file. 1010 LV_ANY1 CP (HL) The actual VERIFY, i.e. compare the fetched byte with that held in memory. 1011 JP NZ,#2938,REP_12 Give an error if they don't match. 1014 LV_ANY2 INC HL Next memory address. 1015 DEC DE One byte less to go. 1016 LD A,D 1017 OR E 1018 RET Z Exit if no more bytes left. 1019 LV_ANY3 PUSH HL 101A PUSH DE 101B CALL #1028,JP_(#1DE8) Load one byte with appropriate routine. 101E POP DE 101F POP HL 1020 CALL #0A19,TEST_VERIF 1023 JR NZ,#1010,LV_ANY1 Jump if VERIFYing. 1025 LD (HL),A Otherwise store the byte. 1026 JR #1014,LV_ANY2 Repeat for all bytes. THE 'JUMP TO (#1DE8)' SUBROUTINE This small subroutine jumps to the routine pointed to by the contents of #1DE8. It is used by the 'LV_ANY' routine above to fetch a byte for LOADing (from the network) or VERIFYing. 1028 JP_(#1DE8) LD HL,(#1DE8) Fetch the jump address and jump to it. 102B JP (HL) THE 'FORMAT' COMMAND SYNTAX ROUTINE This routine tests if the command has the appropriate syntax. 102C FORMAT RST #28,NEXT_C_RAM Advance CH_ADD to next character. 102D AND #DF Only capitals. 102F CP "N" 1031 JR NZ,#1045,FORMAT_SD Jump if the character wasn't a "N". 1033 CALL #0A5E,EXPT_DEVN Evaluate the station number. 1036 CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 1039 CALL #0AE1,TEST_STAT Check the station number. 103C LD A,(#1E01) Fetch station number and 103F LD (#029C),A store it into the system var. 'NSTAT'. 1042 JP #0419,END Finished. Now check if it is one of the format disk commands. 1045 FORMAT_SD CP "S" 1047 JR NZ,#105B,FORMAT_D Jump if it wasn't "S". 1049 RST #28,NEXT_C_RAM Next character. 104A AND #DF Only capitals. 104C CP "D" 104E JP NZ,#2920,REP_0 Give an error if not a "D". 1051 LD A,(#1DDA) Fetch current control port state. 1054 OR #04 Set 'Single Density'. 1056 LD (#1DDA),A 1059 JR #1068,FORMAT_1 105B FORMAT_D CP "D" 105D JP NZ,#2920,REP_0 Give an error if not a "D". 1060 LD A,(#1DDA) 1063 AND #FB Set 'Double Density'. 1065 LD (#1DDA),A 1068 FORMAT_1 RST #28,NEXT_C_RAM Next character. 1069 CP 13 106B JR NZ,#1070,FORMAT_2 Jump if it isn't a carriage return. 106D JP #0419,END Finished? NOTE: It seems that there are two undocumented FORMAT commands, 'FORMAT sd' and 'FORMAT d' followed by 'ENTER'. They set or reset the single/double density bit of the control port state respectively. 1070 FORMAT_2 CALL #0A76,EXPT_DEVN1 Evaluate the drive number. 1073 CP 204 Jump if the current character isn't 1075 JR NZ,#1081,FORMAT_3 'TO'. 1077 CALL #0AA2,SWAP_UFIAS Exchange UFIA1 and UFIA2. 107A RST #28,NEXT_C_RAM Update CH_ADD. 107B CALL #0A76,EXPT_DEVN1 Evaluate 2nd drive number. 107E CALL #0AA2,SWAP_UFIAS Exchange UFIA's again. 1081 FORMAT_3 CALL #0409,ST_END_RAM Confirm end of statement and exit when syntax checking. 1084 CALL #2984,JTEST_DRV Check if the drive is defined. 1087 RST #10,CALBAS 1088 DEFW #0D6E,CLS_LOWER Clear lower screen area. 108A SET 5,(IY+2) Signal 'lower screen has to be cleared'. 108E CALL #29AB,JSURE_MSG Print 'Are you SURE ? (y/n)' message. 1091 CALL #298A,JTEST_Y Wait for a key, Zero set means 'Y' 1094 JP NZ,#0419,END pressed. Finished when not sure. 1097 CALL #298D,JFRMT_RUN Otherwise FORMAT the disk. 109A JP #0419,END Finished. The stream handling routines I THE 'EVALUATE STREAM NUMBER' SUBROUTINE A single numeric expression is evaluated and the result, in the range 0..15 is stored into 'STRM_NUM1'. 109D EXPT_#_NR RST #28,NEXT_C_RAM Advance CH_ADD. 109E EXPT_#_NR1 RST #10,CALBAS Evaluate stream number. 109F DEFW #1C82,EXPT_1NUM 10A1 RST #30,SYNTAX_Z Return if syntax is being checked. 10A2 RET Z 10A3 PUSH AF 10A4 RST #10,CALBAS Fetch the number. 10A5 DEFW #1E99,FIND_INT2 10A7 CP 16 Give an error if it isn't in the range 10A9 JP NC,2932,REP_9 0..15. ('Invalid station' ?) 10AC LD (#1E03),BC Store stream number into 'STRM_NUM1'. 10AE POP AF 10B0 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. 10B1 MOVE CALL #115B,EXPT_EXP1 Evaluate stream or channel expression. 10B4 CP 204 The keyword 'TO' must be present, 10B6 JP NZ,#2920,REP_0 give an error if 'TO' is missing. 10B9 CALL #0AA2,SWAP_UFIAS Exchange the UFIA's. 10BC CALL #115B,EXPT_EXP1 Evaluate second stream or channel expression. 10BF CALL #0AA2,SWAP_UFIAS Exchange the UFIA's again. 10C2 CALL #0409,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_STEAL' is called to signal to the 'D_INPUT' routine at #148A that the 'END of file' error isn't to be generated. 10C5 CALL #09D8,SIGN_STEAL See above. 10C8 LD A,191 This is the keyword 'IN', it is used to 10CA LD (#1E02),A signal 'READ channel'. 10CD CALL #1188,OP_MOVE Open the source channel/stream. 10D0 LD HL,(23631) Save (CHANS). 10D3 PUSH HL 10D4 LD A,(#1E02) Save 'DIR_DESCR1' into 'DIR_DESCR2'. 10D7 LD (#1E1E),A 10DA CALL #0AA2,SWAP_UFIAS Exchange the UFIA's. 10DD LD A,223 This is the keyword 'OUT'. 10DF LD (#1E02),A Signal 'WRITE channel'. 10E2 LD IX,#1AC3 Pointer to DFCA. 10E6 CALL #1188,OP_MOVE Open the destination channel/stream. 10E9 JR NC,#10F7,MOVE_RUN1 Jump if opening was successfull. I.e. file was 'new' or 'old' file was overwritten. 10EB LD IX,(#1E1E) Otherwise reclaim first channel. (Second 10EF CALL #114C,RECL_CHAN wasn't opened so nothing to reclaim.) 10F2 POP HL Drop (CHANS) address. 10F3 POP HL ?? Drop what? 10F4 JP #0419,END Finished. 10F7 MOVE_RUN1 CALL #0AA2,SWAP_UFIAS Exchange UFIA's again. To my knowledge the instructions at #10D0, #10D3, #10F2 and from #10FA to #1106 aren't needed with the DISCiPLE. 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 DISCiPLE, however, nothing is situated between 23734 and (CHANS). 10FA POP DE Retrieve 'old' (CHANS). 10FB LD HL,(23631) Fetch 'new' (CHANS). 10FE OR A Calculate the space which was inserted 10FF SBC HL,DE under (CHANS). 1101 LD DE,(#1E05) Adjust first channels address. 1105 ADD HL,DE 1106 LD (#1E05),HL 1109 MOVE_RUN2 LD HL,(#1E05) Make 'current' the first channel. 110C LD (23633),HL (CURCHL) 110F MOVE_RUN3 RST #10,CALBAS Call 'INPUT_A' in the 'main' ROM to 1110 DEFW #15E6,INPUT_A read a byte. 1112 JR C,#1118,MOVE_RUN4 Jump with acceptable codes. 1114 JR Z,#110F,MOVE_RUN3 Repeat if no byte read. 1116 JR #1123,MOVE_RUN5 Jump if EOF has been reached. An acceptable code has been found. 1118 MOVE_RUN4 LD HL,(#1E1E) Make 'current' the 2nd channel. 111B LD (23633),HL (CURCHL) 111E RST #10,CALBAS Use 'main' ROM 'PRINT_A_2' to send the 111F DEFW #15F2,PRINT_A_2 byte to the 2nd channel. 1121 JR #1109,MOVE_RUN2 Repeat until EOF. EOF has been reached. 1123 MOVE_RUN5 XOR A Clear FLAGS3. 1124 LD (#1ACF),A 1127 LD HL,(23631) Store current (CHANS). 112A PUSH HL 112B CALL #0AA2,SWAP_UFIAS Exchange the UFIA's. 112E CALL #11C0,CL_MOVE Close the destination channel. 1131 CALL #0AA2,SWAP_UFIAS Exchange the UFIA's again. Again the instructions at address #1127, #112A and from #1134 to #1140 aren't needed with the DISCiPLE. 1134 POP DE Restore initial address of CHANS. 1135 LD HL,(23631) Fetch current (CHANS). 1138 OR A Calculate the amount of bytes reclaimed 1139 SBC HL,DE after the deletion of the second channel. 113B LD DE,(#1E05) Calculate the new start address of the 113F ADD HL,DE first channel. 1140 LD (#1E05),HL And store it. 1143 CALL #11C0,CL_MOVE Close the source channel. 1146 CALL #11D6,RECL_TEMP Reclaim temporary channels. 1149 JP #0419,END Finished. THE 'RECLAIM CHANNEL' SUBROUTINE This subroutine is used to reclaim the channel pointed to by IX. 114C RECL_CHAN LD C,(IX+9) Fetch channel length. 114F LD B,(IX+10) 1152 PUSH BC 1153 PUSH IX Channel start to HL. 1155 POP HL 1156 RST #10,CALBAS Call 'RECLAIM_2' in the 'main' ROM to 1157 DEFW #19E8,RECLAIM_2 reclaim the channel. 1159 POP BC 115A 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. 115B EXPT_EXP1 RST #28,NEXT_C_RAM Advance CH_ADD. 115C CP "#" Jump to 'EXPT_#_NR' to evaluate stream 115E JP Z,#109D,EXPT_#_NR number if character is a '#'. 1161 EXPT_EXP2 LD (#1E04),A Otherwise store device letter. 1164 AND #DF Only capitals. 1166 CP "D" If device letter isn't "D" then 1168 CALL NZ,#0A3E,MD_SYNTAX1 evaluate microdrive syntax. 116B CALL #0A5E,EXPT_DEVN Evaluate device number. 116E CALL #0A1E,SEPARATOR If there is a separator exit via 1171 JP Z,#0ABC,EXP_F_NAME 'EXP_F_NAME' to evaluate a filename. 1174 RST #30,SYNTAX_Z 1175 RET Z Return if checking syntax. 1176 PUSH AF 1177 LD A,(#1E04) Fetch device letter. 117A AND #DF Only capitals. 117C CP "D" If the device is "D" or "M" then there 117E JP Z,#2924,REP_2 must be a name present. Give an error 1181 CP "M" if no name specified. 1183 JP Z,#2924,REP_2 1186 POP AF 1187 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. 1188 OP_MOVE LD A,(#1E03) Fetch stream number. 118B INC A Jump to open a temporary channel, i.e. if 118C JR Z,#1199,OP_MOVE1 the stream was nonexistent. 118E DEC A 118F RST #10,CALBAS Open the channel attached to stream A. 1190 DEFW #1601,CHAN_OPEN 1192 LD HL,(23633) Store the channels address (CURCHL) 1195 LD (#1E05),HL into UFIA1. 1198 RET Return. 1199 OP_MOVE1 LD A,(#1E04) Fetch device letter. 119C AND #DF Capitals only. 119E CP "M" 11A0 JR Z,#11A6,OP_MOVE2 Jump if it's a "M". 11A2 CP "D" 11A4 JR NZ,#11B7,OP_MOVE3 Jump if it isn't a "D". 11A6 OP_MOVE2 CALL #2984,JTEST_DRV Check if the drive is defined. 11A9 CALL #128D,OP_TEMP_D Open a temporary "D" channel. 11AC LD A,(#1E05) Save 'DIR_DESCR1' into 'PROG_NUM1'. 11AF LD (#1E02),A 11B2 LD (#1E05),IX Store channels address. 11B6 RET 11B7 OP_MOVE3 CP "N" 11B9 JP NZ,#2920,REP_0 Give an error if device isn't "N". 11BC CALL #09DD,SIGN_NET Otherwise signal 'using network'. 11BF 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. 11C0 CL_MOVE LD A,(#1E03) Fetch stream number. 11C3 INC A 11C4 RET NZ Return if a stream has been used. 11C5 LD A,(#1E04) Otherwise fetch device letter. 11C8 AND #DF Only capitals. 11CA CP "N" 11CC JR Z,#11D5,CL_MOVE1 Jump if it was "N". 11CE LD IX,(#1E05) Fetch channel address. 11D2 JP #1205,CLOSE_CHAN Close the channel and exit. 11D5 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). 11D6 RECL_TEMP LD IX,(23631) Point to the start of the channel area. 11DA LD DE,20 IX now points to the first 11DD ADD IX,DE 'non-standard' channel. 11DF RECL_T1 LD A,(IX+0) 11E2 CP #80 Return if the end marker was found, i.e. 11E4 RET Z there are no more channels, 11E5 LD A,(IX+4) Fetch channel specifier. 11E8 CP "D"+128 11EA JR NZ,11F1,RECL_T2 Jump if not a temporary "D" channel. 11EC CALL #1205,CLOSE_CHAN 11EF JR #11D6,RECL_TEMP Permanent "D" channels mustn't be closed, except when 'CLEAR #' was given. 11F1 RECL_T2 CALL #09FB,TEST_SERV 11F4 JR Z,#11FB,RECL_T3 Jump if not 'CLEAR # executing'. 11F6 CALL #114C,RECL_CHAN Otherwise reclaim the channel. 11F9 JR #11D6,RECL_TEMP Skip this channel. 11FB RECL_T3 LD E,(IX+9) Fetch channel length. 11FE LD D,(IX+10) 1201 ADD IX,DE Point to the next channel. 1203 JR #11DF,RECL_T1 Repeat for all channels. THE 'CLOSE CHANNEL' SUBROUTINE This subroutine closes the channel pointed to by IX. 1205 CLOSE_CHAN PUSH IX 1207 POP HL 1208 LD DE,(23631) (CHANS). 120C OR A 120D SBC HL,DE Calculate channel offset. 120F INC HL 1210 LD (#1DED),HL The channel is CLOSEd by jumping into the 1213 JP #142E,CLOSE_0 'CLOSE' routine THE 'OPEN' COMMAND SYNTAX ROUTINE This routine deals with the 'OPEN #' command concerning DISCiPLE channels, Spectrum channels are handled by the 'main' ROM. 1216 OPEN# CALL #109D,EXPT_#_NR Evaluate stream number. 1219 CALL #0A1E,SEPARATOR 121C JP NZ,#2920,REP_0 Give an error if no separator found. 121F CALL #1161,EXPT_EXP2 Evaluate channel specifier. 1222 CP 13 1224 JR Z,#1233,OPEN#_2 Jump if no more parameters. 1226 CP 191 1228 JR Z,#122F,OPEN#_1 Jump if 'IN' specified. 122A CP 223 122C JP NZ,#2924,REP_2 Give error if no 'OUT' specified. 122F OPEN#_1 LD (#1E02),A Store the channel type (IN or OUT) in 'PROG_NUM1'. 1232 RST #28,NEXT_C_RAM Advance CH_ADD. 1233 OPEN#_2 CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 1236 LD A,(#1E03) Fetch stream number. 1239 RST #10,CALBAS Call 'main' ROM 'STR_DATA1' routine; on 123A DEFW #1727,STR_DATA1 exit, BC holds 'stream data'. 123C LD HL,17 123F AND A 1240 SBC HL,BC Give an error if the current stream was 1242 JP C,#295C,REP_30 already used by the DISCiPLE. 1245 LD A,(#1E04) Fetch channel specifier. 1248 AND #DF Only capitals. 124A CP "D" 124C JR Z,#1253,OPEN#_3 Jump if opening a "D" channel. 124E CP "M" Give an error if not opening a "M" 1250 JP NZ,#2920,REP_0 channel. 1253 OPEN#_3 CALL #2984,JTEST_DRV See if the drive is defined. 1256 LD A,10 Signal 'OPENTYPE file'. 1258 LD (#1E05),A 125B CALL #1261,OPEN_CHAN Open the channel. 125E JP #0419,END Finished. THE 'OPEN "D" CHANNEL' SUBROUTINE This is the actual OPEN routine referred to the "D" channel. 1261 OPEN_CHAN LD A,(#1E03) Fetch stream number. 1264 ADD A,A The streams area entries are two bytes each. 1265 LD HL,23574 Address of data for stream 0. 1268 LD E,A 1269 LD D,0 126B ADD HL,DE Index into STRMS area. 126C PUSH HL 126D CALL #128D,OP_TEMP_D Open a temporary "D" channel. On return HL 1270 POP DE holds new channel offset. 1271 RET C Return when an error occurred. 1272 BIT 0,(IX+12) 1276 JR Z,#1284,MAKE_PERM Jump if this is a 'read' file. 1278 IN A,(27) Read Floppy Disk Controller status. 127A BIT 6,A Test the 'write protect' bit. 127C JR Z,#1284,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. 127E CALL #114C,RECL_CHAN Otherwise reclaim the channel. 1281 JP #294E,REP_23 And give an error. 1284 MAKE_PERM RES 7,(IX+4) Make the channel permanent by resetting bit 7 of the channel specifier. 1288 EX DE,HL DE holds new channel offset. 1289 LD (HL),E Store it into the STRMS area. 128A INC HL 128B LD (HL),D 128C RET Finished. THE 'OPEN TEMP. "D" CHANNEL' SUBROUTINE This subroutine is used to open a temporary "D" channel in the CHANS area. 128D OP_TEMP_D LD IX,(23631) Start of channel area (CHANS). 1291 LD DE,20 Point to the first 'non-standard' 1294 ADD IX,DE channel. 1296 OP_TEMP1 LD A,(IX+0) 1299 CP #80 129B JR Z,#12D2,OP_TEMP4 Jump if end of CHANS area is reached. 129D LD A,(IX+4) Otherwise fetch channel specifier. 12A0 AND #5F Clear bit 7 and make capital. 12A2 CP "D" 12A4 JR NZ,#12C8,OP_TEMP3 Jump if this isn't a "D" channel. 12A6 LD A,(#1E01) Fetch drive number. 12A9 CP (IX+11) Jump if this channel uses a different 12AC JR NZ,#12C8,OP_TEMP3 drive. 12AE PUSH IX 12B0 POP HL Start of channel to HL. 12B1 LD DE,20 Filename offset. 12B4 ADD HL,DE 12B5 EX DE,HL DE points to the name of this channel. 12B6 LD HL,#1E06 HL points to the name of the channel to 12B9 LD B,10 be opened. 12BB OP_TEMP2 LD A,(DE) 12BC XOR (HL) 12BD AND #DF Capitalize. 12BF JR NZ,#12C8,OP_TEMP3 Jump if not the same file. 12C1 INC HL 12C2 INC DE 12C3 DJNZ #12BB,OP_TEMP2 Repeat for all 10 characters. 12C5 JP #295E,REP_31 Give an error if the channel already exists. 12C8 OP_TEMP3 LD E,(IX+9) Fetch the length of the channel. 12CB LD D,(IX+10) 12CE ADD IX,DE Point to the next channel. 12D0 JR #1296,OP_TEMP1 Repeat for all channels. The channel wasn't already present in memory so it can be opened. 12D2 OP_TEMP4 PUSH IX 12D4 LD A,#10 Scan the CATalogue for a matching 12D6 CALL #2993,JSCAN_CAT filename. 12D9 LD A,(#1E02) Get channel type (read/write). 12DC JP NZ,#1338,OP_TEMP5 Jump if file not found. 12DF CP 223 12E1 JP Z,#1600,OP_T_PATCH Jump if OUTput channel. 12E4 LD BC,551 Length of INput channel. 12E7 CALL #13A1,CHAN_SPC Create the room for the channel. 12EA CALL #29B4,JRPT_HL Make HL point to the CAT entry. 12ED POP IX 12EF CALL #2984,JTEST_DRV See if the drive is defined. 12F2 NOP 12F3 NOP 12F4 NOP 12F5 LD A,0 Signal 'READing'. 12F7 LD (IX+12),A 12FA LD BC,39 Offset of buffer from start of channel. 12FD LD (IX+15),C 1300 LD (IX+16),B 1303 PUSH HL HL points to the CATalogue entry. 1304 PUSH IX IX points to the start of the channel. 1306 POP HL 1307 LD DE,19 Offset of directory description. 130A ADD HL,DE 130B EX DE,HL 130C POP HL Pointer to CAT entry. 130D LD BC,11 Move the directory description and the 1310 LD A,(HL) filename to the channel. 1311 LD (#1E05),A Store dir. descr. in UFIA1. 1314 LDIR 1316 INC HL Skip length in sectors, i.e. point to 1317 INC HL track and sector bytes. 1318 LD B,(HL) Fetch first track and sector. 1319 INC HL 131A LD C,(HL) 131B PUSH BC 131C LD BC,196 131F ADD HL,BC HL points to file header - 1 in CAT 1320 LD A,(HL) entry. That is the MSB of the file 1321 LD (IX+18),A length (number of 64K blocks). 1324 INC HL 1325 LD BC,9 1328 LDIR Copy the file header to the channel. 132A LD DE,#1FEA 132D LD BC,22 Copy the SNAP registers (?). 1330 LDIR 1332 POP DE Get track and sector in DE. 1333 CALL #29BD,JRSAD Load the sector at DE. 1336 JR #138A,OP_TEMP8 The file was not found, so if the channel isn't for OUTput give an error. 1338 OP_TEMP5 CP 191 133A JP Z,#2954,REP_26 Give error if it is an INput channel. 133D OP_TEMP6 LD BC,787 Length of OUTput channel. 1340 CALL #13A1,CHAN_SPC Create the room for the channel. 1343 POP IX 1345 CALL #2984,JTEST_DRV See if the drive is defined. 1348 NOP 1349 NOP 134A NOP 134B LD A,1 Signal 'WRITEing'. 134D LD (IX+12),A 1350 LD BC,275 Offset of databuffer from the start of 1353 LD (IX+15),C the channel. 1356 LD (IX+16),B 1359 CALL #29A8,JOFSM_2 Open the file. 135C JR Z,#1369,OP_TEMP7 Jump if file doesn't exist (anymore). 135E LD BC,787 Length of an OUTput channel. 1361 PUSH IX Start of the channel to HL. 1363 POP HL 1364 RST #10,CALBAS Reclaim the channel. 1365 DEFW #19E8,RECLAIM_2 1367 SCF Signal 'error'. 1368 RET Finished. 1369 OP_TEMP7 JR #138A,OP_TEMP8 Jump forward. The Command code 71 patch THE 'PAGE-IN DISCIPLE' SUBROUTINE This is called by using 'command code' 71. On return the DISCiPLE is paged-in and the HL register contains 1, to indicate that this is a DISCiPLE. 136B PATCH POP HL Drop 'HOOK_RET' return address. 136C LD HL,#0000 Clear 'D_ERR_SP'. 136F LD (#0296),HL 1372 INC HL Signal 'this is a DISCiPLE'. 1373 RET The stream handling routines II THE 'OPEN TEMP. "D" CHANNEL' CONTINUED Before the routine continues there are first some 'leftovers' from System 3c. 1374 ADD HL,DE 1375 EX DE,HL 1376 LD HL,(#1E1E) 1379 LD BC,#001E 137C ADD HL,BC 137D LD BC,#0009 1380 LDIR 1382 LD HL,#1FEA 1385 LD BC,#0016 1388 LDIR Now continue with the 'OPEN a temporary "D" channel' routine. 138A OP_TEMP8 PUSH IX 138C POP DE Start of channel to DE. 138D LD HL,#13B9,D_CH_DATA Start of the "D" channel data. 1390 LD BC,11 Copy the 11 bytes channel data to the 1393 LDIR channel area. 1395 PUSH IX Start of channel to HL. 1397 POP HL 1398 LD DE,(23631) HL-(CHANS)+1 gives the required 'stream 139C OR A offset'. 139D SBC HL,DE 139F INC HL 13A0 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). 13A1 CHAN_SPC LD (#13C2),BC Store the length of the channel into the "D" channel data table. 13A5 LD HL,(23635) Fetch the start address of the channel 13A8 DEC HL ((PROG)-1). 13A9 PUSH HL 13AA PUSH BC 13AB RST #10,CALBAS Create the required space by calling 13AC DEFW #1655,MAKE_ROOM 'main' ROM 'MAKE_ROOM'. 13AE POP BC 13AF POP HL Clear the created space. 13B0 CHAN_SPC1 LD (HL),0 13B2 INC HL 13B3 DEC BC 13B4 LD A,B 13B5 OR C 13B6 JR NZ,#13B0,CHAN_SPC1 13B8 RET THE '"D" CHANNEL DATA' TABLE The '11' bytes that compose the initial part of a "D" channel are as follows: 13B9 D_CH_DATA DEFW #0008 Main ROM 'output' routine. 13BB DEFW #0008 Main ROM 'input' routine. 13BD DEFB "D"+128 Channel specifier. 13BE DEFW #150D DISCiPLE system 'output' routine. 13C0 DEFW #148A DISCiPLE system 'input' routine. 13C2 DEFW 551 Length of a (read) channel. THE 'CLOSE #' COMMAND SYNTAX ROUTINE Unlike the Interface 1 and the Opus Discovery, the DISCiPLE doesn't page-in in the middle of the 'main' ROM 'CLOSE' routine. But because the 'main' ROM routine can't cope with DISCiPLE 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. 13C4 CLOSE# RST #28,NEXT_C_RAM Next character. 13C5 CP "*" 13C7 JP NZ,#2920,REP_0 Give an error if it isn't a '*'. 13CA RST #28,NEXT_C_RAM Next character. 13CB CP 13 13CD JR Z,#13E2,CLOSE_#* Jump if statement ended with ENTER. 13CF CP ":" 13D1 JR Z,#13E2,CLOSE_#* Also if statement ended with a ':'. 13D3 CALL #109E,EXPT_#_NR1 Evaluate stream number. 13D6 CALL #0409,ST_END_RAM Confirm end of statement and exit when syntax checking. 13D9 LD A,(#1E03) Fetch stream number. 13DC CALL #140C,CLOSE_STRM Close the stream. 13DF JP #0419,END Finished. 13E2 CLOSE_#* CALL #0409,ST_END_RAM Confirm end of statement and exit if 13E5 JR #13F4,CLEAR#_R1 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). 13E7 CLEAR# RST #28,NEXT_C_RAM Advance CH_ADD. 13E8 CP "#" 13EA JP NZ,#2920,REP_0 Give an error if it isn't a '#'. 13ED RST #28,NEXT_C_RAM 13EE CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 13F1 CALL #09D3,SIGN_SERV Signal 'CLEAR #'. 13F4 CLEAR#_R1 XOR A Start with stream 0. 13F5 CLEAR#_R2 PUSH AF 13F6 CALL #140C,CLOSE_STRM Close this stream. 13F9 POP AF 13FA INC A Next stream. 13FB CP 16 Repeat until all streams 0..15 have 13FD JR C,#13F5,CLEAR#_R2 been CLOSEd. 13FF CALL #11D6,RECL_TEMP Reclaim temporary channels. 1402 XOR A 1403 LD (#1DEF),A Clear 'MAP_USED' (=POKE @6999,0). 1406 LD (#1ACF),A Clear FLAGS3. 1409 JP #0419,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. 140C CLOSE_STRM RST #10,CALBAS Call 'STR_DATA1'. 140D DEFW #1727,STR_DATA1 140F LD A,C 1410 OR B Return if the stream is already CLOSEd 1411 RET Z (i.e. stream data = 0). 1412 LD (#1DED),BC Store stream data. 1416 PUSH HL 1417 LD HL,(23631) Make HL point to the start of the 141A DEC HL channel attached to the stream to be 141B ADD HL,BC CLOSEd ((CHANS)+'stream data'). 141C EX (SP),HL HL now holds the address of the stream data. 141D RST #10,CALBAS A call in the middle of the 'main' ROM 141E DEFW #16EB,CLOSE_0 'CLOSE' routine is made to update STRMS contents. 1420 POP IX IX points to the start of the channel 1422 LD A,B to be removed. 1423 OR C 1424 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. 1425 LD A,(IX+4) Fetch channel specifier. 1428 AND #5F Clear bit 7 (temporary) and make capital. 142A CP "D" 142C JR NZ,#143C,CLOSE_1 Jump if it isn't a "D" channel. 142E CLOSE_0 BIT 0,(IX+12) 1432 JR Z,#143C,CLOSE_1 Jump if it is an 'INput' channel. 1434 CALL #09FB,TEST_SERV Jump if doing a 'CLEAR #', i.e. just 1437 JR NZ,#143C,CLOSE_1 remove the channel. 1439 CALL #15ED,CL_PATCH Empty the buffer. 143C CLOSE_1 CALL #114C,RECL_CHAN Reclaim the channel. Now all data refering to the stream attached to the channels moved down are updated. 143F XOR A Start with stream 0. 1440 LD HL,23574 Address of data for stream 0. 1443 CLOSE_2 LD (#1AC8),HL Use 'FILE_ADDR' as a temporary storage. 1446 LD E,(HL) Fetch stream data. 1447 INC HL 1448 LD D,(HL) 1449 LD HL,(#1DED) Fetch stream data for CLOSEd stream. 144C AND A Jump if the stream data found is lower 144D SBC HL,DE than that of the CLOSEd stream (i.e. 144F JR NC,#145C,CLOSE_3 channel has not been moved). 1451 EX DE,HL Fetched stream data to HL. 1452 AND A 1453 SBC HL,BC Calculate the new stream data. 1455 EX DE,HL New stream data to DE. 1456 LD HL,(#1AC8) Restore stream data address. 1459 LD (HL),E Store new stream data. 145A INC HL 145B LD (HL),D 145C CLOSE_3 LD HL,(#1AC8) Make HL point to next stream data. 145F INC HL 1460 INC HL 1461 INC A Increment stream number. 1462 CP 16 1464 JR C,#1443,CLOSE_2 Repeat for all streams 0..15. 1466 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). 1467 CLS# RST #28,NEXT_C_RAM Next character. 1468 CP "#" 146A JP NZ,#2920,REP_0 Give error if it isn't a '#'. 146D RST #28,NEXT_C_RAM Next character. 146E CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 1471 LD HL,56 The 'initial' attribute value. 1474 LD (23693),HL Store 56 into ATTR_P, clear MASK_P. 1477 LD (23695),HL Store 56 into ATTR_T, clear MASK_T. 147A LD (IY+14),L Store 56 also for lower screen attribute. 147D LD (IY+87),H Clear P_FLAG. 1480 LD A,7 Set white border. 1482 OUT (254),A 1484 RST #10,CALBAS Call 'main' ROM 'CLS' routine. 1485 DEFW #0D6B,CLS 1487 JP #0419,END Finished. THE '"D" CHANNEL INPUT' ROUTINE This is a peculiar routine, although the DISCiPLE 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 #1491. From that address on it's largely the same as the Interface 1 'CALL_INP' routine, which routine handles all the IF1's channels. 148A D_INPUT LD IX,(23633) IX points to the start of the current channel (CURCHL). 148E LD HL,#14DC,DCHAN_IN Address of "D" input service routine. 1491 RES 3,(IY+2) Signal 'the mode is to be considered as being unchanged'. 1495 PUSH HL Store address of service routine. 1496 LD HL,(23613) HL points to error address (ERR_SP). 1499 LD E,(HL) Fetch the error address. 149A INC HL 149B LD D,(HL) 149C AND A 149D LD HL,#107F,ED_ERROR If the error address is 'ED_ERROR' 14A0 SBC HL,DE ('main' ROM) then an INPUT command was 14A2 JR NZ,#14CB,D_INKEY$ used. Jump if unequal to 'ED_ERROR'. Now deal with an 'INPUT #' command referred to a "D" channel. 14A4 POP HL Restore address of service routine. 14A5 LD SP,(23613) Clear the machine stack (ERR_SP). 14A9 POP DE Remove 'ED_ERROR'. 14AA POP DE 14AB LD (23613),DE Restore the old value of ERR_SP. 14AF D_INPUT1 PUSH HL Store address of service routine. 14B0 LD DE,#14B5,D_INP_END Return address is 'D_INP_END' below. 14B3 PUSH DE 14B4 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. 14B5 D_INP_END JR C,#14BD,D_INP_ACC Jump with acceptable codes. 14B7 JP NZ,#2956,REP_27 Give the 'END of file' error when the Zero flag is reset. 14BA POP HL Otherwise restore address of service 14BB JR #14AF,D_INPUT1 routine and try again. 14BD D_INP_ACC CP 13 14BF JR Z,#14C7,D_INPUT2 Jump if the code is ENTER. 14C1 RST #10,CALBAS Otherwise the byte is to be added to 14C2 DEFW #0F85,ADD_CHAR0 the INPUT line. This is done by calling into the 'ADD_CHAR' subroutine. 14C4 POP HL Restore address of service routine and 14C5 JR #14AF,D_INPUT1 read the next byte. 14C7 D_INPUT2 POP HL Drop the address of the service routine 14C8 JP #0050,UNPAGE_1 and page-out the DISCiPLE system. Now deal with the reading of a single byte. 14CB D_INKEY$ POP HL Restore address of the servce routine. 14CC LD DE,#14D1,D_INK$_END Return address is 'D_INK$_END' below. 14CF PUSH DE 14D0 JP (HL) Jump to the service routine. 14D1 D_INK$_END RET C Return with acceptable codes or 14D2 RET Z with no byte read. 14D3 CALL #0A00,TEST_STEAL Give the 'END of file' error if not 14D6 JP Z,#2956,REP_27 executing a 'MOVE' command. 14D9 OR 1 Otherwise return with Zero and Carry 14DB 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. 14DC DCHAN_IN BIT 0,(IX+12) Give 'Reading a WRITE file' error if 14E0 JP NZ,#2944,REP_18 it's an OUTput channel. 14E3 LD A,(IX+31) Decrease LSB of file length. 14E6 SUB 1 14E8 LD (IX+31),A 14EB JR NC,#1505,DCHAN_IN1 Jump if more bytes left. 14ED LD A,(IX+32) Decrease MID byte of file length. 14F0 SUB 1 14F2 LD (IX+32),A 14F5 JR NC,#1505,DCHAN_IN1 Jump if more bytes left. 14F7 LD A,(IX+18) Decrease MSB of file length. 14FA SUB 1 14FC LD (IX+18),A 14FF JR NC,#1505,DCHAN_IN1 Jump if more bytes left. 1501 XOR A Otherwise EOF has been reached, so reset Zero and Carry flag to signal 'End Of File'. 1502 ADD A,13 The return byte is 13. 1504 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. 1505 DCHAN_IN1 CALL #29A2,JLBYT Load one byte, read a new sector from disk when the buffer is empty. 1508 CALL #297B,JBORD_REST Restore border colour. 150B SCF Signal 'acceptable code'. 150C 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 'JSBYT' routine, which handles the saving of the byte. The only thing done here is incrementing the file length bytes. 150D DCHAN_OUT LD IX,(23633) IX point to current channel (CURCHL). 1511 BIT 0,(IX+12) Give 'Writing a READ file' error if 1515 JP Z,#2946,REP_19 it's an INput channel. 1518 CALL #29C3,JSBYT Save the byte in the A register. 151B CALL #297B,JBORD_REST Restore the border colour. 151E NOP 151F NOP 1520 NOP 1521 NOP 1522 PUSH IX 1524 LD BC,229 1527 ADD IX,BC IX now points to the file header. 1529 INC (IX+2) Update file length, skip higher bytes 152C JR NZ,#1536,DCHAN_OUT1 if it isn't necessary to update them. 152E INC (IX+3) 1531 JR NZ,#1536,DCHAN_OUT1 1533 INC (IX+0) 1536 DCHAN_OUT1 POP IX 1538 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). 1539 HXFER PUSH IX 153B POP HL 153C LD DE,#1E01 Start of 'UFIA1'. 153F LD BC,24 1542 LDIR Transfer the UFIA to 'UFIA1'. 1544 LD IX,#1AC3 IX points to the DFCA. 1548 CALL #2984,JTEST_DRV Check if the specified drive is 154B 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 DISCiPLE RAM. 'OFSM' should be used for files which don't contain a 9 byte header at the start of the file. 154C OFSM CALL #1539,HXFER Transfer UFIA to DFCA. 154F JP #29A8,JOFSM_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. 1552 HOFLE CALL #154C,OFSM Transfer UFIA to DFCA and open the file sector map. 1555 CALL #0D2F,SAVE_HEAD1 Transfer the 9 byte file header to the 1558 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. 1559 HSVBK CALL #1579,BCDE_DEHL Transfer BC to DE and DE to HL. 155C JP #29C9,JHSVBK_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). 155F HGFLE CALL #1539,HXFER Transfer the UFIA to the DFCA. 1562 JP #299C,JHGFLE_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. 1565 HLDBK CALL #1579,BCDE_DEHL Transfer BC to DE and DE to HL. 1568 JP #29A5,JLOAD_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. 156B HERAZ CALL #1539,HXFER Transfer the UFIA to the DFCA. 156E CALL #0985,FIND_FILE Find the file, HL points to the directory entry of the file (contained in the disk buffer). 1571 JP NZ,#2954,REP_26 Give error if file not found. 1574 LD (HL),0 Directory description 0 means ERASEd. 1576 JP #29CF,JWSAD 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. 1579 BCDE_DEHL PUSH DE 157A PUSH BC 157B POP DE 157C POP HL 157D LD IX,#1AC3 1581 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. 1582 HRSAD PUSH BC 1583 PUSH IX 1585 LD IX,#1AC3 1589 CALL #2987,JTEST_DRV1 See if the drive held in the A register is defined. 158C CALL #29BD,JRSAD Load the sector into the disk buffer. 158F POP HL 1590 PUSH DE 1591 LD DE,#1BD6 Start of disk buffer. 1594 EX DE,HL 1595 CALL #0D22,GET_SECLEN Fetch sector length in BC. 1598 LDIR Move sector to specified address. 159A PUSH DE 159B POP IX Update IX. 159D POP DE Restore DE and BC. 159E POP BC 159F 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. 15A0 HWSAD PUSH BC 15A1 PUSH IX 15A3 POP HL 15A4 LD IX,#1AC3 15A8 CALL #2987,JTEST_DRV1 See if the drive held in the A register 15AB PUSH DE is defined. 15AC LD DE,#1BD6 15AF CALL #0D22,GET_SECLEN Fetch the sector length into BC. 15B2 LDIR Move BC bytes to the disk buffer. 15B4 POP DE 15B5 PUSH HL 15B6 CALL #29CF,JWSAD Write sector DE to disk. 15B9 POP IX 15BB POP BC 15BC 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. 15BD RSAD LD IX,#1AC3 15C1 JP #29BD,JRSAD 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. 15C4 WSAD LD IX,#1AC3 15C8 JP #29CF,JWSAD Save the sector. Miscalleneous routines II THE 'SEND COMMAND BLOCK' SUBROUTINE This subroutine sends a command block over the network. It is used whenever the master station wants to steal a file from or force one upon a pupil station. In System 3c the code from address #15DC was replaced by one call to the ROM in order to free 62 bytes for some patches. 15CB SEND_BLOCK LD A,(#1E01) Fetch destination station number. 15CE LD (#1DFD),A 15D1 LD A,(#029C) Fetch own station number from (NSTAT). 15D4 CP 1 15D6 JP NZ,#295A,REP_29 Give error if not the master station. 15D9 LD (#1DFE),A Store own station number. 15DC CALL #28DD,REQ_SERV4 Send the command block over the network. 15DF RET THE 'TEST PRINTER' SUBROUTINE This small piece of code was added in System 3c to overcome the hanging up of the DISCiPLE during booting when the system is setup for a printer, but there isn't one present. It returns with Carry set if the printer mustn't be initialized. 15E0 TEST_PRTR LD A,(#02A3) (ZXPNT) 15E3 AND A Jump if the printer isn't to be handled 15E4 JR NZ,#15EB,TEST_PRTR1 by the DISCiPLE. 15E6 IN A,(31) 15E8 BIT 6,A Check the busy line of the printer. 15EA RET NZ Return if it's high. If a printer isn't attached it is impossible for the line to be high, if the printer is off-line this line is held low by the printer. 15EB TEST_PRTR1 SCF Set Carry to signal no printer. 15EC RET Finished. THE 'CLOSE #' PATCH This patch cures the bug related to 'OPENTYPE' files on drive 2. System 3b mixed up the soft- and hardware's representation of drive 1 and 2. So when closing an 'OPENTYPE' file on drive 2, the software representation of drive 2 (10 binary) was send to the hardware which resulted in the selection of side 2 of drive 2. 15ED CL_PATCH LD E,(IX+17) Fetch sector and track. 15F0 LD D,(IX+18) 15F3 LD A,(IX+11) Fetch drive number (hardware 15F6 LD (#1ACE),A representation, so 1 or 0). 15F9 CALL #29C6,JSLCT_DRV Select track, sector, side and drive (uses hardware representation). 15FC CALL #2981,JCFSM Close the file sector map. 15FF 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. 1600 OP_T_PATCH PUSH HL 1601 LD HL,(#0296) 1604 LD A,H 1605 OR L Jump back to the 'OP_TEMP' routine if 1606 POP HL 'D_ERR_SP' is zero (this isn't the case 1607 JP Z,#133D,OP_TEMP6 during command code execution). 160A JP #2958,REP_28 Otherwise give 'File NAME used' error. THE 'NEW' PATCH When the file copy command is finished the DISCiPLE jumps to the 'NEW' routine. With System 3b this always was a 48K 'NEW', in System 3c this was altered. 160D TO_NEW BIT 4,(IY+1) Jump if not in 128K mode HL contains 1611 JP Z,#004F,UNPAGE_HL #11B7, the address of 48K 'NEW'. 1614 CALL #5B00,SWAP Call the paging subroutine of the 128. 1617 DI 1618 LD BC,#00C7 Address of 128 'NEW' routine. 161B JP #0046,UNPAGE_BC The Printer routines THE 'COPY SCREEN' ROUTINE This routine has two entry points. The first one, #161E, is used with the BASIC commands 'SAVE/LOAD/VERIFY/MERGE SCREEN$'. The second entry point (#1621) is used for the 'COPY' command itself. Depending on the parameter following the 'SCREEN$', the normal or the grey scale screen dump is used. 161E DUMP_SCR$ POP HL Drop the return address (within the routine which called 'EXPT_PARMS'). 161F JR #1627,COPY_1 Jump forward. 1621 COPY RST #28,NEXT_C_RAM Advance CH_ADD. 1622 CP 170 Give 'Nonsense in GDOS' error if 1624 JP NZ,#2920,REP_0 command isn't followed by 'SCREEN$'. 1627 COPY_1 LD A,"1" Default is '1' for 'normal' dump. 1629 LD (#1E00),A 162C RST #28,NEXT_C_RAM Advance CH_ADD 162D CP 13 162F JR Z,#1639,COPY_2 Jump with ENTER. 1631 CP ":" 1633 JR Z,#1639,COPY_2 Also jump with ':'. 1635 LD (#1E00),A Otherwise store character. 1638 RST #28,NEXT_C_RAM Update CH_ADD again. 1639 COPY_2 CALL #0409,ST_END_RAM Confirm end of statement and exit during syntax checking. 163C LD A,(#1E00) 163F CP "1" Normal screendump if '1' followed the 1641 CALL Z,#164C,COPS 'SCREEN$'. 1644 CP "2" Grey scale in case of a '2'. 1646 CALL Z,#16B2,COPS2 Ignore other values. 1649 JP #0419,END Finished. THE 'NORMAL SCREENDUMP' SUBROUTINE This routine dumps a normal screendump to the printer. It can be called also by using command code 58 (#3A). 164C COPS LD HL,16384 Start of screen. 164F LD DE,#02BA Print the escape sequence for n/72 inch 1652 CALL #1779,PO_ESC_SEQ line feeds. 1655 LD A,8 Make it 8/72. 1657 CALL #1944,PNTP 165A C1_LINE LD DE,#02C2 Print the escape sequence for a normal 165D CALL #1779,PO_ESC_SEQ screendump. (60 dpi) 1660 LD A,0 Signal '256 dot columns will follow' to 1662 CALL #1944,PNTP the printer. 1665 LD A,1 1667 CALL #1944,PNTP 166A PUSH HL 166B C1_CHAR LD B,8 Eight pixels in each byte. 166D C1_PIXEL PUSH HL 166E C1_PIXROW CALL #1751,PIXEL_COL Get pixel colour. 1671 AND #04 1673 JR NZ,#1676,C1_ADD_DOT Jump with colour codes 4-7 (no dot). 1675 SCF Set a dot for colour codes 0-3. 1676 C1_ADD_DOT LD A,(#1978) Incorporate one dot in dot column. 1679 RLA 167A LD (#1978),A 167D INC H Next pixel row. 167E LD A,H 167F AND #07 1681 JR NZ,#166E,C1_PIXROW Repeat until all eight pixelrows have been 'scanned'. 1683 LD A,(#1978) 1686 CALL #1944,PNTP Print the dot column. 1689 POP HL Repeat until all eight pixels in a byte 168A DJNZ #166D,C1_PIXEL have been printed. One character cell (64 pixels) has been printed now. 168C INC L Next character position. 168D LD A,L 168E AND #1F 1690 JR NZ,#166B,C1_CHAR Loop for all 32 character columns. 1692 CALL #16A2,ADV_PAPER Advance printer paper one line. 1695 POP HL 1696 LD A,H 1697 ADD A,8 Make HL point to the next screen third. 1699 LD H,A 'N_CHARROW' will adjust HL if necessary. 169A CALL #176C,N_CHARROW Calculate the address of the next 169D JR NZ,#165A,C1_LINE characterrow and loop until end of pixel area reached. 169F JP #1745,DUMP_EXIT Exit via 'DUMP_EXIT' to reset printer. THE 'ADVANCE PRINTER PAPER' SUBROUTINE This subroutine advances the paper by sending a CR (carriage return) and (when needed) a LF (line feed) to the printer. 16A2 ADV_PAPER LD A,13 Send a CR to the printer. 16A4 CALL #1944,PNTP 16A7 LD A,(#02A0) This is 'LFEED'. 16AA AND A 16AB RET Z Return if no LF has to be printed. 16AC LD A,10 Otherwise send a LF. 16AE CALL #1944,PNTP 16B1 RET Finished. THE 'GREYSCALE SCREENDUMP' SUBROUTINE This routine prints a large screendump. It can also be called by using command code 66 (#42). NOTE: With System 3b this routine printed a greyscale dump but with the System 3c 'improvement' of the 'PIXEL_CLR' subroutine the greyscales have been limited to black and white only. The routine now just produces a larger screendump (3*3 dots for each pixel). 16B2 COPS2 LD HL,#57E0 Address of the lowest pixelrow of the charactersquare in the bottom left corner. 16B5 LD DE,#02BA Print the escape sequence for n/72 inch 16B8 CALL #1779,PO_ESC_SEQ line feeds. 16BB LD A,6 Make it 6/72. 16BD CALL #1944,PNTP 16C0 LD B,128 There are 128 2-pixel columns. 16C2 LD C,8 8 pixels make one byte. Start with leftmost bit in a byte. 16C4 C2_2PIXCOL PUSH BC 16C5 PUSH HL 16C6 LD DE,#02EA Print the escape sequence for the 16C9 CALL #1779,PO_ESC_SEQ greyscale bitimage mode. 16CC LD B,24 There are 24 characterrows. 16CE C2_SCRROW PUSH BC 16CF PUSH HL 16D0 LD B,8 A character has 8 pixelrows. 16D2 C2_PIXROW PUSH BC 16D3 PUSH HL 16D4 LD DE,#1BD6 Clear the buffer for the 2 pixels. 16D7 LD B,3 16D9 C2_CLRBUF XOR A 16DA LD (DE),A 16DB INC DE 16DC DJNZ #16D9,C2_CLRBUF 16DE LD B,2 The dot columns for 2 pixels are build up each time. 16E0 C2_2PIX PUSH BC 16E1 PUSH HL 16E2 LD B,C 16E3 CALL #1751,PIXEL_COL Get the colour of the (B-1)th pixel. 16E6 AND #07 Keep only the least significant 3 bits. 16E8 INC A Make the range 1..8. 16E9 LD B,A 16EA LD C,0 Set the bit in the C register which 16EC SCF corresponds to the colour. 16ED C2_MK_MASK RL C 16EF DJNZ #16ED,C2_MK_MASK 16F1 LD DE,#02F2 DE points to the 'GREYSCALE' table. 16F4 LD HL,#1BD6 HL points to the 2-pixel buffer. 16F7 LD B,3 Each pixel is printed as 3*3 dots. 16F9 C2_DOTCOL PUSH BC 16FA LD B,3 16FC C2_DOTROW LD A,(DE) Get colour pattern. 16FD AND C Only keep the bit with the right colour. 16FE LD A,(HL) 16FF JR Z,#1702,C2_ADD_DOT Jump if bit isn't set. 1701 SCF Otherwise set this dot. 1702 C2_ADD_DOT RL A Incorporate this dot. 1704 LD (HL),A 1705 INC DE Next entry in 'GREYSCALE' table. 1706 DJNZ #16FC,C2_DOTROW Repeat for 3 dotrows. 1708 INC HL 1709 POP BC 170A DJNZ #16F9,C2_DOTCOL Repeat for 3 dotcolumns. 170C POP HL 170D POP BC 170E DEC C Next pixel. 170F DJNZ #16E0,C2_2PIX Two pixels are handled at a time. 1711 LD B,3 Three dotcolumns are to be printed. 1713 LD HL,#1BD6 1716 C2_PRT3X3 LD A,(HL) Print each dotcolumn in turn. 1717 CALL #1944,PNTP 171A INC HL 171B DJNZ #1716,C2_PRT3X3 Repeat for all three. 171D POP HL 171E DEC H Next pixelrow. 171F POP BC Repeat for the eight pixelrows in a 1720 DJNZ #16D2,C2_PIXROW character square. 1722 POP HL 1723 LD A,L One character row up. 1724 SUB 32 1726 LD L,A 1727 JR NC,#172D,C2_CHRROW Jump if still within the same third. 1729 LD A,H Otherwise update MSB of address. 172A SUB 8 172C LD H,A 172D C2_CHRROW POP BC 172E DJNZ #16CE,C2_SCRROW Repeat for the 24 rows on the screen. 1730 CALL #16A2,ADV_PAPER Advance the paper. 1733 POP HL 1734 POP BC 1735 DEC C Skip the two pixels which have already 1736 DEC C been printed. 1737 JR NZ,#173C,C2_BYTE Jump if not all pixels within this byte have been printed. 1739 LD C,8 Otherwise reset 'pixels in a byte' counter 173B INC HL and point to the next character position to the right. 173C C2_BYTE DJNZ #16C4,C2_2PIXCOL Repeat for the 128 2-pixelcolumns. 173E LD B,4 Advance the paper for four lines. 1740 C2_ADVPAP CALL #16A2,ADV_PAPER 1743 DJNZ #1740,C2_ADVPAP 1745 DUMP_EXIT LD DE,#02BA Print the escape sequence for n/72 inch 1748 CALL #1779,PO_ESC_SEQ line feeds. 174B LD A,(#029F) Make it (LSPCE)/72. 174E JP #1944,PNTP Exit via 'PNTP'. THE 'PIXEL COLOUR' SUBROUTINE In System 3b this routine returned with the low 3 bits of the A register holding the colour of the Bth pixel from address HL (i.e. the paper colour for an 'off' pixel and the ink colour for an 'on' pixel). Because some normal screen dumps came out as a solid black mess the routine was somewhat changed in System 3c (from #1762-#1764). The routine now returns with %111 for an on pixel and with %000 for an off pixel. However now the greyscale dump is reduced to a 'no more greyscales' large screendump. 1751 PIXEL_COL PUSH HL Save address of current 8-pixels. 1752 PUSH BC Save pixel number (range 1..8). 1753 XOR A 1754 SCF 1755 PIXEL_COL1 RLA Now set (B-1)th bit of A (range 0..7). 1756 DJNZ #1755,PIXEL_COL1 1758 AND (HL) Zero flag now reflects state of pixel (i.e. set means pixel set). 1759 PUSH AF These seven instructions don't serve 175A LD A,H any purpose anymore. They were used in 175B RRCA Sys 3b to calculate the attribute 175C RRCA address. 175D RRCA 175E AND #03 1760 OR #58 1762 POP AF Restore flags. 1763 LD A,#38 PAPER 7, INK 0. 1765 POP BC 1766 POP HL 1767 RET NZ Return with %000 if pixel was set. 1768 RRCA Otherwise move bit3-5 to bit0-2. 1769 RRCA 176A RRCA 176B RET Return with %111. THE 'NEXT CHAR. ROW ADDRESS' SUBROUTINE This subroutine calculates the address of the next characterrow, if the end of the pixel area is reached a return with Zero set will be made. 176C N_CHARROW LD A,L Update low address byte to next character row. 176D ADD A,32 The carry will be reset within display 176F LD L,A thirds. 1770 CCF Invert carry. 1771 SBC A,A A holds #FF within same third, 0 else. 1772 AND #F8 A will hold #F8 (i.e. -8) within a 1774 ADD A,H third, but 0 when a new third is 1775 LD H,A reached. Update high byte (which was already incremented by 8). 1776 CP #58 Return with the Zero flag set if 1778 RET attributes reached. THE 'PRINT ESCAPE SEQUENCE' SUBROUTINE This subroutine is used to send escape sequences to the printer. The start of the sequence is held in the DE register, a sequence ends with a CHR$ 128. 1779 PO_ESC_SEQ LD A,(DE) Fetch a code. 177A CP 128 177C RET Z Exit if it's 128. 177D CALL #1944,PNTP Otherwise send it to the printer. 1780 INC DE 1781 JR #1779,PO_ESC_SEQ Continue until the sequence is finished. THE '"P" CHANNEL OUTPUT' ROUTINE This routine handles the DISCiPLE's "P" channel, the @6 system variable (PCODE) signals if it's to be handled as a "t" or a "b" channel. (As with the Opus Discovery and the ZX Interface 1.) This routine handles also the sending of the CATalogue over the network whenever a pupil gives the 'CAT' command. 1783 PCHAN_OUT LD (#1978),A 1786 CALL #09FB,TEST_SERV 1789 JR Z,#1796,PCHAN_OUT1 Jump if not serving the network. 178B PUSH IX When serving the network the byte to be 178D LD A,(#1978) printed is send over the network. 1790 CALL #2966,JN_OUTPUT 1793 POP IX 1795 RET 1796 PCHAN_OUT1 LD A,(#029E) This is PCODE. 1799 AND A 179A LD A,(#1978) Fetch the code to be send to the 179D JP NZ,#1944,PNTP printer, send it right away if (PCODE)=1, i.e. when the DISCiPLE mustn't interfere. 17A0 LD HL,(#1974) Jump to the appropriate 'output' 17A3 JP (HL) routine. This is the normal 'output' routine, but a few (control) characters are followed by one or two operands, these have to be handled different. This is done by altering the 'output' routine address. 17A4 P_ALL LD HL,#029D This is 'WIDTH'. 17A7 CP 32 17A9 JP NC,#1892,P_NOCTRL Jump if not a control code (>=32). 17AC CP 6 This is the "PRINT comma" code. 17AE JP C,#184D,P_ESCAPE Jump with codes < 6. 17B1 JR NZ,#17C1,P_NOCOMMA Jump with codes > 6. 17B3 LD A,(HL) Fetch the number of characters per 17B4 SRL A line, divide it by two. 17B6 LD B,A 17B7 LD HL,#1976 #1976 holds the position on the current line (i.e. the number of characters already printed on this line). 17BA SUB (HL) 17BB JR C,#17E2,P_NEWLINE Jump if already on 2nd half of line. 17BD LD H,B Otherwise jump with H holding the 17BE JP #1864,P_TAB center position of the line. 17C1 P_NOCOMMA CP 8 This is "cursor left" or "backspace". 17C3 JP C,#184D,P_ESCAPE Jump with codes < 8. 17C6 JR NZ,#17D4,P_NOBACK Jump with codes > 8 (examine further). 17C8 LD HL,#1976 Get current position. 17CB LD A,(HL) 17CC AND A 17CD RET Z Return if already on leftmost position. 17CE DEC (HL) Otherwise decrement current position. 17CF LD A,127 This isn't "BACKSPACE", this is "DELETE" ! 17D1 JP #1944,PNTP Print a "DELETE". 17D4 P_NOBACK CP 13 This is "ENTER" or "CARRIAGE RETURN". 17D6 JR C,#184D,P_ESCAPE Jump with codes < 13. 17D8 JR NZ,#180E,P_NOENTER Jump with codes > 13. 17DA LD HL,#1977 This flag, when set, indicates that a 17DD BIT 0,(HL) newline has already been send to the printer. I.e. the previous line was full (see #19EB). 17DF RES 0,(HL) Reset the flag. 17E1 RET NZ Return if this newline has been send already. 17E2 P_NEWLINE LD HL,#1977 Signal 'newline has been send'. 17E5 RES 0,(HL) 17E7 LD HL,#1976 17EA LD (HL),0 Set current position to 0. 17EC LD A,(#02A0) Fetch (LFEED), the number of line feeds 17EF AND A needed after a carriage return. 17F0 JR Z,#17FA,P_CARRET Jump if it is 0. 17F2 LD B,A Otherwise send the line feeds. 17F3 P_LFEED LD A,10 CHR$ 10 is line feed. 17F5 CALL #1944,PNTP 17F8 DJNZ #17F3,P_LFEED Loop until (LFEED) line feeds send. 17FA P_CARRET LD A,13 Now send the carriage return. 17FC CALL #1944,PNTP 17FF LD A,(#02A1) Fetch (LMARG), that is the left margin. 1802 AND A 1803 RET Z Return if it is 0. 1804 LD B,A Otherwise send (LMARG) spaces. 1805 LD (HL),A Adjust current print position. 1806 P_LMARG LD A,32 1808 CALL #1944,PNTP 180B DJNZ #1806,P_LMARG Loop until (LMARG) spaces send. 180D RET Finished. Now the control codes with operands are handled. The control codes from INK to OVER (16..21) and ESC (27) require a single operand, whereas the control characters AT & TAB are required to be followed by two operands. The following routines leads to the control character code being stored in TVDATA-lo, the first operand in TVDATA-hi or the A register if there is only a single operand required, and the second operand in the A register. The ESC control code is handled separately, the single operand is send directly to the printer. 180E P_NOENTER CP 16 This is "INK control". 1810 JR C,#184D,P_ESCAPE Jump with codes < 16. 1812 CP 24 This is "TAB control"+1. 1814 JR NC,#1860,P_QUEST Jump with codes >= 24. 1816 CP 22 This is "AT control". 1818 JR NC,#1848,P_2_OPER Jump with AT & TAB. 181A LD DE,#1827,P_CONT Otherwise the '"P" channel output' routine is to be changed to 'P_CONT'. 181D P_TV_1 LD (23566),A Store the control character code in (TVDATA-lo). The current 'output' routine address is changed temporarily. 1820 P_CHANGE LD HL,#1974 HL points to the 'output' routine 1823 LD (HL),E address. Enter the new 'output' routine 1824 INC HL address and thereby force the next 1825 LD (HL),D character to be considered as an 1826 RET operand. Once the operands have been collected the routine continues. 1827 P_CONT LD DE,#17A4,P_ALL Restore the original address for 182A CALL #1820,P_CHANGE 'P_ALL'. 182D LD HL,(23566) Fetch the control code and the first operand if there are indeed two operands (TVDATA). 1830 LD D,A The 'last' operand and the control code 1831 LD A,L are moved. 1832 CP 22 1834 JR C,#183A,P_CO_TEMPS Jump if handling INK to OVER. 1836 JR NZ,#1864,P_TAB Jump if handling TAB. 1838 JR #188F,P_AT Jump if handling AT. The control codes INK to OVER are handled by the 'main' ROM 'CO_TEMP' routine. It is entered with the control code in the A register and the parameter in the D register. Note that all changes are to the 'temporary' system variables. 183A P_CO_TEMPS LD HL,#2211,CO_TEMP_5 Return via the calling routine to 183D EX (SP),HL 'CO_TEMP' in the 'main' ROM. 183E PUSH HL 183F RET 1840 P_TV_2 LD DE,#1827,P_CONT Store the first operand in TVDATA-hi 1843 LD (23567),A and change the address of the 'output' 1846 JR #1820,P_CHANGE routine to 'P_CONT'. Enter here when handling the control codes AT & TAB. 1848 P_2_OPER LD DE,#1840,P_TV_2 The control code will be stored in 184B JR #181D,P_TV_1 TVDATA-lo and the address of the 'output' routine changed to 'P_TV_2'. 184D P_ESCAPE CP 27 184F JR NZ,#1860,P_QUEST Print a '?' if it isn't ESC. 1851 LD DE,#1857,P_ESC Otherwise change the address of the 1854 JP #1820,P_CHANGE 'output' routine to 'P_ESC'. Enter here when handling the ESC control code, the character code following the ESC is send directly to the printer. 1857 P_ESC LD DE,#17A4,P_ALL Restore the original address for 185A CALL #1820,P_CHANGE 'P_ALL'. 185D JP #1944,PNTP Send the code following the ESC to the printer. A question mark is printed whenever an attempt is made to print an unprintable character code. 1860 P_QUEST LD A,63 The character '?'. 1862 JR #1892,P_NOCTRL Send it to the printer. Now deal with the TAB control code. 1864 P_TAB LD A,(#029D) Fetch (WIDTH), that is the line length. 1867 LD B,A 1868 LD A,H Fetch the position where to TAB (or AT) 1869 SUB B to. 186A JR C,#1872,P_INRANGE Jump if position is on this line. 186C LD HL,#046C,REPORT_B Otherwise return to 'REPORT_B' in the 186F EX (SP),HL 'main' ROM ('Integer out of range'). 1870 PUSH HL 1871 RET 1872 P_INRANGE LD A,(#1976) Fetch current position. 1875 LD B,A 1876 LD A,H 1877 SUB B 1878 PUSH HL Print on a new line if print position 1879 CALL C,#17E2,P_NEWLINE exceeds TAB position. 187C POP HL 187D LD A,(#1976) Fetch the current position again. 1880 SUB H Calculate the number of spaces wanted. 1881 RET Z Return if already there. 1882 CPL The number is negative so make it 1883 INC A positive. 1884 LD B,A Print the needed spaces. 1885 P_SPACE LD A,32 1887 PUSH BC 1888 CALL #17A4,P_ALL 188B POP BC 188C DJNZ #188C,P_SPACE 188E RET Enter here when handling AT. 188F P_AT LD H,D Store the second operand and continue 1890 JR #1864,P_TAB in the TAB routine. The 'not control' characters are divided into four groups: the ordinary characters, the tokens, the graphics and the user-defined graphics. 1892 P_NOCTRL CP 128 This is the first graphic. 1894 JR C,#18FD,P_ASCII Jump with ASCII characters (< 128). 1896 CP 144 This is the first UDG. 1898 JR NC,#18A3,P_TOK&UDG Jump with UDG's and tokens. 189A LD B,A Construct the graphic in the 189B RST #10,CALBAS calculator's memory area by calling 189C DEFW #0B38,PO_GR_1 'PO_GR_1' in the 'main' ROM. 189E LD HL,23698 HL points to the start of the graphic form; i.e. MEMBOT. 18A1 JR #18BA,P_GRAPH Jump to print the graphic character. 18A3 P_TOK&UDG SUB 165 This is the RND token. 18A5 JR C,#18AD,P_UDGS Jump with UDG's (< 165). 18A7 LD HL,#0C10,PO_TOKENS The routine indirectly jumps to the 18AA EX (SP),HL 'PO_TOKENS' routine in the 'main' ROM 18AB PUSH HL to expand the token. That routine then 18AC RET calls recursively the 'P_ALL' routine above for each character of the token. 18AD P_UDGS ADD A,21 Adjust range, UDG's now from 0..20. 18AF LD BC,(23675) BC points to the start of the UDG area 18B3 LD H,0 (UDG). 18B5 LD L,A Pass the code to HL. 18B6 ADD HL,HL Each UDG is made by eight bytes, so 18B7 ADD HL,HL multiply the code by eight. 18B8 ADD HL,HL 18B9 ADD HL,BC 18BA P_GRAPH LD DE,#1964 Move the eight bytes to the DISCiPLEs 18BD LD BC,8 internal printerbuffer. 18C0 LDIR Now the eight pixelrows are converted to eight dotcolumns. 18C2 PUSH IX 18C4 LD IX,#1973 The last address of the dotcolumns. 18C8 LD B,8 Each graphic has eight pixelrows. 18CA P_GRAPH1 LD HL,#1964 Address of the graphic's pixelrows. 18CD LD C,8 Each pixelrow has eight pixels. 18CF P_GRAPH2 LD D,(HL) Each bit is moved in turn into the E 18D0 RR D register. 18D2 LD (HL),D 18D3 RL E 18D5 INC HL 18D6 DEC C 18D7 JR NZ,#18CF,P_GRAPH2 Repeat for the eight pixels. 18D9 LD (IX+0),E Store the dotcolumn. 18DC DEC IX 18DE DJNZ #18CA,P_GRAPH1 Repeat for the eight rows. 18E0 POP IX 18E2 LD DE,#02C2 Print the escape sequence for 60 dpi. 18E5 CALL #1779,PO_ESC_SEQ 18E8 LD A,8 Signal to the printer 'there follow 18EA CALL #1944,PNTP eight bytes of bitimage data'. 18ED LD A,0 18EF CALL #1944,PNTP 18F2 LD B,8 Send the eight bytes to the printer. 18F4 P_GRAPH3 LD A,(HL) 18F5 CALL #1944,PNTP 18F8 INC HL 18F9 DJNZ #18F4,P_GRAPH3 18FB JR #192F,P_UP_POS Update the current position. Now deal with the printing of normal ASCII characters. 18FD P_ASCII LD HL,#1977 1900 RES 0,(HL) Reset 'newline already send' flag. 1902 LD (#1978),A 1905 LD A,(#02A2) Fetch (GRAPH), when it's 1 the DISCiPLE 1908 AND A has to generate the graphic 1909 LD A,(#1978) representation of some characters. 190C JR Z,#192C,P_OTHERS Jump if the normal code has to be send. Because some Spectrum characters aren't supported by all printers the DISCiPLE can send the graphic representation of those characters instead of the original character code. The characters supported by System 3d are £, # and (c). 190E CP "£" 1910 JR NZ,#1918,P_NOPOUND Jump if it isn't '£'. 1912 LD HL,#02D2 Point to the bitimage data for £. 1915 JP #18BA,P_GRAPH Handle it as an ordinary graphic. 1918 P_NOPOUND CP "#" 191A JR NZ,#1922,P_NOPOWER Jump if it isn't '#'. 191C LD HL,#02DA Point to the bitimage data for #. 191F JP #18BA,P_GRAPH Handle it as a graphic. 1922 P_NOPOWER CP "(c)" 1924 JR NZ,#192C,P_OTHERS Jump to handle all non '(c)' characters. 1926 LD HL,#02E2 Point to the bitimage data for (c). 1929 JP #18BA,P_GRAPH Handle it as a graphic. Finally the normal characters can be send to the printer. 192C P_OTHERS CALL #1944,PNTP Send the character to the printer. 192F P_UP_POS LD A,(#1976) Update the current position. 1932 INC A 1933 LD (#1976),A 1936 LD HL,#029D HL points to WIDTH. 1939 SUB (HL) 193A RET C Return if the line isn't full yet. 193B CALL #17E2,P_NEWLINE Otherwise someone has forgotten that 193E LD HL,#1977 printer lines aren't endless, so print 1941 SET 0,(HL) a 'NEWLINE' and signal 'ignore next 1943 RET character if it is a CR'. THE 'SEND A BYTE TO PRINTER' SUBROUTINE This routine is also called by using command code 57 (#39). It sends the 8 bit code in the A register to the printer port, after checking if the printer is busy. The BREAK key is tested. 1944 PNTP LD (#1978),A Store the code temporarily. 1947 PNTP_1 CALL #03FA,TEST_BREAK Exit if the BREAK key is pressed. 194A IN A,(31) Test the BUSY line of the printer. 194C BIT 6,A 194E JR Z,#1947,PNTP_1 Wait until printer isn't BUSY. 1950 LD A,(#1978) Send the code to the printer port. 1953 OUT (251),A 1955 LD A,(#1DDA) Fetch current control port status. 1958 OR #40 Give a STROBE. 195A OUT (31),A 195C AND #BF Reset STROBE. 195E OUT (31),A 1960 LD A,(#1978) Return with the A register holding the 1963 RET outputted byte. THE 'PRINTER WORKSPACE' Here follows the workspace used by the printer routines. 1964 DEFS 8 196C DEFS 8 1974 DEFW #17A4 Address of 'output' routine for "P". 1976 DEFB 0 Holds the current print position. 1977 DEFB 0 The 'ENTER' flag. 1978 DEFB 0 Temporary store for byte to be send. The system message routines Finally there follow some messages. A message follows directly after the CALL to the ROM print routine. Note that the CALLs were altered in system 3d, to make it possible to print while command code 67 (PCAT) is executing. 1979 MSG_0 CALL #3C1D,PO_MSG1 197C DEFM "* DISCiPLE .. DISC" 198E DEFB " "+128 198F MSG_1 CALL #3C1D,PO_MSG1 1992 DEFM " DIRECTORY *" 199E DEFB 13,13+128 19A0 MSG_2 CALL #3C1D,PO_MSG1 19A3 DEFB 13,13 19A5 DEFM "Number of free K-Bytes =" 19BD DEFB " "+128 19BE MSG_3 CALL #3C1D,PO_MSG1 19C1 DEFM "(c) Miles Gordon Technology DOS 3d" 19E1 DEFB 13,13+128 19E3 MSG_4 CALL #3C1D,PO_MSG1 19E6 DEFB 13 19E7 DEFM "CHANGE disc ..press SPAC" 19FF DEFB "E"+128