SPECTRUM 48k ROM ROUTINES
=========================

Notes:
* The notation $xxxx.nnn refers to ROM address $xxxx and page nnn in The
  Complete Spectrum ROM Disassembly by Ian Logan & Frank O'Hara.
  A '.' separator means the routine is in the 48K BASIC ROM on the 128k. This
  is ROM.1 on the +128k/+2 and ROM.3 on the +2A/+3.
  A 'E' separator means the routine is in the Editor ROM.0 on the 128k.
  A 'S' separator means the routine is in the Syntax ROM.1 on the 128k +2A/+3.
* The notation {nnn} refers to footnote nnn.
* The term "last value" refers to the top entry on the calculator stack;
  ie. the 5 bytes before (STKEND). If the result of a routine is not stored
  in the registers then it will be in "last value".
* The term "stack the number" means "convert to 5-byte FP form and store as
  "last value" on the calculator stack".
* For a thorough explanation of the use of the calculator stack refer to
  Toni Baker's excellent ZX Computing series "Machine Code Calculator":
  http://www.users.globalnet.co.uk/~jg27paw4/type-ins/zx-comp/mccalc.zip

$0000.  1  START      (RST $00) the start
$0008.  1  ERROR_1    (RST $08) the error restart
$0010.  1  PRINT_A_1  (RST $10) print A (BC,DE,HL preserved)
$0028.  1  FP_CALC    (RST $28) start the FP calculator (DEFB $38 stops)
$0030.  1  BC_SPACES  (RST $30) make BC bytes of space at the end of (WORKSP)
$0038.  1  MASK_INT   (RST $38) increment (FRAMES) and scan the keyboard
$028e.  5  KEY_SCAN   {001} the keyboard scanning subroutine
$0145   S
$03b5. 11  BEEPER     {002} play note length DE (f*t), pitch HL (T/4)
$03f8. 11  BEEP       {002} play note length "last-1 value", pitch "last value"
$04c2. 15  SA_BYTES         save DE header(A=$00)/data(A=$ff) bytes from IX
$0828   S
$0556. 17  LD_BYTES   {003} load DE header(A=$00)/data(A=$ff) bytes   to IX
$0884   S
$09f4. 33  PRINT_OUT        print A (BC,DE,HL not preserved)
$0adc. 36  PO_STORE         store row,col,address for current output file
$0b03. 36  PO_FETCH         set B,C=row,col, HL=address for current output file
$0b24. 36  PO_ANY           print A at B,C=row,col, HL=address
$0bdb. 39  PO_ATTR          set the attributes for the current character
$0c0a. 39  PO_MSG           print message entry A from table at DE
$0c10. 39  PO_TOKENS        print token entry A from table at DE
$0c41. 40  PO_SEARCH  {004} search for Ath entry in table at DE, returns in DE
$0c55. 40  PO_SCR           test for scroll on line B
$0d4d. 43  TEMPS            set temporary colours
$0d6b. 44  CLS              the CLS command routine
$0d6e. 44  CLS_LOWER        clear the lower screen
$0daf. 44  CL_ALL           clear the whole display area
$21ef   E
$22c7   S
$0dd9. 45  CL_SET           set HL=address in current output file of row,col B,C
$0e00. 45  CL_SCROLL        scroll up B lines from bottom (1-23)
$0e44. 46  CL_LINE          clear bottom B lines of display file
$0e88. 48  CL_ATTR          set DE=atttribute address for display address HL
$0e9b. 48  CL_ADDR          set HL=display address for line B
$0eac. 48  COPY             the COPY command routine
$21a7   E
$20ce   S
$0ecd. 49  COPY_BUFF        copy the printer buffer to the printer
$0edf. 49  CLEAR_PRB        clear the printer buffer
$0ef4. 49  COPY_LINE        copy pixel line B from address HL to the printer
$0f2c. 50  EDITOR           enter characters into the current EDIT/INPUT line
$1097. 55  CLEAR_SP         reclaim the work area addressed by HL
$10a8. 55  KEY_INPUT        input a character to A from channel "K"
$111d. 56  ED_COPY          copy the EDIT/INPUT line to the lower screen
$1190. 57  SET_HL           set HL/DE=first/last address of (E_LINE) or (WORKSP)
$1195. 58  SET_DE           set    DE=      last address of (E_LINE) or (WORKSP)
$11b7. 59  NEW              the NEW command routine
$21aa   E
$2280   S
$12a2. 61  MAIN_EXEC        the main execution loop
$155d. 64  MAIN_ADD         add a new line to the BASIC program area
$15d4. 65  WAIT_KEY         wait for a character to A from channel (CURCHL)
$15e6. 66  INPUT_AD         input a character to A from channel (CURCHL)
$1601. 66  CHAN_OPEN        open a channel to stream A
$1652. 67  ONE_SPACE        make room for 1 byte at HL
$1655. 67  MAKE_ROOM        make room for BC bytes at HL
$1664. 68  POINTERS         update pointers by BC bytes made/reclaimed after HL
$1695. 69  LINE_NO          get a 16-bit line number from (HL) or (DE)
$16b0. 69  SET_MIN          reclaim E_LINE, WORKSP, STKBOT/END areas
$16bf. 69  SET_WORK         reclaim WORKSP, STKBOT/END areas
$16c5. 70  SET_STK          reclaim STKBOT/END area
$16d4. 70  REC_EDIT   {018} reclaim E_LINE area
$16e5. 70  CLOSE            CLOSE stream "last value"
$1736. 71  OPEN             OPEN channel "last value" for stream "last-1 value"
$1793. 73  CAT_ETC          the CAT/ERASE/FORMAT/MOVE commands routine
$1be5   E  CAT
$1c0c   E  ERASE
$0641   E  FORMAT
$1af0   E  MOVE
$17f5. 74  LLIST            the LLIST command routine
$1b71   E
$17f9. 74  LIST             the LIST command routine
$1b75   E
$1855. 75  OUT_LINE         print a BASIC line from HL
$196e. 79  LINE_ADDR        set HL=line HL address, DE=previous line address
$1980. 79  CP_LINES         set Carry if line (HL) less than line BC
$198b. 80  EACH_STMT        find statement #D or token #E starting from HL
$19b8. 80  NEXT_ONE   {005} find next line in (PROG) or next variable in (VARS)
$19e5. 81  RECLAIM_1        reclaim from HL to DE-1
$19e8. 81  RECLAIM_2        reclaim BC bytes from HL
$19fb. 82  E_LINE_NO        set BC=line number in E_LINE area (0 if none)
$1a1b. 82  OUT_NUM_1        print number 0-9999 from BC, no padding
$1a28. 82  OUT_NUM_2        print number 0-9999 from (HL), space padded
$1b17. 86  LINE_SCAN  {006} check syntax of EDIT (E_LINE) line
$17af   E
$0fbf   S
$1b76. 88  STMT_RET         return point after correct statement interpretation
$1821   E
$1031   S
$1b8a. 88  LINE_RUN         run the EDIT (E_LINE) line
$1838   E
$1048   S
$1c1f. 91  CLASS_01         prepare LET,READ,INPUT
$18f9   E
$110c   S
$1c7a. 93  EXPT_2NUM        Scanning CLASS_08, expect 2 numeric expressions
$190a   E
$1c82. 93  EXPT_1NUM        Scanning CLASS_06, expect 1 numeric expression
$190e   E
$1c8c. 93  EXPT_EXP         Scanning CLASS_0A, expect 1 string  expression
$1916   E
$1c96. 93  PERMS            set permanent colours from temporary colours
$191a   E
$112d   S
$1cde. 94  FETCH_NUM  {007} evaluate a numeric "next expression" at (CH_ADD)
$1cf0. 95  IF               the IF command routine
$1967   E
$1d86. 97  LOOK_PROG  {008} search for token E starting at address HL
$1ded. 99  READ             the READ command routine
$19ab   E
$1e27.100  DATA             the DATA command routine
$19eb   E
$1e85.101  TWO_PARAM  {009} set A="last value" and BC="last-1 value"
$1e94.101  FIND_INT1        set A ="last value"; quit with report B if too big
$1e99.101  FIND_INT2        set BC="last value"; quit with report B if too big
$1ea1.102  RUN              the RUN command routine
$1A02   E
$1eac.102  CLEAR            the CLEAR command routine
$1204   S
$1eed.103  GO_SUB           the GO SUB command routine
$1a53   E
$1f05.103  TEST_ROOM        check for sufficient free RAM; report 4 if not
$1f1a.103  FREE_MEM   {010} set BC=amount of memory in use
$1f23.104  RETURN           the RETURN command routine
$1a6f   E
$1d03. 95  FOR              the FOR command routine
$1981   E
$1f3a.104  PAUSE      {011} pause "last value" 1/50ths seconds (or until key)
$1f3d.104  PAUSE_1    {011} pause BC 1/50ths seconds (or until key)
$1f54.104  BREAK_KEY        reset Carry if BREAK pressed, set otherwise
$162a   S
$1f60.105  DEF_FN           the DEF FN command routine
$1a8c   E
$1fc9.106  LPRINT           the LPRINT command routine
$2174   E
$1bb2. 89  REM              the REM command routine
$1862   E
$1fcd.106  PRINT            the PRINT command routine
$2178   E
$203c.108  PR_STRING        print BC characters from DE
$2089.109  INPUT            the INPUT command routine
$218c   E
$2294.115  BORDER           the BORDER command routine; BORDER="last value"
$22aa.115  PIXEL_ADD        set HL=address and A=bit# of pixel at B,C=y,x
$22b0.115  PIXEL_ADD+6      same as PIXEL_ADD but avoids check on y coord
$22cb.116  POINT            return POINT "last val" row,col as "last val" 0/1
$22dc.116  PLOT             PLOT "last value"
$22e5.116  PLOT_SUB         PLOT B,C=y,x
$2307.117  STK_TO_BC  {012} set B="last value", C="last-1 value"
$2314.117  STK_TO_A   {012} set A="last value", C=sign of "last value"
$2320.117  CIRCLE           at x="last-2 val", y="last-1 val ", r="last value"
$21ae   E
$2286   S
$2382.119  DRAW       {013} draw a line from (COORDS) to offset "last value"
$21be   E
$2296   S
$2477.123  LINE_DRAW        draw a line from (COORDS) to offset "last value"
$24b7.124  DRAW_LINE        same as LINE_DRAW but doesn't exit via TEMPS
$24fb.127  SCANNING         evaluate the "next expression" at (CH_ADD)
$2535.128  S_SCRN$_S        evaluate SCREEN$ at "last value" row,col
$254f.128  S_SCRN_LP        evaluate SCREEN$ at DE for B chars in set at HL
$2580.129  S_ATTR_S         evaluate ATTR at "last value" row,col
$28b2.141  LOOK_VARS  {014} find the variable addressed by (CH_ADD)
$2ab1.150  STK_ST_0         stack AEDCB as string array/slice (A=0)
$2ab2.150  STK_ST_$         stack AEDCB as any string
$2ab6.150  STK_STORE        stack AEDCB
$2aee.151  DE,(DE+1)        performs the action "LD DE,(DE+1)"
$2aff.151  LET        {015} assign a variable from LET, READ or INPUT
$2b59.153  L_NUMERIC        copy "last value" to HL-5
$2bf1.157  STK_FETCH        fetch "last value" to AEDCB
$2c02.156  DIM              the DIM command routine
$21d5   E
$2c88.159  ALPHANUM         set Carry if A is alphanumeric
$2c8d.159  ALPHA            set Carry if A is alphabetic
$2c9b.160  DEC_TO_FP  {016} stack the decimal number at (CH_ADD)
$2d1b.161  NUMERIC          reset Carry if A is a digit $30-$39, else set Carry
$2d22.162  STK_DIGIT        stack the number in A if it is a digit
$2d28.162  STACK_A          stack the number in A
$2d2b.162  STACK_BC         stack the number in BC
$2d3b.162  INT_TO_FP        stack the decimal integer at (CH_ADD)
$2da2.166  FP_TO_BC         fetch "last value" to BC
$2dd5.167  FP_TO_A          fetch "last value" to A
$2de3.167  PRINT_FP         print "last value" as a number
$30a9.179  HL=HL*DE         set HL=HL*DE
$33b4.194  STACK_NUM        stack the 5-byte FP form number addressed at HL
$35de.207  VAL/VAL$   {017} evaluate VAL/VAL$ "last value", return "last value"
$361f.208  STR$             evaluate STR$ "last value", return "last value"


$028e.  5  KEY_SCAN   {001} the keyboard scanning subroutine
On returning from $028e KEY_SCAN the DE register and the Zero flag indicate
which keys are being pressed.

. The Zero flag is reset if pressing more than two keys, or pressing two
  keys and neither is a shift key; DE identifies two of the keys.
. The Zero flag is set otherwise, and DE identifies the keys.
. If pressing just the two shift keys then DE = $2718.
. If pressing one shift key and one other key, then D identifies the shift
  key and E identifies the other key.
. If pressing any one key, then D=$ff and E identifies the key.
. If pressing no key, then DE=$ffff.

The key codes returned by KEY_SCAN are shown below.

KEY_SCAN key codes: hex, decimal, binary
? hh dd bbbbbbbb   ? hh dd bbbbbbbb   ? hh dd bbbbbbbb   ? hh dd bbbbbbbb
1 24 36 00100011   Q 25 37 00100101   A 26 38 00100110  CS 27 39 00100111
2 1c 28 00011100   W 1d 29 00011101   S 1e 30 00011110   Z 1f 31 00011111
3 14 20 00010100   E 15 21 00010101   D 16 22 00010110   X 17 23 00010111
4 0c 12 00001100   R 0d 13 00001101   F 0e 14 00001110   C 0f 15 00001111
5 04  4 00000100   T 05  5 00000101   G 06  6 00000110   V 07  7 00000111
6 03  3 00000011   Y 02  2 00000010   H 01  1 00000001   B 00  0 00000000
7 0b 11 00001011   U 0a 10 00001010   J 09  9 00001001   N 08  8 00001000
8 13 19 00010011   I 12 18 00010010   K 11 17 00010001   M 10 16 00010000
9 1b 27 00011011   O 1a 26 00011010   L 19 25 00011001  SS 18 24 00011000
0 23 35 00100011   P 22 34 00100010  EN 21 33 00100001  SP 20 32 00100000


$03b5. 11  BEEPER     {002} play note length DE (f*t) with pitch HL (T/4)
This subroutine is entered with the DE register pair holding the value
'f*t', where a note of given frequency 'f' is to have a duration of 't'
seconds, and the HL register pair holding a value equal to the number of T
states in the "timing loop" divided by '4'; eg. for "middle C" to be
produced for one second DE holds $0105 (INT(261.3*1)) and HL holds +066A
(derived from 6689/4-30.125).


$0556. 17  LD_BYTES   {003} load DE header(A=$00)/data(A=$ff) bytes   to IX
Set Carry for LOAD, reset Carry for VERIFY.


$0c41. 40  PO_SEARCH  {004} search for Ath entry in table at DE, returns in DE
Resets Carry if initial character is a letter, sets Carry otherwise.


$19b8. 80  NEXT_ONE   {005} find next line in (PROG) or next variable in (VARS)
Searches from line/variable at HL and returns next address in HL.


$1b17. 86  LINE_SCAN  {006} check syntax of EDIT (E_LINE) line
The parsing routine of the BASIC interpreter is entered at LINE-SCAN when
syntax is being checked, and at LINE-RUN when a BASIC program of one or
more statements is to be executed. Each statement is considered in turn and
the system variable CH-ADD is used to point to each code of the statement
as it occurs in the program area or the editing area.


$1cde. 94  FETCH_NUM  {007} evaluate a numeric "next expression" at (CH_ADD)
Result is stored as "last value"; zero if no following expression.


$1d86. 97  LOOK_PROG  {008} search for token E starting at address HL
Used to search for DATA, DEF FN and NEXT statements.


$1e85.101  TWO_PARAM  {009} set A="last value" and BC="last-1 value"
The topmost parameter on the calculator stack must be compressible into a
single register. It is two's complemented if it is negative. The second
parameter must be compressible into a register pair.


$1f1a.103  FREE_MEM   {010} set BC=amount of memory in use
The expression "65536-USR 7962" (7962=$1f1a) gives the amount of free RAM.


$1f3a.104  PAUSE      {011} pause "last value" 1/50ths seconds (or until key)
$1f3d.104  PAUSE_1    {011} pause BC 1/50ths seconds (or until key)
System variable FLAGS (23611) bit 5 set if a key has been pressed.


$2307.117  STK_TO_BC  {012} set B="last value", C="last-1 value"
$2314.117  STK_TO_A   {012} set A="last value", C=sign of "last value"
Quit with report B if too big.


$2382.119  DRAW       {013} draw a line from (COORDS) to offset "last value"
Gets a third (optional) angle parameter by a call to $1c82 EXPT_1NUM.


$28b2.141  LOOK_VARS  {014} find the variable addressed by (CH_ADD)
Called whenever a search of the variables area or of the arguments of a DEF
FN statement is required. Entered with (CH-ADD) pointing to the first
letter of the name of the variable whose location is being sought.

The exit parameters are:
* (CH-ADD) points to the first location after the name of the variable as it
  occurs in the BASIC line.
* When "variable not found":
  . Carry is set.
  . Zero is set only when the search was for an array variable.
  . HL points to the first letter of the name of the variable as it occurs in
    the BASIC line.
* When "variable found":
  . Carry is reset.
  . Zero is set for both simple string variables and all array variables.
  . HL points to the letter of a short name, or the last character of a long
    name, of the existing entry that was found in the variables area.

In all cases C bits 5 & 6 indicate the type of variable being handled. Bit
7 is the complement of the SYNTAX/RUN flag, but only when the subroutine is
used in runtime will bits 0 to 4 hold the code of the variable's letter. In
syntax time the return is always made with Carry reset. Zero is set for
arrays and reset for all other variables.


$2aff.151  LET        {015} assign a variable from LET, READ or INPUT
When the destination variable is a newly declared variable then DEST will
point to the first letter of the variable's name as it occurs in the BASIC
line. Bit 1 of FLAGX will be set. However if the destination variable
exists already then bit 1 of FLAGX will be reset and DEST will point for a
numeric variable to the location before the five bytes of the old number
and for a string variable to the first location of the old string. Bit 0 of
FLAGX is set if the destination variable is a complete simple string
variable.


$2c9b.160  DEC_TO_FP  {016} stack the decimal number at (CH_ADD)
Also handles BIN numbers.


$35de.207  VAL/VAL$   {017} evaluate VAL/VAL$ "last value", return "last value"
Set B=$1d for VAL, B=$18 for VAL$.


$16d4. 70  REC_EDIT   {018} reclaim E_LINE area
Not used by the 48k ROM; probably left over from the ZX80/81.


48k ROM ERROR REPORTS
=====================
Do a JP to the given address to return to BASIC with the indicated error report.

0 - OK                                 $1bb0
1 - NEXT without FOR                   $1dd8
2 - Variable not found                 $0670, $1c2e
3 - Subscript wrong                    $2a20
4 - Out of memory                      $1f15
5 - Out of screen                      $0c86
6 - Number too big                     $31ad, $3703
7 - RETURN without GOSUB               $1f36
8 - End of file                        $15e4
9 - STOP statement                     $1cee
A - Invalid argument                   $34e7, $371a
B - Integer out of range               $046c, $1e9f, $24f9, $35dc
C - Nonsense in BASIC                  $1c8a, $21ce
D - BREAK - CONT repeats               $0d00
E - Out of DATA                        $1e08
F - Invalid file name                  $0642, $1765
G - No room for line                   $1555
H - STOP in INPUT                      $21d4
I - FOR without NEXT                   $1d84
J - Invalid I/O device                 $15c4
K - Invalid colour                     $2244
L - BREAK into program                 $1b7b
M - RAMTOP no good                     $1eda
N - Statement lost                     $1bec
O - Invalid stream                     $160e, $1725
P - FN without DEF                     $2812
Q - Parameter error                    $288b
R - Tape loading error                 $0806
