DOSPLUS 3.5 for the Model I - O/CMD Disassembled
Page Customization
Page Index
O/CMD
Other Navigation
Introduction/Summary
DOSPLUS 3.5 O/CMD Disassembly - CMD"O", the Sort of BASIC Arrays (Model I)
O/CMD is the array sort of Extended Disk BASIC, CMD"O", whose heading names it SORT - BASIC Multi key/array sort - 1.7. It is a load module of 4 blocks, 835 bytes, at 5200H-554FH (54E8H-54F4H, its variables, are not in the file), with the transfer address 5200H, after the two comment records (the name O and the copyright notice). The Model I and Model III files are identical byte for byte, and so are the two pages apart from their links.
It runs only from Extended Disk BASIC: BASIC/CMD's CMD (5C48H) treats the one letter O, which is none of its own options, as a DOS command for CMNDI@, so the DOS loads O/CMD at 5200H and calls it. O takes BASIC's text pointer off the stack under CMNDI@'s return address (5212H) and, when the sort is done, returns straight into the ROM's statement loop (528DH), so the statement goes on after it. Run from the DOS command level it only shows its heading. TBASIC cannot run it, since its CMD runs no DOS commands.
The Statement
CMD"O",count,[+|-]primary(start)[+key|-key...][,tag,...]. The count must not be 0; the primary key array carries the subscript of the first element to sort, which holds for every array named; up to nine more key arrays follow, each after + (ascending) or - (descending), and then up to twenty tag arrays, each after a comma. A key decides the order of two elements when the keys before it are equal; tag arrays are moved with the keys and never compared. Every array must already exist (O does not dimension one) with one dimension and with the elements start to start + count - 1 (Illegal function call otherwise). The type of an array is its suffix (% $ ! #) or the DEF type of its first letter, as BASIC takes it (535EH).
The Parts of O/CMD
| Address | Contents |
|---|---|
| 5200H-5279H | The start: the caller test, the count, the primary key, the other keys and the tags (5200H, 524EH, 5267H). |
| 527AH-5323H | The Shell sort (527AH) and its compare and exchange (52B8H). |
| 5324H-53EBH | Taking an array: its name and type, its search in the array area, its entry in the table (5324H, 532FH, 535EH). |
| 53ECH-548FH | The address of an element (53ECH, 53FDH) and the compare of two elements by type (5423H). |
| 5490H-554FH | The heading, the variables and the table of the arrays (5490H). |
The Sort
The sort is a Shell sort with the gaps n/2, n/4 and so on down to 1 (527AH). For each gap every element is compared with the one a gap after it; when they are out of order they are exchanged and the compare goes back by a gap. Two elements are compared by type (5423H): integers, single and double precision by the ROM's compare routines, strings character by character, a shorter string that is the start of the other being the lesser. An exchange swaps the elements of the deciding key array and of every array after it in the table, tags included; a string array has its descriptors swapped, not its text (52C2H). Keys before the deciding one are equal and are not swapped. Since a Shell sort is not stable, elements equal on every key may change their order.
Differences from the Manual
The manual (Disk BASIC, page 5-51) describes the statement as the bytes take it. What it does not say: at most ten key arrays (the primary one and nine more) and twenty tag arrays are taken, more being a Syntax error; the arrays must exist and have one dimension; the order of equal elements is not kept. One test in the bytes does not work as meant: an array named twice should be Illegal function call, but the test compares both bytes of each stored address with the high byte of the new one (532FH), so in practice an array named twice is accepted, and it is then exchanged twice, which undoes the move for that array.
Variables
O/CMD Variables
| Address Size | Contents |
|---|---|
| 54E8H 1 byte | Type The type of the array being looked for (53A5H). |
| 54E9H-54EAH 2 bytes | Count The number of elements to sort (5222H). |
| 54EBH-54ECH 2 bytes | Start The subscript of the first element to sort, for every array (5241H). |
| 54EDH-54EEH 2 bytes | Limit The count less the gap (5297H). |
| 54EFH-54F0H 2 bytes | Index j The compare's index (52A2H). |
| 54F1H-54F2H 2 bytes | Gap The gap of the Shell sort (5282H). |
| 54F3H-54F4H 2 bytes | Index i The pass's index (529CH). |
| 54F5H-554FH 91 bytes | Array table Thirty entries of flags and an array entry address, and an end byte 00H (54F5H). |
Outside Routines
| Address | Contents |
|---|---|
| 4467H | SYS0/SYS: DSPLY@, the heading (520CH). |
| 402DH | SYS0/SYS: EXIT@ (520FH). |
| 1E46H | ROM: evaluate a positive integer (5215H, 523CH). |
| 1E3DH | ROM: test for a letter (535FH). |
| 0A39H | ROM: compare two integers (545EH). |
| 0A0CH | ROM: compare two single precision numbers (5450H). |
| 0A78H | ROM: compare two double precision numbers, reversed (5440H). |
| 1E4AH | ROM: Illegal function call (521AH and others). |
| 1997H | ROM: Syntax error (525EH, 526EH, 5362H). |
Disassembly
5200H - CMD"O"
O/CMD's transfer address. O sorts BASIC arrays, run from Extended Disk BASIC as CMD"O",count,[+|-]primary(start)[+key|-key...][,tag,...]: BASIC/CMD's CMD passes the one letter O to CMNDI@ as a DOS command, and the DOS loads O/CMD at 5200H and calls it. From the DOS command level (return address 402DH) it only shows its heading. From BASIC it takes the count (54E9H), the primary key array and its start subscript (54EBH), up to nine more key arrays and up to twenty tag arrays into its table (54F5H), sorts them (527AH), and returns straight into the ROM's statement loop with Register Pair HL at the end of the statement, past CMNDI@.
524EH - More Key Arrays
Each further key array is +name or -name (no subscript: the start subscript of the primary one holds for all). At most nine more are taken (Register C), then a comma starts the tag arrays.
5267H - The Tag Arrays
Each tag array follows a comma and moves with the key arrays but is not compared. At most twenty are taken (Register C).
527AH - The Sort
A Shell sort with gaps n/2, n/4 and so on down to 1 (n the count at 54E9H): for each gap, each element i from 0 to n-gap-1 is compared with the one a gap after it and, while they are out of order, the two are exchanged and the compare goes back by one gap (54EFH). The elements are those of the start subscript (54EBH) plus i. The compare uses the key arrays in their order: a key whose two elements are equal passes the decision to the next key; when all keys are equal nothing moves. An exchange swaps the elements of the deciding key array and of every array after it in the table, the tag arrays included.
52B8H - Compare and Exchange
Compares the two elements of the current key (5423H). Equal: the next key array decides (52F2H). Out of order (01H in an ascending key, FFH in a descending one): the elements of this array and of every array after it are exchanged, and the compare goes back one gap. In order: the next element i.
5324H - Another Array
Takes the name of a key or tag array at Register Pair HL, finds the array (535EH) and enters it into the table with the flags in Register B (532FH). Register C, the caller's count, is kept.
532FH - Enter an Array
Register A the flags, Register Pair BC the number of elements, Register Pair DE the array's entry. The count plus the start subscript must not pass the number of elements (else Illegal function call). The array is put into the first free entry of the table at 54F5H (three bytes: the flags, the entry's address). The test meant to refuse an array named twice compares both bytes of each entry's address with Register D only, so it refuses an array only when the low and high bytes of the old entry both equal the high byte of the new one; an array named twice is in practice accepted.
535EH - Find an Array
Takes a variable name at Register Pair HL (a letter, then letters and digits, of which the first two count) with its type: a suffix %, $, ! or #, else the type of its first letter from the ROM's DEF table at 4101H. Then the array of that name and type is looked for from ARYTAB (40FBH) to STREND (40FDH): it must exist (Illegal function call) and have one dimension. Returns Register Pair DE = the array's entry, Register Pair BC = its number of elements, Register Pair HL at the last character of the name or at its suffix.
53ECH - Two Elements
For the table entry at Index Register IX: Register Pair HL a subscript, Register Pair DE the gap. Returns Register Pair HL = the address of that element, Register Pair DE = the address of the element a gap after it, Register B the length of an element and Register C the entry's flags, and Index Register IX moved to the next entry.
53FDH - The Address of an Element
Register Pair HL a subscript, Index Register IX a table entry. The element's length (the array's type: 2, 3, 4 or 8) times the subscript is added to the first element, 8 bytes after the array's entry. The multiplication by 3 uses the parity of Register A: OR A after SUB 04H gives parity even only for FFH (a string).
5423H - Compare Two Elements
The element at Register Pair HL is compared with the one at Register Pair DE by the type in Register B: integers by the ROM's 0A39H, single precision by 0A0CH, double precision by 0A78H, strings character by character (a string that is the start of the other is the lesser). Register A returns 00H for equal, 01H when the first is greater, FFH when it is less.
5490H - The Heading and the Variables
Data.