4400H - The Start of the Main File
The boot sector copies the data bytes of 19 sectors to 4400H-55FFH and jumps to 4400H. The first instruction jumps over the texts and variables that fill 4403H-4726H to the initialization at 4727H. The eight characters MICRODOS that follow are what the boot sector checks for in the first sector.
4400
JUMP to 4727H, the initialization of MicroDOS. The boot sector jumps here (its 4237H) when the last sector of the main file has been copied, with the Stack Pointer at 41FCH and interrupts off; CMD"M" writes this byte and the rest of 4400H-55FFH back to sectors 1-19 of a diskette (491BH).
4403-440A
DEFM "MICRODOS" 4D 49 43 52 4F 44 4F 53
The eight characters MICRODOS. In the first sector of the main file they are bytes 4-11, which the boot sector compares with its own copy (its 421DH) before it loads anything; a diskette without them gets NO MICRODOS. No code of the main file reads them.
440BH - Sign-On Text Buffer (440BH-448BH)
The text the boot sector displays when it has checked MICRODOS (its 4226H displays the first sector from 430CH, which is 440BH here), up to a 00H byte. CMD"H",A$ (4802H) replaces it with the first 128 characters of a string, a down arrow (0AH) in the string becoming 0DH, and a 00H after it (4851H); CMD"M" must follow to put the new text on the diskette. The buffer is 129 bytes, 440BH-448BH; the bytes after the 00H are not used.
440B-4458
DEFM "A SIMPLE, POWERFUL DOS",0DH,"WRITTEN BY JAMES W. STUTSMAN",0DH,"FOR PERCOM DATA COMPANY",0DH,0DH,00H 41 20 53 49 4D 50 4C 45 2C 20 50 4F 57 45 52 46 55 4C 20 44 4F 53 0D 57 52 49 54 54 45 4E 20 42 59 20 4A 41 4D 45 53 20 57 2E 20 53 54 55 54 53 4D 41 4E 0D 46 4F 52 20 50 45 52 43 4F 4D 20 44 41 54 41 20 43 4F 4D 50 41 4E 59 0D 0D 00
The sign-on text on this diskette: A SIMPLE, POWERFUL DOS, WRITTEN BY JAMES W. STUTSMAN and FOR PERCOM DATA COMPANY, each followed by 0DH (a new line), one more 0DH for a blank line, and the 00H at 4458H that ends it. The boot sector displays it at the top left corner of the cleared screen, before it loads the rest of this file.
4459-448B
DEFM "CRLNUM",09H,"EQU",09H,"40ECH",09H,09H,";CURRENT LINE NUMBER",0CH,17H,"&PRGEND",09H,"EQU" 43 52 4C 4E 55 4D 09 45 51 55 09 34 30 45 43 48 09 09 3B 43 55 52 52 45 4E 54 20 4C 49 4E 45 20 4E 55 4D 42 45 52 0C 17 26 50 52 47 45 4E 44 09 45 51 55
The rest of the sign-on buffer, after the 00H at 4458H that ends the text: bytes no code reads, which CMD"H" overwrites with a longer text. On this diskette they are a piece of assembler source text (CRLNUM EQU 40ECH ;CURRENT LINE NUMBER, PRGEND EQU) with two other bytes, 0CH and 17H.
448CH - Variables of the Disk Routines
The drive, track and sector of the next transfer, the length byte and data pointer of the sector, the size of a diskette, the stepping rate, the last error status, the format count, the track each drive's head is on and the sector order of a formatted track. 4492H and 4494H are the two bytes the manual tells owners of 35 track or slower drives to POKE before CMD"M" (POKE 17554,35 and POKE 17556,3).
448C
DEFB 01H 01
Drive select bit of the drive to use: 01H, 02H, 04H or 08H for drives 0-3 (the bit the latch at 37E1H needs). 4B55H stores it from the drive number of a DSSSS expression or a CMD drive argument; the initialization sets 01H (drive 0, 4780H). Read by the drive select at 4D47H, 4DC4H, 4DFAH and 4E10H, by the error exit at 4902H and by LOC(0) at 4FCDH.
448D
DEFB 00H 00
Track of the next sector to transfer, 0 to (4492H) - 1. Set by the DSSSS conversion at 4B37H, by CMD"M" (4929H, track 0), by the step to the next sector at 49A8H and by the format loop (4870H-48BBH). Read by the seek at 4D6CH and 4D97H, by the format at 4CC2H and by LOC(0) at 4FDCH. 00H here: track 0, the track of sector 1, which CMD"M" was writing when this copy of the byte was saved.
448E
DEFB 01H 01
Sector of the next transfer within its track, 0 to (4493H) - 1. Set at 4B3BH, 4929H, 4931H and 49A8H, and by the format's check through Register Pair HL (4876H, 48BDH, 48D2H, 48BAH). The seek at 4D77H puts it in the controller's sector register; LOC(0) reads it at 4FE6H. 01H here: sector 1, which CMD"M" was writing when this copy of the byte was saved.
448F
DEFB FFH FF
The length byte of the sector being transferred: the number of data bytes, written as byte 0 of a sector by 4BF6H, and taken from byte 0 of a sector after a read (4BB0H). FFH here: the length of sector 1 (255 data bytes), which CMD"M" was writing when this copy of the byte was saved.
4490-4491
DEFW 4400H 00 44
Data pointer of the sector being transferred: where the data bytes are taken from for a write (4BF6H) or copied to after a read (4BBDH, 4D80H). Set from the string of GET and PUT (4B74H-4B79H), from a field buffer (4B61H), by the chain write (4981H), MERGE's sector read and byte fetch (4A96H, 4A7DH), GET's new string space (4ADCH), LOAD (558CH) and by CMD"M" (4923H). 4400H here: the data of sector 1, which CMD"M" was writing when this copy of the word was saved.
4492
DEFB 28H 28
Number of tracks of a diskette: 28H, 40 tracks (0-39). The DSSSS conversion (4B20H) turns a sector number of 40 x 10 = 400 or more into INVALID SECTOR NUMBER; the format (4878H), the step to the next sector (4991H) and LOC(1) (4FF7H) read it. The manual has owners of 35 track drives POKE 17554,35 here.
4493
DEFB 0AH 0A
Number of sectors of a track: 0AH, 10. Read by the format (4878H), the DSSSS conversion (4B24H), the step to the next sector (4991H), the format (4CA1H) and LOC(0) and LOC(1) (4FD6H, 4FF1H).
4494
DEFB 03H 03
The stepping rate bits of the Seek and Restore commands (bits 1-0): 03H here, 40 ms. Read at 4D9DH and 4DACH. The manual: Percom drives step in 20 milliseconds, and POKE 17556,3 sets 40 milliseconds for drives that cannot step faster.
4495
DEFB 00H 00
The last controller status: the wait at 4DD0H stores it on every pass of every command, the error paths at 48F7H, 4BEEH, 4C65H and 4C89H store the status of the failure, 4D85H sets 00H before each transfer and the initialization 00H (4786H). The error exit at 490FH reports DISK DRIVE NOT AVAILABLE when its bit 7 (NOT READY) is set; LOC(2) returns it (5002H).
4496
DEFB 00H 00
Format count: the number of sectors the last format could not verify, added up at 48B2H, set to 00H by the initialization (4789H) and at the start of a format (487CH); LOC(3) returns it (500BH).
4497-449A
DEFB 00H,FFH,FFH,FFH 00 FF FF FF
The track each drive's head is on, drives 0-3 (4497H drive 0 ... 449AH drive 3). FFH means not known, so the next seek restores the head to track 0 first. The initialization sets all four to FFH (4776H, 4779H), and so does the error exit for the drive that failed (490DH); the seek (4D44H) reads and updates them. Here drive 0 has 00H, track 0, where its head was when CMD"M" wrote this copy, and drives 1-3 have FFH.
449B-44A4
DEFB 00H,05H,01H,06H,02H,07H,03H,08H,04H,09H 00 05 01 06 02 07 03 08 04 09
The order of the sector numbers on a formatted track: 0, 5, 1, 6, 2, 7, 3, 8, 4, 9, one sector skipped between two numbers. The format reads it at 4CA5H.
44A5H - Auto-Type Buffer (44A5H-4525H) and Its Pointer
The characters the keyboard driver at 478FH hands to Level II BASIC as if typed, one each time BASIC asks for a key, up to a 00H byte. The initialization points 4526H at the first one (476DH). CMD"K",A$ (482BH) replaces them with the first 128 characters of a string, a down arrow (0AH) becoming ENTER (0DH), and a 00H after it (4851H); CMD"M" must follow. 129 bytes, 44A5H-4525H; the bytes after the 00H are not used.
44A5-44AF
DEFM 0DH,"LOAD 30,R",0DH 0D 4C 4F 41 44 20 33 30 2C 52 0D
The auto-type text on this diskette: ENTER, which answers the ROM's MEMORY SIZE? question (the initialization ends in the ROM's 00B5H), then LOAD 30,R and ENTER, which loads and runs the BASIC program at sector 30 of drive 0 (the menu on this diskette).
44B0
DEFB 00H 00
The 00H that ends the auto-type text: when the driver at 478FH fetches it, it puts MicroDOS's keyboard scan at 47A3H in its place (479BH-479EH), which goes on in the ROM's driver at 03FBH.
44B1-4525
DEFM 09H,"EQU",09H,"40FBH",09H,09H,";END OF SIMPLE VARIABLESp",17H," ARREND",09H,"EQU",09H,"40FDH",09H,09H,";END OF ARRAYS",A2H,17H,"$ACCUM",09H,"EQU",09H,"4121H",09H,09H,";NUMBER ACCUMULATOR",D4H,17H,1EH,"INBU" 09 45 51 55 09 34 30 46 42 48 09 09 3B 45 4E 44 20 4F 46 20 53 49 4D 50 4C 45 20 56 41 52 49 41 42 4C 45 53 70 17 20 41 52 52 45 4E 44 09 45 51 55 09 34 30 46 44 48 09 09 3B 45 4E 44 20 4F 46 20 41 52 52 41 59 53 A2 17 24 41 43 43 55 4D 09 45 51 55 09 34 31 32 31 48 09 09 3B 4E 55 4D 42 45 52 20 41 43 43 55 4D 55 4C 41 54 4F 52 D4 17 1E 49 4E 42 55
The rest of the auto-type buffer, after the 00H at 44B0H: bytes no code reads, which CMD"K" overwrites with a longer text. On this diskette they are pieces of assembler source text (EQU 40FBH ;END OF SIMPLE VARIABLES, ARREND EQU 40FDH ;END OF ARRAYS, ACCUM EQU 4121H ;NUMBER ACCUMULATOR, INBU) with other bytes among them.
4526-4527
DEFW 44B1H B1 44
Auto-type pointer: the address of the next character the keyboard driver at 478FH hands out. The initialization sets it to 44A5H (476DH) and the driver adds 1 after each character (4795H). 44B1H here, one past the 00H at 44B0H, the value it had when this copy was written by CMD"M".
4528H - Texts: Version and LAST SECTOR USED
The two texts of the main file that the code displays itself through the ROM's 28A7H: the version text at initialization (4761H) and the end of SAVE (4957H).
4528-4580
DEFM "PERCOM MICRODOS VERSION 2.20",0DH,"COPYRIGHT (C) 1979 PERCOM DATA COMPANY",0DH,"ALL RIGHTS RESERVED",0DH,00H 50 45 52 43 4F 4D 20 4D 49 43 52 4F 44 4F 53 20 56 45 52 53 49 4F 4E 20 32 2E 32 30 0D 43 4F 50 59 52 49 47 48 54 20 28 43 29 20 31 39 37 39 20 50 45 52 43 4F 4D 20 44 41 54 41 20 43 4F 4D 50 41 4E 59 0D 41 4C 4C 20 52 49 47 48 54 53 20 52 45 53 45 52 56 45 44 0D 00
The version text, displayed by the initialization (4764H) after the ROM's screen setup: PERCOM MICRODOS VERSION 2.20, COPYRIGHT (C) 1979 PERCOM DATA COMPANY and ALL RIGHTS RESERVED, each followed by 0DH, and the 00H that ends it.
4581-4593
DEFM "LAST SECTOR USED =",00H 4C 41 53 54 20 53 45 43 54 4F 52 20 55 53 45 44 20 3D 00
The text LAST SECTOR USED = and its 00H, displayed at the end of SAVE (495AH), followed by the DSSSS number of the last sector written (495DH-4963H).
4594H - Boot Sector Image (4594H-4693H, Runs at 4200H)
A copy of the boot sector, written by CMD"M" (and CMD"I") as track 0, sector 0 of a diskette (491BH): the byte at 4594H is the length byte FEH and 4595H-4692H are its 254 data bytes; 4693H is not written from here. The rows show the code as it runs: the ROM reads the sector into 4200H-42FFH at a reset and jumps to 4200H, so every address in the comments is 394H below the address of the row (4200H for 4594H). Nothing in the main file runs these bytes where they are. The boot sector checks track 0, sector 1 for MICRODOS, loads the main file from sectors 1-19 into 4400H-55FFH and jumps to 4400H.
4594
CP 00H FE 00
Compare Register A with 00H (runs at 4200H). Register A holds the last byte the ROM took from the controller's data register while reading the boot sector (its 06C4H); the flags are never tested. The first byte, FEH at 4594H, is the length byte of the sector: CMD"M" takes it from here into 448FH (491EH-4920H) and the sector write at 4BF6H writes it as byte 0, followed by the 254 data bytes 4595H-4692H (4201H-42FEH when the sector runs). The second byte, 00H at 4595H, is the first of those data bytes.
4596
LD SP,41FCH 31 FC 41
Load the Stack Pointer with 41FCH. The ROM left it at 407DH (its 0693H). The calls and pushes of the boot sector go below 41FCH: its own deepest use is 41F2H-41FBH (the return address of the read at 4212H or 4247H, the return of 424CH's call to 4275H, the return of the call to 42B9H at 4299H, Register Pair AF pushed at 42B9H and the return of its call to 42C7H). The ROM routines called at 01C9H, 0033H, 0060H and 002BH push more below. 41FCH-41FFH are not used.
4599
GOSUB to the ROM's clear screen routine at 01C9H: it sends 1CH (cursor to 3C00H, the top left corner, and 64 characters a line) and 1FH (clear to the end of the screen) through the display routine. The ROM set up the display's control block at 401DH from its 06D2H table before reading the boot sector, so the display routine works here.
459C
LD BC,4300H 01 00 43
Load Register Pair BC with 4300H, the start of the 256 byte sector buffer 4300H-43FFH. After the EXX at 4211H it is Register Pair BC', the pointer the read loop at 4263H stores each byte through.
459F
LD DE,37ECH 11 EC 37
Load Register Pair DE with 37ECH, the controller's command register (written) and status register (read). After the EXX at 4211H it is Register Pair DE', through which 425DH, 4267H, 42BFH, 42C0H and 42CDH read the status and write the commands.
45A2
LD HL,37EFH 21 EF 37
Load Register Pair HL with 37EFH, the controller's data register. After the EXX at 4211H it is Register Pair HL', from which the read loop takes each byte of a sector (4262H).
45A5
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: BC' = 4300H (buffer pointer), DE' = 37ECH (command and status) and HL' = 37EFH (data) for the whole boot. The main set is left free for the signature check, the copy and the texts; each routine below that works the controller through the alternate set starts and ends with EXX.
45A6
GOSUB to 424CH to read the sector named by 42DDH (track, 00H) and 42DEH (sector, 01H): track 0, sector 1, the first sector of the MicroDOS main file, into the buffer 4300H-43FFH. 424CH comes back only when the read had no error; an error goes to DISK ERROR at 42A2H.
45A9H - Boot Sector Image: Check for MICRODOS (Runs at 4215H)
The first sector of the main file carries the eight characters MICRODOS at bytes 4-11 (its byte 0 is the length byte FFH and bytes 1-3 are the JP 4727H that becomes 4400H-4402H of the main file). They are compared with the same eight characters in the boot sector; a diskette that does not have them gets NO MICRODOS.
45A9
LD DE,42F1H 11 F1 42
Point Register Pair DE to 42F1H, the eight characters MICRODOS in the boot sector (they are also the end of the NO MICRODOS text that starts at 42ECH).
45AC
LD HL,4304H 21 04 43
Point Register Pair HL to 4304H, byte 4 of the sector just read into the buffer: where the main file's MICRODOS (its 4403H-440AH) is when the first sector is in the buffer.
45AF
LD B,08H 06 08
Load Register B with 08H, the number of characters to compare.
45B1
LD A,(DE) 1A
Fetch the next character of MICRODOS in the boot sector (Register Pair DE, 42F1H-42F8H) into Register A.
45B2
CP (HL) BE
Compare Register A with the byte at the same place in the buffer (Register Pair HL, 4304H-430BH).
45B3
If they differ, track 0, sector 1 of the diskette in drive 0 is not MicroDOS's: JUMP to 42A7H to display NO MICRODOS.
45B6
INC DE 13
Point Register Pair DE to the next character of MICRODOS in the boot sector.
45B7
INC HL 23
Point Register Pair HL to the next byte of the buffer.
45B8
Decrement Register B, the characters left to compare, and LOOP BACK to 421DH (45B1H in this image) until all eight have matched. Register Pair HL then holds 430CH, the byte after MICRODOS in the buffer.
45BAH - Boot Sector Image: Sign-On Text and Load of the Main File (Runs at 4226H)
The text after MICRODOS in the first sector is displayed, then the data bytes of the first sector and of each sector after it are copied to 4400H upward. A sector whose length byte is FFH (255 data bytes) means more sectors follow; a sector with any other length is the last one, and the boot jumps to 4400H. On this diskette the main file is 19 sectors, track 0 sectors 1-9 and track 1 sectors 0-9, the last with the length 12H: 18 x 255 + 18 = 4608 bytes, 4400H-55FFH.
45BA
GOSUB to 42D4H to display the text at Register Pair HL (430CH in the buffer, which becomes 440BH of the main file) up to its 00H byte: A SIMPLE, POWERFUL DOS, WRITTEN BY JAMES W. STUTSMAN and FOR PERCOM DATA COMPANY, each followed by 0DH (new line), and one more 0DH for a blank line. The screen was cleared at 4205H, so the text starts at the top left corner.
45BD
LD DE,4400H 11 00 44
Point Register Pair DE to 4400H, where the main file goes: the data bytes of each sector are copied there one after the other.
45C0
LD B,00H 06 00
Load Register B with 00H, the high byte of the count of bytes to copy (a sector holds at most 255 data bytes). The loop comes back here after each further sector is read.
45C2
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, byte 0 of the sector in the buffer: its length byte.
45C5
LD C,(HL) 4E
Load Register C with the length byte at 4300H (Register Pair HL): FFH for every sector of the main file but the last, 12H for the last one. Register Pair BC is now the number of data bytes to copy (00FFH or 0012H). A length byte of 00H would make Register Pair BC 0000H and the copy run for 65536 bytes; no sector of the main file has one.
45C6
LD A,(HL) 7E
Load Register A with the same length byte from 4300H (Register Pair HL), for the test at 4236H.
45C7
INC HL 23
Point Register Pair HL to 4301H, the first data byte of the sector.
45C8
LDIR ED B0
Copy Register Pair BC bytes from the buffer (Register Pair HL, from 4301H) to the main file's place (Register Pair DE). Register Pair DE ends one byte past the last byte copied, where the next sector's data bytes go; Register Pair BC ends 0000H.
45CA
INC A 3C
Increment Register A, the length byte: FFH becomes 00H and sets the Z flag; any other length leaves NZ.
45CB
If the sector just copied was not a full one (its length byte was not FFH), the whole main file is in memory: JUMP to 4400H, the first instruction of the main file, JP 4727H (runs at 4237H). After the 19 sectors CMD"M" writes, that happens after track 1, sector 9 (length 12H), with Register Pair DE = 5600H, one past the last byte loaded, Register A = 13H and the Stack Pointer still at 41FCH.
45CE
LD HL,42DEH 21 DE 42
Point Register Pair HL to 42DEH, the sector number of the sector to read next.
45D1
LD A,09H 3E 09
Load Register A with 09H, the highest sector number of a track (sectors 0-9).
45D3
INC (HL) 34
Add 1 to the sector number at 42DEH (Register Pair HL): the sector after the one just copied.
45D4
CP (HL) BE
Compare 09H in Register A with the new sector number at 42DEH (Register Pair HL): the Carry flag is set when the sector number has passed 9.
45D5
If the sector number is 9 or less, it is on the same track: JUMP to 4247H (45DBH in this image) to read it.
45D7
LD (HL),00H 36 00
Otherwise the track is finished: set the sector number at 42DEH (Register Pair HL) to 00H.
45D9
DEC HL 2B
Point Register Pair HL to 42DDH, the track number.
45DA
INC (HL) 34
Add 1 to the track number at 42DDH (Register Pair HL): the next sector is sector 0 of the next track.
45DB
GOSUB to 424CH to read the sector named by 42DDH (track) and 42DEH (sector) into the buffer 4300H-43FFH: on this diskette track 0 sectors 2-9, then track 1 sectors 0-9.
45DE
LOOP BACK to 422CH (45C0H in this image) to copy the data bytes of the sector just read.
45E0H - Boot Sector Image: Read One Sector (Runs at 424CH)
Reads the sector of drive 0 named by 42DDH (track) and 42DEH (sector) into the buffer 4300H-43FFH, taking each byte from the data register when the controller shows DATA REQUEST. It returns only after a read without error, with the alternate set holding 4300H, 37ECH and 37EFH again; an error goes to DISK ERROR at 42A2H and does not return.
45E0
GOSUB to 4275H to select drive 0 (waiting for it when it was not ready), seek the head to the track at 42DDH and put the sector number at 42DEH in the sector register. 4275H comes back only when the seek had no error.
45E3
LD A,88H 3E 88
Load Register A with 88H, the Read Sector command.
| 1771 FDC Command: 88H (10001000) | | Function Description |
| 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | | Command=Read Sector (bits 7-5 = 100) m = 0: one sector b = 1: IBM sector length E = 0: no head load delay |
45E5
GOSUB to 42B9H to wait until the controller is not busy, write the command in Register A (88H) to 37ECH and wait until the controller shows BUSY.
45E8
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: BC = 4300H (the buffer pointer), DE = 37ECH (the status register), HL = 37EFH (the data register).
45E9
JUMP to 425DH (45F1H in this image) to read the status for the first byte.
45EB
AND 81H E6 81
No byte was waiting. Keep bit 7 (NOT READY) and bit 0 (BUSY) of the status in Register A.
45ED
XOR 01H EE 01
Flip bit 0 of Register A: the result is 00H only while the controller is busy and the drive is ready.
45EF
If the controller has finished (BUSY is off) or the drive is not ready, the read is over: JUMP to 4267H (45FBH in this image) to check its status.
45F1
LD A,(DE) 1A
Fetch the controller's status from 37ECH (Register Pair DE) into Register A.
45F2
BIT 1,A CB 4F
Test bit 1 of Register A, DATA REQUEST: 1 when a byte of the sector is waiting in the data register.
45F4
If no byte is waiting, JUMP to 4257H (45EBH in this image) to see whether the read is still running.
45F6
LD A,(HL) 7E
Fetch the byte from the data register 37EFH (Register Pair HL) into Register A.
45F7
LD (BC),A 02
Store Register A in the buffer at Register Pair BC (4300H for the first byte of the sector).
45F8
INC BC 03
Point Register Pair BC to the next byte of the buffer.
45F9
LOOP BACK to 425DH (45F1H in this image) to wait for the next byte of the sector; Register Pair BC points where it goes.
45FB
LD A,(DE) 1A
Fetch the status after the read from 37ECH (Register Pair DE) into Register A.
45FC
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = 37ECH, DE = 37EFH.
45FD
LD (HL),D0H 36 D0
Write D0H to the command register 37ECH (Register Pair HL): Force Interrupt, which ends any command that is still running.
| 1771 FDC Command: D0H (11010000) | | Function Description |
| 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | | Command=Force Interrupt (bits 7-4 = 1101) I3-I0 = 0000: end the command, no interrupt |
45FF
EX DE,HL EB
Exchange Register Pairs DE and HL back: DE = 37ECH, HL = 37EFH.
4600
AND 9CH E6 9C
Keep the error bits of the status in Register A: bit 7 NOT READY, bit 4 RECORD NOT FOUND, bit 3 CRC ERROR and bit 2 LOST DATA.
4602
If any of them is set, JUMP to 42A2H (4636H in this image) to display DISK ERROR. The return addresses stay on the stack; that path ends with a reset of the computer.
4604
LD BC,4300H 01 00 43
Set Register Pair BC back to 4300H, the start of the buffer, for the next read.
4607
EXX D9
Exchange back to the main register set; the alternate set keeps 4300H, 37ECH and 37EFH.
4608
RET C9
RETURN to the caller with the sector in 4300H-43FFH.
4609H - Boot Sector Image: Select Drive 0 and Seek (Runs at 4275H)
Selects drive 0. If the drive was not ready before the select (its motor was off), waits about one second for the motor to come up to speed. Then puts the track from 42DDH in the data register and the sector from 42DEH in the sector register and gives the Seek command with verify. Returns when the seek had no error; with an error it falls into DISK ERROR at 42A2H.
4609
LD A,(37ECH) 3A EC 37
Fetch the controller's status from 37ECH into Register A, before drive 0 is selected again.
460C
RLCA 07
Rotate Register A left: bit 7 of the status, NOT READY, goes into the Carry flag.
460D
LD A,01H 3E 01
Load Register A with 01H, the select bit of drive 0.
| Drive Select Latch: 01H (00000001) | | Function Description |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | | Bits 0-3: one bit per drive drive 0 selected |
460F
LD (37E1H),A 32 E1 37
Store Register A (01H) to the drive select latch at 37E1H: drive 0 is selected and its motor runs.
4612
If the drive was ready (NOT READY was 0, Carry clear), JUMP to 428BH (461FH in this image) to seek.
4614
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H, the longest count of the ROM's delay.
4617
GOSUB to the ROM's delay at 0060H: with Register Pair BC = 0000H it loops 65536 times, about 0.96 second, so the drive motor comes up to speed. It returns with Register Pair BC = 0000H.
461A
LD A,01H 3E 01
Load Register A with 01H, the select bit of drive 0.
461C
LD (37E1H),A 32 E1 37
Store Register A (01H) to the drive select latch at 37E1H once more, so drive 0 stays selected with its motor running.
461F
LD A,(42DDH) 3A DD 42
Fetch the track to read from 42DDH into Register A (00H for track 0, 01H for track 1).
4622
LD (37EFH),A 32 EF 37
Store Register A in the data register 37EFH: the Seek command takes the track to go to from there.
4625
LD A,(42DEH) 3A DE 42
Fetch the sector to read from 42DEH into Register A.
4628
LD (37EEH),A 32 EE 37
Store Register A in the sector register 37EEH, for the Read Sector command that follows the seek.
462B
LD A,17H 3E 17
Load Register A with 17H, the Seek command with verify.
| 1771 FDC Command: 17H (00010111) | | Function Description |
| 0 | 0 | 0 | 1 | 0 | 1 | 1 | 1 | | Command=Seek (bits 7-4 = 0001) h = 0: no head load delay V = 1: verify the track ID r1 r0 = 11: 40 ms stepping rate |
462D
GOSUB to 42B9H to wait until the controller is not busy, write the Seek command in Register A (17H) to 37ECH and wait until the controller shows BUSY.
4630
GOSUB to 42C7H to wait until the seek is finished (BUSY off). Register A comes back with the status from 37ECH.
4633
AND 98H E6 98
Keep the error bits of the status after a seek in Register A: bit 7 NOT READY, bit 4 SEEK ERROR (no ID field of the track was found when verifying) and bit 3 CRC ERROR (an ID field read when verifying was bad).
4635
RET Z C8
If none of them is set, RETURN to 424FH: the head is on the track. Otherwise fall through into 42A2H to display DISK ERROR.
4636H - Boot Sector Image: Disk Error and No MicroDOS (Runs at 42A2H)
The two ways the boot can fail. A read or seek error displays DISK ERROR; a diskette without MICRODOS in track 0, sector 1 displays NO MICRODOS. Either way the screen is cleared, the text is displayed on the second line, and a key press resets the computer, which boots from drive 0 again.
4636
LD HL,42DFH 21 DF 42
Point Register Pair HL to 42DFH, the DISK ERROR text. A seek error falls through to here from 42A1H; a read error jumps here from 426EH.
4639
JUMP to 42AAH (463EH in this image) to display the DISK ERROR text at Register Pair HL (42DFH).
463B
LD HL,42ECH 21 EC 42
The check at 421FH jumps here. Point Register Pair HL to 42ECH, the NO MICRODOS text.
463E
GOSUB to the ROM's clear screen routine at 01C9H: cursor to the top left corner in 64 characters a line, and clear the screen. Register Pair HL keeps the address of the text.
4641
GOSUB to 42D4H to display the text at Register Pair HL. Both texts start with 17H (32 characters a line) and E8H (40 spaces, two screen positions each in that mode), so the message starts on the second line of the screen, eight characters in.
4644
GOSUB to the ROM's keyboard scan at 002BH: Register A comes back with the character of a key just pressed, or 00H when no key is pressed.
4647
OR A B7
Test Register A, the character from the keyboard.
4648
If Register A is 00H (no key was pressed), LOOP BACK to 42B0H (4644H in this image) to scan the keyboard again.
464A
JUMP to 0000H, the ROM's reset: it boots from drive 0 again, so another diskette can be tried. With BREAK held down there, the ROM starts BASIC without the disk instead (its 068BH-0690H).
464DH - Boot Sector Image: Give the Controller a Command (Runs at 42B9H)
Entered with the command in Register A (88H Read Sector from 4251H, 17H Seek from 4299H). Waits until the controller is not busy, writes the command and waits until the controller shows BUSY, so that the next status read belongs to the new command.
464D
PUSH AF F5
Save Register Pair AF on the stack: Register A holds the command (88H or 17H), which the wait at 42C7H would change.
464E
GOSUB to 42C7H to wait until the controller is not busy.
4651
POP AF F1
Restore Register Pair AF from the stack: Register A holds the command again (88H or 17H).
4652
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: DE = 37ECH.
4653
LD (DE),A 12
Write the command in Register A to the command register 37ECH (Register Pair DE).
4654
LD A,(DE) 1A
Fetch the status from 37ECH (Register Pair DE) into Register A.
4655
BIT 0,A CB 47
Test bit 0 of Register A (the status from 37ECH): BUSY, 1 while the controller works on a command.
4657
LOOP BACK to 42C0H (4654H in this image) until BUSY is on: the controller has started the command.
4659
EXX D9
EXX: exchange back to the main register set; the alternate set keeps 4300H, 37ECH and 37EFH.
465A
RET C9
RETURN to the caller: the controller has started the command that is in Register A.
465BH - Boot Sector Image: Wait While the Controller Is Busy (Runs at 42C7H)
Reads the status until BUSY is off, selecting drive 0 again on every pass so that its motor keeps running for as long as the command lasts. Returns the last status in Register A.
465B
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: DE = 37ECH.
465C
LD A,01H 3E 01
Load Register A with 01H, the select bit of drive 0.
465E
LD (37E1H),A 32 E1 37
Store Register A (01H) to the drive select latch at 37E1H on every pass: drive 0 stays selected and its motor keeps running.
4661
LD A,(DE) 1A
Fetch the status from 37ECH (Register Pair DE) into Register A.
4662
BIT 0,A CB 47
Test bit 0 of Register A (the status from 37ECH): BUSY, 1 while the controller works on a command.
4664
LOOP BACK to 42C8H (465CH in this image) while the controller is busy.
4666
EXX D9
EXX: exchange back to the main register set (the alternate set keeps 4300H, 37ECH and 37EFH). Register A keeps the last status, with BUSY off.
4667
RET C9
RETURN to the caller with the status in Register A.
4668H - Boot Sector Image: Display a Text (Runs at 42D4H)
Displays the text at Register Pair HL through the ROM, one character at a time, up to the 00H byte that ends it. Used for the sign-on text from the first sector (4226H) and for the two error texts (42ADH).
4668
LD A,(HL) 7E
Fetch the next character of the text at Register Pair HL into Register A.
4669
OR A B7
Test Register A, the character just fetched: 00H ends the text.
466A
RET Z C8
If it is 00H, RETURN to the caller, with Register Pair HL pointing at the 00H.
466B
GOSUB to the ROM's display routine at 0033H to display the character in Register A at the cursor. Control codes act: 0DH starts a new line, 17H sets 32 characters a line, C0H-FFH display (code - C0H) spaces. The routine keeps Register Pair HL and leaves Register Pair DE holding 401DH, the display's control block.
466E
INC HL 23
Point Register Pair HL to the next character of the text.
466F
LOOP BACK to 42D4H (4668H in this image) for the next character of the text at Register Pair HL.
4671H - Boot Sector Image: Track and Sector Numbers and Texts (Runs at 42DDH)
The two variables of the load and the texts of the boot. The bytes up to 42FEH are the 254 data bytes the length byte at 4200H counts; 42FFH is the last byte of the sector.
4671
DEFB 00H 00
The track of the sector to read: 00H as the sector is written, so the first read is on track 0. 4246H adds 1 when the sector number passes 9 (01H for track 1); 428BH puts it in the data register for the seek.
4672
DEFB 01H 01
The sector to read: 01H as the sector is written, so the first read is track 0, sector 1, the first sector of the main file. 423FH adds 1 after each sector is copied and 4243H sets it to 00H at the start of a new track; 4291H puts it in the sector register.
4673-467F
DEFM 17H,E8H,"DISK ERROR",00H 17 E8 44 49 53 4B 20 45 52 52 4F 52 00
The DISK ERROR text, displayed by 42ADH after a read or seek error: 17H (32 characters a line), E8H (40 spaces), DISK ERROR, and the 00H that ends it.
4680-4684
DEFM 17H,E8H,"NO " 17 E8 4E 4F 20
The start of the NO MICRODOS text, displayed by 42ADH when track 0, sector 1 does not have MICRODOS: 17H (32 characters a line), E8H (40 spaces) and NO followed by a space. It has no 00H; the text runs on into MICRODOS at 42F1H.
4685-468D
DEFM "MICRODOS",00H 4D 49 43 52 4F 44 4F 53 00
The eight characters MICRODOS that the check at 421DH compares with bytes 4-11 of the first sector (4304H-430BH), and at the same time the end of the NO MICRODOS text from 42ECH, ended by the 00H at 42F9H.
468E-4692
DEFM "$STEP" 24 53 54 45 50
Five bytes that no code reads (42FAH-42FEH when the sector runs), the last of the 254 data bytes that the length byte FEH counts.
4693
DEFB 4CH 4C
The 256th byte of the image, L (42FFH when the sector runs). It is not one of the 254 data bytes the length byte FEH counts, so CMD"M" does not write it: the sector write at 4BF6H copies the length byte and the 254 data bytes into its buffer at 4300H and writes the buffer, so the last byte of sector 0 on the diskette is whatever 43FFH held (48H on this diskette). Nothing reads it.
4694H - Level II BASIC Vectors (Copied to 4152H-41E4H)
Level II BASIC sends the disk statements and functions and a set of hooks through 3 byte vectors at 4152H-41E4H, which the ROM fills with JP 012DH (error 23) for the 28 statements and functions and with RET for the 21 hooks. The initialization copies these 49 jumps over them (4741H-474AH). CMD, GET, PUT, LOAD, MERGE and SAVE go straight to their code; the other statements and functions MicroDOS has, and the & of a constant, go through the jump table at 4E19H; EOF, TIME$, OPEN, CLOSE, NAME and KILL keep JP 012DH. Four hooks are used (the error message hook 41A6H, USR 41A9H, NEW and END 41BBH, MID$ 41D9H) and the rest jump to the ROM's RET at 0043H. The rows run at 4152H-41E4H; nothing runs them here.
4694
Copied to 4152H-4154H, the vector of the CVI function (token E6H). JUMP to the entry at 4E25H of MicroDOS's jump table.
4697
Copied to 4155H-4157H, the vector of FN (a call of a DEF FN function) (token BEH, from the ROM's 2524H). JUMP to the entry at 4E43H of MicroDOS's jump table.
469A
Copied to 4158H-415AH, the vector of the CVS function (token E7H). JUMP to the entry at 4E28H of MicroDOS's jump table.
469D
Copied to 415BH-415DH, the vector of the DEF statement (token B0H). JUMP to the entry at 4E3DH of MicroDOS's jump table.
46A0
Copied to 415EH-4160H, the vector of the CVD function (token E8H). JUMP to the entry at 4E2BH of MicroDOS's jump table.
46A3
Copied to 4161H-4163H, the vector of the EOF function (token E9H). JUMP to the ROM's 012DH, which reports error 23 (E = 2CH): MicroDOS has no such statement or function and its message list calls it FEATURE NOT IMPLEMENTED.
46A6
Copied to 4164H-4166H, the vector of the LOC function (token EAH). JUMP to the entry at 4E4FH of MicroDOS's jump table.
46A9
Copied to 4167H-4169H, the vector of the LOF function (token EBH). JUMP to the entry at 4E4CH of MicroDOS's jump table.
46AC
Copied to 416AH-416CH, the vector of the MKI$ function (token ECH). JUMP to the entry at 4E1CH of MicroDOS's jump table.
46AF
Copied to 416DH-416FH, the vector of the MKS$ function (token EDH). JUMP to the entry at 4E1FH of MicroDOS's jump table.
46B2
Copied to 4170H-4172H, the vector of the MKD$ function (token EEH). JUMP to the entry at 4E22H of MicroDOS's jump table.
46B5
Copied to 4173H-4175H, the vector of the CMD statement (token 85H). JUMP to MicroDOS's 47C9H.
46B8
Copied to 4176H-4178H, the vector of the TIME$ function (token C7H, from the ROM's 2510H). JUMP to the ROM's 012DH, which reports error 23 (E = 2CH): MicroDOS has no such statement or function and its message list calls it FEATURE NOT IMPLEMENTED.
46BB
Copied to 4179H-417BH, the vector of the OPEN statement (token A2H). JUMP to the ROM's 012DH, which reports error 23 (E = 2CH): MicroDOS has no such statement or function and its message list calls it FEATURE NOT IMPLEMENTED.
46BE
Copied to 417CH-417EH, the vector of the FIELD statement (token A3H). JUMP to the entry at 4E19H of MicroDOS's jump table.
46C1
Copied to 417FH-4181H, the vector of the GET statement (token A4H). JUMP to MicroDOS's 4AAEH.
46C4
Copied to 4182H-4184H, the vector of the PUT statement (token A5H). JUMP to MicroDOS's 4AE4H.
46C7
Copied to 4185H-4187H, the vector of the CLOSE statement (token A6H). JUMP to the ROM's 012DH, which reports error 23 (E = 2CH): MicroDOS has no such statement or function and its message list calls it FEATURE NOT IMPLEMENTED.
46CA
Copied to 4188H-418AH, the vector of the LOAD statement (token A7H). JUMP to MicroDOS's 49AEH.
46CD
Copied to 418BH-418DH, the vector of the MERGE statement (token A8H). JUMP to MicroDOS's 49F6H.
46D0
Copied to 418EH-4190H, the vector of the NAME statement (token A9H). JUMP to the ROM's 012DH, which reports error 23 (E = 2CH): MicroDOS has no such statement or function and its message list calls it FEATURE NOT IMPLEMENTED.
46D3
Copied to 4191H-4193H, the vector of the KILL statement (token AAH). JUMP to the ROM's 012DH, which reports error 23 (E = 2CH): MicroDOS has no such statement or function and its message list calls it FEATURE NOT IMPLEMENTED.
46D6
Copied to 4194H-4196H, the vector of the & of a constant (&H) (from the ROM's 24C8H). JUMP to the entry at 4E3AH of MicroDOS's jump table.
46D9
Copied to 4197H-4199H, the vector of the LSET statement (token ABH). JUMP to the entry at 4E2EH of MicroDOS's jump table.
46DC
Copied to 419AH-419CH, the vector of the RSET statement (token ACH). JUMP to the entry at 4E31H of MicroDOS's jump table.
46DF
Copied to 419DH-419FH, the vector of the INSTR function (token C5H, from the ROM's 2506H). JUMP to the entry at 4E58H of MicroDOS's jump table.
46E2
Copied to 41A0H-41A2H, the vector of the SAVE statement (token ADH). JUMP to MicroDOS's 4941H.
46E5
Copied to 41A3H-41A5H, the vector of the LINE statement (token 9CH). JUMP to the entry at 4E37H of MicroDOS's jump table.
46E8
Copied to 41A6H-41A8H, the vector of the error message hook (called by the ROM at 19ECH before it displays an error). JUMP to the entry at 4E34H of MicroDOS's jump table.
46EB
Copied to 41A9H-41ABH, the vector of the USR hook (called by the ROM at 27FEH). JUMP to the entry at 4E40H of MicroDOS's jump table.
46EE
Copied to 41ACH-41AEH, the vector of the READY hook (called by the ROM at 1A1CH). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
46F1
Copied to 41AFH-41B1H, the vector of the keyboard line input hook (called by the ROM at 0368H). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
46F4
Copied to 41B2H-41B4H, the vector of the hook after a line is tokenized (called by the ROM at 1AA1H). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
46F7
Copied to 41B5H-41B7H, the vector of the hook after a program line is stored (called by the ROM at 1AECH). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
46FA
Copied to 41B8H-41BAH, the vector of the hook after the line pointers and CLEAR (called by the ROM at 1AF2H). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
46FD
Copied to 41BBH-41BDH, the vector of the NEW and END hook (called by the ROM at 1B8CH and 1DB0H). JUMP to the entry at 4E49H of MicroDOS's jump table.
4700
Copied to 41BEH-41C0H, the vector of the PRINT hook (called by the ROM at 2174H). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
4703
Copied to 41C1H-41C3H, the vector of the character output hook (called by the ROM at 032CH). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
4706
Copied to 41C4H-41C6H, the vector of the keyboard scan hook (called by the ROM at 0358H). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
4709
Copied to 41C7H-41C9H, the vector of the RUN hook (called by the ROM at 1EA6H). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
470C
Copied to 41CAH-41CCH, the vector of the PRINT item hook (called by the ROM at 206FH). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
470F
Copied to 41CDH-41CFH, the vector of the number output hook (called by the ROM at 20C6H). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
4712
Copied to 41D0H-41D2H, the vector of the PRINT end of line hook (called by the ROM at 2103H). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
4715
Copied to 41D3H-41D5H, the vector of the TAB and comma hook (called by the ROM at 2108H and 2141H). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
4718
Copied to 41D6H-41D8H, the vector of the INPUT hook (called by the ROM at 219EH). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
471B
Copied to 41D9H-41DBH, the vector of the MID$ statement hook (jumped to by the ROM at 2AECH when MID$ starts a statement). JUMP to the entry at 4E55H of MicroDOS's jump table.
471E
Copied to 41DCH-41DEH, the vector of the READ and INPUT assignment hook (called by the ROM at 222DH). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
4721
Copied to 41DFH-41E1H, the vector of the hook after INPUT and LIST (called by the ROM at 2278H and 2B44H). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
4724
Copied to 41E2H-41E4H, the vector of the SYSTEM hook (called by the ROM at 02B2H). JUMP to the ROM's 0043H, a RET: the hook does nothing, as with the RET the ROM puts in the hooks.
4727H - Initialization
The boot sector jumps here through 4400H. The initialization does what the ROM's own BASIC start-up (0075H-00B2H) does, without its clear screen (00B2H), with 40A0H set to 5A64H for the stack, and with three changes: the 49 vectors at 4152H-41E4H get MicroDOS's jumps; BASIC programs start at 5A01H instead of 42E9H, which leaves 5600H-59FFH for the four field buffers; and the keyboard driver is MicroDOS's auto-type driver at 478FH. It displays the version text, sets the disk variables and jumps into the ROM's MEMORY SIZE? question at 00B5H, which the first auto-typed character (ENTER) answers.
4727
LD DE,4080H 11 80 40
Point Register Pair DE to 4080H, the RAM area that receives the ROM's table of BASIC variables and its division routine.
472A
LD HL,18F7H 21 F7 18
Point Register Pair HL to 18F7H, the start of that table in the ROM.
472D
LD BC,0027H 01 27 00
Load Register Pair BC with 0027H, its length: 39 bytes.
4730
LDIR ED B0
Copy the 39 bytes from 18F7H-191DH (Register Pair HL) to 4080H-40A6H (Register Pair DE), as the ROM does at 0075H-007EH. Register Pair BC ends 0000H.
4732
LD HL,41E5H 21 E5 41
Point Register Pair HL to 41E5H, the three bytes before the keyboard input buffer at 41E8H.
4735
LD (HL),3AH 36 3A
Store 3AH (:) at 41E5H (Register Pair HL), as the ROM does at 0083H.
4737
INC HL 23
Point Register Pair HL to 41E6H, the second of the three bytes before the input buffer.
4738
LD (HL),00H 36 00
Store 00H at 41E6H (Register Pair HL), as the ROM does at 0086H with its Register B = 00H.
473A
INC HL 23
Point Register Pair HL to 41E7H, the third of the three bytes before the input buffer.
473B
LD (HL),2CH 36 2C
Store 2CH (,) at 41E7H (Register Pair HL), as the ROM does at 0088H.
473D
INC HL 23
Point Register Pair HL to 41E8H, the start of the keyboard input buffer.
473E
LD (40A7H),HL 22 A7 40
Store Register Pair HL (41E8H) at 40A7H-40A8H, the ROM's pointer to the keyboard input buffer, as the ROM does at 008BH.
4741
LD DE,4152H 11 52 41
Point Register Pair DE to 4152H, the first of the 49 three byte vectors Level II BASIC sends its disk statements, disk functions and hooks through.
4744
LD HL,4694H 21 94 46
Point Register Pair HL to 4694H, MicroDOS's 49 jumps for them.
4747
LD BC,0093H 01 93 00
Load Register Pair BC with 0093H, the length: 147 bytes (49 x 3).
474A
LDIR ED B0
Copy 4694H-4726H (Register Pair HL) to 4152H-41E4H (Register Pair DE): from here on the ROM's disk statements and functions and the hooks go to MicroDOS. Register Pair BC ends 0000H.
474C
LD HL,5A64H 21 64 5A
Load Register Pair HL with 5A64H, an address in the RAM above the first BASIC program, for 40A0H.
474F
LD (40A0H),HL 22 A0 40
Store Register Pair HL (5A64H) at 40A0H-40A1H, the ROM's start of string space. The ROM's 1B8FH called at 475EH sets the stack from it; the ROM's MEMORY SIZE? code (00B5H) sets 40A0H again from the top of memory.
4752
LD HL,5A00H 21 00 5A
Point Register Pair HL to 5A00H, the byte before the first BASIC program line.
4755
LD (HL),00H 36 00
Store 00H at 5A00H (Register Pair HL), the 00H byte that Level II BASIC needs before the first line of a program (the ROM's own start-up puts it at 42E8H).
4757
INC HL 23
Point Register Pair HL to 5A01H, where the first line of a BASIC program goes.
4758
LD (40A4H),HL 22 A4 40
Store Register Pair HL (5A01H) at 40A4H-40A5H, the ROM's start of the BASIC program. Programs start at 5A01H under MicroDOS, above the four 256 byte field buffers at 5600H-59FFH.
475B
LD SP,41F8H 31 F8 41
Load the Stack Pointer with 41F8H, as the ROM does at 00ACH, for the call below.
475E
GOSUB to the ROM's 1B8FH: it takes its return address off the stack, sets 40E8H to (40A0H) less 2 (5A62H) and the Stack Pointer to (40A0H), 5A64H, resets the pointer of the temporary strings at 40B3H to 40B5H, makes the video the output device (409CH = 00H), clears 40DCH, pushes 0000H and returns: the stack now lies below 5A64H.
4761
LD HL,4528H 21 28 45
Point Register Pair HL to 4528H, the version text PERCOM MICRODOS VERSION 2.20, COPYRIGHT (C) 1979 PERCOM DATA COMPANY, ALL RIGHTS RESERVED.
4764
GOSUB to the ROM's 28A7H to display the text at Register Pair HL up to its 00H byte. The screen still holds the sign-on text the boot sector displayed, so the version text follows it.
4767
LD HL,478FH 21 8F 47
Point Register Pair HL to 478FH, MicroDOS's auto-type keyboard driver.
476A
LD (4016H),HL 22 16 40
Store Register Pair HL (478FH) at 4016H-4017H, the driver address of the keyboard's control block at 4015H: each time the ROM asks the keyboard for a key (002BH), it calls 478FH instead of its own driver at 03E3H.
476D
LD HL,44A5H 21 A5 44
Point Register Pair HL to 44A5H, the first character of the auto-type text.
4770
LD (4526H),HL 22 26 45
Store Register Pair HL (44A5H) at 4526H-4527H, the auto-type pointer the driver at 478FH reads.
4773
LD HL,FFFFH 21 FF FF
Load Register Pair HL with FFFFH, the value that marks a head position as not known.
4776
LD (4497H),HL 22 97 44
Store Register Pair HL (FFFFH) at 4497H-4498H: the head of drive 0 and of drive 1 is on an unknown track, so the first seek on either drive restores it to track 0 first (4D64H-4D69H).
4779
LD (4499H),HL 22 99 44
Store Register Pair HL (FFFFH) at 4499H-449AH: the same for drives 2 and 3.
477C
INC HL 23
Increment Register Pair HL from FFFFH to 0000H.
477D
LD (448DH),HL 22 8D 44
Store Register Pair HL (0000H) at 448DH-448EH: track 0, sector 0, the position of the next transfer.
4780
LD A,01H 3E 01
Load Register A with 01H, the select bit of drive 0.
4782
LD (448CH),A 32 8C 44
Store Register A (01H) at 448CH: drive 0 is the drive of the next transfer.
4785
XOR A AF
Load Register A with 00H (XOR A also clears the Carry flag), for the two stores below.
4786
LD (4495H),A 32 95 44
Store Register A (00H) at 4495H, the status of the last disk error: none.
4789
LD (4496H),A 32 96 44
Store Register A (00H) at 4496H, the count of sectors the last format could not verify: none.
478C
JUMP to the ROM's 00B5H, which displays MEMORY SIZE? and reads a line from the keyboard. The auto-type driver answers it with the ENTER at 44A5H (all memory), then types LOAD 30,R and ENTER, so the ROM sets the top of memory, displays its sign-on and READY, and BASIC loads and runs the program at sector 30.
478FH - Auto-Type Keyboard Driver
The ROM calls this as the keyboard driver (4016H), through its 03C2H, each time it wants a key. It hands out the characters of the auto-type text one at a time, from the address at 4526H, as if they were typed. When it reaches the 00H that ends the text, it puts MicroDOS's keyboard scan at 47A3H in the control block in its place and reports no key; from then on the keyboard works normally. The ROM saves Register Pair BC (its 0013H), Register Pairs HL and DE and Index Register IX (its 03C2H) around the driver, so it may use them.
478F
LD DE,(4526H) ED 5B 26 45
Load Register Pair DE with the auto-type pointer from 4526H-4527H: the address of the next character to hand out (44A5H for the first).
4793
LD A,(DE) 1A
Fetch the character at Register Pair DE into Register A.
4794
INC DE 13
Point Register Pair DE to the character after it.
4795
LD (4526H),DE ED 53 26 45
Store Register Pair DE at 4526H-4527H, so the next call hands out the next character.
4799
OR A B7
Test Register A, the character fetched: 00H ends the text.
479A
RET NZ C0
If it is not 00H, RETURN to the ROM with the character in Register A, as if that key had been pressed.
479B
LD DE,47A3H 11 A3 47
The text is finished. Load Register Pair DE with 47A3H, MicroDOS's keyboard scan.
479E
LD (4016H),DE ED 53 16 40
Store Register Pair DE (47A3H) at 4016H-4017H, the driver address of the keyboard's control block: from now on the ROM's key requests go to the keyboard scan at 47A3H.
47A2
RET C9
RETURN to the ROM with Register A = 00H: no key this time.
47A3H - Keyboard Scan with Debounce
The keyboard driver after the auto-type text is finished. It is the ROM's keyboard scan (03E3H-03FAH) with a debounce added: when a key is newly found down, it waits 1250 counts of the ROM's delay (about 18 ms) and reads the key's row again, and takes the key only when it is still down. Then it goes on in the ROM's driver at 03FBH, which works out the character. ROM version 1.3 has its own debounce at 03FBH (JP 011CH: a wait of 0500H counts and the same test), so on that ROM a key is tested twice; in the earlier Model I ROMs 03FBH goes straight on to the character (LD A,D).
47A3
LD HL,4036H 21 36 40
Point Register Pair HL to 4036H, the ROM's image of keyboard rows 0-6 (4036H-403CH): each byte holds the keys of its row that were down at the last scan.
47A6
LD BC,3801H 01 01 38
Point Register Pair BC to 3801H, the address that reads keyboard row 0 (@ and A-G).
47A9
LD D,00H 16 00
Load Register D with 00H, the number of the row being scanned.
47AB
LD A,(BC) 0A
Read the keys of the row at Register Pair BC (3801H, 3802H, 3804H ... 3840H) into Register A: one bit a key, 1 = down.
47AC
LD E,A 5F
Copy the row's keys from Register A into Register E, the row's new state.
47AD
XOR (HL) AE
XOR Register A (the row's keys now) with the row's state at the last scan (Register Pair HL, 4036H + the row number): the bits that changed are 1.
47AE
LD (HL),E 73
Store the row's new state (Register E) in the image at Register Pair HL.
47AF
AND E A3
AND Register A (the bits that changed) with Register E (the keys down now): the bits of keys that went down since the last scan.
47B0
If a key in this row went down, JUMP to 47BAH to check it.
47B2
INC D 14
Add 1 to Register D, the number of the row being scanned (0-6).
47B3
INC L 2C
Point Register Pair HL to the image byte of the next row (Register L + 1).
47B4
RLC C CB 01
Rotate Register C left: the row address in Register Pair BC moves to the next row (3802H, 3804H ... 3840H).
47B6
LOOP BACK to 47ABH while bit 7 of Register C is 0: rows 0-6 (3801H-3840H). Row 7 (3880H, the SHIFT keys) is not scanned for new keys.
47B9
RET C9
RETURN with Register A = 00H: no key went down.
47BA
LD E,A 5F
Load Register E with the bits of the keys that went down in this row (Register A).
47BB
PUSH BC C5
Save Register Pair BC, the address of the row, on the stack.
47BC
LD BC,04E2H 01 E2 04
Load Register Pair BC with 04E2H (1250), the count of the ROM's delay.
47BF
GOSUB to the ROM's delay at 0060H: 1250 times 14.66 microseconds, about 18 ms, for the key contacts to settle.
47C2
POP BC C1
Restore the row's address into Register Pair BC.
47C3
LD A,(BC) 0A
Read the keys of the row at Register Pair BC again into Register A.
47C4
AND E A3
AND Register A (the row read again) with Register E (the keys that went down): the bits of those keys still down.
47C5
RET Z C8
If none of them is still down, it was contact bounce: RETURN with Register A = 00H, no key.
47C6
The key is down. JUMP to the ROM's keyboard driver at 03FBH with Register D = the row number, Register E = the key's bit in the row, Register Pair BC = the row address and Register Pair HL = the row's byte in the image at 4036H; the ROM works out the character and returns it to its caller.
47C9H - CMD Statement
Level II sends CMD (token 85H) here through its vector at 4173H, with Register Pair HL pointing past the token. CMD takes a string of one character, the letter of the command: F (format, 47F2H), I (format and write MicroDOS, 4818H), H (set the sign-on text, 4802H), K (set the auto-type text, 482BH) or M (write MicroDOS, 4841H). Any other letter gives ILLEGAL FUNCTION CALL; a string of another length gives SYNTAX ERROR. Each command needs a comma and its argument after the string.
47C9
GOSUB to the ROM's expression evaluator at 2337H to evaluate the expression at Register Pair HL (the string after CMD). The result is in the ROM's accumulator (its descriptor address at 4121H for a string); Register Pair HL points past the expression.
47CC
PUSH HL E5
Save Register Pair HL, the BASIC text pointer past the string, on the stack.
47CD
GOSUB to the ROM's 29D7H: it gives TYPE MISMATCH if the result is not a string, releases the string if it is a temporary one, and returns Register Pair HL pointing at its descriptor (length, then the address of the characters).
47D0
LD A,(HL) 7E
Load Register A with the string's length from its descriptor (Register Pair HL).
47D1
DEC A 3D
Subtract 1 from Register A, the string's length: 00H only for a string of one character.
47D2
If the string is not exactly one character long, JUMP to the ROM's 1997H to report SYNTAX ERROR.
47D5
INC HL 23
Point Register Pair HL to the low byte of the address in the descriptor.
47D6
LD E,(HL) 5E
Load Register E with the low byte of the string's address, from the descriptor at Register Pair HL.
47D7
INC HL 23
Point Register Pair HL to the high byte of the string's address in its descriptor.
47D8
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE is the address of the string's one character.
47D9
LD A,(DE) 1A
Fetch the character, the letter of the command, from Register Pair DE into Register A.
47DA
POP HL E1
Restore Register Pair HL, the BASIC text pointer past the string.
47DB
CP 46H FE 46
Compare Register A, the command letter, with 46H (F), format.
47DD
If it is F, JUMP to 47F2H: format a diskette.
47DF
CP 49H FE 49
Compare Register A, the command letter, with 49H (I), format and write MicroDOS.
47E1
If it is I, JUMP to 4818H: format a diskette and write MicroDOS on it.
47E3
CP 48H FE 48
Compare Register A, the command letter, with 48H (H), the sign-on text.
47E5
If it is H, JUMP to 4802H: set the sign-on text.
47E7
CP 4BH FE 4B
Compare Register A, the command letter, with 4BH (K), the auto-type text.
47E9
If it is K, JUMP to 482BH: set the auto-type text.
47EB
CP 4DH FE 4D
Compare Register A, the command letter, with 4DH (M), write MicroDOS.
47ED
If it is M, JUMP to 4841H: write MicroDOS on a diskette.
47EF
Any other letter: JUMP to the ROM's 1E4AH to report ILLEGAL FUNCTION CALL.
47F2H - CMD"F": Format a Diskette
CMD"F",D formats every track of the diskette in drive D (0-3) and checks every sector (4870H). Register Pair HL points past the string "F" when the dispatcher at 47DDH jumps here.
47F2
RST 08H => 2CH CF 2C
Check that the next character of the BASIC text at Register Pair HL is a comma (2CH) and step past it; anything else is a SYNTAX ERROR. The ROM's RST 08H takes the byte after it, 2CH, as the character to expect.
47F4
GOSUB to 4B3FH to evaluate the drive number at Register Pair HL and store its select bit at 448CH (INVALID DRIVE NUMBER for a number above 3).
47F7
DEC HL 2B
Step Register Pair HL back one character, so that the RST 10H below fetches the character that ended the expression again.
47F8
RST 10H D7
Fetch the next character of the BASIC text through the ROM's RST 10H: Register Pair HL moves to it and Register A holds it; the Z flag is set when it ends the statement (00H or a colon).
47F9
If anything else follows the drive number, JUMP to the ROM's 1997H to report SYNTAX ERROR.
47FC
PUSH HL E5
Save Register Pair HL, the BASIC text pointer, on the stack.
47FD
GOSUB to 4870H to format and check the diskette in the drive at 448CH.
4800
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
4801
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the statement.
4802H - CMD"H": Set the Sign-On Text
CMD"H",A$ copies the first 128 characters of A$ to the sign-on buffer at 440BH (4851H), where the boot sector finds it when it reads the first sector of the main file. Only the copy in memory changes; CMD"M" writes it to a diskette.
4802
RST 08H => 2CH CF 2C
Check that the next character at Register Pair HL is a comma (2CH) and step past it, or report SYNTAX ERROR.
4804
GOSUB to the ROM's expression evaluator at 2337H to evaluate the string expression at Register Pair HL; Register Pair HL ends past it.
4807
DEC HL 2B
Step Register Pair HL back one character for the RST 10H below.
4808
RST 10H D7
Fetch the next character of the BASIC text through RST 10H: Register Pair HL moves to it, Register A holds it, Z when the statement ends there.
4809
If anything else follows, JUMP to the ROM's 1997H to report SYNTAX ERROR.
480C
PUSH HL E5
Save Register Pair HL, the BASIC text pointer, on the stack.
480D
GOSUB to the ROM's 29D7H: TYPE MISMATCH unless the result is a string; Register Pair HL comes back pointing at its descriptor.
4810
LD DE,440BH 11 0B 44
Point Register Pair DE to 440BH, the sign-on buffer.
4813
GOSUB to 4851H to copy the string described at Register Pair HL to 440BH, at most 128 characters, a down arrow (0AH) becoming 0DH, and a 00H after it.
4816
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
4817
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the statement.
4818H - CMD"I": Format a Diskette and Write MicroDOS on It
CMD"I",D does CMD"F",D and then CMD"M",D: it formats the diskette in drive D (4870H) and writes the boot sector image and the main file to sectors 0-19 (491BH).
4818
RST 08H => 2CH CF 2C
Check that the next character at Register Pair HL is a comma (2CH) and step past it, or report SYNTAX ERROR.
481A
GOSUB to 4B3FH to evaluate the drive number at Register Pair HL and store its select bit at 448CH.
481D
DEC HL 2B
Step Register Pair HL back one character for the RST 10H below.
481E
RST 10H D7
Fetch the next character of the BASIC text through RST 10H: Register Pair HL moves to it, Register A holds it, Z when the statement ends there.
481F
If anything else follows the drive number, JUMP to the ROM's 1997H to report SYNTAX ERROR.
4822
PUSH HL E5
Save Register Pair HL, the BASIC text pointer, on the stack.
4823
GOSUB to 4870H to format and check the diskette in the drive at 448CH.
4826
GOSUB to 491BH to write the boot sector image and MicroDOS (4400H-55FFH) to sectors 0-19 of the same drive.
4829
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
482A
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the statement.
482BH - CMD"K": Set the Auto-Type Text
CMD"K",A$ copies the first 128 characters of A$ to the auto-type buffer at 44A5H (4851H), a down arrow (0AH) becoming ENTER (0DH). At the next boot the auto-type driver at 478FH types them. Only the copy in memory changes; CMD"M" writes it to a diskette.
482B
RST 08H => 2CH CF 2C
Check that the next character at Register Pair HL is a comma (2CH) and step past it, or report SYNTAX ERROR.
482D
GOSUB to the ROM's expression evaluator at 2337H to evaluate the string expression at Register Pair HL; Register Pair HL ends past it.
4830
DEC HL 2B
Step Register Pair HL back one character for the RST 10H below.
4831
RST 10H D7
Fetch the next character of the BASIC text through RST 10H: Register Pair HL moves to it, Register A holds it, Z when the statement ends there.
4832
If anything else follows, JUMP to the ROM's 1997H to report SYNTAX ERROR.
4835
PUSH HL E5
Save Register Pair HL, the BASIC text pointer, on the stack.
4836
GOSUB to the ROM's 29D7H: TYPE MISMATCH unless the result is a string; Register Pair HL comes back pointing at its descriptor.
4839
LD DE,44A5H 11 A5 44
Point Register Pair DE to 44A5H, the auto-type buffer.
483C
GOSUB to 4851H to copy the string described at Register Pair HL to 44A5H, at most 128 characters, a down arrow (0AH) becoming 0DH, and a 00H after it.
483F
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
4840
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the statement.
4841H - CMD"M": Write MicroDOS on a Diskette
CMD"M",D writes the boot sector image (4594H) to sector 0 and MicroDOS as it is in memory, 4400H-55FFH, to sectors 1-19 of the diskette in drive D (491BH). The diskette must be formatted.
4841
RST 08H => 2CH CF 2C
Check that the next character at Register Pair HL is a comma (2CH) and step past it, or report SYNTAX ERROR.
4843
GOSUB to 4B3FH to evaluate the drive number at Register Pair HL and store its select bit at 448CH.
4846
DEC HL 2B
Step Register Pair HL back one character for the RST 10H below.
4847
RST 10H D7
Fetch the next character of the BASIC text through RST 10H: Register Pair HL moves to it, Register A holds it, Z when the statement ends there.
4848
If anything else follows the drive number, JUMP to the ROM's 1997H to report SYNTAX ERROR.
484B
PUSH HL E5
Save Register Pair HL, the BASIC text pointer, on the stack.
484C
GOSUB to 491BH to write the boot sector image and MicroDOS to sectors 0-19 of the drive at 448CH.
484F
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
4850
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the statement.
4851H - Copy a String to a Text Buffer
Used by CMD"H" (DE = 440BH) and CMD"K" (DE = 44A5H). Entered with Register Pair HL pointing at a string's descriptor (length, then address). Copies at most 128 characters to Register Pair DE, changing each 0AH (down arrow) to 0DH, and ends the copy with a 00H byte. An empty string leaves only the 00H.
4851
LD A,(HL) 7E
Load Register A with the string's length from its descriptor (Register Pair HL).
4852
OR A B7
Test Register A, the string's length: Z when the string is empty.
4853
If the string is empty, JUMP to 486DH to store only the ending 00H.
4855
CP 80H FE 80
Compare Register A, the string's length, with 80H (128).
4857
If it is less than 128, JUMP to 485BH to copy all of it.
4859
LD A,80H 3E 80
Otherwise load Register A with 80H: only the first 128 characters are copied, so the copy and its 00H fit the 129 byte buffer.
485B
LD B,A 47
Load Register B with the number of characters to copy (Register A).
485C
INC HL 23
Point Register Pair HL to the low byte of the string's address in the descriptor.
485D
LD A,(HL) 7E
Load Register A with the low byte of the address of the string's characters, from the descriptor at Register Pair HL.
485E
INC HL 23
Point Register Pair HL to the high byte of the address in the descriptor.
485F
LD H,(HL) 66
Load Register H with the high byte of the address, from the descriptor at Register Pair HL.
4860
LD L,A 6F
Load Register L with the low byte (Register A): Register Pair HL is the address of the string's first character.
4861
LD A,(HL) 7E
Fetch the next character of the string (Register Pair HL) into Register A.
4862
CP 0AH FE 0A
Compare Register A with 0AH, the code of the down arrow key, which the manual says to type where a line should end (an ENTER cannot be put in a string).
4864
If it is not 0AH, JUMP to 4868H to store it as it is.
4866
LD A,0DH 3E 0D
Load Register A with 0DH (ENTER) in place of the down arrow.
4868
LD (DE),A 12
Store the character in Register A in the buffer at Register Pair DE.
4869
INC DE 13
Point Register Pair DE to the next byte of the buffer.
486A
INC HL 23
Point Register Pair HL to the next character of the string.
486B
Decrement Register B, the characters left, and LOOP BACK to 4861H until all are copied.
486D
XOR A AF
Load Register A with 00H, the byte that ends the copied text.
486E
LD (DE),A 12
Store Register A (00H) after the last character at Register Pair DE: it ends the text for the boot sector (the sign-on text) or for the auto-type driver.
486F
RET C9
RETURN to CMD"H" or CMD"K" with the text copied and ended.
4870H - Format and Check a Diskette
Used by CMD"F" and CMD"I". Formats every track of the drive at 448CH (4C91H), track 0 to (4492H) - 1, then reads every sector of every track back (48BCH). A track with sectors that do not read is stepped off and back and formatted again, then restored, sought and formatted a third time; the sectors that still do not read are added to the count at 4496H, which LOC(3) returns. A track that 4C91H cannot write at all in three tries ends the statement with CAN'T FORMAT DISK. On return 448DH-448EH hold the last track and its last sector.
4870
LD HL,448DH 21 8D 44
Point Register Pair HL to 448DH, the track of the next transfer.
4873
XOR A AF
Load Register A with 00H, for the track and sector numbers below.
4874
LD (HL),A 77
Store Register A (00H) at 448DH (Register Pair HL): start with track 0.
4875
INC HL 23
Point Register Pair HL to 448EH, the sector number of the next transfer.
4876
LD (HL),A 77
Store Register A (00H) at 448EH (Register Pair HL): sector 0.
4877
DEC HL 2B
Point Register Pair HL back to 448DH, the track number, which the loops below step with INC (HL).
4878
LD DE,(4492H) ED 5B 92 44
Load Register Pair DE from 4492H-4493H: Register E = the number of tracks (28H, 40) and Register D = the number of sectors of a track (0AH, 10).
487C
LD (4496H),A 32 96 44
Store 00H (Register A) at 4496H: no sector has failed yet.
487F
LD B,E 43
Load Register B with the number of tracks (Register E), the count of the format loop.
4880
GOSUB to 4C91H to format the track at 448DH of the drive at 448CH.
4883
INC (HL) 34
Add 1 to the track number at 448DH (Register Pair HL).
4884
Decrement Register B, the tracks left, and LOOP BACK to 4880H until every track is formatted.
4886
LD (HL),B 70
Store Register B (00H after the loop) at 448DH (Register Pair HL): start the check at track 0.
4887
LD B,E 43
Load Register B with the number of tracks (Register E) again, the count of the check loop.
4888
GOSUB to 48BCH to read every sector of the track at 448DH. It returns Z when all of them read, otherwise NZ with Register A = the number that did not.
488B
If the whole track read, JUMP to 48B5H for the next track.
488D
LD A,43H 3E 43
Load Register A with 43H, the Step In command without track register update (rate bits 11).
| 1771 FDC Command: 43H (01000011) | | Function Description |
| 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | | Command=Step In (bits 7-5 = 010) u = 0: track register unchanged h = 0: no head load delay V = 0: no verify r1 r0 = 11: 40 ms stepping rate |
488F
GOSUB to 4DBCH to give the command in Register A and wait until it is done: the head moves one track in.
4892
LD A,63H 3E 63
Load Register A with 63H, the Step Out command without track register update (rate bits 11).
| 1771 FDC Command: 63H (01100011) | | Function Description |
| 0 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | | Command=Step Out (bits 7-5 = 011) u = 0: track register unchanged h = 0: no head load delay V = 0: no verify r1 r0 = 11: 40 ms stepping rate |
4894
GOSUB to 4DBCH to give it and wait: the head is back on the track, and the controller's track register never changed.
4897
GOSUB to 4C91H to format the track at 448DH again.
489A
GOSUB to 48BCH to read every sector of the track again.
489D
If they all read now, JUMP to 48B5H for the next track.
489F
GOSUB to 4DACH to restore the head to track 0 (Restore command with the stepping rate at 4494H).
48A2
GOSUB to 4D89H to seek the track at 448DH again.
48A5
GOSUB to 4C91H to format the track a third time.
48A8
GOSUB to 48BCH to read every sector of the track once more.
48AB
If they all read now, JUMP to 48B5H for the next track.
48AD
LD C,A 4F
Load Register C with the number of sectors of this track that still do not read (Register A from 48BCH).
48AE
LD A,(4496H) 3A 96 44
Fetch the count of failed sectors from 4496H into Register A.
48B1
ADD A,C 81
Add this track's failures (Register C) to Register A, the count so far.
48B2
LD (4496H),A 32 96 44
Store Register A, the new count of sectors that would not read, at 4496H for LOC(3).
48B5
INC (HL) 34
Add 1 to the track number at 448DH (Register Pair HL).
48B6
Decrement Register B, the tracks left, and LOOP BACK to 4888H until every track is checked.
48B8
DEC (HL) 35
Subtract 1 from the track number at 448DH (Register Pair HL): the last track (27H, 39).
48B9
INC HL 23
Point Register Pair HL to 448EH, the sector number, left at the number of sectors of a track (0AH) by the last check.
48BA
DEC (HL) 35
Subtract 1 from the sector number at 448EH (Register Pair HL): the last sector of the track (09H).
48BB
RET C9
RETURN to CMD"F" or CMD"I" with the whole diskette formatted and checked.
48BCH - Read Every Sector of a Track
Used by the format at 4870H, entered with Register Pair HL = 448DH and Register D = the number of sectors of a track. Reads sectors 0 to D - 1 of the track at 448DH (4C6DH, which reads a sector without keeping its data) and counts those that do not read. Returns with Register Pair HL = 448DH again, 448EH = the number of sectors, Register A = the number of sectors that failed and the Z flag set when none did. Register Pair BC is kept.
48BC
INC HL 23
Point Register Pair HL to 448EH, the sector number.
48BD
LD (HL),00H 36 00
Store 00H at 448EH (Register Pair HL): start the check with sector 0.
48BF
PUSH BC C5
Save Register Pair BC, the format's track count, on the stack.
48C0
LD B,D 42
Load Register B with the number of sectors of a track (Register D), the count of the loop.
48C1
LD C,00H 0E 00
Load Register C with 00H, the count of sectors that do not read.
48C3
PUSH BC C5
Save Register Pair BC (the sectors left and the failures) on the stack.
48C4
PUSH DE D5
Save Register Pair DE (the geometry) on the stack.
48C5
PUSH HL E5
Save Register Pair HL (448EH) on the stack around the select and the read.
48C6
GOSUB to 4D44H to select the drive at 448CH, seek the track at 448DH and put the sector at 448EH in the sector register.
48C9
GOSUB to 4C6DH to read the sector; the Carry flag comes back set when it did not read.
48CC
POP HL E1
Restore Register Pair HL (448EH) from the stack after the read.
48CD
POP DE D1
Restore Register Pair DE (Register D = the sectors of a track) from the stack.
48CE
POP BC C1
Restore Register Pair BC (the sectors left and the failures) from the stack.
48CF
If the sector read (No Carry), JUMP to 48D2H.
48D1
INC C 0C
Add 1 to Register C, the count of sectors that did not read.
48D2
INC (HL) 34
Add 1 to the sector number at 448EH (Register Pair HL).
48D3
Decrement Register B, the sectors left, and LOOP BACK to 48C3H until every sector of the track is read.
48D5
LD A,C 79
Load Register A with the count of sectors that did not read (Register C).
48D6
POP BC C1
Restore the format's track count into Register Pair BC.
48D7
DEC HL 2B
Point Register Pair HL back to 448DH, the track number.
48D8
OR A B7
Test Register A, the number of sectors that did not read: Z when every sector read.
48D9
RET C9
RETURN to the format with Register A = the failures and Register Pair HL = 448DH.
48DAH - Disk Error Exits
Each entry loads Register E with a Level II error code (the error number less 1, times 2) for the ROM's error handler at 19A2H, which displays the message through MicroDOS's message list (52DEH). The first three report at once; the others first keep the controller's status (48F4H). The numbers are the ones in MicroDOS's message list at 52F1H.
48DA
LD E,2EH 1E 2E
Load Register E with 2EH, error 24, INVALID DRIVE NUMBER (a drive number above 3, or a drive select bit of 00H).
48DC
JUMP to 4918H to report the error in Register E (INVALID DRIVE NUMBER).
48DE
LD E,30H 1E 30
Load Register E with 30H, error 25, INVALID SECTOR NUMBER (the DSSSS conversion at 4B33H: the sector is past the last track).
48E0
JUMP to 4918H to report the error in Register E (INVALID SECTOR NUMBER).
48E2
LD E,34H 1E 34
Load Register E with 34H, error 27, DISK WRITE PROTECTED (the status before a write had bit 6 set, 4C01H; or the format's 4C9CH).
48E4
JUMP to 4918H to report the error in Register E (DISK WRITE PROTECTED).
48E6
LD E,32H 1E 32
Load Register E with 32H, error 26, DISK READ/WRITE ERROR (a sector that did not read or write after all tries, 4BACH and 4C2FH).
48E8
JUMP to 48F4H to keep the controller's status and report it.
48EA
LD E,38H 1E 38
Load Register E with 38H, error 29, DISK MISSING OR DOOR OPEN (the controller stayed busy for 65536 tests, 4DE0H).
48EC
JUMP to 48F4H to keep the status and report it.
48EE
LD E,42H 1E 42
Load Register E with 42H, error 34, DISK SEEK ERROR (a seek or restore that failed, 4D93H and 4DB9H).
48F0
JUMP to 48F4H to keep the status and report it.
48F2
LD E,44H 1E 44
Load Register E with 44H, error 35, CAN'T FORMAT DISK (the format at 4D1CH).
48F4
LD A,(37ECH) 3A EC 37
Fetch the controller's status from 37ECH into Register A.
48F7
LD (4495H),A 32 95 44
Store Register A, the controller's status, at 4495H, where LOC(2) finds it.
48FA
LD A,D0H 3E D0
Load Register A with D0H, the Force Interrupt command.
| 1771 FDC Command: D0H (11010000) | | Function Description |
| 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | | Command=Force Interrupt (bits 7-4 = 1101) I3-I0 = 0000: end the command, no interrupt |
48FC
LD (37ECH),A 32 EC 37
Write Register A (D0H) to the command register 37ECH: whatever command is running is ended.
48FF
LD HL,4496H 21 96 44
Point Register Pair HL to 4496H, the byte before the table of head positions at 4497H-449AH.
4902
LD A,(448CH) 3A 8C 44
Fetch the drive select bit of the drive that failed from 448CH into Register A.
4905
AND 0FH E6 0F
Keep bits 3-0 of Register A, the select bits of the four drives.
4907
OR 08H F6 08
Set bit 3 of Register A, so that the search below stops at drive 3's entry even when no bit is set.
4909
RRCA 0F
Rotate Register A right: the lowest bit goes into the Carry flag.
490A
INC HL 23
Point Register Pair HL to the next drive's entry in the table (4497H for drive 0).
490B
LOOP BACK to 4909H until the drive's select bit has come out into the Carry flag: Register Pair HL then points at its entry, 4497H + the drive number.
490D
LD (HL),FFH 36 FF
Store FFH at the drive's entry (Register Pair HL): its head position is not known any more, so the next seek on it restores the head to track 0 first.
490F
LD A,(4495H) 3A 95 44
Fetch the status kept at 4495H into Register A.
4912
OR A B7
Test Register A, the status kept: the Sign flag is its bit 7, NOT READY.
4913
If the drive was ready (bit 7 = 0), JUMP to the ROM's 19A2H to report the error in Register E.
4916
LD E,40H 1E 40
Otherwise load Register E with 40H, error 33, DISK DRIVE NOT AVAILABLE, in place of the error found.
4918
JUMP to the ROM's error handler at 19A2H with the error code in Register E: it keeps the line number of the error and displays the message through the hook at 41A6H (MicroDOS's 52DEH).
491BH - Write MicroDOS to Sectors 0-19
Used by CMD"M" and CMD"I". Writes the boot sector image at 4594H as track 0, sector 0 (its first byte, FEH, as the length byte), then the main file 4400H-55FFH, 4608 bytes, as a chain of sectors starting at track 0, sector 1 (4968H): 18 sectors of 255 bytes and one of 18 bytes, sectors 1-19.
491B
LD HL,4594H 21 94 45
Point Register Pair HL to 4594H, the boot sector image.
491E
LD A,(HL) 7E
Load Register A with the first byte of the image at Register Pair HL, FEH: the length byte of the boot sector, 254 data bytes.
491F
INC HL 23
Point Register Pair HL to 4595H, the first of those data bytes.
4920
LD (448FH),A 32 8F 44
Store Register A (FEH) at 448FH, the length of the sector to write.
4923
LD (4490H),HL 22 90 44
Store Register Pair HL (4595H) at 4490H-4491H, the data pointer of the sector to write.
4926
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H: track 0 and sector 0 for 448DH-448EH.
4929
LD (448DH),HL 22 8D 44
Store Register Pair HL (0000H) at 448DH-448EH: track 0, sector 0.
492C
GOSUB to 4BF6H to write the sector: the length byte FEH and the 254 bytes 4595H-4692H.
492F
LD A,01H 3E 01
Load Register A with 01H, the sector where the main file starts.
4931
LD (448EH),A 32 8E 44
Store Register A (01H) at 448EH: track 0, sector 1, where the main file starts.
4934
LD DE,4400H 11 00 44
Point Register Pair DE to 4400H, the start of the main file.
4937
LD HL,5600H 21 00 56
Load Register Pair HL with 5600H, one past its end.
493A
OR A B7
Clear the Carry flag (OR Register A with itself) for the subtraction below.
493B
SBC HL,DE ED 52
Subtract Register Pair DE from Register Pair HL: HL = 1200H, the 4608 bytes of the main file.
493D
GOSUB to 4968H to write Register Pair HL bytes from Register Pair DE as a chain of sectors from track 0, sector 1.
4940
RET C9
RETURN to CMD"M" or CMD"I" with sectors 0-19 written.
4941H - SAVE Statement
Level II sends SAVE (token ADH) here through its vector at 41A0H. SAVE DSSSS writes the BASIC program, from the start of the program (40A4H) to the start of the variables (40F9H), as it is in memory, as a chain of sectors from drive D, sector SSSS (4968H): every sector but the last holds 255 bytes, the last fewer (none when the program is a multiple of 255 bytes long). Nothing checks what the sectors held before. Then it displays LAST SECTOR USED = and the DSSSS number of the last sector written.
4941
GOSUB to 4AFBH to evaluate the DSSSS expression at Register Pair HL: the drive's select bit goes to 448CH, the track to 448DH and the sector to 448EH (INVALID DRIVE NUMBER or INVALID SECTOR NUMBER when they do not fit).
4944
DEC HL 2B
Step Register Pair HL back one character for the RST 10H below.
4945
RST 10H D7
Fetch the next character of the BASIC text through RST 10H: Register Pair HL moves to it, Register A holds it, Z when the statement ends there.
4946
If anything else follows, JUMP to the ROM's 1997H to report SYNTAX ERROR.
4949
PUSH HL E5
Save Register Pair HL, the BASIC text pointer, on the stack.
494A
LD DE,(40A4H) ED 5B A4 40
Load Register Pair DE with the start of the BASIC program from 40A4H-40A5H (5A01H under MicroDOS).
494E
LD HL,(40F9H) 2A F9 40
Load Register Pair HL with the start of the simple variables from 40F9H-40FAH: one past the 00H 00H that ends the program.
4951
OR A B7
Clear the Carry flag (OR Register A with itself) for the subtraction below.
4952
SBC HL,DE ED 52
Subtract Register Pair DE from Register Pair HL: HL = the length of the program in bytes.
4954
GOSUB to 4968H to write Register Pair HL bytes from Register Pair DE (the program) as a chain of sectors from the position at 448CH-448EH. It leaves 448DH-448EH on the last sector written.
4957
LD HL,4581H 21 81 45
Point Register Pair HL to 4581H, the text LAST SECTOR USED =.
495A
GOSUB to the ROM's 28A7H to display the text at Register Pair HL up to its 00H byte.
495D
GOSUB to 4E52H (JP 4FC7H, the work of LOC(0)): it puts the DSSSS number of the drive, track and sector at 448CH-448EH, the last sector written, into the ROM's accumulator as an integer.
4960
GOSUB to the ROM's 0FBDH to turn the number in the accumulator into text; Register Pair HL comes back pointing at it, ended by 00H.
4963
GOSUB to the ROM's 28A7H to display that text at Register Pair HL: the number of the last sector used.
4966
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
4967
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the SAVE statement.
4968H - Write a Chain of Sectors
Used by SAVE (4954H) and by the write of MicroDOS (493DH). Entered with Register Pair DE = the address of the data and Register Pair HL = its length, and with 448CH-448EH naming the first sector. Writes full sectors of 255 bytes, stepping to the next sector after each one (498FH), while 255 or more bytes are left; then writes the last sector with the bytes that are left (fewer than 255, or none) and returns from 559EH through 4977H. The length byte of each sector tells the boot sector, LOAD and MERGE whether another sector follows (FFH) or not.
4968
LD A,H 7C
Load Register A with the high byte of the bytes left (Register H).
4969
GOSUB to 559EH: it returns when 255 or more bytes are left; otherwise it writes the last sector with the Register L bytes that are left (4977H) and returns to the caller of 4968H, not here.
496C
LD BC,00FFH 01 FF 00
Load Register Pair BC with 00FFH: a full sector of 255 data bytes.
496F
GOSUB to 497DH to write a sector of Register C (255) bytes from Register Pair DE; it moves Register Pair DE on by 255 and takes 255 from Register Pair HL.
4972
GOSUB to 498FH to step 448DH-448EH to the next sector.
4975
LOOP BACK to 4968H for the rest of the data, with Register Pair DE and Register Pair HL moved on by 255.
4977H - Write the Last Sector of a Chain
Reached from 559EH (55A4H) with Register Pair HL = the bytes left, fewer than 255, after that routine has taken its own return address off the stack, so the RET here returns to the caller of 4968H.
4977
LD B,H 44
Load Register B with the high byte of the bytes left (Register H, 00H).
4978
LD C,L 4D
Load Register C with the low byte (Register L): Register Pair BC is the number of bytes for the last sector, 00H-FEH.
4979
GOSUB to 497DH to write the last sector of Register C bytes from Register Pair DE.
497C
RET C9
RETURN to the caller of 4968H (SAVE or the write of MicroDOS), with 448DH-448EH on the last sector written.
497DH - Write One Sector of a Chain
Entered with Register C = the number of data bytes (the length byte), Register Pair DE = their address and Register Pair BC = the same number (B = 00H). Writes the sector at 448CH-448EH (4BF6H). Returns with Register Pair HL reduced by Register Pair BC and Register Pair DE moved on by it.
497D
LD A,C 79
Load Register A with the number of data bytes of the sector (Register C).
497E
LD (448FH),A 32 8F 44
Store Register A, the number of data bytes, at 448FH, the length byte the sector write puts in byte 0 of the sector.
4981
LD (4490H),DE ED 53 90 44
Store Register Pair DE, the address of the data, at 4490H-4491H, the data pointer of the sector write.
4985
GOSUB to 4BF6H to write the sector: the length byte and that many bytes from 4490H to the drive, track and sector at 448CH-448EH.
4988
OR A B7
Clear the Carry flag (OR Register A with itself) for the subtraction below.
4989
SBC HL,BC ED 42
Subtract Register Pair BC (the bytes just written) from Register Pair HL, the bytes left.
498B
EX DE,HL EB
Exchange Register Pairs DE and HL: HL = the address of the data just written, DE = the bytes left.
498C
ADD HL,BC 09
Add Register Pair BC to Register Pair HL: the address of the next data to write.
498D
EX DE,HL EB
Exchange back: Register Pair DE = the address of the next data, Register Pair HL = the bytes left.
498E
RET C9
RETURN to the chain write with Register Pair DE on the next data and Register Pair HL = the bytes left.
498FH - Step to the Next Sector
Moves 448DH-448EH to the next sector: the next sector of the same track, or sector 0 of the next track after the last sector of a track. Register Pairs HL and DE are kept. It was meant to report DISK OVERFLOW past the last track, but the test at 49A0H compares the wrong value: Register A still holds the number of sectors of a track (0AH), which is always below the number of tracks (28H), so the track number goes on past the last track and the error at 49A3H is not reached.
498F
PUSH HL E5
Save Register Pair HL (the chain write's bytes left) on the stack.
4990
PUSH DE D5
Save Register Pair DE (the chain write's data address) on the stack.
4991
LD HL,(4492H) 2A 92 44
Load Register Pair HL from 4492H-4493H: Register L = the number of tracks (28H), Register H = the number of sectors of a track (0AH).
4994
EX DE,HL EB
Exchange Register Pairs DE and HL: Register E = the number of tracks, Register D = the number of sectors of a track.
4995
LD HL,(448DH) 2A 8D 44
Load Register Pair HL from 448DH-448EH: Register L = the track, Register H = the sector.
4998
INC H 24
Add 1 to the sector number in Register H: the sector after the one just used.
4999
LD A,H 7C
Copy the new sector number from Register H into Register A.
499A
CP D BA
Compare Register A, the new sector number, with the number of sectors of a track (Register D).
499B
If it is still on the track, JUMP to 49A8H to store it.
499D
LD H,00H 26 00
Otherwise set the sector number (Register H) to 00H.
499F
INC L 2C
Add 1 to the track number in Register L: the next track.
49A0
CP E BB
Compare Register A with the number of tracks (Register E). Register A still holds the sector number that passed the end of the track, equal to the number of sectors of a track (0AH), not the new track number in Register L: with 10 sectors and 40 tracks the Carry flag is always set here.
49A1
If Register A is below the number of tracks (always, with the values at 4492H-4493H), JUMP to 49A8H to store the new track and sector.
49A3
LD E,36H 1E 36
Load Register E with 36H, error 28, DISK OVERFLOW.
49A5
JUMP to the ROM's 19A2H to report the error in Register E, DISK OVERFLOW.
49A8
LD (448DH),HL 22 8D 44
Store Register Pair HL at 448DH-448EH: the track (Register L) and the sector (Register H) of the next transfer.
49AB
POP DE D1
Restore Register Pair DE (the caller's) from the stack.
49AC
POP HL E1
Restore Register Pair HL (the caller's) from the stack.
49AD
RET C9
RETURN to the caller with 448DH-448EH on the next sector.
49AEH - LOAD Statement
Level II sends LOAD (token A7H) here through its vector at 4188H. LOAD DSSSS or LOAD DSSSS,R reads the chain of sectors that starts at drive D, sector SSSS into memory from the start of the BASIC program (40A4H) up, after a NEW; ,R then runs the program. Before each sector the address is checked against the stack (558CH): a program that does not fit gives OUT OF MEMORY after another NEW, so no part of it stays in memory.
49AE
GOSUB to 4AFBH to evaluate the DSSSS expression at Register Pair HL and store the drive's select bit, the track and the sector at 448CH-448EH.
49B1
DEC HL 2B
Step Register Pair HL back one character for the RST 10H below.
49B2
RST 10H D7
Fetch the next character of the BASIC text through RST 10H: Register Pair HL moves to it, Register A holds it, Z when the statement ends there.
49B3
LD A,00H 3E 00
Load Register A with 00H, the flag for load only; LD does not change the flags.
49B5
If the statement ends after the DSSSS expression, JUMP to 49C0H with Register A = 00H.
49B7
RST 08H => 2CH CF 2C
Check that the next character is a comma (2CH) and step past it, or report SYNTAX ERROR.
49B9
RST 08H => 52H CF 52
Check that the next character is R (52H) and step past it, or report SYNTAX ERROR. The RST 10H the ROM does after the match sets Z when the statement ends there.
49BB
If anything follows the R, JUMP to the ROM's 1997H to report SYNTAX ERROR.
49BE
LD A,FFH 3E FF
Load Register A with FFH, the flag for load and run.
49C0
LD (4121H),A 32 21 41
Store Register A, the flag (00H or FFH), at 4121H, the low byte of the ROM's accumulator: NEW and the loading below do not touch it, and 49ECH tests it at the end.
49C3
GOSUB to the ROM's NEW at 1B4DH: the program is cleared (00H 00H at its start, 40F9H set past them), the variables, the string space and the stack are reset; its call through the hook at 41BBH clears the lengths of the four field buffers (4E5BH).
49C6
LD HL,(40A4H) 2A A4 40
Load Register Pair HL with the start of the BASIC program from 40A4H-40A5H (5A01H): the first sector's data goes there.
49C9
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the amount to move Register Pair HL on before the first sector.
49CC
ADD HL,DE 19
Add Register Pair DE (0000H at first, then 00FFH) to Register Pair HL: the address for the next sector's data.
49CD
GOSUB to 558CH to store Register Pair HL at 4490H-4491H, the data pointer, and check that 256 bytes from there stay below the stack; otherwise NEW and OUT OF MEMORY.
49D0
GOSUB to 4B7FH to read the sector at 448CH-448EH into 4300H-43FFH and copy its data bytes to the address at 4490H. 448FH comes back with the sector's length byte.
49D3
LD A,(448FH) 3A 8F 44
Fetch the length byte from 448FH into Register A.
49D6
LD E,A 5F
Copy Register A, the length byte, into Register E: Register Pair DE is the number of bytes just loaded (Register D is still 00H).
49D7
INC A 3C
Increment Register A: FFH (a full sector) becomes 00H.
49D8
If the sector was not full, it was the last: JUMP to 49DFH.
49DA
GOSUB to 498FH to step 448DH-448EH to the next sector.
49DD
LOOP BACK to 49CCH to load it after the 255 bytes just loaded.
49DF
GOSUB to the ROM's 1AF8H to set the link of every line of the loaded program, from 40A4H; it returns with Register Pair HL on the second 00H byte of the 00H 00H that ends the program.
49E2
INC HL 23
Point Register Pair HL past that byte: the end of the program.
49E3
LD (40F9H),HL 22 F9 40
Store Register Pair HL at 40F9H-40FAH, the start of the simple variables.
49E6
GOSUB to the ROM's 1B5DH, the clear of RUN: it sets 40DFH to the start of the program less 1, resets the variables, the arrays and the string space, and goes through the hook at 41BBH again.
49E9
LD HL,(40DFH) 2A DF 40
Load Register Pair HL from 40DFH-40E0H: the start of the program less 1 (5A00H), where the ROM starts executing.
49EC
LD A,(4121H) 3A 21 41
Fetch the flag from 4121H into Register A (00H: LOAD, FFH: LOAD ,R).
49EF
OR A B7
Test Register A, the flag: Z for LOAD without ,R.
49F0
If it is 00H, JUMP to the ROM's 1A19H, which displays READY and waits for a command.
49F3
Otherwise JUMP to the ROM's 1D1EH, the statement loop, with Register Pair HL at 5A00H: the program runs from its first line.
49F6H - MERGE Statement
Level II sends MERGE (token A8H) here through its vector at 418BH. MERGE DSSSS reads a program saved by SAVE from the chain at drive D, sector SSSS, one line at a time (4A4AH), and puts each line into the program in memory the way the ROM does with a line typed in: a line with the same number is replaced. It ends at the 00H 00H that ends the saved program, in the ROM's READY. A line that does not fit gives OUT OF MEMORY (the ROM's 1955H); the lines merged up to then stay.
49F6
POP BC C1
Take the return address into the ROM's statement loop off the stack into Register Pair BC: MERGE does not return there, it ends at READY (4A47H).
49F7
GOSUB to 4AFBH to evaluate the DSSSS expression at Register Pair HL and store the drive's select bit, the track and the sector at 448CH-448EH.
49FA
DEC HL 2B
Step Register Pair HL back one character for the RST 10H below.
49FB
RST 10H D7
Fetch the next character of the BASIC text through RST 10H: Register Pair HL moves to it, Register A holds it, Z when the statement ends there.
49FC
If anything else follows, JUMP to the ROM's 1997H to report SYNTAX ERROR.
49FF
LD A,FFH 3E FF
Load Register A with FFH, the length byte of a full sector.
4A01
LD (4300H),A 32 00 43
Store Register A (FFH) at 4300H, the length byte of the sector buffer, as if a full sector had been read before: the first byte fetched (4A82H) reads the first sector of the chain.
4A04
INC A 3C
Increment Register A from FFH to 00H, the count of bytes left in the buffer.
4A05
LD (448FH),A 32 8F 44
Store Register A (00H) at 448FH: no bytes of the sector buffer are left to fetch.
4A08
GOSUB to 4A4AH to read the next line of the saved program: Register Pair DE = its line number, Register Pair BC = its length with link and line number, the text in the keyboard input buffer at (40A7H); Z when the end of the program was reached.
4A0B
If the saved program has ended, JUMP to 4A47H, READY.
4A0D
LD (40ECH),DE ED 53 EC 40
Store the line number (Register Pair DE) at 40ECH-40EDH, the ROM's current line for EDIT and LIST.
4A11
PUSH DE D5
Save Register Pair DE, the line number, on the stack.
4A12
PUSH BC C5
Save Register Pair BC, the length of the line, on the stack.
4A13
GOSUB to the ROM's 1B2CH to look for the line with the number in Register Pair DE: Register Pair BC comes back with the address of that line, or of the first line with a higher number (or of the end of the program), and the Carry flag set when the line exists.
4A16
PUSH BC C5
Save Register Pair BC, where the line goes, on the stack.
4A17
If the line exists (Carry set), GOSUB to the ROM's 2BE4H to remove it: the lines after it are moved down over it and 40F9H is lowered.
4A1A
POP DE D1
Restore the address where the line goes into Register Pair DE.
4A1B
LD HL,(40F9H) 2A F9 40
Load Register Pair HL with the end of the program from 40F9H-40FAH.
4A1E
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (Stack Pointer): Register Pair HL = the length of the new line, the end of the program goes on the stack.
4A1F
POP BC C1
Take the end of the program off the stack into Register Pair BC.
4A20
ADD HL,BC 09
Add Register Pair BC, the end of the program, to Register Pair HL, the length of the line: Register Pair HL = the new end of the program.
4A21
PUSH HL E5
Save Register Pair HL, the new end of the program, on the stack.
4A22
GOSUB to the ROM's 1955H: it checks that there is room up to Register Pair HL (else OUT OF MEMORY) and moves the bytes from Register Pair DE (where the line goes) up to Register Pair BC (the old end) so that they end at Register Pair HL, opening a gap for the line.
4A25
POP HL E1
Restore the new end of the program into Register Pair HL.
4A26
LD (40F9H),HL 22 F9 40
Store Register Pair HL, the new end, at 40F9H-40FAH, the start of the simple variables.
4A29
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the address of the gap for the line.
4A2A
LD (HL),H 74
Store Register H at the first byte of the gap (Register Pair HL): a link that is not 00H, so that the gap counts as a line until 1AF8H sets the real links.
4A2B
POP DE D1
Restore the line number into Register Pair DE.
4A2C
PUSH HL E5
Save the address of the line (Register Pair HL) on the stack.
4A2D
INC HL 23
Point Register Pair HL past the link, to the second byte of the link.
4A2E
INC HL 23
Point Register Pair HL to the line number's place.
4A2F
LD (HL),E 73
Store the low byte of the line number (Register E) at Register Pair HL.
4A30
INC HL 23
Point Register Pair HL to the next byte, for the high byte of the line number.
4A31
LD (HL),D 72
Store the high byte of the line number (Register D) at Register Pair HL.
4A32
INC HL 23
Point Register Pair HL to where the text of the line goes.
4A33
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = where the text goes.
4A34
LD HL,(40A7H) 2A A7 40
Load Register Pair HL with the address of the keyboard input buffer from 40A7H-40A8H, where 4A4AH put the text of the line.
4A37
LD A,(HL) 7E
Fetch the next byte of the text (Register Pair HL) into Register A.
4A38
LD (DE),A 12
Store Register A, the byte of the text, in the program at Register Pair DE.
4A39
INC DE 13
Point Register Pair DE to the next byte of the program.
4A3A
INC HL 23
Point Register Pair HL to the next byte of the text.
4A3B
OR A B7
Test Register A, the byte just copied: 00H ends the line.
4A3C
LOOP BACK to 4A37H until the 00H that ends the line has been copied.
4A3E
POP DE D1
Restore the address of the new line into Register Pair DE.
4A3F
GOSUB to the ROM's 1AF8H to set the link of every line of the program again.
4A42
GOSUB to the ROM's 1B5DH, the clear of RUN: the variables, arrays and string space are reset after the program changed, and the stack is reset with the return address kept.
4A45
LOOP BACK to 4A08H for the next line of the saved program.
4A47
JUMP to the ROM's 1A19H, which displays READY and waits for a command.
4A4AH - Read One Line of a Saved Program
Used by MERGE. Takes the bytes of the saved program one at a time from the chain of sectors (4A6CH): the link (2 bytes), and when it is 0000H the end of the program (returns Z); otherwise the line number (2 bytes, into Register Pair DE) and the text of the line up to and including its 00H byte, into the keyboard input buffer at (40A7H). Returns NZ with Register Pair BC = 4 + the number of text bytes with the 00H, the length the line takes in memory.
4A4A
LD BC,0004H 01 04 00
Load Register Pair BC with 0004H: the link and the line number count towards the length of the line.
4A4D
GOSUB to 4A6CH to fetch the next byte of the saved program into Register A: the low byte of the link.
4A50
LD D,A 57
Keep Register A, the low byte of the link, in Register D.
4A51
GOSUB to 4A6CH to fetch the high byte of the link into Register A.
4A54
OR D B2
OR Register A (the high byte) with Register D (the low byte): Z when the link is 0000H, the end of the program.
4A55
RET Z C8
If the program has ended, RETURN with the Z flag set.
4A56
GOSUB to 4A6CH to fetch the low byte of the line number.
4A59
LD E,A 5F
Keep Register A, the low byte of the line number, in Register E.
4A5A
GOSUB to 4A6CH to fetch the high byte of the line number.
4A5D
LD D,A 57
Keep Register A, the high byte, in Register D: Register Pair DE is the line number.
4A5E
LD HL,(40A7H) 2A A7 40
Load Register Pair HL with the address of the keyboard input buffer from 40A7H-40A8H.
4A61
GOSUB to 4A6CH to fetch the next byte of the line's text into Register A.
4A64
LD (HL),A 77
Store Register A, the byte of the text, in the input buffer at Register Pair HL.
4A65
INC HL 23
Point Register Pair HL to the next byte of the buffer.
4A66
INC BC 03
Add 1 to the length of the line in Register Pair BC.
4A67
OR A B7
Test Register A, the byte just stored: 00H ends the line.
4A68
LOOP BACK to 4A61H until the 00H has been stored.
4A6A
INC A 3C
Increment Register A from 00H to 01H, which clears the Z flag: a line was read.
4A6B
RET C9
RETURN to MERGE with NZ, the line number in Register Pair DE and its length in Register Pair BC.
4A6CH - Fetch the Next Byte of a Chain
Used by MERGE through 4A4AH. Returns the next data byte of the chain of sectors in Register A, reading the next sector (4A82H) when the one in the buffer is used up. 448FH counts the bytes left in the buffer; 4490H points at the next one. Register Pair HL is kept.
4A6C
LD A,(448FH) 3A 8F 44
Fetch the number of bytes left in the sector buffer from 448FH into Register A.
4A6F
OR A B7
Test Register A, the bytes left in the buffer: Z when none is left.
4A70
If none is left, GOSUB to 4A82H to read the next sector of the chain; Register A comes back with its length byte (the bytes it holds).
4A73
DEC A 3D
Subtract 1 from Register A, the bytes left: the byte about to be fetched is taken off.
4A74
LD (448FH),A 32 8F 44
Store Register A, the bytes left, at 448FH for the next fetch.
4A77
PUSH HL E5
Save Register Pair HL (the caller's) on the stack.
4A78
LD HL,(4490H) 2A 90 44
Load Register Pair HL with the data pointer from 4490H-4491H: the next byte in the sector buffer.
4A7B
LD A,(HL) 7E
Fetch the byte at Register Pair HL into Register A.
4A7C
INC HL 23
Point Register Pair HL to the byte after the one fetched.
4A7D
LD (4490H),HL 22 90 44
Store Register Pair HL at 4490H-4491H for the next fetch.
4A80
POP HL E1
Restore Register Pair HL (the caller's) from the stack.
4A81
RET C9
RETURN to 4A4AH with the byte of the chain in Register A and Register Pair HL as it was.
4A82H - Read the Next Sector of a Chain
Used by 4A6CH. If the sector last read was a full one (its length byte at 4300H is FFH), reads the sector at 448CH-448EH into 4300H-43FFH, sets 448FH to its length byte and 4490H to 4301H, and when it is full itself steps 448DH-448EH on to the next sector (498FH). If the last sector read was not full, the chain has no more sectors: it stores 00H at 4301H and returns 01H, so that one more byte is fetched from wherever 4490H points. A last sector with the length 00H does not come here when it is read: it is read through 4A8BH (the sector before it was full), 4A9FH returns 00H, and 4A73H makes the bytes left FFH, so the next 255 fetches take the old bytes of the buffer from 4301H on. Returns the number of bytes now in the buffer in Register A. Register Pairs HL, DE and BC are kept.
4A82
PUSH HL E5
Save Register Pair HL (the caller's) on the stack.
4A83
PUSH DE D5
Save Register Pair DE (the caller's line number) on the stack.
4A84
PUSH BC C5
Save Register Pair BC (the caller's line length) on the stack.
4A85
LD A,(4300H) 3A 00 43
Fetch the length byte of the sector last read from 4300H into Register A (FFH set by MERGE before the first read).
4A88
INC A 3C
Increment Register A, the length byte: a full sector (FFH) gives 00H.
4A89
If the last sector was not full, the chain has ended: JUMP to 4AA6H.
4A8B
GOSUB to 4B8CH to read the sector at 448CH-448EH into 4300H-43FFH; it stores the sector's length byte at 448FH.
4A8E
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the length byte of the sector just read.
4A91
LD A,(HL) 7E
Load Register A with the length byte at 4300H (Register Pair HL).
4A92
LD (448FH),A 32 8F 44
Store Register A, the length byte, at 448FH: the number of data bytes to fetch from this sector.
4A95
INC HL 23
Point Register Pair HL to 4301H, the first data byte.
4A96
LD (4490H),HL 22 90 44
Store Register Pair HL (4301H) at 4490H-4491H, the pointer of the next byte to fetch.
4A99
INC A 3C
Increment Register A, the length byte: FFH (full) gives 00H.
4A9A
If this sector is not full, it is the last of the chain: JUMP to 4A9FH without stepping on.
4A9C
GOSUB to 498FH to step 448DH-448EH to the next sector, for the next read.
4A9F
LD A,(448FH) 3A 8F 44
Fetch the length byte from 448FH into Register A again: the bytes now in the buffer.
4AA2
POP BC C1
Restore Register Pair BC (the caller's) from the stack.
4AA3
POP DE D1
Restore Register Pair DE (the caller's) from the stack.
4AA4
POP HL E1
Restore Register Pair HL (the caller's) from the stack.
4AA5
RET C9
RETURN with the number of bytes in the buffer in Register A.
4AA6
LD HL,4301H 21 01 43
The chain has ended. Point Register Pair HL to 4301H.
4AA9
XOR A AF
Load Register A with 00H, the byte stored at 4301H.
4AAA
LD (HL),A 77
Store Register A (00H) at 4301H (Register Pair HL).
4AAB
INC A 3C
Increment Register A to 01H: one byte is reported in the buffer.
4AAC
JUMP to 4AA2H to restore the registers and return.
4AAEH - GET Statement
Level II sends GET (token A4H) here through its vector at 417FH. GET A$,DSSSS reads drive D, sector SSSS into the string variable A$, which gets the sector's data bytes and their number as its length; GET #N,DSSSS reads it into field buffer N (1-4), whose first byte takes the length. A string that is shorter than the data is given new string space first.
4AAE
GOSUB to 4B59H to work out where the data goes: for #N, Register Pair DE = the field buffer's address (its length byte), 4490H = the address after it and Register C = FFH; for a variable, Register Pair DE = its descriptor, 4490H = the address of its characters and Register C = its length.
4AB1
RST 08H => 2CH CF 2C
Check that the next character is a comma (2CH) and step past it, or report SYNTAX ERROR.
4AB3
GOSUB to 4AFBH to evaluate the DSSSS expression at Register Pair HL and store the drive's select bit, the track and the sector at 448CH-448EH; Register Pairs DE and BC are kept.
4AB6
DEC HL 2B
Step Register Pair HL back one character for the RST 10H below.
4AB7
RST 10H D7
Fetch the next character of the BASIC text through RST 10H: Register Pair HL moves to it, Register A holds it, Z when the statement ends there.
4AB8
If anything else follows, JUMP to the ROM's 1997H to report SYNTAX ERROR.
4ABB
PUSH HL E5
Save Register Pair HL, the BASIC text pointer, on the stack.
4ABC
PUSH DE D5
Save Register Pair DE, the descriptor or field buffer address, on the stack.
4ABD
PUSH BC C5
Save Register Pair BC, with the room for the data in Register C, on the stack.
4ABE
GOSUB to 4B8CH to read the sector into 4300H-43FFH; it stores the sector's length byte at 448FH.
4AC1
LD A,(448FH) 3A 8F 44
Fetch the length byte from 448FH into Register A: the number of data bytes read.
4AC4
POP BC C1
Restore Register Pair BC: Register C = the room for the data.
4AC5
POP DE D1
Restore Register Pair DE: the descriptor or field buffer address.
4AC6
LD (DE),A 12
Store Register A, the number of data bytes, at Register Pair DE as the length: in the string's descriptor, or in the first byte of the field buffer.
4AC7
CP C B9
Compare Register A, the number of data bytes, with the room for the data (Register C).
4AC8
If the data is shorter than the room, JUMP to 4ADFH to copy it where it is.
4ACA
If it is just as long, JUMP to 4ADFH as well.
4ACC
PUSH DE D5
The string variable is too short for the data. Save Register Pair DE, its descriptor, on the stack.
4ACD
GOSUB to 55A7H: it sets the variable's length to 00H and gets new string space for Register A bytes through the ROM's 2857H, which describes it in the temporary descriptor at 40D3H-40D5H.
4AD0
POP DE D1
Restore the variable's descriptor into Register Pair DE.
4AD1
LD HL,40D3H 21 D3 40
Point Register Pair HL to 40D3H, the temporary descriptor of the new string space.
4AD4
LD BC,0003H 01 03 00
Load Register Pair BC with 0003H, the size of a descriptor.
4AD7
LDIR ED B0
Copy Register Pair BC (3) bytes from 40D3H-40D5H (Register Pair HL) to the variable's descriptor at Register Pair DE: its length and the address of its new space.
4AD9
LD HL,(40D4H) 2A D4 40
Load Register Pair HL with the address of the new string space from 40D4H-40D5H.
4ADC
LD (4490H),HL 22 90 44
Store Register Pair HL, the new string space, at 4490H-4491H: the data is copied there.
4ADF
GOSUB to 4BB4H to copy the data bytes of the sector (their number is its byte 0 at 4300H) from 4301H to the address at 4490H.
4AE2
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
4AE3
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the GET statement.
4AE4H - PUT Statement
Level II sends PUT (token A5H) here through its vector at 4182H. PUT A$,DSSSS writes the characters of A$, with its length as the length byte, to drive D, sector SSSS; PUT #N,DSSSS writes field buffer N (1-4) with its length, the first byte of the buffer, as the length byte.
4AE4
GOSUB to 4B59H to work out where the data is: for #N, Register Pair DE = the field buffer's address (its length byte) and 4490H = the address after it; for a variable, Register Pair DE = its descriptor and 4490H = the address of its characters.
4AE7
RST 08H => 2CH CF 2C
Check that the next character is a comma (2CH) and step past it, or report SYNTAX ERROR.
4AE9
GOSUB to 4AFBH to evaluate the DSSSS expression at Register Pair HL and store the drive's select bit, the track and the sector at 448CH-448EH; Register Pair DE is kept.
4AEC
DEC HL 2B
Step Register Pair HL back one character for the RST 10H below.
4AED
RST 10H D7
Fetch the next character of the BASIC text through RST 10H: Register Pair HL moves to it, Register A holds it, Z when the statement ends there.
4AEE
If anything else follows, JUMP to the ROM's 1997H to report SYNTAX ERROR.
4AF1
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the descriptor or field buffer address, Register Pair DE = the BASIC text pointer.
4AF2
LD A,(HL) 7E
Load Register A with the length at Register Pair HL: the string's from its descriptor, or the field buffer's from its first byte.
4AF3
LD (448FH),A 32 8F 44
Store Register A, the length, at 448FH, the length byte of the sector to write.
4AF6
GOSUB to 4BF6H to write the sector: the length byte and that many bytes from the address at 4490H.
4AF9
EX DE,HL EB
Exchange Register Pairs DE and HL back: Register Pair HL = the BASIC text pointer.
4AFA
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the PUT statement.
4AFBH - Evaluate a DSSSS Expression
Used by SAVE, LOAD, MERGE, GET and PUT. Evaluates the expression at Register Pair HL, makes it an integer, and splits it (4B10H) into the drive (the ten thousands, 0-3) and the sector number, which becomes a track and a sector of that track. Register Pairs DE and BC are kept; Register Pair HL comes back past the expression.
4AFB
PUSH DE D5
Save Register Pair DE (the caller's, for GET and PUT the data's descriptor) on the stack.
4AFC
PUSH BC C5
Save Register Pair BC (the caller's, for GET the room for the data) on the stack.
4AFD
GOSUB to the ROM's expression evaluator at 2337H to evaluate the DSSSS expression at Register Pair HL into the ROM's accumulator; Register Pair HL comes back past it.
4B00
PUSH HL E5
Save Register Pair HL, the BASIC text pointer, on the stack.
4B01
LD A,02H 3E 02
Load Register A with 02H, the type code of an integer.
4B03
GOSUB to the ROM's 2819H to change the accumulator to the type in Register A: an integer, 32767 at most (OVERFLOW above).
4B06
LD HL,(4121H) 2A 21 41
Load Register Pair HL with the integer from 4121H-4122H.
4B09
GOSUB to 4B10H to split it into drive, track and sector at 448CH-448EH.
4B0C
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
4B0D
POP BC C1
Restore Register Pair BC (the caller's) from the stack.
4B0E
POP DE D1
Restore Register Pair DE (the caller's) from the stack.
4B0F
RET C9
RETURN to the statement with 448CH-448EH set and Register Pair HL past the expression.
4B10H - Split a DSSSS Number
Entered with the DSSSS number in Register Pair HL. The ten thousands are the drive (4B49H stores its select bit at 448CH); the rest, SSSS, is divided by the sectors of a track (4493H) into a track (448DH) and a sector (448EH). A track past the last one ((4492H) tracks) gives INVALID SECTOR NUMBER. A number from -22768 to -1 is taken as drive 0, track 0 and sector (the low byte of the number). For -32768 to -22769 the subtraction of 10000 overflows to a positive result, so the loop counts on (-30000 gives drive 3 with 5536 left, INVALID SECTOR NUMBER); the sector loop overflows the same way for -32768 to -32759.
4B10
LD DE,2710H 11 10 27
Load Register Pair DE with 2710H (10000), the value of one drive in a DSSSS number.
4B13
XOR A AF
Load Register A with 00H, the drive number to count up.
4B14
SBC HL,DE ED 52
Subtract 10000 (Register Pair DE) from the number in Register Pair HL (the Carry flag is clear: XOR A cleared it, and the loop below only comes back with a positive result).
4B16
If the result is negative, the drive number is complete: JUMP to 4B1CH.
4B19
INC A 3C
Add 1 to the drive number in Register A: another 10000 was taken off.
4B1A
LOOP BACK to 4B14H to take off another 10000.
4B1C
ADD HL,DE 19
Add Register Pair DE (10000) back: Register Pair HL = the sector number SSSS, 0-9999.
4B1D
GOSUB to 4B49H to check the drive number in Register A (INVALID DRIVE NUMBER above 3) and store its select bit at 448CH.
4B20
LD A,(4492H) 3A 92 44
Fetch the number of tracks from 4492H into Register A.
4B23
LD B,A 47
Load Register B with Register A, the number of tracks: the most tracks the division may count.
4B24
LD A,(4493H) 3A 93 44
Fetch the number of sectors of a track from 4493H into Register A.
4B27
LD E,A 5F
Load Register E with Register A, the sectors of a track.
4B28
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = the sectors of a track (000AH).
4B2A
XOR A AF
Load Register A with 00H, the track number to count up; this also clears the Carry flag.
4B2B
SBC HL,DE ED 52
Subtract the sectors of a track (Register Pair DE) from the sector number in Register Pair HL.
4B2D
If the result is negative, the track is found: JUMP to 4B36H.
4B30
INC A 3C
Add 1 to the track number in Register A: another track's sectors were taken off.
4B31
Decrement Register B, the tracks left, and LOOP BACK to 4B2BH while there are tracks left.
4B33
The sector number is past the last track: JUMP to 48DEH to report INVALID SECTOR NUMBER.
4B36
ADD HL,DE 19
Add Register Pair DE (the sectors of a track) back: Register Pair HL = the sector within the track (Register L).
4B37
LD (448DH),A 32 8D 44
Store the track number (Register A) at 448DH.
4B3A
LD A,L 7D
Load Register A with the sector within the track (Register L).
4B3B
LD (448EH),A 32 8E 44
Store Register A, the sector within the track, at 448EH.
4B3E
RET C9
RETURN to 4AFBH with the drive, track and sector stored at 448CH-448EH.
4B3FH - Evaluate a Drive Number
Used by CMD"F", CMD"I" and CMD"M". Evaluates the expression at Register Pair HL as a number 0-255 (INVALID DRIVE NUMBER above 255 or below 0), then 4B49H checks it and stores the drive's select bit at 448CH.
4B3F
GOSUB to the ROM's expression evaluator at 2337H to evaluate the drive expression at Register Pair HL; Register Pair HL comes back past it.
4B42
GOSUB to the ROM's 2B05H: it makes the accumulator an integer in Register Pair DE and returns NZ when Register D is not 00H (above 255 or negative).
4B45
If the number is above 255 or negative, JUMP to 48DAH to report INVALID DRIVE NUMBER.
4B48
LD A,E 7B
Load Register A with the number (Register E).
4B49H - Store the Drive's Select Bit
Entered with a drive number in Register A (from 4B1DH or 4B48H). A drive above 3 gives INVALID DRIVE NUMBER; otherwise its select bit (01H, 02H, 04H or 08H for drives 0-3) is stored at 448CH.
4B49
CP 04H FE 04
Compare the drive number in Register A with 04H.
4B4B
If it is 4 or more, JUMP to 48DAH to report INVALID DRIVE NUMBER.
4B4E
INC A 3C
Add 1 to the drive number in Register A: the number of rotations below.
4B4F
LD B,A 47
Load Register B with Register A, the count of rotations.
4B50
LD A,80H 3E 80
Load Register A with 80H, which the first rotation turns into 01H.
4B52
RLCA 07
Rotate Register A left: 80H becomes 01H on the first pass, then 02H, 04H, 08H.
4B53
Decrement Register B and LOOP BACK to 4B52H: after drive number + 1 rotations Register A holds the drive's select bit.
4B55
LD (448CH),A 32 8C 44
Store Register A, the drive's select bit, at 448CH.
4B58
RET C9
RETURN to the caller with the select bit in Register A and at 448CH.
4B59H - Find the Data of GET and PUT
Used by GET (4AAEH) and PUT (4AE4H). Entered with the first character after the token in Register A and Register Pair HL on it. For #N (a field buffer, 1-4) it returns Register Pair DE = the buffer's address (5600H, 5700H, 5800H or 5900H, whose first byte is its length), 4490H = the address after it and Register C = FFH, the room in a buffer. For a string variable it returns Register Pair DE = its descriptor, 4490H = the address of its characters and Register C = its length.
4B59
CP 23H FE 23
Compare Register A, the character after the token, with 23H (#).
4B5B
If it is not #, JUMP to 4B69H to find a string variable.
4B5D
GOSUB to 4E46H (JP 4E66H) to evaluate the field buffer number after # and return Register Pair DE = the buffer's address (INVALID FIELD BUFFER NUMBER outside 1-4).
4B60
INC DE 13
Point Register Pair DE to the byte after the buffer's length byte, the first data byte.
4B61
LD (4490H),DE ED 53 90 44
Store Register Pair DE, the buffer's first data byte, at 4490H-4491H, the data pointer.
4B65
DEC DE 1B
Point Register Pair DE back to the buffer's length byte.
4B66
LD C,FFH 0E FF
Load Register C with FFH: a field buffer holds up to 255 data bytes.
4B68
RET C9
RETURN to GET or PUT with Register Pair DE = the field buffer and Register C = FFH.
4B69
GOSUB to the ROM's 260DH to find (or make) the variable named at Register Pair HL: Register Pair DE comes back with the address of its value, for a string the descriptor, and its type is set at 40AFH.
4B6C
GOSUB to the ROM's 0AF4H: TYPE MISMATCH unless the variable is a string.
4B6F
PUSH DE D5
Save Register Pair DE, the descriptor's address, on the stack.
4B70
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the descriptor, Register Pair DE = the BASIC text pointer.
4B71
LD C,(HL) 4E
Load Register C with the string's length, byte 0 of the descriptor at Register Pair HL.
4B72
INC HL 23
Point Register Pair HL to byte 1 of the descriptor.
4B73
LD A,(HL) 7E
Load Register A with the low byte of the address of the string's characters, from Register Pair HL.
4B74
LD (4490H),A 32 90 44
Store Register A at 4490H, the low byte of the data pointer.
4B77
INC HL 23
Point Register Pair HL to byte 2 of the descriptor.
4B78
LD A,(HL) 7E
Load Register A with the high byte of the address, from Register Pair HL.
4B79
LD (4491H),A 32 91 44
Store Register A at 4491H: 4490H-4491H is the address of the string's characters.
4B7C
EX DE,HL EB
Exchange Register Pairs DE and HL back: Register Pair HL = the BASIC text pointer.
4B7D
POP DE D1
Restore the descriptor's address into Register Pair DE.
4B7E
RET C9
RETURN to GET or PUT with Register Pair DE = the descriptor and Register C = the length.
4B7FH - Read a Sector and Copy Its Data
Used by LOAD (49D0H). Reads the sector at 448CH-448EH (4B8CH) and copies its data bytes to the address at 4490H (4BB4H). Register Pairs HL, DE and BC are kept.
4B7F
PUSH HL E5
Save Register Pair HL (LOAD's load address) on the stack.
4B80
PUSH DE D5
Save Register Pair DE (LOAD's step) on the stack.
4B81
PUSH BC C5
Save Register Pair BC (the caller's) on the stack around the read.
4B82
GOSUB to 4B8CH to read the sector into 4300H-43FFH and store its length byte at 448FH.
4B85
GOSUB to 4BB4H to copy its data bytes from 4301H to the address at 4490H.
4B88
POP BC C1
Restore Register Pair BC (the caller's) from the stack after the read.
4B89
POP DE D1
Restore Register Pair DE (LOAD's step) from the stack.
4B8A
POP HL E1
Restore Register Pair HL (LOAD's load address) from the stack.
4B8B
RET C9
RETURN to LOAD with the sector's data copied and its length at 448FH.
4B8CH - Read a Sector
Reads the sector at 448CH-448EH into the buffer 4300H-43FFH and stores its length byte (byte 0) at 448FH. Three reads (4BC4H) are tried; if all fail, the head is stepped in and back out and three more are tried; if those fail, the head is restored to track 0, the track is sought again and three more are tried. If those fail too, DISK READ/WRITE ERROR.
4B8C
GOSUB to 4D44H to select the drive at 448CH, seek the track at 448DH and put the sector at 448EH in the sector register. It returns with Register Pair HL = 4300H and the alternate set loaded with 4300H, 37ECH and 37EFH.
4B8F
GOSUB to 4BC4H to read the sector, up to three times; the Carry flag comes back set when every try failed.
4B92
If the sector was read (No Carry from 4BC4H), JUMP to 4BAFH.
4B94
LD A,43H 3E 43
Load Register A with 43H, the Step In command without track register update (rate bits 11).
| 1771 FDC Command: 43H (01000011) | | Function Description |
| 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | | Command=Step In (bits 7-5 = 010) u = 0: track register unchanged h = 0: no head load delay V = 0: no verify r1 r0 = 11: 40 ms stepping rate |
4B96
GOSUB to 4DBCH to give the command and wait until it is done: the head moves one track in.
4B99
LD A,63H 3E 63
Load Register A with 63H, the Step Out command without track register update (rate bits 11).
| 1771 FDC Command: 63H (01100011) | | Function Description |
| 0 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | | Command=Step Out (bits 7-5 = 011) u = 0: track register unchanged h = 0: no head load delay V = 0: no verify r1 r0 = 11: 40 ms stepping rate |
4B9B
GOSUB to 4DBCH to give it and wait: the head is back on the track.
4B9E
GOSUB to 4BC4H to try three more reads of the same sector.
4BA1
If the sector was read now (No Carry), JUMP to 4BAFH.
4BA3
GOSUB to 4DACH to restore the head to track 0.
4BA6
GOSUB to 4D89H to seek the track at 448DH again.
4BA9
GOSUB to 4BC4H to try three more reads after the restore and seek.
4BAC
If they failed too, JUMP to 48E6H to report DISK READ/WRITE ERROR.
4BAF
LD A,(HL) 7E
Load Register A with the sector's length byte from 4300H (Register Pair HL).
4BB0
LD (448FH),A 32 8F 44
Store Register A, the length byte, at 448FH: the number of data bytes in the sector.
4BB3
RET C9
RETURN to the caller with the sector in 4300H-43FFH and its length at 448FH.
4BB4H - Copy a Sector's Data
Copies the data bytes of the sector in the buffer, as many as its length byte at 4300H says, from 4301H to the address at 4490H. A length of 00H copies nothing.
4BB4
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the length byte of the sector in the buffer.
4BB7
LD C,(HL) 4E
Load Register C with the length byte at 4300H (Register Pair HL).
4BB8
INC HL 23
Point Register Pair HL to 4301H, the first data byte.
4BB9
XOR A AF
Load Register A with 00H (XOR A), for Register B and the test below.
4BBA
LD B,A 47
Load Register B with Register A (00H): Register Pair BC = the number of data bytes.
4BBB
OR C B1
OR Register C into Register A: Z when the length is 00H.
4BBC
RET Z C8
If the sector holds no data (Z from OR C), RETURN without copying.
4BBD
LD DE,(4490H) ED 5B 90 44
Load Register Pair DE with the data pointer from 4490H-4491H, where the data goes.
4BC1
LDIR ED B0
Copy Register Pair BC bytes from 4301H (Register Pair HL) to the address in Register Pair DE.
4BC3
RET C9
RETURN to the caller with the data copied to the address that was at 4490H.
4BC4H - Read a Sector, Three Tries
Gives the Read Sector command up to three times (4BCDH). Returns with the Carry flag clear after a read without error, set when all three failed.
4BC4
LD B,03H 06 03
Load Register B with 03H, the number of tries.
4BC6
GOSUB to 4BCDH to read the sector into 4300H-43FFH.
4BC9
RET NC D0
If it was read without error (No Carry), RETURN.
4BCA
Decrement Register B, the tries left, and LOOP BACK to 4BC6H while any are left.
4BCC
RET C9
RETURN with the Carry flag set: three reads failed.
4BCDH - Read a Sector Once
Gives the Read Sector command to the drive selected and sought by 4D44H and stores each byte in the buffer through Register Pair BC' (4300H), taking it from the data register whenever the status shows DATA REQUEST. Returns with the Carry flag clear when the status has no error bit (NOT READY, RECORD NOT FOUND, CRC ERROR, LOST DATA); otherwise stores the status at 4495H and returns with the Carry flag set.
4BCD
LD A,88H 3E 88
Load Register A with 88H, the Read Sector command.
| 1771 FDC Command: 88H (10001000) | | Function Description |
| 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | | Command=Read Sector (bits 7-5 = 100) m = 0: one sector b = 1: IBM sector length E = 0: no head load delay |
4BCF
GOSUB to 4DE3H to select the drive, wait until the controller is not busy, write the command in Register A to 37ECH and wait until it shows BUSY.
4BD2
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: Register Pair BC = 4300H (the buffer pointer), DE = 37ECH (the status), HL = 37EFH (the data register).
4BD3
JUMP to 4BDBH to read the status for the first byte.
4BD5
AND 81H E6 81
No byte was waiting. Keep bit 7 (NOT READY) and bit 0 (BUSY) of the status in Register A.
4BD7
XOR 01H EE 01
Flip bit 0: Register A is 00H only while the controller is busy and the drive is ready.
4BD9
If the read is over (BUSY off) or the drive is not ready, JUMP to 4BE5H to check the status.
4BDB
LD A,(DE) 1A
Fetch the controller's status from 37ECH (Register Pair DE) into Register A.
4BDC
BIT 1,A CB 4F
Test bit 1 of Register A, DATA REQUEST: 1 when a byte of the sector is waiting.
4BDE
If no byte is waiting, JUMP to 4BD5H to see whether the read is still running.
4BE0
LD A,(HL) 7E
Fetch the byte from the data register 37EFH (Register Pair HL) into Register A.
4BE1
LD (BC),A 02
Store Register A, the byte read, in the buffer at Register Pair BC.
4BE2
INC BC 03
Point Register Pair BC to the next byte of the buffer.
4BE3
LOOP BACK to 4BDBH for the next byte; Register Pair BC points where it goes.
4BE5
LD A,(DE) 1A
Fetch the status after the read from 37ECH (Register Pair DE) into Register A.
4BE6
AND 9CH E6 9C
Keep the error bits of Register A, the status: 7 NOT READY, 4 RECORD NOT FOUND, 3 CRC ERROR, 2 LOST DATA. AND also clears the Carry flag.
4BE8
LD BC,4300H 01 00 43
Set Register Pair BC back to 4300H, the start of the buffer; LD does not change the flags.
4BEB
If no error bit is set, JUMP to 4BF4H with the Carry flag clear.
4BED
LD A,(DE) 1A
Fetch the status from 37ECH (Register Pair DE) again into Register A.
4BEE
LD (4495H),A 32 95 44
Store Register A, the status, at 4495H, the status of the last error, for LOC(2).
4BF1
LD (HL),D0H 36 D0
Write D0H to 37EFH (Register Pair HL), the data register. D0H is the Force Interrupt command, but the command register is 37ECH; here it only loads the data register. The loop left when BUSY went off or the drive showed NOT READY, so the command is ended or the drive is not ready.
4BF3
SCF 37
Set the Carry flag: the read failed, and 4BC4H tries again.
4BF4
EXX D9
Exchange back to the main register set; the alternate set keeps 4300H, 37ECH and 37EFH.
4BF5
RET C9
RETURN to 4BC4H with the Carry flag telling whether the read failed.
4BF6H - Write a Sector
Writes the sector at 448CH-448EH: byte 0 is the length byte from 448FH, then that many data bytes from the address at 4490H, all put in the buffer at 4300H first. The whole 256 byte buffer is written, so the bytes past the data are whatever the buffer held. The test for a write protected diskette reads bit 6 of the status at 37ECH: it is WRITE PROTECT only when 4D44H has just given a Restore or Seek. When the head was already on the track, the status is that of the last command (usually the read that checked the last write, whose bit 6 is a data mark bit), and a protected diskette then fails every write and ends in DISK READ/WRITE ERROR instead. Three writes, each followed by a read to check it, are tried (4C36H); if all fail, the head is stepped in and back out and three more are tried; then the head is restored to track 0, the track sought again and three more tried. If those fail too, DISK READ/WRITE ERROR. Register Pairs HL, DE and BC are kept.
4BF6
PUSH HL E5
Save Register Pair HL (the caller's) on the stack.
4BF7
PUSH DE D5
Save Register Pair DE (the caller's) on the stack.
4BF8
PUSH BC C5
Save Register Pair BC (the caller's) on the stack.
4BF9
GOSUB to 4D44H to select the drive at 448CH, seek the track at 448DH and put the sector at 448EH in the sector register. It returns with Register Pair HL = 4300H, the buffer, and Register Pair DE = the data pointer from 4490H.
4BFC
LD A,(37ECH) 3A EC 37
Fetch the controller's status from 37ECH into Register A. It is the status after a seek only when 4D44H has just given a Restore or Seek; otherwise it is the status of the last command given.
4BFF
BIT 6,A CB 77
Test bit 6 of Register A: after a Restore or Seek it is WRITE PROTECT, 1 when the diskette's notch is covered (after a read it is a data mark bit).
4C01
If the diskette is write protected, JUMP to 48E2H to report DISK WRITE PROTECTED.
4C04
LD A,(448FH) 3A 8F 44
Fetch the length byte of the sector to write from 448FH into Register A.
4C07
LD C,A 4F
Load Register C with Register A, the length byte.
4C08
LD B,00H 06 00
Load Register B with 00H: Register Pair BC = the number of data bytes.
4C0A
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = 4300H, the buffer, Register Pair HL = the address of the data.
4C0B
LD (DE),A 12
Store the length byte (Register A) in byte 0 of the buffer, 4300H (Register Pair DE).
4C0C
INC DE 13
Point Register Pair DE to 4301H, where the data bytes go.
4C0D
OR A B7
Test Register A, the length: Z when there is no data.
4C0E
If the length is 00H, JUMP to 4C12H: there is no data to copy.
4C10
LDIR ED B0
Copy Register Pair BC data bytes from Register Pair HL to the buffer from 4301H (Register Pair DE).
4C12
GOSUB to 4C36H to write the buffer to the sector and read it back, up to three times; the Carry flag comes back set when every try failed.
4C15
If the sector was written (No Carry from 4C36H), JUMP to 4C32H.
4C17
LD A,43H 3E 43
Load Register A with 43H, the Step In command without track register update (rate bits 11).
| 1771 FDC Command: 43H (01000011) | | Function Description |
| 0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | | Command=Step In (bits 7-5 = 010) u = 0: track register unchanged h = 0: no head load delay V = 0: no verify r1 r0 = 11: 40 ms stepping rate |
4C19
GOSUB to 4DBCH to give the command and wait until it is done: the head moves one track in.
4C1C
LD A,63H 3E 63
Load Register A with 63H, the Step Out command without track register update (rate bits 11).
| 1771 FDC Command: 63H (01100011) | | Function Description |
| 0 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | | Command=Step Out (bits 7-5 = 011) u = 0: track register unchanged h = 0: no head load delay V = 0: no verify r1 r0 = 11: 40 ms stepping rate |
4C1E
GOSUB to 4DBCH to give it and wait: the head is back on the track.
4C21
GOSUB to 4C36H to try three more writes of the same sector.
4C24
If the sector was written now (No Carry), JUMP to 4C32H.
4C26
GOSUB to 4DACH to restore the head to track 0.
4C29
GOSUB to 4D89H to seek the track at 448DH again.
4C2C
GOSUB to 4C36H to try three more writes after the restore and seek.
4C2F
If they failed too, JUMP to 48E6H to report DISK READ/WRITE ERROR.
4C32
POP BC C1
Restore Register Pair BC (the caller's) from the stack.
4C33
POP DE D1
Restore Register Pair DE (the caller's) from the stack.
4C34
POP HL E1
Restore Register Pair HL (the caller's) from the stack.
4C35
RET C9
RETURN to the caller with the sector written.
4C36H - Write a Sector, Three Tries
Writes the buffer to the sector (4C44H) and reads the sector back (4C6DH) up to three times. Returns with the Carry flag clear when a write and the read after it were both without error, set when all three tries failed.
4C36
LD B,03H 06 03
Load Register B with 03H, the number of tries.
4C38
GOSUB to 4C44H to write the buffer 4300H-43FFH to the sector.
4C3B
If the write failed (Carry), JUMP to 4C41H for the next try.
4C3D
GOSUB to 4C6DH to read the sector back without keeping its data.
4C40
RET NC D0
If it read without error (No Carry), RETURN: the sector is written.
4C41
Decrement Register B, the tries left, and LOOP BACK to 4C38H while any are left.
4C43
RET C9
RETURN with the Carry flag set: three tries failed.
4C44H - Write a Sector Once
Gives the Write Sector command to the drive selected and sought by 4D44H and writes the bytes of the buffer through Register Pair BC' (4300H), one each time the status shows DATA REQUEST. Returns with the Carry flag clear when the status has no error bit (NOT READY, WRITE PROTECT, WRITE FAULT, LOST DATA); otherwise stores the status at 4495H and returns with the Carry flag set.
4C44
LD A,A8H 3E A8
Load Register A with A8H, the Write Sector command.
| 1771 FDC Command: A8H (10101000) | | Function Description |
| 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | | Command=Write Sector (bits 7-5 = 101) m = 0: one sector b = 1: IBM sector length E = 0: no head load delay a1 a0 = 00: data mark FBH (normal) |
4C46
GOSUB to 4DE3H to select the drive, wait until the controller is not busy, write the command to 37ECH and wait until it shows BUSY.
4C49
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: Register Pair BC = 4300H (the buffer pointer), DE = 37ECH (the status), HL = 37EFH (the data register).
4C4A
JUMP to 4C52H to read the status for the first byte.
4C4C
AND 81H E6 81
The controller wants no byte. Keep bit 7 (NOT READY) and bit 0 (BUSY) of the status in Register A.
4C4E
XOR 01H EE 01
Flip bit 0: Register A is 00H only while the controller is busy and the drive is ready.
4C50
If the write is over (BUSY off) or the drive is not ready, JUMP to 4C5CH to check the status.
4C52
LD A,(DE) 1A
Fetch the controller's status from 37ECH (Register Pair DE) into Register A.
4C53
BIT 1,A CB 4F
Test bit 1 of Register A, DATA REQUEST: 1 when the controller wants the next byte.
4C55
If it wants none, JUMP to 4C4CH to see whether the write is still running.
4C57
LD A,(BC) 0A
Fetch the next byte of the buffer (Register Pair BC) into Register A.
4C58
LD (HL),A 77
Write Register A, the byte from the buffer, to the data register 37EFH (Register Pair HL).
4C59
INC BC 03
Point Register Pair BC to the next byte of the buffer.
4C5A
LOOP BACK to 4C52H for the next byte; Register Pair BC points at it.
4C5C
LD A,(DE) 1A
Fetch the status after the write from 37ECH (Register Pair DE) into Register A.
4C5D
AND E4H E6 E4
Keep the error bits of a write in Register A: 7 NOT READY, 6 WRITE PROTECT, 5 WRITE FAULT, 2 LOST DATA. AND also clears the Carry flag.
4C5F
LD BC,4300H 01 00 43
Set Register Pair BC back to 4300H, the start of the buffer; LD does not change the flags.
4C62
If no error bit is set, JUMP to 4C6BH with the Carry flag clear.
4C64
LD A,(DE) 1A
Fetch the status from 37ECH (Register Pair DE) again into Register A.
4C65
LD (4495H),A 32 95 44
Store Register A, the status, at 4495H, the status of the last error, for LOC(2).
4C68
LD (HL),D0H 36 D0
Write D0H to 37EFH (Register Pair HL), the data register; as at 4BF1H, the Force Interrupt command does not reach the command register 37ECH from here.
4C6A
SCF 37
Set the Carry flag: the write failed, and 4C36H tries again.
4C6B
EXX D9
EXX: exchange back to the main register set; the alternate set keeps 4300H, 37ECH and 37EFH.
4C6C
RET C9
RETURN to 4C36H with the Carry flag telling whether the write failed.
4C6DH - Read a Sector Back to Check It
Used after each write (4C3DH) and by the check of a formatted track (48C9H). Gives the Read Sector command and takes every byte from the data register without keeping it. Returns with the Carry flag clear when the status has no error bit (NOT READY, RECORD NOT FOUND, CRC ERROR, LOST DATA); otherwise stores the status at 4495H and returns with the Carry flag set.
4C6D
LD A,88H 3E 88
Load Register A with 88H, the Read Sector command.
| 1771 FDC Command: 88H (10001000) | | Function Description |
| 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | | Command=Read Sector (bits 7-5 = 100) m = 0: one sector b = 1: IBM sector length E = 0: no head load delay |
4C6F
GOSUB to 4DE3H to select the drive, wait until the controller is not busy, write the command to 37ECH and wait until it shows BUSY.
4C72
EXX D9
Exchange Register Pairs BC, DE and HL with the alternate set: Register Pair DE = 37ECH (the status), HL = 37EFH (the data register).
4C73
JUMP to 4C7BH to read the status for the first byte.
4C75
AND 81H E6 81
No byte was waiting. Keep bit 7 (NOT READY) and bit 0 (BUSY) of the status in Register A.
4C77
XOR 01H EE 01
Flip bit 0: Register A is 00H only while the controller is busy and the drive is ready.
4C79
If the read is over (BUSY off) or the drive is not ready, JUMP to 4C83H to check the status.
4C7B
LD A,(DE) 1A
Fetch the controller's status from 37ECH (Register Pair DE) into Register A.
4C7C
BIT 1,A CB 4F
Test bit 1 of Register A, DATA REQUEST: 1 when a byte of the sector is waiting.
4C7E
If no byte is waiting, JUMP to 4C75H to see whether the read is still running.
4C80
LD A,(HL) 7E
Fetch the byte from the data register 37EFH (Register Pair HL) into Register A; it is not kept, the read only takes it so the controller can go on.
4C81
LOOP BACK to 4C7BH for the next byte of the sector.
4C83
LD A,(DE) 1A
Fetch the status after the read from 37ECH (Register Pair DE) into Register A.
4C84
AND 9CH E6 9C
Keep the error bits of Register A, the status: 7 NOT READY, 4 RECORD NOT FOUND, 3 CRC ERROR, 2 LOST DATA. AND also clears the Carry flag.
4C86
If no error bit is set, JUMP to 4C8FH with the Carry flag clear.
4C88
LD A,(DE) 1A
Fetch the status from 37ECH (Register Pair DE) again into Register A.
4C89
LD (4495H),A 32 95 44
Store Register A, the status, at 4495H, the status of the last error, for LOC(2).
4C8C
LD (HL),D0H 36 D0
Write D0H to 37EFH (Register Pair HL), the data register; as at 4BF1H, the Force Interrupt command does not reach the command register 37ECH from here.
4C8E
SCF 37
Set the Carry flag: the read (or the check after a write) failed.
4C8F
EXX D9
EXX: exchange back to the main register set; the alternate set keeps 4300H, 37ECH and 37EFH.
4C90
RET C9
RETURN to the caller with the Carry flag telling whether the read failed.
4C91H - Format One Track
Used by the format at 4870H. Selects the drive at 448CH and seeks the track at 448DH (4D44H); bit 6 of the status then gives DISK WRITE PROTECTED, when 4D44H has given a Restore or Seek (otherwise the status is the last command's, as at 4BFFH). Then gives the Write Track command and feeds the controller the whole track, one byte each time it shows DATA REQUEST: a gap of 14 FFH, and for each of the (4493H) sectors, in the order of the table at 449BH: six 00H, the ID mark FEH, the track, side 00H, the sector number, size code 01H (256 bytes), the CRC (F7H), 12 FFH, six 00H, the data mark FBH, the length byte 00H (an empty sector) and 255 E5H, the CRC and 12 FFH; then FFH until the track ends. The controller ends the command at the index hole; a track that ends early or a status with any bit set is written again, three times in all, and then gives CAN'T FORMAT DISK. Register Pairs HL, DE and BC are kept. The main register set keeps the tries (C), the sectors left (B) and the pointer into the sector table (HL); the alternate set sends the bytes (B' count, C' byte, DE' 37ECH, HL' 37EFH).
4C91
PUSH HL E5
Save Register Pair HL (448DH for the format) on the stack.
4C92
PUSH DE D5
Save Register Pair DE (the geometry) on the stack.
4C93
PUSH BC C5
Save Register Pair BC (the format's track count) on the stack.
4C94
GOSUB to 4D44H to select the drive at 448CH and seek the track at 448DH; the alternate set comes back with DE' = 37ECH and HL' = 37EFH.
4C97
LD A,(37ECH) 3A EC 37
Fetch the controller's status from 37ECH into Register A: the status after the Restore or Seek 4D44H gave, or of the last command when it gave none.
4C9A
BIT 6,A CB 77
Test bit 6 of Register A: after a Restore or Seek it is WRITE PROTECT, 1 when the diskette's notch is covered.
4C9C
If the diskette is write protected, JUMP to 48E2H to report DISK WRITE PROTECTED.
4C9F
LD C,03H 0E 03
Load Register C with 03H, the number of times the track may be written.
4CA1
LD A,(4493H) 3A 93 44
Fetch the number of sectors of a track from 4493H into Register A. A failed write of the track comes back here.
4CA4
LD B,A 47
Load Register B with Register A, the sectors of a track: the sectors left to lay down.
4CA5
LD HL,449BH 21 9B 44
Point Register Pair HL to 449BH, the table of sector numbers in the order they go on the track.
4CA8
LD A,F4H 3E F4
Load Register A with F4H, the Write Track command.
| 1771 FDC Command: F4H (11110100) | | Function Description |
| 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | | Command=Write Track (bits 7-4 = 1111) E = 1: head load delay In the data, F7H writes the two CRC bytes and F8H-FEH are written as address marks |
4CAA
GOSUB to 4DE3H to select the drive, wait until the controller is not busy, write the command to 37ECH and wait until it shows BUSY.
4CAD
EXX D9
Exchange to the alternate register set, which sends the bytes: DE' = 37ECH, HL' = 37EFH.
4CAE
LD C,FFH 0E FF
Load Register C' with FFH, the byte of the gap at the start of the track.
4CB0
LD B,0EH 06 0E
Load Register B' with 0EH, the count: 14 bytes.
4CB2
GOSUB to 4D2BH to send the byte in Register C' Register B' times.
4CB5
LD C,00H 0E 00
Load Register C' with 00H. Each sector starts here.
4CB7
LD B,06H 06 06
Load Register B' with 06H: six 00H before the ID mark.
4CB9
GOSUB to 4D2BH to send Register C' (00H) Register B' (6) times.
4CBC
LD C,FEH 0E FE
Load Register C' with FEH, which the controller writes as the ID address mark.
4CBE
INC B 04
Increment Register B' from 00H to 01H: one byte.
4CBF
GOSUB to 4D2BH to send Register C' (FEH) once: the ID address mark.
4CC2
LD A,(448DH) 3A 8D 44
Fetch the track number from 448DH into Register A.
4CC5
LD C,A 4F
Load Register C' with Register A, the track number: byte 1 of the ID field.
4CC6
INC B 04
Increment Register B' from 00H to 01H: one byte to send.
4CC7
GOSUB to 4D2BH to send Register C', the track number, once.
4CCA
LD C,B 48
Load Register C' with Register B' (00H after the send): the side, byte 2 of the ID field.
4CCB
INC B 04
Increment Register B' from 00H to 01H: one byte to send.
4CCC
GOSUB to 4D2BH to send Register C' (00H), the side, once.
4CCF
EXX D9
EXX: exchange to the main register set, where Register Pair HL points into the sector table; the alternate set keeps the sending registers.
4CD0
LD A,(HL) 7E
Fetch the next sector number from the table (Register Pair HL, from 449BH) into Register A.
4CD1
INC HL 23
Point Register Pair HL to the next entry of the table.
4CD2
EXX D9
EXX: exchange back to the alternate register set, which sends the bytes.
4CD3
LD C,A 4F
Load Register C' with Register A, the sector number: byte 3 of the ID field.
4CD4
INC B 04
Increment Register B' from 00H to 01H: one byte to send.
4CD5
GOSUB to 4D2BH to send Register C', the sector number, once.
4CD8
INC B 04
Increment Register B' from 00H to 01H: one byte to send.
4CD9
LD C,B 48
Load Register C' with Register B' (01H): the size code of a 256 byte sector, byte 4 of the ID field.
4CDA
GOSUB to 4D2BH to send Register C' (01H), the size code, once.
4CDD
LD C,F7H 0E F7
Load Register C' with F7H, which the controller turns into the two CRC bytes of the ID field.
4CDF
INC B 04
Increment Register B' from 00H to 01H: one byte to send.
4CE0
GOSUB to 4D2BH to send Register C' (F7H) once: the controller writes the ID field's two CRC bytes.
4CE3
LD C,FFH 0E FF
Load Register C' with FFH, the gap after the ID field.
4CE5
LD B,0CH 06 0C
Load Register B' with 0CH: 12 bytes of the gap after the ID field.
4CE7
GOSUB to 4D2BH to send Register C' (FFH) Register B' (12) times.
4CEA
LD C,B 48
Load Register C' with Register B' (00H after the send).
4CEB
LD B,06H 06 06
Load Register B' with 06H: six 00H before the data mark.
4CED
GOSUB to 4D2BH to send Register C' (00H) Register B' (6) times.
4CF0
LD C,FBH 0E FB
Load Register C' with FBH, which the controller writes as the data address mark.
4CF2
INC B 04
Increment Register B' from 00H to 01H: one byte to send.
4CF3
GOSUB to 4D2BH to send Register C' (FBH) once: the data address mark.
4CF6
LD C,B 48
Load Register C' with Register B' (00H): byte 0 of the sector, its length byte, 00H for an empty sector.
4CF7
INC B 04
Increment Register B' from 00H to 01H: one byte to send.
4CF8
GOSUB to 4D2BH to send Register C' (00H) once: the length byte of an empty sector.
4CFB
LD C,E5H 0E E5
Load Register C' with E5H, the filler of the rest of the sector.
4CFD
DEC B 05
Decrement Register B' from 00H to FFH: 255 bytes.
4CFE
GOSUB to 4D2BH to send them: with the length byte the sector holds 256 bytes.
4D01
LD C,F7H 0E F7
Load Register C' with F7H, which the controller turns into the two CRC bytes of the data field.
4D03
INC B 04
Increment Register B' from 00H to 01H: one byte to send.
4D04
GOSUB to 4D2BH to send Register C' (F7H) once: the controller writes the data field's two CRC bytes.
4D07
LD C,FFH 0E FF
Load Register C' with FFH, the gap after the sector.
4D09
LD B,0CH 06 0C
Load Register B' with 0CH: 12 bytes of the gap after the sector.
4D0B
GOSUB to 4D2BH to send Register C' (FFH) Register B' (12) times.
4D0E
EXX D9
EXX: exchange to the main register set, where Register B counts the sectors left; the alternate set keeps the sending registers.
4D0F
DEC B 05
Decrement Register B, the sectors left to lay down.
4D10
EXX D9
Exchange back to the alternate set; EXX does not change the flags.
4D11
If sectors are left, LOOP BACK to 4CB5H for the next one.
4D13
LD C,FFH 0E FF
Load Register C' with FFH, the filler to the end of the track; Register B' is 00H, a count of 256.
4D15
GOSUB to 4D2BH to send FFH until the controller ends the command at the index hole. The track is shorter than these bytes, so 4D2BH leaves through 4D34H, which comes back to 4D18H with Register A = the final status.
4D18
OR A B7
Test Register A: the final status (00H when the track was written without error), or the complement of the status when the track ended before the last bytes (4D41H).
4D19
If it is 00H, JUMP to 4D21H: the track is formatted.
4D1B
DEC C 0D
Decrement Register C, the number of times the track may still be written.
4D1C
If none is left, JUMP to 48F2H to report CAN'T FORMAT DISK.
4D1F
JUMP back to 4CA1H to write the whole track again.
4D21
POP BC C1
Restore Register Pair BC (the format's) from the stack.
4D22
POP DE D1
Restore Register Pair DE (the format's) from the stack.
4D23
POP HL E1
Restore Register Pair HL (the format's 448DH) from the stack.
4D24
RET C9
RETURN to the format with the track written and Register Pairs HL, DE and BC as they were.
4D25
AND E5H E6 E5
The controller wants no byte. Keep the status bits 7 (NOT READY), 6 (WRITE PROTECT), 5 (WRITE FAULT), 2 (LOST DATA) and 0 (BUSY) in Register A.
4D27
XOR 01H EE 01
Flip bit 0: Register A is 00H only while the controller is busy and no error bit is set.
4D29
If the command has ended or an error bit is set, JUMP to 4D34H.
4D2B
LD A,(DE) 1A
Fetch the controller's status from 37ECH (Register Pair DE') into Register A. 4D2BH sends the byte in Register C' Register B' times (256 when Register B' is 00H).
4D2C
BIT 1,A CB 4F
Test bit 1 of Register A, DATA REQUEST: 1 when the controller wants the next byte.
4D2E
If it wants none, JUMP to 4D25H to see whether the command is still running.
4D30
LD (HL),C 71
Write the byte in Register C' to the data register 37EFH (Register Pair HL').
4D31
Decrement Register B', the bytes left, and LOOP BACK to 4D2BH until they are all sent.
4D33
RET C9
RETURN to the format with Register B' = 00H, every byte of the run sent.
4D34
EX DE,HL EB
The command has ended. Exchange Register Pairs DE' and HL': HL' = 37ECH.
4D35
LD A,(HL) 7E
Fetch the final status from 37ECH (Register Pair HL') into Register A.
4D36
EX DE,HL EB
Exchange Register Pairs DE' and HL' back: DE' = 37ECH, HL' = 37EFH.
4D37
EXX D9
EXX: exchange to the main register set (Register C, the tries left); the alternate set keeps 37ECH and 37EFH.
4D38
POP DE D1
Take the return address of this call of 4D2BH off the stack into Register Pair DE: it tells which byte run was being sent.
4D39
LD HL,4D18H 21 18 4D
Load Register Pair HL with 4D18H, the return address of the last call (4D15H), the run of FFH to the end of the track.
4D3C
OR A B7
Clear the Carry flag for the subtraction; Register A keeps the status.
4D3D
SBC HL,DE ED 52
Subtract the return address (Register Pair DE) from Register Pair HL (4D18H): Z when the command ended during the last run, as it should.
4D3F
If it did, JUMP to 4D18H with the status in Register A.
4D41
CPL 2F
Otherwise the track ended (or failed) before all its sectors were written: complement Register A, so that it is not 00H (unless the status was FFH).
4D42
JUMP to 4D18H with Register A not 00H, to try the track again.
4D44H - Select, Seek and Set the Sector
Used before every sector transfer and before formatting a track. Finds the drive's entry in the table of head positions at 4497H-449AH (INVALID DRIVE NUMBER when no select bit is set), loads the alternate set with 4300H, 37ECH and 37EFH, selects the drive (4DF6H), puts the drive's head position in the track register, restores the head first when it is not known (FFH), seeks the track at 448DH when the head is elsewhere, and puts the sector at 448EH in the sector register. Returns with Register Pair HL = 4300H, Register Pair DE = the data pointer from 4490H and 00H at 4495H.
4D44
LD HL,4497H 21 97 44
Point Register Pair HL to 4497H, the head position of drive 0.
4D47
LD A,(448CH) 3A 8C 44
Fetch the drive select bit from 448CH into Register A.
4D4A
LD B,04H 06 04
Load Register B with 04H, the number of drives.
4D4C
RRA 1F
Rotate Register A right through the Carry flag: the next lowest bit goes into the Carry flag.
4D4D
If it was the drive's bit, JUMP to 4D55H with Register Pair HL on its entry.
4D4F
INC HL 23
Point Register Pair HL to the next drive's entry.
4D50
Decrement Register B and LOOP BACK to 4D4CH for the next drive.
4D52
No select bit was set in bits 0-3: JUMP to 48DAH to report INVALID DRIVE NUMBER.
4D55
PUSH HL E5
Save Register Pair HL, the drive's entry in the table, on the stack.
4D56
LD BC,4300H 01 00 43
Load Register Pair BC with 4300H, the sector buffer.
4D59
LD DE,37ECH 11 EC 37
Load Register Pair DE with 37ECH, the controller's command and status register.
4D5C
LD HL,37EFH 21 EF 37
Load Register Pair HL with 37EFH, the controller's data register.
4D5F
EXX D9
Exchange them into the alternate set: BC' = 4300H, DE' = 37ECH, HL' = 37EFH, as the transfer routines need them.
4D60
GOSUB to 4DF6H to select the drive, waiting for the motor when it was off.
4D63
POP HL E1
Restore the drive's entry in the table into Register Pair HL.
4D64
LD A,(HL) 7E
Fetch the drive's head position from its entry (Register Pair HL) into Register A.
4D65
LD (37EDH),A 32 ED 37
Store Register A, the head position, in the controller's track register 37EDH: the controller and the head now agree on the track (FFH when it is not known).
4D68
INC A 3C
Increment Register A, the head position: FFH (not known) becomes 00H.
4D69
If the head position is not known, GOSUB to 4DACH to restore the head to track 0.
4D6C
LD A,(448DH) 3A 8D 44
Fetch the track to use from 448DH into Register A.
4D6F
LD (HL),A 77
Store Register A, the track to use, in the drive's entry at Register Pair HL: the head will be on that track.
4D70
LD A,(37EDH) 3A ED 37
Fetch the controller's track register from 37EDH into Register A (00H after a restore, else the old head position).
4D73
CP (HL) BE
Compare Register A, the track register, with the track to use, now at Register Pair HL.
4D74
If the head is on another track, GOSUB to 4D89H to seek the track at 448DH.
4D77
LD A,(448EH) 3A 8E 44
Fetch the sector of the transfer from 448EH into Register A.
4D7A
LD (37EEH),A 32 EE 37
Store Register A, the sector, in the controller's sector register 37EEH.
4D7D
LD HL,4300H 21 00 43
Point Register Pair HL to 4300H, the sector buffer.
4D80
LD DE,(4490H) ED 5B 90 44
Load Register Pair DE with the data pointer from 4490H-4491H.
4D84
XOR A AF
Load Register A with 00H (XOR A), for the error status below.
4D85
LD (4495H),A 32 95 44
Store Register A (00H) at 4495H: no error status yet for this transfer.
4D88
RET C9
RETURN to the caller with Register Pair HL = 4300H and Register Pair DE = the data pointer.
4D89H - Seek the Track, With a Restore if Needed
Seeks the track at 448DH (4D97H). If the seek fails, restores the head to track 0 and seeks again; if that fails too, DISK SEEK ERROR.
4D89
GOSUB to 4D97H to seek the track at 448DH; the Carry flag comes back set when the status after the seek shows NOT READY, SEEK ERROR or CRC ERROR.
4D8C
RET NC D0
If the seek succeeded (No Carry), RETURN to the caller.
4D8D
GOSUB to 4DACH to restore the head to track 0.
4D90
GOSUB to 4D97H to seek the track again after the restore.
4D93
If it failed again, JUMP to 48EEH to report DISK SEEK ERROR.
4D96
RET C9
RETURN to the caller with the head on the track.
4D97H - Seek the Track
Gives the Seek command to the track at 448DH, with the stepping rate bits from 4494H and without verify, and waits until it is done (4DBCH). Returns the Carry flag clear when the status after it has none of the bits 7 (NOT READY), 4 (SEEK ERROR) and 3 (CRC ERROR), set otherwise; without verify only NOT READY can be set.
4D97
LD A,(448DH) 3A 8D 44
Fetch the track to seek from 448DH into Register A.
4D9A
LD (37EFH),A 32 EF 37
Store Register A, the track, in the controller's data register 37EFH: the Seek command takes the track to go to from there.
4D9D
LD A,(4494H) 3A 94 44
Fetch the stepping rate from 4494H into Register A (03H here).
4DA0
AND 03H E6 03
Keep bits 1-0 of Register A, the stepping rate.
4DA2
OR 10H F6 10
Set bit 4: Register A = 10H + the rate bits, the Seek command with no head load and no verify (bit 2 is 0).
| 1771 FDC Command: 13H (00010011) | | Function Description |
| 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | | Command=Seek (bits 7-4 = 0001) h = 0: no head load delay V = 0: no verify r1 r0 = 11: 40 ms stepping rate |
4DA4
GOSUB to 4DBCH to give the command in Register A and wait until it is done; Register A comes back with the status.
4DA7
AND 98H E6 98
Keep the bits 7 (NOT READY), 4 (SEEK ERROR) and 3 (CRC ERROR) of the status in Register A; AND also clears the Carry flag. Without verify the controller sets neither bit 4 nor bit 3 after a seek, so in effect only NOT READY is tested.
4DA9
RET Z C8
If none is set, RETURN with the Carry flag clear: the head is on the track.
4DAA
SCF 37
Set the Carry flag: the seek failed, and 4D89H restores and tries again.
4DAB
RET C9
RETURN to the caller with the Carry flag set.
4DACH - Restore the Head to Track 0
Gives the Restore command with the stepping rate bits from 4494H and waits until it is done (4DBCH). It succeeds when the status after it shows TRACK 0 (bit 2) and none of the bits 7 (NOT READY), 4 (SEEK ERROR) and 3 (CRC ERROR); otherwise DISK SEEK ERROR.
4DAC
LD A,(4494H) 3A 94 44
Fetch the stepping rate from 4494H into Register A.
4DAF
AND 03H E6 03
Keep its bits 1-0: Register A = 00H + the rate, the Restore command without head load and without verify.
| 1771 FDC Command: 03H (00000011) | | Function Description |
| 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | | Command=Restore (bits 7-4 = 0000) h = 0: no head load delay V = 0: no verify r1 r0 = 11: 40 ms stepping rate |
4DB1
GOSUB to 4DBCH to give the command and wait until it is done; Register A comes back with the status.
4DB4
AND 9CH E6 9C
Keep the bits 7 (NOT READY), 4 (SEEK ERROR), 3 (CRC ERROR) and 2 (TRACK 0) of Register A, the status.
4DB6
XOR 04H EE 04
Flip bit 2 of Register A: the result is 00H only when the head is on track 0 and no error bit is set.
4DB8
RET Z C8
If the head is on track 0 without error (Z), RETURN to the caller.
4DB9
Otherwise JUMP to 48EEH to report DISK SEEK ERROR.
4DBCH - Give a Command and Wait Until It Is Done
Entered with a command in Register A: gives it (4DE3H) and then waits until the controller is not busy (4DBFH). Returns the last status in Register A.
4DBC
GOSUB to 4DE3H to select the drive, wait until the controller is not busy, write the command in Register A to 37ECH and wait until it shows BUSY.
4DBFH - Wait Until the Controller Is Not Busy
Reads the status through Register Pair DE' (37ECH) until BUSY is off, selecting the drive at 448CH again on every pass so that its motor keeps running, and storing each status at 4495H. After 65536 passes with BUSY still on, it ends the command (D0H) and reports DISK MISSING OR DOOR OPEN. Returns the last status in Register A; Register Pair BC is kept.
4DBF
EXX D9
Exchange to the alternate register set: Register Pair DE' = 37ECH.
4DC0
PUSH BC C5
Save Register Pair BC' (the buffer pointer) on the stack.
4DC1
LD BC,0000H 01 00 00
Load Register Pair BC' with 0000H, a count of 65536 passes.
4DC4
LD A,(448CH) 3A 8C 44
Fetch the drive select bit from 448CH into Register A.
4DC7
LD (37E1H),A 32 E1 37
Store Register A, the drive select bit, to the drive select latch at 37E1H: the drive stays selected and its motor keeps running.
4DCA
DEC BC 0B
Decrement the pass count in Register Pair BC'.
4DCB
LD A,B 78
Copy the high byte of the pass count (Register B') into Register A.
4DCC
OR C B1
OR in its low byte (Register C'): Register A is 00H when the count has reached 0000H.
4DCD
If 65536 passes have gone by, JUMP to 4DDAH: the controller never finished.
4DCF
LD A,(DE) 1A
Fetch the controller's status from 37ECH (Register Pair DE') into Register A.
4DD0
LD (4495H),A 32 95 44
Store Register A, the status, at 4495H, the status LOC(2) reports.
4DD3
BIT 0,A CB 47
Test bit 0 of Register A, the status: BUSY, 1 while the controller works.
4DD5
LOOP BACK to 4DC4H while the controller is busy.
4DD7
POP BC C1
Restore Register Pair BC' (the buffer pointer).
4DD8
EXX D9
EXX: exchange back to the main register set; the alternate set keeps 4300H, 37ECH and 37EFH.
4DD9
RET C9
RETURN to the caller with the last status in Register A, BUSY off.
4DDA
LD A,D0H 3E D0
Load Register A with D0H, the Force Interrupt command.
| 1771 FDC Command: D0H (11010000) | | Function Description |
| 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | | Command=Force Interrupt (bits 7-4 = 1101) I3-I0 = 0000: end the command, no interrupt |
4DDC
LD (37ECH),A 32 EC 37
Write Register A (D0H) to the command register 37ECH: the command that never finished is ended.
4DDF
EXX D9
EXX: exchange back to the main register set (Register Pair BC' of the alternate set stays on the stack; the error ends the statement).
4DE0
JUMP to 48EAH to report DISK MISSING OR DOOR OPEN.
4DE3H - Give the Controller a Command
Entered with a command in Register A. Selects the drive (4DF6H), waits until the controller is not busy (4DBFH), writes the command to 37ECH through Register Pair DE' and waits until the controller shows BUSY, so that the next status read belongs to the new command.
4DE3
PUSH AF F5
Save Register Pair AF, with the command in Register A, on the stack.
4DE4
GOSUB to 4DF6H to select the drive, waiting for the motor when it was off.
4DE7
GOSUB to 4DBFH to wait until the controller is not busy.
4DEA
POP AF F1
Restore Register Pair AF from the stack: Register A holds the command again.
4DEB
EXX D9
Exchange to the alternate register set: Register Pair DE' = 37ECH.
4DEC
LD (DE),A 12
Write the command in Register A to the command register 37ECH (Register Pair DE').
4DED
EXX D9
EXX: exchange back to the main register set; the alternate set keeps 4300H, 37ECH and 37EFH.
4DEE
LD A,(37ECH) 3A EC 37
Fetch the controller's status from 37ECH into Register A.
4DF1
BIT 0,A CB 47
Test bit 0 of Register A, the status: BUSY, 1 once the controller has taken the command.
4DF3
LOOP BACK to 4DEEH until BUSY is on: the controller has started the command.
4DF5
RET C9
RETURN to the caller with the command running.
4DF6H - Select the Drive
Writes the drive select bit from 448CH to the latch at 37E1H. If the status read before that showed NOT READY (the motor was off), it waits about 0.59 second for the motor to come up to speed (65536 passes of a two instruction loop), then selects the drive again. On that path a select bit of 00H gives INVALID DRIVE NUMBER (4D52H catches it first in practice). Register Pair BC is kept.
4DF6
EXX D9
Exchange to the alternate register set: Register Pair DE' = 37ECH, HL' = 37EFH.
4DF7
EX DE,HL EB
Exchange Register Pairs DE' and HL': HL' = 37ECH.
4DF8
BIT 7,(HL) CB 7E
Test bit 7 of the status at 37ECH (Register Pair HL'), NOT READY, before the drive is selected: 1 when the selected drive's motor is off.
4DFA
LD A,(448CH) 3A 8C 44
Fetch the drive select bit from 448CH into Register A.
4DFD
LD (37E1H),A 32 E1 37
Store Register A, the drive select bit, to the drive select latch at 37E1H: the drive is selected and its motor runs.
4E00
EX DE,HL EB
Exchange Register Pairs DE' and HL' back: DE' = 37ECH, HL' = 37EFH.
4E01
If the drive was ready (bit 7 was 0), JUMP to 4E17H.
4E03
AND 0FH E6 0F
Keep bits 3-0 of the select bit in Register A.
4E05
If none is set, JUMP to 48DAH to report INVALID DRIVE NUMBER.
4E08
PUSH BC C5
Save Register Pair BC' (the alternate set's buffer pointer) on the stack around the delay.
4E09
XOR A AF
Load Register A with 00H (XOR A), the start of the inner count.
4E0A
LD B,A 47
Load Register B' with Register A (00H): 256 outer passes.
4E0B
DEC A 3D
Decrement Register A, the inner count: from 00H it runs 256 times before it is 00H again.
4E0C
LOOP BACK to 4E0BH until Register A is 00H again.
4E0E
Decrement Register B' and LOOP BACK to 4E0BH for 256 outer passes: 65536 passes of DEC A and JR NZ, about 1,050,000 T-states, close to 0.59 second at the Model I's 1.774 MHz.
4E10
LD A,(448CH) 3A 8C 44
Fetch the drive select bit from 448CH into Register A again.
4E13
LD (37E1H),A 32 E1 37
Store Register A, the drive select bit, to the drive select latch at 37E1H once more, so the drive stays selected with its motor running.
4E16
POP BC C1
Restore Register Pair BC' (the buffer pointer) from the stack.
4E17
EXX D9
EXX: exchange back to the main register set; the alternate set keeps 4300H, 37ECH and 37EFH.
4E18
RET C9
RETURN to the caller with the drive selected.
4E19H - MicroDOS Jump Table
Most of the vectors at 4152H-41E4H (copied from 4694H) that MicroDOS uses jump into this table, which jumps on to the code (CMD, GET, PUT, LOAD, MERGE and SAVE go straight to theirs); 4E46H and 4E52H are entries the main file itself uses (4B5DH, 495DH). One JP per entry.
4E19
JUMP to 4EC0H: FIELD (vector 417CH), the FIELD LOAD and FIELD SAVE statements.
4E1C
JUMP to 4F12H: MKI$ (vector 416AH), a number as a 2 byte string.
4E1F
JUMP to 4F16H: MKS$ (vector 416DH), a number as a 4 byte string.
4E22
JUMP to 4F1AH: MKD$ (vector 4170H), a number as an 8 byte string.
4E25
JUMP to 4F2DH: CVI (vector 4152H), a 2 byte string as an integer.
4E28
JUMP to 4F31H: CVS (vector 4158H), a 4 byte string as a single precision number.
4E2B
JUMP to 4F35H: CVD (vector 415EH), an 8 byte string as a double precision number.
4E2E
JUMP to 4F4CH: LSET (vector 4197H), a string into a field, left justified.
4E31
JUMP to 4F4FH: RSET (vector 419AH), a string into a field, right justified.
4E34
JUMP to 52DEH: the error message hook (41A6H), which displays MicroDOS's own message for every error number.
4E37
JUMP to 501DH: LINE, the LINE INPUT statement (vector 41A3H).
4E3A
JUMP to 503EH: the & of a hexadecimal constant (vector 4194H).
4E3D
JUMP to 507AH: DEF (vector 415BH): DEF FN, DEF FIELD and DEF USR.
4E40
JUMP to 519EH: the USR hook (41A9H), the call of a USR function.
4E43
JUMP to 5092H: FN (vector 4155H), the call of a DEF FN function.
4E46
JUMP to 4E66H: evaluate a field buffer number (used by 4B5DH).
4E49
JUMP to 4E5BH: the NEW and END hook (41BBH), which empties the four field buffers.
4E4C
JUMP to 5010H: LOF (vector 4167H), the length of a field buffer.
4E4F
JUMP to 4FB4H: LOC (vector 4164H), the last sector, the size, the error status or the format count.
4E52
JUMP to 4FC7H: the DSSSS number of the last sector used, the work of LOC(0) (used by SAVE at 495DH).
4E55
JUMP to 51DBH: the MID$ statement hook (41D9H).
4E58
JUMP to 5257H: INSTR (vector 419DH), the position of one string in another.
4E5BH - Empty the Four Field Buffers
Reached through the hook at 41BBH, which the ROM calls from 1B8CH and 1DB0H: after NEW, RUN, CLEAR, END, CLOAD, every program line typed in or deleted (1AEFH), and MicroDOS's own LOAD and MERGE (49C3H, 49E6H, 4A42H). Sets the length byte of each field buffer (5600H, 5700H, 5800H, 5900H) to 00H; the data in them stays.
4E5B
LD B,04H 06 04
Load Register B with 04H, the number of field buffers.
4E5D
LD HL,5600H 21 00 56
Point Register Pair HL to 5600H, the length byte of field buffer 1.
4E60
XOR A AF
Load Register A with 00H (XOR A), the length stored in each buffer.
4E61
LD (HL),A 77
Store Register A (00H) as the length of the field buffer at Register Pair HL.
4E62
INC H 24
Add 1 to Register H: Register Pair HL moves 256 bytes on, to the next field buffer's length byte (5700H, 5800H, 5900H).
4E63
Decrement Register B and LOOP BACK to 4E61H for the next buffer.
4E65
RET C9
RETURN to the ROM with the four field buffers empty.
4E66H - Evaluate a Field Buffer Number
Used by GET and PUT (through 4E46H), DEF FIELD (4E7FH) and FIELD (4ECBH). Entered with Register A = the character at Register Pair HL. Skips a # if there is one, evaluates the number (1-4) and returns Register Pair DE = the address of that field buffer, 5600H + (number - 1) x 100H. A number outside 1-4 gives INVALID FIELD BUFFER NUMBER; one above 255, ILLEGAL FUNCTION CALL. LOF enters at 4E6EH with the number in Register A.
4E66
CP 23H FE 23
Compare Register A, the character at Register Pair HL, with 23H (#).
4E68
If it is not #, JUMP to 4E6BH: the number follows at once.
4E6A
RST 10H D7
Fetch the next character of the BASIC text through RST 10H, past the #: Register Pair HL moves to it and Register A holds it.
4E6B
GOSUB to the ROM's 2B1CH to evaluate the expression at Register Pair HL as a number 0-255 (ILLEGAL FUNCTION CALL above); it comes back in Register A.
4E6E
DEC A 3D
Subtract 1 from the field buffer number in Register A: 0-3 for buffers 1-4. LOF (5013H) enters here.
4E6F
CP 04H FE 04
Compare Register A, the buffer number less 1, with 04H.
4E71
If Register A is 0-3 (Carry), the buffer number is 1-4: JUMP to 4E78H.
4E73
LD E,3EH 1E 3E
Otherwise load Register E with 3EH, error 32, INVALID FIELD BUFFER NUMBER (a number of 0 gives FFH here as well).
4E75
JUMP to the ROM's 19A2H to report the error in Register E, INVALID FIELD BUFFER NUMBER.
4E78
LD DE,5600H 11 00 56
Load Register Pair DE with 5600H, field buffer 1.
4E7B
ADD A,D 82
Add Register A, the buffer number less 1, to Register D, the high byte 56H.
4E7C
LD D,A 57
Load Register D with Register A: Register Pair DE = 5600H, 5700H, 5800H or 5900H.
4E7D
RET C9
RETURN to the caller with the field buffer's address in Register Pair DE.
4E7EH - DEF FIELD Statement
DEF FIELD #N,W1 AS V1$,W2 AS V2$,... (reached from DEF at 5081H with Register Pair HL on the FIELD token). Points the string variables at consecutive pieces of field buffer N: each variable's descriptor gets the width as its length and the address in the buffer. The widths may add up to 255 at most (FIELD OVERFLOW). When they add up to more than the buffer's length byte, the length byte is raised to their sum.
4E7E
RST 10H D7
Fetch the next character of the BASIC text through RST 10H, past the FIELD token: Register Pair HL moves to it and Register A holds it.
4E7F
GOSUB to 4E66H to evaluate #N and return Register Pair DE = the address of the field buffer.
4E82
PUSH DE D5
Save Register Pair DE, the field buffer's address, on the stack for the length at the end.
4E83
INC DE 13
Point Register Pair DE to the buffer's first data byte, where the first field starts.
4E84
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H: no width to add yet.
4E87
XOR A AF
Load Register A with 00H, the sum of the widths so far.
4E88
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = where the next field starts.
4E89
ADD HL,BC 09
Add the width of the field just made (Register Pair BC, Register B is 00H) to Register Pair HL.
4E8A
LD B,A 47
Load Register B with the sum of the widths so far (Register A).
4E8B
EX DE,HL EB
Exchange back: Register Pair DE = where the next field starts, Register Pair HL = the BASIC text pointer.
4E8C
LD A,(HL) 7E
Fetch the character at Register Pair HL into Register A.
4E8D
CP 2CH FE 2C
Compare Register A, the character after the last field, with 2CH (,).
4E8F
If no comma follows, the list has ended: JUMP to 4EB9H.
4E91
PUSH DE D5
Save Register Pair DE, where the next field starts, on the stack.
4E92
PUSH BC C5
Save Register Pair BC, with the sum of the widths in Register B, on the stack.
4E93
GOSUB to the ROM's 2B1BH: past the comma (RST 10H), evaluate the width as a number 0-255; it comes back in Register A.
4E96
PUSH AF F5
Save Register Pair AF, with the width in Register A, on the stack.
4E97
RST 08H => 41H CF 41
Check that the next character is A (41H) and step past it, or report SYNTAX ERROR.
4E99
RST 08H => 53H CF 53
Check that the next character is S (53H) and step past it, or report SYNTAX ERROR.
4E9B
GOSUB to the ROM's 260DH to find (or make) the variable named at Register Pair HL: Register Pair DE comes back with the address of its descriptor.
4E9E
GOSUB to the ROM's 0AF4H: TYPE MISMATCH unless the variable is a string.
4EA1
POP AF F1
Restore Register Pair AF: the width is in Register A again.
4EA2
POP BC C1
Restore Register Pair BC: Register B = the sum of the widths before this field.
4EA3
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = where this field starts, the BASIC text pointer goes on the stack.
4EA4
LD C,A 4F
Load Register C with Register A, the width of this field.
4EA5
LD A,B 78
Load Register A with Register B, the sum of the widths before this field.
4EA6
ADD A,C 81
Add Register C, the width, to Register A: the sum including this field.
4EA7
If it is 255 or less (No Carry), JUMP to 4EAEH.
4EA9
LD E,3AH 1E 3A
Otherwise load Register E with 3AH, error 30, FIELD OVERFLOW.
4EAB
JUMP to the ROM's 19A2H to report the error in Register E, FIELD OVERFLOW.
4EAE
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the variable's descriptor, Register Pair DE = where the field starts.
4EAF
LD (HL),C 71
Store the width (Register C) as the variable's length, at Register Pair HL.
4EB0
INC HL 23
Point Register Pair HL to byte 1 of the descriptor.
4EB1
LD (HL),E 73
Store the low byte of the field's address (Register E) at Register Pair HL.
4EB2
INC HL 23
Point Register Pair HL to byte 2 of the descriptor.
4EB3
LD (HL),D 72
Store the high byte (Register D) at Register Pair HL: the variable's characters are now this piece of the field buffer.
4EB4
LD B,00H 06 00
Load Register B with 00H: Register Pair BC = the width, for the next field's start.
4EB6
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
4EB7
LOOP BACK to 4E88H to move the field start on by the width and look for the next field.
4EB9
POP DE D1
Restore the field buffer's address into Register Pair DE.
4EBA
LD A,(DE) 1A
Load Register A with the buffer's length byte at Register Pair DE.
4EBB
CP B B8
Compare Register A, the buffer's length, with the sum of the widths (Register B).
4EBC
RET NC D0
If the length is already as large (No Carry), RETURN to the statement loop.
4EBD
LD A,B 78
Otherwise load Register A with Register B, the sum of the widths.
4EBE
LD (DE),A 12
Store Register A as the buffer's length at Register Pair DE: GET and PUT now move that many bytes.
4EBF
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the statement.
4EC0H - FIELD LOAD and FIELD SAVE Statements
Level II sends FIELD (token A3H) here through its vector at 417CH, with Register A = the character after it. FIELD LOAD #N USING S$ (LOAD token A7H) copies the string S$ (any string expression) into field buffer N and sets the buffer's length to the string's length. FIELD SAVE #N USING V$ (SAVE token ADH) copies field buffer N, as many bytes as its length, into the string variable V$, giving V$ new string space when it is shorter. The string is the data itself: nothing is read from or written to the diskette. Anything else after FIELD is a SYNTAX ERROR.
4EC0
PUSH AF F5
Save Register Pair AF on the stack: Register A holds the token after FIELD.
4EC1
CP A7H FE A7
Compare Register A, the token after FIELD, with A7H, the LOAD token.
4EC3
If Register A is the LOAD token, JUMP to 4ECAH.
4EC5
CP ADH FE AD
Compare Register A, the token after FIELD, with ADH, the SAVE token.
4EC7
If it is neither, JUMP to the ROM's 1997H to report SYNTAX ERROR.
4ECA
RST 10H D7
Fetch the next character of the BASIC text through RST 10H, past the LOAD or SAVE token: Register Pair HL moves to it and Register A holds it.
4ECB
GOSUB to 4E66H to evaluate #N and return Register Pair DE = the address of the field buffer.
4ECE
RST 08H => BFH CF BF
Check that the next character is the USING token (BFH) and step past it, or report SYNTAX ERROR.
4ED0
POP AF F1
Restore Register Pair AF: Register A holds the token after FIELD again.
4ED1
CP A7H FE A7
Compare Register A, the token after FIELD, with A7H, the LOAD token.
4ED3
If Register A is not LOAD, it is SAVE: JUMP to 4EE9H.
4ED5
PUSH DE D5
FIELD LOAD. Save Register Pair DE, the field buffer's address, on the stack.
4ED6
GOSUB to the ROM's expression evaluator at 2337H to evaluate the string expression at Register Pair HL.
4ED9
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the field buffer's address, the BASIC text pointer goes on the stack.
4EDA
PUSH HL E5
Save Register Pair HL, the field buffer's address, on the stack again.
4EDB
GOSUB to the ROM's 29D7H: TYPE MISMATCH unless the result is a string; Register Pair HL comes back pointing at its descriptor.
4EDE
LD A,(HL) 7E
Load Register A with the string's length from its descriptor at Register Pair HL.
4EDF
INC HL 23
Point Register Pair HL to byte 1 of the descriptor.
4EE0
LD E,(HL) 5E
Load Register E with the low byte of the address of the string's characters, from Register Pair HL.
4EE1
INC HL 23
Point Register Pair HL to byte 2 of the descriptor.
4EE2
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the string's characters.
4EE3
POP HL E1
Restore the field buffer's address into Register Pair HL.
4EE4
LD (HL),A 77
Store Register A, the string's length, as the buffer's length byte at Register Pair HL.
4EE5
INC HL 23
Point Register Pair HL to the buffer's first data byte.
4EE6
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the string's characters (from), Register Pair DE = the buffer's data (to).
4EE7
JUMP to 4F08H to copy Register A bytes from Register Pair HL to Register Pair DE.
4EE9
PUSH DE D5
FIELD SAVE. Save Register Pair DE, the field buffer's address, on the stack.
4EEA
GOSUB to the ROM's 260DH to find (or make) the variable named at Register Pair HL: Register Pair DE comes back with the address of its descriptor.
4EED
GOSUB to the ROM's 0AF4H: TYPE MISMATCH unless the variable is a string.
4EF0
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the field buffer's address, the BASIC text pointer goes on the stack.
4EF1
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the field buffer's address, Register Pair HL = the variable's descriptor.
4EF2
LD A,(DE) 1A
Load Register A with the buffer's length byte at Register Pair DE.
4EF3
INC DE 13
Point Register Pair DE to the buffer's first data byte.
4EF4
PUSH DE D5
Save Register Pair DE, the buffer's first data byte, on the stack: the copy starts there.
4EF5
CP (HL) BE
Compare Register A, the buffer's length, with the variable's length (its descriptor at Register Pair HL).
4EF6
If the buffer's data is shorter than the string, JUMP to 4F02H to copy it into the string where it is.
4EF8
If it is just as long, JUMP to 4F02H as well.
4EFA
PUSH HL E5
The string is too short. Save Register Pair HL, the variable's descriptor, on the stack.
4EFB
GOSUB to the ROM's 2857H to get new string space for Register A bytes: Register Pair DE comes back with its address (the temporary descriptor at 40D3H describes it too).
4EFE
POP HL E1
Restore the variable's descriptor into Register Pair HL.
4EFF
GOSUB to the ROM's 285DH, the end of 2857H, to write the length (Register A) and the address of the new space (Register Pair DE) into the variable's descriptor at Register Pair HL.
4F02
LD (HL),A 77
Store Register A, the buffer's length, as the variable's length (Register Pair HL, its descriptor).
4F03
INC HL 23
Point Register Pair HL to byte 1 of the descriptor.
4F04
LD E,(HL) 5E
Load Register E with the low byte of the address of the variable's characters, from Register Pair HL.
4F05
INC HL 23
Point Register Pair HL to byte 2 of the descriptor.
4F06
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the variable's characters (to).
4F07
POP HL E1
Restore the buffer's first data byte into Register Pair HL (from).
4F08
LD C,A 4F
Load Register C with the number of bytes to copy (Register A).
4F09
LD B,00H 06 00
Load Register B with 00H: Register Pair BC = the number of bytes to copy.
4F0B
OR A B7
Test Register A, the number of bytes to copy.
4F0C
If it is 00H, JUMP to 4F10H: nothing to copy.
4F0E
LDIR ED B0
Copy Register Pair BC bytes from Register Pair HL to Register Pair DE.
4F10
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
4F11
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the statement.
4F12H - MKI$, MKS$ and MKD$
Level II sends MKI$, MKS$ and MKD$ here (vectors 416AH, 416DH, 4170H) with the argument in the ROM's accumulator. The number is made the type of the function (integer, single or double precision) and its 2, 4 or 8 bytes become the characters of a new string, the function's result.
4F12
LD A,02H 3E 02
MKI$: load Register A with 02H, the type code of an integer and its size in bytes.
4F14
JUMP to 4F1CH with Register A = 02H, the type and size of an integer.
4F16
LD A,04H 3E 04
MKS$: load Register A with 04H, single precision, 4 bytes.
4F18
JUMP to 4F1CH with Register A = 04H, the type and size of a single precision number.
4F1A
LD A,08H 3E 08
MKD$: load Register A with 08H, double precision, 8 bytes.
4F1C
PUSH AF F5
Save Register Pair AF, with the type code in Register A, on the stack.
4F1D
GOSUB to the ROM's 2819H to change the accumulator to the type in Register A.
4F20
POP AF F1
Restore Register Pair AF: the type code is in Register A again.
4F21
GOSUB to the ROM's 2857H to get string space for Register A bytes, described by the temporary descriptor at 40D3H-40D5H.
4F24
LD HL,(40D4H) 2A D4 40
Load Register Pair HL with the address of the new string space from 40D4H-40D5H.
4F27
GOSUB to the ROM's 09FFH to copy the accumulator, as many bytes as its type (2, 4 or 8), to Register Pair HL.
4F2A
JUMP to the ROM's 2A2BH, the end of its CHR$ function: it takes one word off the stack into Register Pair BC and makes the string described at 40D3H the result (2884H).
4F2DH - CVI, CVS and CVD
Level II sends CVI, CVS and CVD here (vectors 4152H, 4158H, 415EH) with a string in the ROM's accumulator. Its first 2, 4 or 8 characters are taken as the bytes of an integer, a single or a double precision number, the function's result. A string shorter than that gives ILLEGAL FUNCTION CALL; a longer one is accepted, its first bytes used.
4F2D
LD A,01H 3E 01
CVI: load Register A with 01H, one less than the bytes of an integer.
4F2F
JUMP to 4F37H with Register A = 01H, one less than the size of an integer.
4F31
LD A,03H 3E 03
CVS: load Register A with 03H, one less than the bytes of a single precision number.
4F33
JUMP to 4F37H with Register A = 03H, one less than the size of a single precision number.
4F35
LD A,07H 3E 07
CVD: load Register A with 07H, one less than the bytes of a double precision number.
4F37
PUSH AF F5
Save Register Pair AF, with 01H, 03H or 07H in Register A, on the stack.
4F38
GOSUB to the ROM's 29D7H: TYPE MISMATCH unless the argument is a string; Register Pair HL comes back pointing at its descriptor.
4F3B
POP AF F1
Restore Register Pair AF: Register A holds 01H, 03H or 07H again.
4F3C
CP (HL) BE
Compare Register A with the string's length in its descriptor at Register Pair HL.
4F3D
If the string is not longer than Register A, it is too short: JUMP to the ROM's 1E4AH to report ILLEGAL FUNCTION CALL.
4F40
INC A 3C
Add 1 to Register A: 02H, 04H or 08H, the type code of the result and its size.
4F41
INC HL 23
Point Register Pair HL to byte 1 of the descriptor.
4F42
LD B,(HL) 46
Load Register B with the low byte of the address of the string's characters, from Register Pair HL.
4F43
INC HL 23
Point Register Pair HL to byte 2 of the descriptor.
4F44
LD H,(HL) 66
Load Register H with the high byte of the address, from Register Pair HL.
4F45
LD L,B 68
Load Register L with the low byte (Register B): Register Pair HL = the string's characters.
4F46
LD (40AFH),A 32 AF 40
Store Register A, the type code, at 40AFH, the type of the ROM's accumulator.
4F49
JUMP to the ROM's 09F7H to copy as many bytes as the type from Register Pair HL into the accumulator: the number is the function's result.
4F4CH - LSET and RSET Statements
Level II sends LSET and RSET here (vectors 4197H, 419AH). LSET V$=S$ and RSET V$=S$ copy S$ into the characters V$ already has (a field of a buffer, after DEF FIELD), without changing V$'s length or address: LSET puts S$ at the left and fills the rest with spaces, RSET puts spaces first and S$ at the right. A longer S$ is cut to V$'s length.
4F4C
XOR A AF
LSET: load Register A with 00H (XOR A), the LSET flag.
4F4D
JUMP to 4F51H with Register A = 00H, the LSET flag.
4F4F
LD A,FFH 3E FF
RSET: load Register A with FFH, the RSET flag.
4F51
PUSH AF F5
Save Register Pair AF on the stack: Register A holds the LSET or RSET flag.
4F52
GOSUB to the ROM's 260DH to find (or make) the variable named at Register Pair HL: Register Pair DE comes back with the address of its descriptor.
4F55
GOSUB to the ROM's 0AF4H: TYPE MISMATCH unless the variable is a string.
4F58
PUSH DE D5
Save the target's descriptor (Register Pair DE) on the stack.
4F59
RST 08H => D5H CF D5
Check that the next character is the = token (D5H) and step past it, or report SYNTAX ERROR.
4F5B
GOSUB to the ROM's expression evaluator at 2337H to evaluate the string expression after it.
4F5E
POP BC C1
Restore the target's descriptor into Register Pair BC.
4F5F
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the LSET or RSET flag, the BASIC text pointer goes on the stack.
4F60
PUSH HL E5
Save Register Pair HL, the flag, on the stack.
4F61
PUSH BC C5
Save Register Pair BC, the target's descriptor, on the stack.
4F62
GOSUB to the ROM's 29D7H: TYPE MISMATCH unless the result is a string; Register Pair HL comes back pointing at the source's descriptor.
4F65
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the target's descriptor, the source's descriptor goes on the stack.
4F66
LD C,(HL) 4E
Load Register C with the target's length from its descriptor at Register Pair HL.
4F67
INC HL 23
Point Register Pair HL to byte 1 of the target's descriptor.
4F68
LD E,(HL) 5E
Load Register E with the low byte of the target's address, from Register Pair HL.
4F69
INC HL 23
Point Register Pair HL to byte 2 of the target's descriptor.
4F6A
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the target's characters.
4F6B
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the target's characters.
4F6C
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the source's descriptor, the target's characters go on the stack.
4F6D
LD B,(HL) 46
Load Register B with the source's length from its descriptor at Register Pair HL.
4F6E
INC HL 23
Point Register Pair HL to byte 1 of the source's descriptor.
4F6F
LD E,(HL) 5E
Load Register E with the low byte of the source's address, from Register Pair HL.
4F70
INC HL 23
Point Register Pair HL to byte 2 of the source's descriptor.
4F71
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the source's characters.
4F72
LD A,C 79
Load Register A with the target's length (Register C).
4F73
SUB B 90
Subtract the source's length (Register B) from Register A, the target's length: the number of spaces to fill.
4F74
If the source fits (No Carry), JUMP to 4F78H with that number.
4F77
XOR A AF
The source is longer than the target: no spaces (Register A = 00H).
4F78
LD B,A 47
Load Register B with Register A, the number of spaces.
4F79
POP HL E1
Restore the target's characters into Register Pair HL.
4F7A
POP AF F1
Restore Register Pair AF: Register A holds the LSET or RSET flag.
4F7B
OR A B7
Test Register A, the LSET or RSET flag: Z for LSET, NZ for RSET.
4F7C
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the target's characters, Register Pair HL = the source's characters.
4F7D
If Register A is FFH (RSET), JUMP to 4F84H for the spaces before the characters.
4F7F
GOSUB to 4F8FH (LSET): it sets Register C to the number of characters to copy and puts the spaces after them.
4F82
JUMP to 4F87H to copy Register C characters to the target.
4F84
GOSUB to 4FA6H (RSET): it sets Register C to the number of characters to copy and puts the spaces before them, moving Register Pair DE past them.
4F87
LD A,C 79
Load Register A with the number of characters to copy (Register C).
4F88
OR A B7
Test Register A, the number of characters to copy.
4F89
If Register A is 00H, nothing is copied: JUMP to 4F8DH.
4F8B
LDIR ED B0
Copy Register Pair BC characters from the source (Register Pair HL) to the target (Register Pair DE).
4F8D
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
4F8E
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the statement.
4F8FH - LSET: Spaces After the Characters
Entered with Register B = the number of spaces, Register C = the target's length, Register Pair DE = the target's characters. When there are spaces, sets Register C to the number of characters to copy (the length less the spaces) and stores the spaces at the end of the target; Register Pair DE still points at its start. Returns at once with Register C unchanged when there are none.
4F8F
LD A,B 78
Load Register A with the number of spaces (Register B).
4F90
OR A B7
Test Register A, the number of spaces: Z when there are none.
4F91
RET Z C8
If there are none, RETURN: Register C (the target's length) is the number of characters to copy.
4F92
NEG ED 44
Negate Register A: minus the number of spaces.
4F94
ADD A,C 81
Add the target's length (Register C) to Register A: the number of characters to copy.
4F95
LD C,A 4F
Load Register C with Register A, the number of characters to copy.
4F96
LD A,B 78
Load Register A with the number of spaces (Register B).
4F97
PUSH DE D5
Save Register Pair DE, the start of the target, on the stack.
4F98
LD B,00H 06 00
Load Register B with 00H: Register Pair BC = the number of characters to copy.
4F9A
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the start of the target.
4F9B
ADD HL,BC 09
Add Register Pair BC, the number of characters, to Register Pair HL: Register Pair HL = where the spaces start.
4F9C
EX DE,HL EB
Exchange back: Register Pair DE = where the spaces start, Register Pair HL = the source's characters.
4F9D
LD B,A 47
Load Register B with Register A, the number of spaces.
4F9E
LD A,20H 3E 20
Load Register A with 20H, the code of a space.
4FA0
LD (DE),A 12
Store Register A, a space, at Register Pair DE.
4FA1
INC DE 13
Point Register Pair DE to the next character.
4FA2
Decrement Register B and LOOP BACK to 4FA0H until all spaces are stored; Register B ends 00H.
4FA4
POP DE D1
Restore the start of the target into Register Pair DE, where the characters are copied.
4FA5
RET C9
RETURN to LSET with Register C = the characters to copy and Register Pair DE = the start of the target.
4FA6H - RSET: Spaces Before the Characters
Entered like 4F8FH. When there are spaces, sets Register C to the number of characters to copy and stores the spaces at the start of the target, leaving Register Pair DE after them, where the characters go. Returns at once when there are none.
4FA6
LD A,B 78
Load Register A with the number of spaces (Register B).
4FA7
OR A B7
Test Register A, the number of spaces: Z when there are none.
4FA8
RET Z C8
If there are none, RETURN: Register C (the target's length) is the number of characters to copy.
4FA9
NEG ED 44
Negate Register A: minus the number of spaces.
4FAB
ADD A,C 81
Add the target's length (Register C) to Register A: the number of characters to copy.
4FAC
LD C,A 4F
Load Register C with Register A, the number of characters to copy.
4FAD
LD A,20H 3E 20
Load Register A with 20H, the code of a space.
4FAF
LD (DE),A 12
Store Register A, a space, at Register Pair DE.
4FB0
INC DE 13
Point Register Pair DE to the next character.
4FB1
Decrement Register B and LOOP BACK to 4FAFH until all spaces are stored; Register B ends 00H and Register Pair DE points where the characters go.
4FB3
RET C9
RETURN to RSET with Register C = the characters to copy and Register Pair DE after the spaces.
4FB4H - LOC Function
Level II sends LOC here through its vector at 4164H, with the argument in the ROM's accumulator. LOC(0): the DSSSS number of the last sector used; LOC(1): the highest sector number of a diskette, (4492H) x (4493H) - 1 = 399; LOC(2): the last controller status kept at 4495H (the wait at 4DD0H stores it after every command, so after a disk error it is the error's status, and after a good transfer that transfer's final status); LOC(3): the number of sectors the last format could not verify (4496H). Any other argument gives ILLEGAL FUNCTION CALL. The result is an integer.
4FB4
GOSUB to the ROM's 2B1FH to make the argument a number 0-255 in Register A (ILLEGAL FUNCTION CALL above).
4FB7
INC A 3C
Increment Register A, the argument of LOC, to set the flags below.
4FB8
DEC A 3D
Decrement Register A again: the flags now show whether the argument is 00H.
4FB9
If Register A is 0, JUMP to 4FC7H for LOC(0).
4FBB
DEC A 3D
Subtract 1 from Register A, the argument of LOC: Z when it was 1.
4FBC
If the argument was 1, JUMP to 4FEEH for LOC(1).
4FBE
DEC A 3D
Subtract 1 from Register A, the argument of LOC: Z when it was 2.
4FBF
If the argument was 2, JUMP to 5002H for LOC(2).
4FC1
DEC A 3D
Subtract 1 from Register A, the argument of LOC: Z when it was 3.
4FC2
If the argument was 3, JUMP to 500BH for LOC(3).
4FC4
Any other number: JUMP to the ROM's 1E4AH to report ILLEGAL FUNCTION CALL.
4FC7
LD HL,0000H 21 00 00
LOC(0), also used by SAVE (through 4E52H). Load Register Pair HL with 0000H, the DSSSS number to build.
4FCA
LD DE,2710H 11 10 27
Load Register Pair DE with 2710H (10000), the value of one drive.
4FCD
LD A,(448CH) 3A 8C 44
Fetch the drive select bit of the last drive used from 448CH into Register A.
4FD0
RRCA 0F
Rotate Register A right: the lowest bit goes into the Carry flag.
4FD1
If the bit that came out was the drive's select bit, JUMP to 4FD6H.
4FD3
ADD HL,DE 19
Add Register Pair DE (10000) to Register Pair HL for each drive below the one used.
4FD4
LOOP BACK to 4FD0H for the next bit of Register A.
4FD6
LD A,(4493H) 3A 93 44
Fetch the number of sectors of a track from 4493H into Register A.
4FD9
LD E,A 5F
Load Register E with Register A, the sectors of a track.
4FDA
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = 000AH.
4FDC
LD A,(448DH) 3A 8D 44
Fetch the track of the last sector used from 448DH into Register A.
4FDF
LD B,A 47
Load Register B with Register A, the track: the number of times to add a track's sectors.
4FE0
OR A B7
Test Register A, the track of the last sector: Z for track 0.
4FE1
If it is track 0, nothing to add: JUMP to 4FE6H.
4FE3
ADD HL,DE 19
Add the sectors of a track (Register Pair DE) to Register Pair HL.
4FE4
Decrement Register B and LOOP BACK to 4FE3H once for each track.
4FE6
LD A,(448EH) 3A 8E 44
Fetch the sector within the track from 448EH into Register A.
4FE9
LD C,A 4F
Load Register C with Register A, the sector: Register Pair BC = the sector (Register B is 00H).
4FEA
ADD HL,BC 09
Add Register Pair BC, the sector, to Register Pair HL = drive x 10000 + track x 10 + sector.
4FEB
JUMP to the ROM's 0A9AH to store Register Pair HL in the accumulator as an integer, the function's result.
4FEE
LD HL,0000H 21 00 00
LOC(1). Load Register Pair HL with 0000H, the total to build.
4FF1
LD A,(4493H) 3A 93 44
Fetch the number of sectors of a track from 4493H into Register A.
4FF4
LD E,A 5F
Load Register E with Register A, the sectors of a track.
4FF5
LD D,00H 16 00
Load Register D with 00H: Register Pair DE = 000AH.
4FF7
LD A,(4492H) 3A 92 44
Fetch the number of tracks from 4492H into Register A.
4FFA
LD B,A 47
Load Register B with Register A, the number of tracks: the number of times to add.
4FFB
ADD HL,DE 19
Add Register Pair DE, the sectors of a track, to Register Pair HL.
4FFC
Decrement Register B and LOOP BACK to 4FFBH once for each track: Register Pair HL = 400.
4FFE
DEC HL 2B
Subtract 1 from Register Pair HL: 399, the highest sector number.
4FFF
JUMP to the ROM's 0A9AH to store Register Pair HL in the accumulator as an integer.
5002
LD A,(4495H) 3A 95 44
LOC(2). Fetch the last controller status kept at 4495H into Register A.
5005
LD L,A 6F
Load Register L with Register A, the value to return.
5006
LD H,00H 26 00
Load Register H with 00H: Register Pair HL = the value, 0-255.
5008
JUMP to the ROM's 0A9AH to store Register Pair HL in the accumulator as an integer.
500B
LD A,(4496H) 3A 96 44
LOC(3). Fetch the format count from 4496H into Register A.
500E
JUMP to 5005H to return Register A as an integer.
5010H - LOF Function
Level II sends LOF here through its vector at 4167H. LOF(N) returns the length byte of field buffer N (1-4): set by GET (the bytes read), by FIELD LOAD (the string's length), raised by DEF FIELD to the sum of its widths, and set to 00H by the hook at 41BBH (4E5BH).
5010
GOSUB to the ROM's 2B1FH to make the argument a number 0-255 in Register A.
5013
GOSUB to 4E6EH to check it (INVALID FIELD BUFFER NUMBER outside 1-4) and return Register Pair DE = the field buffer's address.
5016
LD A,(DE) 1A
Load Register A with the buffer's length byte at Register Pair DE.
5017
LD L,A 6F
Load Register L with Register A, the buffer's length.
5018
LD H,00H 26 00
Load Register H with 00H: Register Pair HL = the length, 0-255.
501A
JUMP to the ROM's 0A9AH to store Register Pair HL in the accumulator as an integer.
501DH - LINE INPUT Statement
Level II sends LINE (token 9CH) here through its vector at 41A3H. LINE INPUT "prompt";V$ displays the prompt, if there is one, reads a whole line from the keyboard, commas and quotes included, and assigns it to the string variable V$. BREAK stops the program.
501D
RST 08H => 89H CF 89
Check that the next character is the INPUT token (89H) and step past it, or report SYNTAX ERROR.
501F
GOSUB to the ROM's 21CDH, the prompt of INPUT: when a quoted string follows, it is displayed and a semicolon must follow it.
5022
GOSUB to the ROM's 260DH to find (or make) the variable named at Register Pair HL: Register Pair DE comes back with the address of its descriptor.
5025
GOSUB to the ROM's 0AF4H: TYPE MISMATCH unless the variable is a string.
5028
PUSH DE D5
Save Register Pair DE, the variable's descriptor, on the stack.
5029
PUSH HL E5
Save Register Pair HL, the BASIC text pointer, on the stack.
502A
GOSUB to the ROM's 0361H to read a line of up to 240 characters into the keyboard input buffer at (40A7H), ended by 00H; it returns Register Pair HL = the byte before the buffer and the Carry flag set when BREAK was pressed.
502D
POP DE D1
Restore the BASIC text pointer into Register Pair DE.
502E
POP BC C1
Restore the variable's descriptor into Register Pair BC.
502F
If BREAK was pressed, JUMP to the ROM's 1DBEH, which stops the program as STOP does.
5032
PUSH BC C5
Save Register Pair BC, the variable's descriptor, on the stack again.
5033
PUSH DE D5
Save Register Pair DE, the BASIC text pointer, on the stack again.
5034
LD B,00H 06 00
Load Register B with 00H, the character that ends the string (only the 00H after the line).
5036
GOSUB to the ROM's 2868H to make the line after Register Pair HL a temporary string, up to its 00H byte; the ROM's accumulator comes back describing it.
5039
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
503A
XOR A AF
Load Register A with 00H (XOR A): Register A + 03H at 1F33H gives the string type.
503B
JUMP to the ROM's 1F32H, the end of LET: with the variable's descriptor on the stack and Register A + 03H = the string type, it assigns the string to the variable and returns to the statement loop.
503EH - Hexadecimal Constants (&H)
The ROM's expression evaluator sends a & here (24C8H, through the vector at 4194H) with Register Pair HL on it. &H followed by hexadecimal digits (0-9, A-F) gives an integer from the low 16 bits: FFFFH is -1. Digits that would go past 16 bits give OVERFLOW. The constant ends at the first character that is not a hexadecimal digit.
503E
INC HL 23
Point Register Pair HL past the & to the H that must follow.
503F
RST 08H => 48H CF 48
Check that the next character is H (48H) and step past it, or report SYNTAX ERROR.
5041
LD DE,0000H 11 00 00
Load Register Pair DE with 0000H, the value to build.
5044
DEC HL 2B
Step Register Pair HL back one character, for the INC HL below.
5045
INC HL 23
Point Register Pair HL to the next character of the constant.
5046
LD A,(HL) 7E
Fetch the character at Register Pair HL into Register A.
5047
GOSUB to the ROM's 1E3EH: the Carry flag comes back clear when Register A is a letter A-Z.
504A
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the value, Register Pair DE = the BASIC text pointer.
504B
If Register A is a letter (No Carry), JUMP to 5059H.
504D
CP 3AH FE 3A
Compare Register A with 3AH, the character after 9.
504F
If it is above 9, the constant has ended: JUMP to 5075H.
5051
CP 30H FE 30
Compare Register A, the character, with 30H, the digit 0.
5053
If it is below 0, the constant has ended: JUMP to 5075H.
5055
SUB 30H D6 30
Subtract 30H from Register A: the value of the digit 0-9.
5057
JUMP to 505FH with the digit's value in Register A.
5059
CP 47H FE 47
Compare Register A, the letter, with 47H (G).
505B
If it is G or above, the constant has ended: JUMP to 5075H.
505D
SUB 37H D6 37
Subtract 37H from Register A: the letters A-F give 10-15.
505F
LD C,A 4F
Load Register C with Register A, the digit's value.
5060
XOR A AF
Load Register A with 00H, which collects the bits shifted out at the top.
5061
LD B,A 47
Load Register B with Register A (00H): Register Pair BC = the digit's value.
5062
ADD HL,HL 29
Shift the value in Register Pair HL left one bit.
5063
ADC A,00H CE 00
Add the bit that came out (the Carry flag) to Register A.
5065
ADD HL,HL 29
Shift the value in Register Pair HL left a second time.
5066
ADC A,00H CE 00
Add the bit that came out (the Carry flag) to Register A.
5068
ADD HL,HL 29
Shift the value in Register Pair HL left a third time.
5069
ADC A,00H CE 00
Add the bit that came out (the Carry flag) to Register A.
506B
ADD HL,HL 29
Shift Register Pair HL left a fourth time: the value times 16.
506C
ADC A,00H CE 00
Add the bit that came out (the Carry flag) to Register A.
506E
If any bit came out at the top, JUMP to the ROM's 07B2H to report OVERFLOW.
5071
ADD HL,BC 09
Add the digit (Register Pair BC) to the value in Register Pair HL.
5072
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the value, Register Pair HL = the BASIC text pointer.
5073
LOOP BACK to 5045H for the next character, with the value in Register Pair DE.
5075
GOSUB to the ROM's 0A9AH to store the value (Register Pair HL) in the accumulator as an integer.
5078
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the BASIC text pointer, on the character that ended the constant.
5079
RET C9
RETURN to the expression evaluator with the constant in the accumulator.
507AH - DEF Statement: DEF FN
Level II sends DEF (token B0H) here through its vector at 415BH, with Register A = the token or character after it. DEF USR goes to 518FH and DEF FIELD to 4E7EH. Otherwise this is DEF FNname(parameters)=expression: the definition is kept by storing the address of its text in a variable whose name is the function's name with bit 7 of its first letter set, so it cannot clash with an ordinary variable; FN (5092H) finds it there. The rest of the statement is skipped. DEF FN is not allowed as a direct command (ILLEGAL DIRECT).
507A
CP C1H FE C1
Compare Register A, the token after DEF, with C1H, the USR token.
507C
If Register A is the USR token, this is DEF USR: JUMP to 518FH.
507F
CP A3H FE A3
Compare Register A with A3H, the FIELD token.
5081
If Register A is the FIELD token, this is DEF FIELD: JUMP to 4E7EH.
5084
GOSUB to the ROM's 2828H: ILLEGAL DIRECT when the line number at 40A2H is FFFFH (a direct command).
5087
GOSUB to 50E4H to check the FN token and find (or make) the function's variable: Register Pair DE comes back with the address of its value, Register Pair HL past the name.
508A
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the variable, Register Pair DE = the BASIC text pointer, on the ( or = of the definition.
508B
LD (HL),E 73
Store Register E, the low byte of the text address, in the variable at Register Pair HL.
508C
INC HL 23
Point Register Pair HL to the next byte of the variable.
508D
LD (HL),D 72
Store Register D, the high byte, at Register Pair HL: the variable holds the address of the definition's text.
508E
EX DE,HL EB
Exchange Register Pairs DE and HL back: Register Pair HL = the BASIC text pointer.
508F
JUMP to the ROM's 1F05H, the DATA statement, which skips the rest of the statement: the definition is only read when FN calls it.
5092H - FN: Call a DEF FN Function
Level II sends the FN token here from its expression evaluator (2524H, vector 4155H), with Register Pair HL on the token. Finds the definition (FUNCTION DEFINITION ERROR when there is none). When it has parameters, their variables are saved on the stack (50F0H), the arguments of the call are assigned to them (514CH), the expression of the definition is evaluated, and the variables get their old values back (5130H). The result is made the type of the function's name. For a string result the code copies the string's descriptor to 40D3H (50D0H-50D8H), but the accumulator (4121H) still points at the result's own descriptor, so nothing uses the copy: when the result is a parameter's string (DEF FNA$(X$)=X$, say), giving X$ its old value changes the result.
5092
GOSUB to 50E4H to check the FN token and find the function's variable: Register Pair DE = the address of its value, Register Pair HL past the name; 40AFH holds the type of the name.
5095
LD A,(40AFH) 3A AF 40
Fetch the type of the function's name from 40AFH into Register A.
5098
PUSH AF F5
Save Register Pair AF, with the type of the name in Register A, on the stack: the result is made this type at the end (50E0H).
5099
LD (40F3H),HL 22 F3 40
Store Register Pair HL, the BASIC text pointer of the call after the name, at 40F3H-40F4H.
509C
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the function's variable, Register Pair DE = the text pointer of the call.
509D
LD A,(HL) 7E
Load Register A with the low byte of the address of the definition, from the variable at Register Pair HL.
509E
INC HL 23
Point Register Pair HL to the high byte of the address in the variable.
509F
LD H,(HL) 66
Load Register H with the high byte of the address, from Register Pair HL.
50A0
LD L,A 6F
Load Register L with Register A, the low byte: Register Pair HL = the definition's text, on its ( or =.
50A1
OR H B4
OR Register H, the high byte, into Register A: Z when the address is 0000H, a function never defined.
50A2
If it was never defined, JUMP to 518AH to report FUNCTION DEFINITION ERROR.
50A5
LD A,(HL) 7E
Fetch the first character of the definition at Register Pair HL into Register A.
50A6
CP 28H FE 28
Compare Register A with 28H, an opening parenthesis: the definition has parameters.
50A8
If the function has no parameters, JUMP to 50B2H.
50AA
GOSUB to 50F0H to save the parameter variables of the definition on the stack.
50AD
GOSUB to 514CH to assign the arguments of the call to the parameters; Register Pair HL comes back on the expression of the definition.
50B0
JUMP to 50B7H to evaluate the expression of the definition at Register Pair HL.
50B2
XOR A AF
No parameters: load Register A with 00H, the mark that nothing was saved.
50B3
PUSH AF F5
Save Register Pair AF (Register A = 00H, the Z flag) on the stack: the mark that nothing was saved.
50B4
PUSH DE D5
Save the text pointer of the call (Register Pair DE) on the stack.
50B5
RST 08H => D5H CF D5
Check that the next character of the definition is the = token (D5H) and step past it, or report SYNTAX ERROR.
50B7
GOSUB to the ROM's expression evaluator at 2337H to evaluate the expression of the definition at Register Pair HL; the result is in the accumulator.
50BA
DEC HL 2B
Step Register Pair HL back one character for the RST 10H below.
50BB
RST 10H D7
Fetch the next character of the definition through RST 10H: Register Pair HL moves to it, Register A holds it, Z when its statement ends there.
50BC
If the expression is followed by anything else, JUMP to the ROM's 1997H to report SYNTAX ERROR.
50BF
LD A,(40AFH) 3A AF 40
Fetch the type of the result from 40AFH into Register A.
50C2
CP 03H FE 03
Compare Register A, the result's type, with 03H, a string.
50C4
If Register A is not 03H, the result is a number: JUMP to 50DBH.
50C6
LD HL,(40B3H) 2A B3 40
Load Register Pair HL with the next free slot of the temporary string descriptors from 40B3H-40B4H.
50C9
EX DE,HL EB
Exchange Register Pair HL, the free slot, into Register Pair DE.
50CA
LD HL,(4121H) 2A 21 41
Load Register Pair HL with the address of the result's descriptor from 4121H-4122H.
50CD
RST 18H DF
Compare Register Pair HL (the result's descriptor) with Register Pair DE (the free slot) through RST 18H: the Carry flag is set when the descriptor lies below it, among the temporary descriptors.
50CE
If the result is a temporary string, JUMP to 50D5H.
50D0
Otherwise (the result is a variable's string), GOSUB to the ROM's 2843H to copy the string into new string space, described at 40D3H. The accumulator (4121H) is not changed: it still points at the variable's descriptor, and the copy is not used.
50D3
JUMP to 50DBH; the copy is described at 40D3H, the result still at the descriptor 4121H points to.
50D5
LD HL,40D3H 21 D3 40
Point Register Pair HL to 40D3H, the ROM's temporary descriptor.
50D8
GOSUB to 517BH to take the last temporary descriptor (the result) off the list and copy it to 40D3H. The accumulator (4121H) still points at the slot just taken off the list.
50DB
POP HL E1
Restore the text pointer of the call into Register Pair HL.
50DC
POP AF F1
Restore the mark into Register Pair AF: NZ when parameters were saved (the 29H mark pushed at 512DH), Z when not (the 00H mark of 50B3H).
50DD
If parameters were saved, GOSUB to 5130H to give them their old values.
50E0
POP AF F1
Restore Register Pair AF: Register A holds the type of the function's name.
50E1
JUMP to the ROM's 2819H to change the result to that type; it returns to the expression evaluator with Register Pair HL past the call.
50E4H - Find a Function's Variable
Used by DEF FN (5087H) and FN (5092H). Checks for the FN token at Register Pair HL and finds (or makes) the simple variable whose name is the function's name with bit 7 of the first letter set. Returns Register Pair DE = the address of its value and Register Pair HL past the name.
50E4
RST 08H => BEH CF BE
Check that the character at Register Pair HL is the FN token (BEH) and step past it, or report SYNTAX ERROR.
50E6
LD A,80H 3E 80
Load Register A with 80H, the flag for no subscript.
50E8
LD (40DCH),A 32 DC 40
Store Register A (80H) at 40DCH: the variable search takes no subscript, the name is a simple variable.
50EB
OR (HL) B6
OR the first letter of the name at Register Pair HL into Register A (80H): the letter with bit 7 set.
50EC
LD B,A 47
Load Register B with Register A, the first character of the name the search uses.
50ED
JUMP to the ROM's 2612H, the variable search after it has taken the first character into Register B: it finds or makes the variable and returns to the caller with Register Pair DE = its value.
50F0H - Save the Parameters of a Function
Called from 50AAH with Register Pair HL on the ( of the definition. For each parameter name it finds (or makes) the variable and pushes its value on the stack: a number's 2, 4 or 8 bytes a word at a time, then the address after them, then the type; a string's descriptor is copied to the temporary descriptors (the ROM's 2888H) and its address and type are pushed. A 00H mark goes first and a 29H mark last. Because it leaves these on the stack, it takes its return address into Index Register IX and returns with JP (IX).
50F0
POP IX DD E1
Take the return address (50ADH) off the stack into Index Register IX.
50F2
XOR A AF
Load Register A with 00H (XOR A, which sets the Z flag).
50F3
PUSH AF F5
Push Register Pair AF (00H, Z): the mark where the restore (5130H) stops.
50F4
LD (40D8H),HL 22 D8 40
Store the address of the definition's ( (Register Pair HL) at 40D8H-40D9H, for 514CH.
50F7
RST 10H D7
Fetch the next character through RST 10H: Register Pair HL moves to it and Register A holds the first letter of the first parameter.
50F8
JUMP to 50FCH for the first parameter, whose name Register Pair HL is on.
50FA
RST 08H => 2CH CF 2C
Check that the next character is a comma (2CH) and step past it, or report SYNTAX ERROR.
50FC
LD C,08H 0E 08
Load Register C with 08H, half the bytes of stack the check below asks for.
50FE
GOSUB to the ROM's 1963H to check that 40FDH (the end of the arrays) plus twice Register C (16 bytes), with the ROM's own margin, stays below the stack; otherwise OUT OF MEMORY.
5101
LD A,80H 3E 80
Load Register A with 80H, the flag for no subscript.
5103
LD (40DCH),A 32 DC 40
Store Register A (80H) at 40DCH: the parameter is a simple variable, no subscript.
5106
GOSUB to the ROM's 260DH to find (or make) the parameter's variable: Register Pair DE = the address of its value, Register Pair HL past its name, 40AFH = its type.
5109
LD A,(40AFH) 3A AF 40
Fetch the type from 40AFH into Register A (02H integer, 03H string, 04H single, 08H double).
510C
RRA 1F
Shift it right: bit 0 goes into the Carry flag, set only for a string; Register A becomes the number of words of a number (1, 2 or 4).
510D
If Register A came from a numeric type (No Carry), JUMP to 5117H.
510F
PUSH DE D5
A string: save the address of its descriptor (Register Pair DE) on the stack.
5110
PUSH HL E5
Save Register Pair HL, the text pointer, on the stack.
5111
GOSUB to the ROM's 2888H to copy the descriptor at Register Pair DE to the next temporary descriptor slot (40B3H), which keeps the old string.
5114
POP HL E1
Restore the text pointer into Register Pair HL.
5115
JUMP to 5122H with Register Pair HL, the text pointer, back.
5117
EX DE,HL EB
A number: exchange Register Pairs DE and HL: Register Pair HL = the variable's value.
5118
LD B,(HL) 46
Load Register B with the next byte of the value at Register Pair HL.
5119
INC HL 23
Point Register Pair HL to the byte after it in the value.
511A
LD C,(HL) 4E
Load Register C with the byte at Register Pair HL.
511B
INC HL 23
Point Register Pair HL to the next pair of bytes of the value.
511C
PUSH BC C5
Push the two bytes (Register Pair BC) on the stack.
511D
DEC A 3D
Decrement Register A, the words of the value left to push.
511E
LOOP BACK to 5118H until the whole value is pushed.
5120
PUSH HL E5
Push the address just past the value (Register Pair HL).
5121
EX DE,HL EB
Exchange Register Pairs DE and HL back: Register Pair HL = the text pointer.
5122
LD A,(40AFH) 3A AF 40
Fetch the parameter's type from 40AFH into Register A.
5125
OR A B7
Test Register A, the type code: NZ, since a type code is never 00H.
5126
PUSH AF F5
Push Register Pair AF (the type in Register A, NZ): one parameter saved.
5127
LD A,(HL) 7E
Fetch the character after the parameter's name at Register Pair HL into Register A.
5128
CP 29H FE 29
Compare Register A with 29H, a closing parenthesis.
512A
If it is not the end of the list, LOOP BACK to 50FAH for the next parameter.
512C
OR A B7
Test Register A (29H): NZ, for the mark below.
512D
PUSH AF F5
Push Register Pair AF (Register A = 29H, NZ): the mark FN (50DCH) takes as parameters saved.
512E
JP (IX) DD E9
JUMP to the return address in Index Register IX (50ADH).
5130H - Give the Parameters Their Old Values
Called from 50DDH with the parameters' saved values on the stack (50F0H). Pops them one parameter at a time, restoring each number's bytes and each string's descriptor, until the 00H mark. Register Pair HL (the text pointer) is kept in the alternate set meanwhile; returns with JP (IX).
5130
POP IX DD E1
Take the return address (50E0H) off the stack into Index Register IX.
5132
EXX D9
Exchange to the alternate register set, keeping the text pointer in Register Pair HL'.
5133
POP AF F1
Pop the next type and flags into Register Pair AF.
5134
If it is the 00H mark (Z), every parameter is restored: JUMP to 5149H.
5136
POP HL E1
Pop the address saved with the parameter into Register Pair HL: past a number's value, or a string's descriptor.
5137
RRA 1F
Shift the type right: the Carry flag is set for a string; Register A becomes the number of words of a number.
5138
If the type was a string (Carry), JUMP to 5144H.
513A
POP BC C1
Pop the next word of the value into Register Pair BC.
513B
DEC HL 2B
Point Register Pair HL to the byte before, back through the value.
513C
LD (HL),C 71
Store Register C, a byte of the saved value, at Register Pair HL.
513D
DEC HL 2B
Point Register Pair HL to the byte before, back through the value.
513E
LD (HL),B 70
Store Register B at Register Pair HL: the word is back in the variable.
513F
DEC A 3D
Decrement Register A, the words left to restore.
5140
LOOP BACK to 513AH until the whole value is restored.
5142
JUMP to 5133H with the value restored, for the next parameter.
5144
GOSUB to 517BH to take the last temporary descriptor (the string's old descriptor, saved at 5111H) off the list and store it in the variable's descriptor at Register Pair HL.
5147
JUMP to 5133H with the descriptor restored, for the next parameter.
5149
EXX D9
EXX: exchange back from the alternate register set: Register Pair HL = the text pointer.
514A
JP (IX) DD E9
JUMP to the return address in Index Register IX (50E0H).
514CH - Assign the Arguments to the Parameters
Called from 50ADH. Takes the arguments of the call (the text at 40F3H, after the name) and the parameter names of the definition (the text at 40D8H, after the () in step, and assigns each argument to its parameter through the ROM's LET (1F2BH), changing its type as needed. Returns with Register Pair HL on the expression of the definition (past its = token) and the text pointer of the call, past its ), on the stack.
514C
LD HL,(40F3H) 2A F3 40
Load Register Pair HL with the text pointer of the call from 40F3H-40F4H.
514F
RST 08H => 28H CF 28
Check that the next character of the call is an opening parenthesis (28H) and step past it, or report SYNTAX ERROR.
5151
PUSH HL E5
Save Register Pair HL, the call's text pointer past its (, on the stack.
5152
LD HL,(40D8H) 2A D8 40
Load Register Pair HL with the address of the definition's ( from 40D8H-40D9H.
5155
LD A,(HL) 7E
Fetch the character at Register Pair HL, the definition's (, into Register A.
5156
CP 28H FE 28
Compare Register A with 28H, an opening parenthesis.
5158
If it is not one, JUMP to 518AH to report FUNCTION DEFINITION ERROR.
515B
RST 10H D7
Fetch the next character of the definition through RST 10H: Register Pair HL moves to it, Register A holds the first letter of the first parameter.
515C
GOSUB to the ROM's 260DH to find the parameter's variable: Register Pair DE = its value, Register Pair HL past its name.
515F
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the call's text pointer, the definition's goes on the stack.
5160
GOSUB to the ROM's 1F2BH, the part of LET that evaluates the expression at Register Pair HL and assigns it to the variable at Register Pair DE: the argument goes into the parameter.
5163
LD A,(HL) 7E
Fetch the character after the argument at Register Pair HL into Register A.
5164
CP 29H FE 29
Compare Register A with 29H, a closing parenthesis.
5166
If Register A is ), the arguments have ended: JUMP to 516FH.
5168
RST 08H => 2CH CF 2C
Check that the next character of the call is a comma (2CH) and step past it, or report SYNTAX ERROR.
516A
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the definition's text pointer.
516B
RST 08H => 2CH CF 2C
Check that the next character of the definition is a comma (2CH) and step past it, or report SYNTAX ERROR: there must be a parameter for each argument.
516D
LOOP BACK to 515CH for the next parameter, Register Pair HL on its name.
516F
RST 10H D7
Fetch the next character of the call through RST 10H, past its ): Register Pair HL moves to it and Register A holds it.
5170
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the definition's text pointer, the call's goes on the stack.
5171
RST 08H => 29H CF 29
Check that the definition's parameters end here with a closing parenthesis (29H), or report SYNTAX ERROR.
5173
RST 08H => D5H CF D5
Check that the = token (D5H) follows, or report SYNTAX ERROR: Register Pair HL is now on the expression.
5175
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the expression of the definition.
5176
POP HL E1
Pop the call's text pointer into Register Pair HL.
5177
EX (SP),HL E3
Exchange Register Pair HL (the call's text pointer) with the top of the stack (at the Stack Pointer), the return address 50B0H.
5178
PUSH HL E5
Push Register Pair HL, the return address, back on top: the call's text pointer now lies under it.
5179
EX DE,HL EB
Exchange Register Pairs DE and HL back: Register Pair HL = the expression of the definition.
517A
RET C9
RETURN to 50B0H with Register Pair HL on the expression of the definition.
517BH - Take the Last Temporary String Descriptor
Entered with Register Pair HL = where a descriptor goes (40D3H, or a parameter's descriptor). Takes the last of the temporary descriptors (the ROM's 29F5H finds it at (40B3H) - 3), removes it from the list by lowering 40B3H, and copies its length and address to Register Pair HL.
517B
PUSH HL E5
Save the destination (Register Pair HL) on the stack.
517C
GOSUB to the ROM's 29F5H: Register Pair HL comes back with the address of the last temporary descriptor and Register Pair BC with the address of its characters.
517F
LD A,(HL) 7E
Load Register A with the length of the descriptor at Register Pair HL.
5180
LD (40B3H),HL 22 B3 40
Store Register Pair HL, its address, at 40B3H-40B4H: it is taken off the list of temporary descriptors.
5183
POP HL E1
Restore the destination into Register Pair HL.
5184
LD (HL),A 77
Store Register A, the length, at the destination (Register Pair HL).
5185
INC HL 23
Point Register Pair HL to the next byte of the destination.
5186
LD (HL),C 71
Store the low byte of the address of the characters (Register C) at Register Pair HL.
5187
INC HL 23
Point Register Pair HL to the next byte of the destination.
5188
LD (HL),B 70
Store the high byte of the address of the characters (Register B) at Register Pair HL.
5189
RET C9
RETURN to the caller with the descriptor copied.
518AH - FUNCTION DEFINITION ERROR
Reached from FN when the function was never defined (50A2H) or its definition has no ( (5158H, which cannot be reached: 514CH is only called after 50A6H has found the ( at 40D8H).
518A
LD E,3CH 1E 3C
Load Register E with 3CH, error 31, FUNCTION DEFINITION ERROR.
518C
JUMP to the ROM's 19A2H to report the error in Register E, FUNCTION DEFINITION ERROR.
518FH - DEF USR Statement
DEF USRn=address (from DEF at 507CH): stores the address in the entry of USRn (n = 0-9, 0 when no digit follows) of the table at 5578H, which USR (519EH) jumps through.
518F
GOSUB to 51C9H to read the digit after USR and return Register Pair DE = its entry in the table at 5578H.
5192
PUSH DE D5
Save Register Pair DE, the entry's address, on the stack.
5193
RST 08H => D5H CF D5
Check that the next character is the = token (D5H) and step past it, or report SYNTAX ERROR.
5195
GOSUB to the ROM's 2B02H to evaluate the address as an integer in Register Pair DE.
5198
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the entry, the text pointer goes on the stack.
5199
LD (HL),E 73
Store the low byte of the address (Register E) in the entry at Register Pair HL.
519A
INC HL 23
Point Register Pair HL to the next byte of the entry.
519B
LD (HL),D 72
Store the high byte of the address (Register D) in the entry at Register Pair HL.
519C
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
519D
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the statement.
519EH - USR: Call a Machine Language Routine
Reached through the USR hook at 41A9H, which the ROM calls at 27FEH with Register Pair HL on the USR token. Takes the ROM's return address off the stack, so the ROM's own USR does not run. Evaluates the argument in parentheses and jumps to the address in the table entry of USRn (5578H), with Register A = the argument's type, Register Pair DE = 4121H (the accumulator) or, for a string, the address of its descriptor, and Register C = n. The routine returns to the ROM's 26E7H, which restores the text pointer. An entry never set holds 1E4AH: ILLEGAL FUNCTION CALL.
519E
POP AF F1
Take the ROM's return address (2801H) off the stack into Register Pair AF.
519F
GOSUB to 51C9H to read the digit after USR (Register Pair BC = the digit times 2) and return Register Pair DE = its entry in the table at 5578H.
51A2
RRC C CB 09
Rotate Register C right: the digit times 2 becomes the digit, 0-9.
51A4
PUSH BC C5
Save Register Pair BC, with the digit in Register C, on the stack.
51A5
PUSH DE D5
Save the entry's address (Register Pair DE) on the stack.
51A6
GOSUB to the ROM's 252CH to evaluate the argument in parentheses into the accumulator.
51A9
POP DE D1
Restore the entry's address into Register Pair DE.
51AA
POP BC C1
Restore Register Pair BC (Register C = the digit).
51AB
PUSH HL E5
Save Register Pair HL, the BASIC text pointer past the ), on the stack.
51AC
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the entry.
51AD
LD A,(HL) 7E
Load Register A with the low byte of the routine's address, from the entry at Register Pair HL.
51AE
INC HL 23
Point Register Pair HL to the high byte of the entry.
51AF
LD H,(HL) 66
Load Register H with the high byte of the routine's address, from Register Pair HL.
51B0
LD L,A 6F
Load Register L with Register A, the low byte: Register Pair HL = the routine's address.
51B1
EX DE,HL EB
Exchange Register Pair HL, the routine's address, into Register Pair DE.
51B2
LD HL,26E7H 21 E7 26
Load Register Pair HL with 26E7H, the ROM's POP HL / RET.
51B5
PUSH HL E5
Push it as the routine's return address: when the routine returns, 26E7H takes the text pointer back into Register Pair HL and returns to the expression evaluator.
51B6
LD HL,4121H 21 21 41
Load Register Pair HL with 4121H, the ROM's accumulator.
51B9
PUSH DE D5
Push the routine's address (Register Pair DE).
51BA
PUSH BC C5
Push Register Pair BC (the digit in Register C).
51BB
LD A,(40AFH) 3A AF 40
Fetch the type of the argument from 40AFH into Register A.
51BE
PUSH AF F5
Push Register Pair AF, with the type in Register A.
51BF
CP 03H FE 03
Compare Register A, the type, with 03H, a string.
51C1
If it is a string, GOSUB to the ROM's 29DAH to release it if it is a temporary one; Register Pair HL comes back with the address of its descriptor.
51C4
POP AF F1
Restore Register Pair AF: Register A holds the type again.
51C5
POP BC C1
Restore Register Pair BC: Register C holds the digit.
51C6
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = 4121H, or the string's descriptor.
51C7
POP HL E1
Pop the routine's address into Register Pair HL.
51C8
JP (HL) E9
JUMP to the routine at Register Pair HL, with Register A, Register Pair DE and Register C as above.
51C9H - Find the USR Table Entry
Used by DEF USR and USR. Fetches the character after the USR token; a digit selects that entry, anything else entry 0. Returns Register Pair DE = 5578H + the digit times 2 and Register Pair BC = the digit times 2.
51C9
RST 10H D7
Fetch the next character through RST 10H, past the USR token: Register Pair HL moves to it, Register A holds it, the Carry flag is set when it is a digit.
51CA
LD BC,0000H 01 00 00
Load Register Pair BC with 0000H: entry 0 when no digit follows.
51CD
If Register A is not a digit (No Carry), JUMP to 51D4H.
51CF
SUB 30H D6 30
Subtract 30H from Register A: the digit's value; this clears the Carry flag.
51D1
RLA 17
Rotate Register A left: the digit times 2, the offset of its entry.
51D2
LD C,A 4F
Load Register C with Register A, the offset of the entry.
51D3
RST 10H D7
Fetch the next character through RST 10H, past the digit: Register Pair HL moves to it and Register A holds it.
51D4
EX DE,HL EB
Exchange Register Pairs DE and HL, keeping the text pointer in Register Pair DE.
51D5
LD HL,5578H 21 78 55
Point Register Pair HL to 5578H, the table of USR addresses.
51D8
ADD HL,BC 09
Add the digit times 2 (Register Pair BC) to Register Pair HL: the entry of USRn.
51D9
EX DE,HL EB
Exchange back: Register Pair DE = the entry, Register Pair HL = the text pointer.
51DA
RET C9
RETURN to the caller with Register Pair DE = the entry and Register Pair HL = the text pointer.
51DBH - MID$ Statement
The ROM's statement dispatcher sends a statement that starts with a token of BCH or above to 2AE7H (its 1D67H), which checks for MID$ (FAH) and jumps through the hook at 41D9H (its 2AECH), with Register Pair HL on the token. MID$(V$,N,M)=S$ replaces characters of V$ from position N on with characters of S$: at most M (when M is given) and at most as many as S$ has; V$ keeps its length, and the replacement stops at its end. N must be 1 to the length of V$, and M 1 to the characters left from N; otherwise ILLEGAL FUNCTION CALL. Before changing V$, the code meant to make sure its characters lie in string space, and copies them there otherwise; the test reads the wrong bytes (51E6H), two bytes of the BASIC text after the comma. With a digit or a letter there it copies, which does no harm. When the second byte is a token of 80H or above (MID$(A$,X+1,...): CDH) and string space starts below that address, the copy is skipped, and a V$ that still points into the program text is changed in place.
51DB
INC HL 23
Point Register Pair HL past the MID$ token, to the ( that must follow.
51DC
RST 08H => 28H CF 28
Check that the next character is an opening parenthesis (28H) and step past it, or report SYNTAX ERROR.
51DE
GOSUB to the ROM's 260DH to find (or make) the variable named at Register Pair HL: Register Pair DE = the address of its descriptor, Register Pair HL past its name.
51E1
GOSUB to the ROM's 0AF4H: TYPE MISMATCH unless the variable is a string.
51E4
PUSH HL E5
Save Register Pair HL, the BASIC text pointer, on the stack.
51E5
PUSH DE D5
Save Register Pair DE, the variable's descriptor, on the stack.
51E6
INC HL 23
Point Register Pair HL one byte on. Register Pair HL is still the BASIC text pointer, not the descriptor (Register Pair DE), so the two bytes read below are the text after the variable's name, not the address of its characters.
51E7
LD E,(HL) 5E
Load Register E with the byte at Register Pair HL.
51E8
INC HL 23
Point Register Pair HL to the next byte of the BASIC text.
51E9
LD D,(HL) 56
Load Register D with the byte at Register Pair HL: Register Pair DE = two bytes of the BASIC text.
51EA
LD HL,(40A0H) 2A A0 40
Load Register Pair HL with the start of string space from 40A0H-40A1H.
51ED
RST 18H DF
Compare Register Pair HL (the start of string space) with Register Pair DE through RST 18H: the Carry flag is set when the start of string space is below Register Pair DE. That happens only when the second byte of text is a token (80H or above) and string space starts below it.
51EE
If Register Pair HL was below Register Pair DE (Carry), JUMP to 51FAH without copying.
51F0
POP HL E1
Restore the variable's descriptor into Register Pair HL.
51F1
PUSH HL E5
Save Register Pair HL, the variable's descriptor, on the stack again.
51F2
GOSUB to the ROM's 2843H to copy the variable's characters into new string space; the temporary descriptor 40D3H describes the copy and Register Pair DE comes back pointing at it.
51F5
POP HL E1
Restore the variable's descriptor into Register Pair HL.
51F6
PUSH HL E5
Save Register Pair HL, the variable's descriptor, on the stack again.
51F7
GOSUB to the ROM's 09D3H to copy the 3 bytes (the type at 40AFH is 03H) of the descriptor at 40D3H (Register Pair DE) to the variable's descriptor (Register Pair HL): the variable now has its own copy in string space.
51FA
POP HL E1
Restore the variable's descriptor into Register Pair HL.
51FB
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the BASIC text pointer, the descriptor goes on the stack.
51FC
RST 08H => 2CH CF 2C
Check that the next character is a comma (2CH) and step past it, or report SYNTAX ERROR.
51FE
GOSUB to the ROM's 2B1CH to evaluate the position N as a number 0-255 in Register A.
5201
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the descriptor, the text pointer goes on the stack.
5202
OR A B7
Test Register A, the position N: Z when it is 0.
5203
If it is 0, JUMP to the ROM's 1E4AH to report ILLEGAL FUNCTION CALL.
5206
DEC A 3D
Subtract 1 from Register A: the position as an offset, N - 1.
5207
CP (HL) BE
Compare Register A, the offset, with the variable's length at Register Pair HL.
5208
If the position is past the end of the string, JUMP to the ROM's 1E4AH to report ILLEGAL FUNCTION CALL.
520B
LD C,A 4F
Load Register C with Register A, the offset N - 1.
520C
LD B,00H 06 00
Load Register B with 00H: Register Pair BC = the offset.
520E
NEG ED 44
Negate Register A, the offset: minus N - 1, for the count below.
5210
ADD A,(HL) 86
Add the variable's length (at Register Pair HL) to Register A: the characters from position N to the end.
5211
LD D,A 57
Load Register D with Register A, the characters left: the most that may be replaced.
5212
INC HL 23
Point Register Pair HL to byte 1 of the descriptor.
5213
LD A,(HL) 7E
Load Register A with the low byte of the address of the characters, from the descriptor at Register Pair HL.
5214
INC HL 23
Point Register Pair HL to byte 2 of the descriptor.
5215
LD H,(HL) 66
Load Register H with the high byte of the address, from Register Pair HL.
5216
LD L,A 6F
Load Register L with Register A, the low byte: Register Pair HL = the variable's characters.
5217
ADD HL,BC 09
Add the offset (Register Pair BC) to Register Pair HL: the character at position N.
5218
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the text pointer, the position goes on the stack.
5219
LD A,(HL) 7E
Fetch the next character of the BASIC text at Register Pair HL into Register A.
521A
CP 2CH FE 2C
Compare Register A with 2CH (,): a length M follows.
521C
If no length M follows, JUMP to 5230H with the limit in Register D.
521E
PUSH DE D5
Save Register Pair DE (the limit in Register D) on the stack.
521F
RST 08H => 2CH CF 2C
Check that the next character is a comma (2CH) and step past it, or report SYNTAX ERROR.
5221
GOSUB to the ROM's 2B1CH to evaluate the length M as a number 0-255 in Register A.
5224
POP DE D1
Restore Register Pair DE: the limit is in Register D again.
5225
CP D BA
Compare Register A, the length M, with Register D, the limit.
5226
If it is just the characters left, JUMP to 5230H.
5228
If it is more than the characters left, JUMP to the ROM's 1E4AH to report ILLEGAL FUNCTION CALL.
522B
OR A B7
Test Register A, the length M: Z when it is 0.
522C
If it is 0, JUMP to the ROM's 1E4AH to report ILLEGAL FUNCTION CALL.
522F
LD D,A 57
Load Register D with Register A, the length M: the new limit.
5230
PUSH DE D5
Save Register Pair DE, with the limit in Register D, on the stack.
5231
RST 08H => 29H CF 29
Check that the next character is a closing parenthesis (29H) and step past it, or report SYNTAX ERROR.
5233
RST 08H => D5H CF D5
Check that the = token (D5H) follows and step past it, or report SYNTAX ERROR.
5235
GOSUB to the ROM's expression evaluator at 2337H to evaluate the replacement S$.
5238
PUSH HL E5
Save Register Pair HL, the text pointer, on the stack.
5239
GOSUB to the ROM's 29D7H: TYPE MISMATCH unless S$ is a string; Register Pair HL comes back with its descriptor.
523C
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the descriptor of S$.
523D
POP HL E1
Restore the text pointer into Register Pair HL.
523E
POP BC C1
Restore Register Pair BC from the stack: the limit is in Register B.
523F
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the position in V$, the text pointer goes on the stack.
5240
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the position in V$, Register Pair HL = the descriptor of S$.
5241
LD A,B 78
Load Register A with Register B, the limit on the characters to replace.
5242
CP (HL) BE
Compare Register A, the limit, with the length of S$ at Register Pair HL.
5243
If the limit is shorter, JUMP to 524AH to copy that many characters.
5245
LD A,(HL) 7E
Otherwise load Register A with the length of S$ from its descriptor at Register Pair HL.
5246
OR A B7
Test Register A, the length of S$: Z when S$ is empty.
5247
If S$ is empty, JUMP to 5255H: nothing to copy.
5249
LD B,A 47
Load Register B with Register A, the length of S$: the number to copy.
524A
INC HL 23
Point Register Pair HL to byte 1 of the descriptor of S$.
524B
LD A,(HL) 7E
Load Register A with the low byte of the address of the characters of S$, from Register Pair HL.
524C
INC HL 23
Point Register Pair HL to byte 2 of the descriptor of S$.
524D
LD H,(HL) 66
Load Register H with the high byte of the address, from Register Pair HL.
524E
LD L,A 6F
Load Register L with Register A, the low byte: Register Pair HL = the characters of S$.
524F
LD A,(HL) 7E
Fetch the next character of S$ at Register Pair HL into Register A.
5250
LD (DE),A 12
Store Register A, the character, in V$ at Register Pair DE.
5251
INC HL 23
Point Register Pair HL to the next character of S$.
5252
INC DE 13
Point Register Pair DE to the next character of V$.
5253
Decrement Register B and LOOP BACK to 524FH until all are copied.
5255
POP HL E1
Restore the BASIC text pointer into Register Pair HL.
5256
RET C9
RETURN to the ROM's statement loop with Register Pair HL on the end of the statement.
5257H - INSTR Function
Level II sends INSTR (token C5H) here from its expression evaluator (2506H, vector 419DH), with Register Pair HL on the token. INSTR(N,S1$,S2$) or INSTR(S1$,S2$) returns the position of the first S2$ in S1$ at or after position N (1 when N is left out), or 0 when there is none, when S2$ is empty, when N is past the end of S1$ or when S2$ is longer than what is left of S1$. N = 0 gives ILLEGAL FUNCTION CALL.
5257
RST 10H D7
Fetch the next character through RST 10H, past the INSTR token: Register Pair HL moves to it and Register A holds it.
5258
GOSUB to the ROM's 2335H: it checks for an opening parenthesis and evaluates the first expression.
525B
RST 20H E7
Test the type of the result through RST 20H: Z when it is a string.
525C
LD A,01H 3E 01
Load Register A with 01H, the position to start at when N is left out.
525E
PUSH AF F5
Save Register Pair AF, with 01H in Register A, on the stack.
525F
If the first argument is a string (S1$), JUMP to 5272H.
5261
POP AF F1
Drop the saved 01H from the stack into Register Pair AF.
5262
GOSUB to the ROM's 2B1FH to make N a number 0-255 in Register A.
5265
OR A B7
Test Register A, the position N: Z when it is 0.
5266
If N is 0, JUMP to the ROM's 1E4AH to report ILLEGAL FUNCTION CALL.
5269
PUSH AF F5
Save Register Pair AF, with N in Register A, on the stack.
526A
RST 08H => 2CH CF 2C
Check that the next character is a comma (2CH) and step past it, or report SYNTAX ERROR.
526C
GOSUB to the ROM's expression evaluator at 2337H to evaluate S1$.
526F
GOSUB to the ROM's 0AF4H: TYPE MISMATCH unless it is a string.
5272
RST 08H => 2CH CF 2C
Check that the next character is a comma (2CH) and step past it, or report SYNTAX ERROR.
5274
PUSH HL E5
Save Register Pair HL, the text pointer, on the stack.
5275
LD HL,(4121H) 2A 21 41
Load Register Pair HL with the address of the descriptor of S1$ from 4121H-4122H.
5278
EX (SP),HL E3
Exchange Register Pair HL with the top of the stack (at the Stack Pointer): Register Pair HL = the text pointer, the descriptor of S1$ goes on the stack.
5279
GOSUB to the ROM's expression evaluator at 2337H to evaluate S2$.
527C
RST 08H => 29H CF 29
Check that the next character is a closing parenthesis (29H) and step past it, or report SYNTAX ERROR.
527E
PUSH HL E5
Save Register Pair HL, the text pointer past the ), on the stack.
527F
GOSUB to the ROM's 29D7H: TYPE MISMATCH unless S2$ is a string; Register Pair HL comes back with its descriptor.
5282
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = the descriptor of S2$.
5283
POP BC C1
Restore the text pointer into Register Pair BC.
5284
POP HL E1
Restore the descriptor of S1$ into Register Pair HL.
5285
POP AF F1
Restore Register Pair AF: Register A holds N (or 01H).
5286
PUSH BC C5
Save Register Pair BC, the text pointer, on the stack again, for the end.
5287
DEC A 3D
Subtract 1 from Register A: the offset N - 1.
5288
CP (HL) BE
Compare Register A, the offset, with the length of S1$ at Register Pair HL.
5289
If N is past the end of S1$, JUMP to 52D6H to return 0.
528C
LD C,A 4F
Load Register C with Register A, the offset N - 1, the position counter.
528D
LD B,00H 06 00
Load Register B with 00H: Register Pair BC = the offset.
528F
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the descriptor of S2$.
5290
LD A,(HL) 7E
Load Register A with the length of S2$ from its descriptor at Register Pair HL.
5291
OR A B7
Test Register A, the length of S2$: Z when S2$ is empty.
5292
If S2$ is empty (Z), JUMP to 52D6H to return 0.
5295
EX DE,HL EB
Exchange Register Pairs DE and HL back: Register Pair HL = the descriptor of S1$.
5296
CP (HL) BE
Compare Register A, the length of S2$, with the length of S1$ at Register Pair HL.
5297
If the lengths of S2$ and S1$ are equal (Z), JUMP to 529CH.
5299
If S2$ is longer than S1$, JUMP to 52D6H to return 0.
529C
LD A,C 79
Load Register A with Register C, the offset N - 1.
529D
NEG ED 44
Negate Register A, the offset: minus N - 1, for the count below.
529F
ADD A,(HL) 86
Add the length of S1$ (at Register Pair HL) to Register A: the characters of S1$ from position N on.
52A0
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the descriptor of S2$.
52A1
CP (HL) BE
Compare Register A, those characters, with the length of S2$ at Register Pair HL.
52A2
If fewer are left than S2$ has, JUMP to 52D6H to return 0.
52A5
SUB (HL) 96
Subtract the length of S2$ (at Register Pair HL) from Register A.
52A6
INC A 3C
Add 1 to Register A: the number of positions to try.
52A7
PUSH AF F5
Save Register Pair AF, with the positions to try in Register A, on the stack.
52A8
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the descriptor of S1$.
52A9
INC HL 23
Point Register Pair HL to byte 1 of the descriptor.
52AA
LD A,(HL) 7E
Load Register A with the low byte of the address of the characters of S1$, from Register Pair HL.
52AB
INC HL 23
Point Register Pair HL to byte 2 of the descriptor of S1$.
52AC
LD H,(HL) 66
Load Register H with the high byte of the address, from Register Pair HL.
52AD
LD L,A 6F
Load Register L with Register A, the low byte: Register Pair HL = the characters of S1$.
52AE
ADD HL,BC 09
Add the offset (Register Pair BC): Register Pair HL = position N of S1$.
52AF
PUSH HL E5
Save Register Pair HL, position N of S1$, on the stack.
52B0
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the descriptor of S2$.
52B1
LD B,(HL) 46
Load Register B with the length of S2$ from its descriptor at Register Pair HL.
52B2
INC HL 23
Point Register Pair HL to byte 1 of the descriptor.
52B3
LD E,(HL) 5E
Load Register E with the low byte of the address of the characters of S2$, from Register Pair HL.
52B4
INC HL 23
Point Register Pair HL to byte 2 of the descriptor of S2$.
52B5
LD D,(HL) 56
Load Register D with the high byte from Register Pair HL: Register Pair DE = the characters of S2$.
52B6
POP HL E1
Restore position N of S1$ into Register Pair HL.
52B7
POP AF F1
Restore Register Pair AF: the number of positions to try is in Register A.
52B8
PUSH AF F5
Save Register Pair AF, with the positions left in Register A, on the stack.
52B9
PUSH BC C5
Save Register Pair BC (Register B = the length of S2$, Register C = the offset of this position).
52BA
PUSH DE D5
Save Register Pair DE, the start of S2$, on the stack.
52BB
PUSH HL E5
Save Register Pair HL, this position in S1$, on the stack.
52BC
LD A,(DE) 1A
Fetch the next character of S2$ (Register Pair DE) into Register A.
52BD
CP (HL) BE
Compare Register A, the character of S2$, with the character of S1$ at Register Pair HL.
52BE
If they differ, JUMP to 52CDH to try the next position.
52C0
INC DE 13
Point Register Pair DE to the next character of S2$.
52C1
INC HL 23
Point Register Pair HL to the next character of S1$.
52C2
Decrement Register B and LOOP BACK to 52BCH until all of S2$ has matched.
52C4
POP AF F1
S2$ was found. Drop the saved position in S1$ from the stack into Register Pair AF.
52C5
POP AF F1
Drop the saved start of S2$ from the stack into Register Pair AF.
52C6
POP HL E1
Pop the saved Register Pair BC into Register Pair HL: Register L = the offset of this position.
52C7
POP AF F1
Drop the positions left from the stack into Register Pair AF.
52C8
LD H,00H 26 00
Load Register H with 00H: Register Pair HL = the offset.
52CA
INC HL 23
Add 1 to Register Pair HL: the position, counted from 1.
52CB
JUMP to 52D9H to return the position in Register Pair HL.
52CD
POP HL E1
Restore this position in S1$ into Register Pair HL.
52CE
POP DE D1
Restore the start of S2$ into Register Pair DE.
52CF
POP BC C1
Restore Register Pair BC (the length of S2$ and the offset).
52D0
POP AF F1
Restore Register Pair AF: the positions left are in Register A.
52D1
INC C 0C
Add 1 to the offset of the position in Register C.
52D2
INC HL 23
Point Register Pair HL to the next position of S1$.
52D3
DEC A 3D
Decrement Register A, the positions left to try.
52D4
LOOP BACK to 52B8H while positions are left (Register A not 00H).
52D6
LD HL,0000H 21 00 00
Not found: load Register Pair HL with 0000H, the result 0.
52D9
GOSUB to the ROM's 0A9AH to store Register Pair HL in the accumulator as an integer, the function's result.
52DC
POP HL E1
Restore the text pointer into Register Pair HL.
52DD
RET C9
RETURN to the expression evaluator with the position in the accumulator.
52DEH - Error Messages
The ROM calls the hook at 41A6H (its 19ECH) before it displays an error as a question mark and a two letter code. MicroDOS takes that path over: it finds the full message for the error number in its list at 52F1H and jumps into the ROM at 1A01H, which displays it, then IN and the line number for an error in a program line, and READY. So every error, those of BASIC too, is displayed in words, without the question mark and without the word ERROR the ROM would add after the code.
52DE
POP HL E1
Take the ROM's return address (19EFH) off the stack into Register Pair HL: the ROM's own display of the error code is skipped.
52DF
LD HL,52F0H 21 F0 52
Point Register Pair HL to 52F0H, the 00H byte before the first message.
52E2
LD A,E 7B
Load Register A with the error code from Register E: (the error number - 1) x 2.
52E3
RRCA 0F
Rotate Register A right: the error code becomes the error number - 1.
52E4
INC A 3C
Add 1 to Register A: the error number itself, 1-35.
52E5
LD B,A 47
Load Register B with Register A, the error number: the number of 00H bytes to pass.
52E6
LD A,(HL) 7E
Fetch the next byte of the list (Register Pair HL) into Register A.
52E7
INC HL 23
Point Register Pair HL to the byte after the one just fetched.
52E8
OR A B7
Test Register A, the byte fetched: 00H ends a message.
52E9
LOOP BACK to 52E6H until a 00H has been passed.
52EB
Decrement Register B and LOOP BACK to 52E6H until the error number of 00H bytes have been passed: Register Pair HL is on the message of that error.
52ED
JUMP to the ROM's 1A01H with the message at Register Pair HL: it displays it, IN and the line number from 40EAH when the error happened in a program line, and goes to READY.
52F0H - Error Message List
The messages of errors 1-35, each ended by a 00H byte, in the order of the Level II error codes (code = (number - 1) x 2): 1-23 are Level II BASIC's own errors, 24-35 MicroDOS's. 52DEH counts 00H bytes from 52F0H to find a message.
52F0
DEFB 00H 00
The 00H before the first message, where the search at 52DEH starts.
52F1-5301
DEFM "NEXT WITHOUT FOR",00H 4E 45 58 54 20 57 49 54 48 4F 55 54 20 46 4F 52 00
Error 1 (code 00H): NEXT WITHOUT FOR. A Level II BASIC error, which the ROM itself would show as ?NF ERROR.
5302-530E
DEFM "SYNTAX ERROR",00H 53 59 4E 54 41 58 20 45 52 52 4F 52 00
Error 2 (code 02H): SYNTAX ERROR. A Level II BASIC error, which the ROM itself would show as ?SN ERROR.
530F-5323
DEFM "RETURN WITHOUT GOSUB",00H 52 45 54 55 52 4E 20 57 49 54 48 4F 55 54 20 47 4F 53 55 42 00
Error 3 (code 04H): RETURN WITHOUT GOSUB. A Level II BASIC error, which the ROM itself would show as ?RG ERROR.
5324-532F
DEFM "OUT OF DATA",00H 4F 55 54 20 4F 46 20 44 41 54 41 00
Error 4 (code 06H): OUT OF DATA. A Level II BASIC error, which the ROM itself would show as ?OD ERROR.
5330-5345
DEFM "ILLEGAL FUNCTION CALL",00H 49 4C 4C 45 47 41 4C 20 46 55 4E 43 54 49 4F 4E 20 43 41 4C 4C 00
Error 5 (code 08H): ILLEGAL FUNCTION CALL. A Level II BASIC error, which the ROM itself would show as ?FC ERROR.
5346-534E
DEFM "OVERFLOW",00H 4F 56 45 52 46 4C 4F 57 00
Error 6 (code 0AH): OVERFLOW. A Level II BASIC error, which the ROM itself would show as ?OV ERROR.
534F-535C
DEFM "OUT OF MEMORY",00H 4F 55 54 20 4F 46 20 4D 45 4D 4F 52 59 00
Error 7 (code 0CH): OUT OF MEMORY. A Level II BASIC error, which the ROM itself would show as ?OM ERROR.
535D-536B
DEFM "UNDEFINED LINE",00H 55 4E 44 45 46 49 4E 45 44 20 4C 49 4E 45 00
Error 8 (code 0EH): UNDEFINED LINE. A Level II BASIC error, which the ROM itself would show as ?UL ERROR.
536C-5382
DEFM "SUBSCRIPT OUT OF RANGE",00H 53 55 42 53 43 52 49 50 54 20 4F 55 54 20 4F 46 20 52 41 4E 47 45 00
Error 9 (code 10H): SUBSCRIPT OUT OF RANGE. A Level II BASIC error, which the ROM itself would show as ?BS ERROR.
5383-5396
DEFM "REDIMENSIONED ARRAY",00H 52 45 44 49 4D 45 4E 53 49 4F 4E 45 44 20 41 52 52 41 59 00
Error 10 (code 12H): REDIMENSIONED ARRAY. A Level II BASIC error, which the ROM itself would show as ?DD ERROR.
5397-53A7
DEFM "DIVISION BY ZERO",00H 44 49 56 49 53 49 4F 4E 20 42 59 20 5A 45 52 4F 00
Error 11 (code 14H): DIVISION BY ZERO. A Level II BASIC error, which the ROM itself would show as ?/0 ERROR.
53A8-53B6
DEFM "ILLEGAL DIRECT",00H 49 4C 4C 45 47 41 4C 20 44 49 52 45 43 54 00
Error 12 (code 16H): ILLEGAL DIRECT. A Level II BASIC error, which the ROM itself would show as ?ID ERROR.
53B7-53C4
DEFM "TYPE MISMATCH",00H 54 59 50 45 20 4D 49 53 4D 41 54 43 48 00
Error 13 (code 18H): TYPE MISMATCH. A Level II BASIC error, which the ROM itself would show as ?TM ERROR.
53C5-53D8
DEFM "OUT OF STRING SPACE",00H 4F 55 54 20 4F 46 20 53 54 52 49 4E 47 20 53 50 41 43 45 00
Error 14 (code 1AH): OUT OF STRING SPACE. A Level II BASIC error, which the ROM itself would show as ?OS ERROR.
53D9-53E8
DEFM "STRING TOO LONG",00H 53 54 52 49 4E 47 20 54 4F 4F 20 4C 4F 4E 47 00
Error 15 (code 1CH): STRING TOO LONG. A Level II BASIC error, which the ROM itself would show as ?LS ERROR.
53E9-5403
DEFM "STRING FORMULA TOO COMPLEX",00H 53 54 52 49 4E 47 20 46 4F 52 4D 55 4C 41 20 54 4F 4F 20 43 4F 4D 50 4C 45 58 00
Error 16 (code 1EH): STRING FORMULA TOO COMPLEX. A Level II BASIC error, which the ROM itself would show as ?ST ERROR.
5404-5412
DEFM "CAN'T CONTINUE",00H 43 41 4E 27 54 20 43 4F 4E 54 49 4E 55 45 00
Error 17 (code 20H): CAN'T CONTINUE. A Level II BASIC error, which the ROM itself would show as ?CN ERROR.
5413-541C
DEFM "NO RESUME",00H 4E 4F 20 52 45 53 55 4D 45 00
Error 18 (code 22H): NO RESUME. A Level II BASIC error, which the ROM itself would show as ?NR ERROR.
541D-5431
DEFM "RESUME WITHOUT ERROR",00H 52 45 53 55 4D 45 20 57 49 54 48 4F 55 54 20 45 52 52 4F 52 00
Error 19 (code 24H): RESUME WITHOUT ERROR. A Level II BASIC error, which the ROM itself would show as ?RW ERROR.
5432-5443
DEFM "UNPRINTABLE ERROR",00H 55 4E 50 52 49 4E 54 41 42 4C 45 20 45 52 52 4F 52 00
Error 20 (code 26H): UNPRINTABLE ERROR. A Level II BASIC error, which the ROM itself would show as ?UE ERROR.
5444-5453
DEFM "MISSING OPERAND",00H 4D 49 53 53 49 4E 47 20 4F 50 45 52 41 4E 44 00
Error 21 (code 28H): MISSING OPERAND. A Level II BASIC error, which the ROM itself would show as ?MO ERROR.
5454-5461
DEFM "BAD FILE DATA",00H 42 41 44 20 46 49 4C 45 20 44 41 54 41 00
Error 22 (code 2AH): BAD FILE DATA. A Level II BASIC error, which the ROM itself would show as ?FD ERROR.
5462-5479
DEFM "FEATURE NOT IMPLEMENTED",00H 46 45 41 54 55 52 45 20 4E 4F 54 20 49 4D 50 4C 45 4D 45 4E 54 45 44 00
Error 23 (code 2CH): FEATURE NOT IMPLEMENTED. A Level II BASIC error, which the ROM itself would show as ?L3 ERROR. The ROM reports it (its 012DH) for every statement and function MicroDOS leaves out: EOF, TIME$, OPEN, CLOSE, NAME and KILL.
547A-548E
DEFM "INVALID DRIVE NUMBER",00H 49 4E 56 41 4C 49 44 20 44 52 49 56 45 20 4E 55 4D 42 45 52 00
Error 24 (code 2EH): INVALID DRIVE NUMBER. A MicroDOS error, reported by 48DAH: a drive number above 3 (4B45H, 4B4BH) or no drive select bit (4D52H, 4E05H).
548F-54A4
DEFM "INVALID SECTOR NUMBER",00H 49 4E 56 41 4C 49 44 20 53 45 43 54 4F 52 20 4E 55 4D 42 45 52 00
Error 25 (code 30H): INVALID SECTOR NUMBER. A MicroDOS error, reported by 48DEH: a sector number past the last track (4B33H).
54A5-54BA
DEFM "DISK READ/WRITE ERROR",00H 44 49 53 4B 20 52 45 41 44 2F 57 52 49 54 45 20 45 52 52 4F 52 00
Error 26 (code 32H): DISK READ/WRITE ERROR. A MicroDOS error, reported by 48E6H: a sector that would not read or write after nine tries (4BACH, 4C2FH).
54BB-54CF
DEFM "DISK WRITE PROTECTED",00H 44 49 53 4B 20 57 52 49 54 45 20 50 52 4F 54 45 43 54 45 44 00
Error 27 (code 34H): DISK WRITE PROTECTED. A MicroDOS error, reported by 48E2H: a write or a format on a diskette whose notch is covered (4C01H, 4C9CH).
54D0-54DD
DEFM "DISK OVERFLOW",00H 44 49 53 4B 20 4F 56 45 52 46 4C 4F 57 00
Error 28 (code 36H): DISK OVERFLOW. A MicroDOS error, reported by 49A3H, in the step to the next sector, which does not reach it (498FH).
54DE-54F7
DEFM "DISK MISSING OR DOOR OPEN",00H 44 49 53 4B 20 4D 49 53 53 49 4E 47 20 4F 52 20 44 4F 4F 52 20 4F 50 45 4E 00
Error 29 (code 38H): DISK MISSING OR DOOR OPEN. A MicroDOS error, reported by 48EAH: the controller stayed busy for 65536 tests (4DE0H).
54F8-5506
DEFM "FIELD OVERFLOW",00H 46 49 45 4C 44 20 4F 56 45 52 46 4C 4F 57 00
Error 30 (code 3AH): FIELD OVERFLOW. A MicroDOS error, reported by 4EA9H: DEF FIELD widths adding up to more than 255.
5507-5520
DEFM "FUNCTION DEFINITION ERROR",00H 46 55 4E 43 54 49 4F 4E 20 44 45 46 49 4E 49 54 49 4F 4E 20 45 52 52 4F 52 00
Error 31 (code 3CH): FUNCTION DEFINITION ERROR. A MicroDOS error, reported by 518AH: FN of a function never defined.
5521-553C
DEFM "INVALID FIELD BUFFER NUMBER",00H 49 4E 56 41 4C 49 44 20 46 49 45 4C 44 20 42 55 46 46 45 52 20 4E 55 4D 42 45 52 00
Error 32 (code 3EH): INVALID FIELD BUFFER NUMBER. A MicroDOS error, reported by 4E73H: a field buffer number outside 1-4.
553D-5555
DEFM "DISK DRIVE NOT AVAILABLE",00H 44 49 53 4B 20 44 52 49 56 45 20 4E 4F 54 20 41 56 41 49 4C 41 42 4C 45 00
Error 33 (code 40H): DISK DRIVE NOT AVAILABLE. A MicroDOS error, reported by 4916H in place of another disk error when the status had NOT READY set.
5556-5565
DEFM "DISK SEEK ERROR",00H 44 49 53 4B 20 53 45 45 4B 20 45 52 52 4F 52 00
Error 34 (code 42H): DISK SEEK ERROR. A MicroDOS error, reported by 48EEH: a seek or restore that failed (4D93H, 4DB9H).
5566-5577
DEFM "CAN'T FORMAT DISK",00H 43 41 4E 27 54 20 46 4F 52 4D 41 54 20 44 49 53 4B 00
Error 35 (code 44H): CAN'T FORMAT DISK. A MicroDOS error, reported by 48F2H: a track that could not be formatted in three tries (4D1CH).
5578H - USR Address Table
Ten addresses, one for each of USR0-USR9, which DEF USRn stores (518FH) and USR jumps through (519EH). As written by CMD"M" they all hold 1E4AH, the ROM's ILLEGAL FUNCTION CALL, so a USR that was never defined reports that error.
5578-5579
DEFW 1E4AH 4A 1E
USR0 (and USR without a digit): 1E4AH, ILLEGAL FUNCTION CALL, until DEF USR0 sets it.
557A-557B
DEFW 1E4AH 4A 1E
USR1: 1E4AH, ILLEGAL FUNCTION CALL, until DEF USR1 sets it.
557C-557D
DEFW 1E4AH 4A 1E
USR2: 1E4AH, ILLEGAL FUNCTION CALL, until DEF USR2 sets it.
557E-557F
DEFW 1E4AH 4A 1E
USR3: 1E4AH, ILLEGAL FUNCTION CALL, until DEF USR3 sets it.
5580-5581
DEFW 1E4AH 4A 1E
USR4: 1E4AH, ILLEGAL FUNCTION CALL, until DEF USR4 sets it.
5582-5583
DEFW 1E4AH 4A 1E
USR5: 1E4AH, ILLEGAL FUNCTION CALL, until DEF USR5 sets it.
5584-5585
DEFW 1E4AH 4A 1E
USR6: 1E4AH, ILLEGAL FUNCTION CALL, until DEF USR6 sets it.
5586-5587
DEFW 1E4AH 4A 1E
USR7: 1E4AH, ILLEGAL FUNCTION CALL, until DEF USR7 sets it.
5588-5589
DEFW 1E4AH 4A 1E
USR8: 1E4AH, ILLEGAL FUNCTION CALL, until DEF USR8 sets it.
558A-558B
DEFW 1E4AH 4A 1E
USR9: 1E4AH, ILLEGAL FUNCTION CALL, until DEF USR9 sets it.
558CH - LOAD: Set the Data Pointer and Check Memory
Called by LOAD (49CDH) before each sector, with Register Pair HL = where the sector's data goes. Stores it at 4490H and checks that it lies at least 256 bytes below the stack. If it does not, the program does not fit: NEW clears what was loaded so far and OUT OF MEMORY is reported, so no part of the program stays in memory. Register Pair DE is kept.
558C
LD (4490H),HL 22 90 44
Store Register Pair HL, where the next sector's data goes, at 4490H-4491H, the data pointer of the sector read.
558F
PUSH DE D5
Save Register Pair DE (LOAD's step) on the stack.
5590
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair DE = where the data goes.
5591
LD HL,0000H 21 00 00
Load Register Pair HL with 0000H, for adding the Stack Pointer.
5594
ADD HL,SP 39
Add the Stack Pointer: Register Pair HL = the Stack Pointer.
5595
DEC H 25
Subtract 1 from Register H: Register Pair HL = the Stack Pointer less 256.
5596
RST 18H DF
Compare Register Pair HL (the Stack Pointer less 256) with Register Pair DE (where the data goes) through RST 18H: the Carry flag is set when the data would go above it.
5597
EX DE,HL EB
Exchange Register Pairs DE and HL back: Register Pair HL = where the data goes.
5598
POP DE D1
Restore Register Pair DE (LOAD's step) from the stack.
5599
RET NC D0
If there is room (No Carry), RETURN to LOAD with Register Pair HL = where the data goes.
559A
Otherwise JUMP to 55AEH: NEW and OUT OF MEMORY.
559C-559D
DEFW 19A2H A2 19
Two bytes, A2H and 19H, that no code reads or runs: the JR at 559AH passes over them and the CALL from 4969H enters at 559EH. As a word they are 19A2H, the ROM's error handler.
559EH - Chain Write: Is This the Last Sector?
Called by the chain write at 4969H with Register A = the high byte of the bytes left and Register Pair HL = the bytes left. Returns when 255 or more are left, so that a full sector is written. Otherwise it drops its own return address and jumps to 4977H, which writes the last sector with the bytes left and returns to the caller of 4968H.
559E
OR A B7
Test Register A, the high byte of the bytes left.
559F
RET NZ C0
If 256 or more bytes are left, RETURN: a full sector is written.
55A0
LD A,L 7D
Load Register A with the low byte of the bytes left (Register L).
55A1
INC A 3C
Add 1 to Register A, the low byte: 255 bytes (FFH) give 00H.
55A2
RET Z C8
If exactly 255 bytes are left, RETURN: a full sector is written, and the next pass writes a last sector with no data.
55A3
POP AF F1
Drop the return address 496CH (back into the loop of 4968H) from the stack into Register Pair AF, so that 4977H returns to the caller of 4968H.
55A4
JUMP to 4977H to write the last sector with the Register L bytes left (00H-FEH).
55A7H - GET: New String Space for the Variable
Called by GET (4ACDH) with Register A = the number of data bytes and Register Pair DE = the variable's descriptor, when the variable is shorter than the data. Sets the variable's length to 00H, so that the garbage collection the ROM may do while finding space does not keep its old characters, and gets new string space for Register A bytes through the ROM's 2857H.
55A7
EX DE,HL EB
Exchange Register Pairs DE and HL: Register Pair HL = the variable's descriptor.
55A8
LD (HL),00H 36 00
Store 00H as the variable's length, at its descriptor (Register Pair HL).
55AA
EX DE,HL EB
Exchange Register Pairs DE and HL back: Register Pair DE = the variable's descriptor.
55AB
JUMP to the ROM's 2857H to get string space for Register A bytes; it describes it at 40D3H-40D5H and returns to GET.
55AEH - LOAD: Out of Memory
Reached from 559AH when a program does not fit.
55AE
GOSUB to the ROM's NEW at 1B4DH to clear the part of the program already loaded.
55B1
JUMP to the ROM's 197AH to report OUT OF MEMORY.
55B4H - Bytes Not Used (55B4H-55FFH)
The last 76 bytes of the main file: 55B4H-55EDH come from the 18th sector, 55EEH-55FFH from the 19th. No code reads or runs them. On this diskette they are a piece of assembler source text.
55B4-55FF
DEFM "AND PROCESSING",EAH,"=",1CH,"; --------------------------",1CH,">",1EH,"CMD",09H,"CALL",09H,"GETVAL",09H,09H,";GET ARGUME" 41 4E 44 20 50 52 4F 43 45 53 53 49 4E 47 EA 3D 1C 3B 20 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 1C 3E 1E 43 4D 44 09 43 41 4C 4C 09 47 45 54 56 41 4C 09 09 3B 47 45 54 20 41 52 47 55 4D 45
Bytes no code reads: assembler source text (AND PROCESSING, a comment line of dashes, CMD CALL GETVAL ;GET ARGUME) with other bytes among it.