×   Main Menu ALL The 8BS News Manuals (New menu) Links Worth a Look Tools Disc and Basic Webring Site Map 8BS Guestbook Old Guest Book Me The Barnsley Rovers   
8-Bit Software

The BBC and Master Computer Public Domain Library

B068 Call Subroutine

Submitted by Steve Fewell

Description:

[&B068] Set BASIC Text Pointer A to point to the subroutine DEFinition's start address
Set the BASIC Text pointer A address (&0B-&0C) to the address pointed to by (&2A-&2B) [where &2A-&2B
is the address of the variable paremeter block for the specified subroutine name - this parameter block contains the start
address of the subroutine's DEFinition].

[&B072] Handle any arguments in the subroutine, and call the subroutine

Now, BASIC Text pointer A (&0B-&0C) points to the start of the subroutine's definition (that is the position
immediately following the subroutine name).
Set A to zero and push this value to the 6502 Stack - this value is the current number of Arguments and LOCAL variables.
Zero the BASIC Text pointer A offset (&0A), so that we will start processing the first character pointed to by
&0B-&0C.

Get the first non-space character pointed to by BASIC text pointer A. If it's an Open Bracket '(', then jump to &B0CB
to process the subroutine's arguments (routine described below); otherwise, decrement BASIC text pointer A offset
(&0A), so that BASIC text pointer A points to the first non-space character found.

[&B080] Any arguments have now been processed, so start executing the subroutine
Push the BASIC Text Pointer B address (&19-&1A) and offset (&1B) to the 6502 stack. BASIC text pointer B points
to the program location after the subroutine name in the FN/PROC call-statement (i.e. the calling location)?

[&B089] Call routine &900B to start executing the subroutine starting at the address after the subroutine name
and argument list (if any) in the subroutine DEFinition.
Note: routine &900B is called - not jumped to, so that we can regain control once the subroutine finishes. The 6502
'RTS' command will return us to address &B08C. This RTS-command is executed at the end of the ENDPROC statement
processing, or at the end of the '=' statement (to specify the end of a function) processing.
Therefore, on return from &900B the subroutine will have been executed (i.e. an ENDPROC will have been found (for a
PROCedure) or an '=' equals-statement will have been found (for a FuNction). This enables BASIC to correctly tidy up and
exit from the subroutine after the subroutine call.

When the Subroutine is called (the 'JSR &900B' statement), the following information is on the 6502 stack:
Address &01FF - The Subroutine type - FN/PROC (i.e. either the PROC token or the FN token)
Address &01FE - The address to return to once the subroutine has executed (PTR A) - Offset (&0A)
Address &01FD - The address to return to once the subroutine has executed (PTR A) - LSB (&0B)
Address &01FC - The address to return to once the subroutine has executed (PTR A) - MSB (&0C)
Address &01FB - The number of Arguments or LOCAL variables used by the Subroutine
Address &01FA - BASIC Text Pointer B - LSB (&19)
Address &01F9 - BASIC Text Pointer B - MSB (&1A)
Address &01F8 - BASIC Text Pointer B - Offset (&1B)
Address &01F7 - Return address for the JSR &900B statement - LSB
Address &01F6 - Return address for the JSR &900B statement - MSB
Address &01F5 - <The next free Stack position - pointed to by the 6502 Stack Pointer>

[&B08C] Now the subroutine code has been executed, so tidy up after the execution of the subroutine:
Retrieve the BASIC text pointer B address (&19-&1A) and offset (&1B) from the 6502 stack.
Retrieve the number of subroutine arguments (and LOCAL variables) from the 6502 stack.

If there are subroutine arguments and LOCAL variables (the value returned from the stack is not zero) then:
* 1) [&B098] Store the number of subroutine arguments and LOCAL variables in location &3F
* 2) Call routine &BD06 to retrieve the Integer value from the BASIC stack to locations &37-&3A
    (the integer value returned is the 2-byte variable value address and 1-byte variable type).
* 3) Call routine &BC6A to set the variable (i.e. the value pointed to by &37-&38) to the value
    from the BASIC stack (i.e. this retrieves the variable's previous value, which was pushed to the BASIC stack when the
    argument/local variable was processed - and the variable parameter block (the variable address and type information)
    was pushed directly after the variable value).
* 4) Decrement location &3F to decrease the number of outstanding arguments and/or LOCAL variables
* 5) If there are more variables (arguments and/or LOCAL variables) that need to be set back to the value
    that they held before the subroutine was called (&3F is not zero) then jump back to &B09A (step 2) to process
    the next variable.
[&B0A4] Now the original values of the arguments and LOCAL variables (if any) have been restored.
Retrieve the BASIC Text Pointer A location (which points to the program location immediately after the subroutine call
statement (i.e. the FN/PROC call) from the 6502 stack (3 bytes are retrieved, &0A-&0B is set to the address value
and &0C is set to the address offset value).

[&B0AA] Retrieve the Keyword token (either FN or PROC, indicating the subroutine call type) from the 6502 stack,
and discard its value, as it is no longer needed.

[&B0AB] Reset the 6502 stack to its original state - before the subroutine call:
Load the character at the top of the BASIC Stack (this is the 6502 stack pointer value before the subroutine call was
made). Set the 6502 Stack pointer to this value.
Set Y to zero. Keep incrementing X and Y, and retrieving the next 6502 stack byte from the BASIC Stack (to its correct
&0100 + X location), until X has reached #&FF.
Now, the 6502 stack has been restored to its original state (i.e. if a subroutine is active, then it will contain the
details of the subroutine.
Add Y bytes to the BASIC Stack pointer (&04-&05) to remove the original 6502 stack contents from the
BASIC stack.

Exit with A set to the value of location &27 (the return value type - if a value was returned (FN-call)).


[&B0CB] Process the subroutine's arguments

Store the BASIC Text Pointer B address (&19-&1A) and offset (&1B) to the 6502 stack.
Call routine &98AE to set BASIC Text pointer B to the position after the bracket in the subroutine definition (that
is: the address in BASIC text pointer A), and read the variable name at that location, getting its address and type
information (and creating the variable if it doesn't exist).
If the zero flag is set on return from routine &98AE then no variable name was found (the name was invalid), so jump
to &B12B to set the 6502 stack pointer to #&FB (to point to the stack location after the call statement address,
retrieve the address to return to once the call statement has executed from the 6502 stack (into PTR A - &0B-&0C)
[so that the error occurs at the call statement program line - and not at the subroutine definition position] and issue
Arguments error (as the required formal parameter was not found).

[&B0D9] Now we have sucessfully obtained details of the first (or next) variable in the subroutine definition (the
formal parameter); later, we will map onto this variable the value from the call statement parameters (i.e. the actual
parameter). But first the value and address of the current variable's contents needs to be stored, and any other formal
parameters need to be processed - this is done as described below.

Store the BASIC Text Pointer B offset to the BASIC Text pointer A offset (so that BASIC text pointer A now also points
to the character after the variable name in the subroutine definition (either DEF PROC or DEF FN).
Retrieve the BASIC Text Pointer B 3-byte value (address and offset) from the 6502 stack - this points to the call
statement (the FN/PROC statement) location.

Retrieve the number of arguments value from the 6502 stack (at location &01FB), and store this value in X.
Store the [formal parameter] variable address and type information (&2A-&2C) on the 6502 stack.
Increment X (the number of subroutine arguments) and store this new number of arguments value on the 6502 stack.

Call routine &B181 to load the value of the variable (the value is pointed to by &2A-&2B) and to store the
current value of the variable on the BASIC Stack - this ensures that if a formal parameter variable has the same name as
an already existing variable, then the original value can be restored once the subroutine has finished executing. Routine
&B181 also pushes the variable's address and type information (&2A-&2C) to the BASIC stack.

Call routine &8CE5 to get the next non-space character pointed to by BASIC Text pointer A (the location after the
variable name (just processed) in the subroutine definition, and compare the character with a comma (','). If it was a
comma, then jump back to &B0CB to process the next [formal parameter] variable name.
Otherwise, check whether the character is a closing bracket ')' - if it isn't then jump to &B12B to set the 6502 stack
pointer to #&FB (to point to the stack location after the call statement address, retrieve the address to return to
once the call statement has executed from the 6502 stack (into PTR A - &0B-&0C) [so that the error occurs at the
call statement program line - not at the subroutine definition position] and issue Arguments error (as the formal
parameter definition is invalid).

[&B0FE] Otherwise, the formal parameters have been declared without problem, and they have been processed, now BASIC
needs to assign the actual parameter values to these formal parameters, this is done as described below.
Firstly zero is stored on the 6502 stack (number of actual arguments that have been processed).
If the first non-space character at the BASIC Text Pointer B location (the program location of the call statement) is not
an open bracket '(' character, then no actual parameters were found, so jump to &B12B to set the 6502 stack pointer
to #&FB (to point to the stack location after the call statement address, retrieve the address to return to once
the call statement has executed from the 6502 stack (into PTR A - &0B-&0C) [so that the error occurs at the call
statement program line - not at the subroutine definition position] and issue Arguments error (as the required actual
parameters have not been provided.

[&B108] Evaluate the next actual parameter value and push the value to the BASIC stack
Call routine &9D3B to evaluate the expression after the open bracket character and to store the expression result in
either the SWA (if the result is a String value), the FWA (if the result is a Floating-Point value) or the IWA (if the
result is an Integer. This result value should be the value of the first actual parameter.

Call routine &BC22 to push the result value to the BASIC Stack.
Store the value in location &27 (the result type) to location &2D and push the IWA value (bytes &2A-&2D) to
the BASIC Stack. Note: This is wasteful - as we only need to store 1-byte to the BASIC stack (not 4). This method is
probably used due to the lack of a routine to push a 1-byte value to the BASIC stack.

Retrieve the number of actual arguments from the 6502 stack (in to register X), increment this counter and push the new
value back to the 6502 stack.
If the next character at the BASIC Text pointer B location (after the actual parameter value we just evaluated) is a
comma ',', then jump back to &B108 to evaluate the next actual parameter and push its value to the BASIC stack.
As the next non-space character is not a comma, it must be a closing bracket - which denotes the finish of the actual
parameter list - if it isn't then jump to &B12B to tidy up, set the BASIC Text pointer A location to the call
statement location and issue Arguments error.

Retrieve the number of actual parameters (in the subroutine call statement) from the 6502 stack (& discard this value - as
we already have it in the X register).
Retrieve the number of formal parameters (in the subroutine definition) from the 6502 stack and store this value in both
location &4C and location &4D.

Compare X (number of actual parameters) with the value in location &4C (number of formal parameters) if they do not
match, then continue to &B12B to tidy up, set the BASIC Text pointer A location to the call statement location and
issue Arguments error.

[&B140] Call routine &BCE6 to retrieve the IWA value from the BASIC stack (this sets location &2D to the
type of the last actual parameter).

Retrieve the last Formal parameter variable's address (2 bytes) & type details from the 6502 stack to locations
&2A-&2C.

If the formal parameter variable is a String (location &2C is negative (#&80 ?)), then:
* [&B16D] Check the actual parameter's type (location &2D) - if it is not zero (i.e. not a String
    value) then jump to &B12B to Set BASIC text pointer A to the call statement
    location (so Error line number is correct) and issue Arguments error.
* Call routine &BCD2 to retrieve the String value from the BASIC Stack (to the SWA).
* Call routine &90AE to set the String variable's value (pointed to by &37-&38) to the SWA
    value
* [&B177] Now the formal parameter variable has been set to the value of the actual parameter.
* Decrement location &4C (the number of arguments to process)
* If there are further arguments to process then jump back to &B140 to set the next Formal parameter
    to its corresponding Actual parameter value.
* Otherwise, all arguments have been processed, so push the value at location &4D (the number of arguments
    in the subroutine call) to the 6502 stack and jump to &B080 to continue with the Subroutine call.
If the formal parameter variable is numeric (location &2C is positive (#&04 or #&05 ?)), then:
* [&B14D] Check the actual parameter's type (location &2D) - if it is zero (String value) then
    jump to &B12B to Set BASIC text pointer A to the call statement location (so that the
    Error Line Number (ERL) is correct) and issue Arguments error.
* Store the Actual parameter's type value (&2D) in location &27
* Call routine &BDC6 to copy the IWA (&2A-&2D) to locations &37-&3A
* If the Actual parameter type (location &27) is an Integer then [&B165] Retrieve the IWA value
    from the BASIC stack
* If the Actual parameter type (location &27) is a Floating-Point value then [&B15D] Retrieve the
    FWA value from the BASIC stack (first call &BBE8 to pop the value and set &4A-&4B to point to the value,
    then call &A541 to load the value pointed to by argp (&4A-&4B) in the FWA).
* [&B168] Call routine &B338 to set the numeric variable's value (at the address pointed to by
    &37-&38) to the current result value (in either the IWA or FWA, depending on the value at location &27)
* [&B177] Now the formal parameter variable has been set to the value of the actual parameter.
* Decrement location &4C (the number of arguments to process)
* If there are further arguments to process then jump back to &B140 to set the next Formal parameter
    to its corresponding Actual parameter value.
* Otherwise, all arguments have been processed, so push the value at location &4D (the number of arguments
    in the subroutine call) to the 6502 stack and jump to &B080 to continue with the Subroutine call.


Disassembly for the Call Subroutine routine

B068 * 178 042 B2 2A LDA (&2A)
B06A   133 011 85 0B STA &0B
B06C   160 001 A0 01 LDY#&01
B06E * 177 042 B1 2A LDA (&2A),Y
B070   133 012 85 0C STA &0C
B072   169 000 A9 00 LDA#&00
B074 H 072 48 PHA
B075 d 100 010 64 0A STZ &0A
B077   032 224 142 20 E0 8E JSR &8EE0 Get next non-space character pointed to by Ptr A
B07A ( 201 040 C9 28 CMP#&28
B07C M 240 077 F0 4D BEQ 77 --> &B0CB Process Subroutine Arguments
B07E   198 010 C6 0A DEC &0A
B080   165 027 A5 1B LDA &1B
B082 H 072 48 PHA
B083   165 025 A5 19 LDA &19
B085 H 072 48 PHA
B086   165 026 A5 1A LDA &1A
B088 H 072 48 PHA
B089   032 011 144 20 0B 90 JSR &900B Execute subroutine (starting at the BASIC program statement at PTR A)
B08C h 104 68 PLA
B08D   133 026 85 1A STA &1A
B08F h 104 68 PLA
B090   133 025 85 19 STA &19
B092 h 104 68 PLA
B093   133 027 85 1B STA &1B
B095 h 104 68 PLA
B096   240 012 F0 0C BEQ 12 --> &B0A4
B098 ? 133 063 85 3F STA &3F
B09A   032 006 189 20 06 BD JSR &BD06 Retrieve Integer from stack to locations &37-&3A
B09D j 032 106 188 20 6A BC JSR &BC6A Set Variable to value from the BASIC Stack
B0A0 ? 198 063 C6 3F DEC &3F
B0A2   208 246 D0 F6 BNE -10 --> &B09A
B0A4 h 104 68 PLA
B0A5   133 012 85 0C STA &0C
B0A7 h 104 68 PLA
B0A8   133 011 85 0B STA &0B
B0AA h 104 68 PLA
B0AB   133 010 85 0A STA &0A
B0AD h 104 68 PLA
B0AE   178 004 B2 04 LDA (&04)
B0B0   170 AA TAX
B0B1   154 9A TXS
B0B2   160 000 A0 00 LDY#&00
B0B4   200 C8 INY
B0B5   232 E8 INX
B0B6   177 004 B1 04 LDA (&04),Y
B0B8   157 000 001 9D 00 01 STA &0100,X
B0BB   224 255 E0 FF CPX#&FF
B0BD   208 245 D0 F5 BNE -11 --> &B0B4
B0BF   152 98 TYA
B0C0 e 101 004 65 04 ADC &04
B0C2   133 004 85 04 STA &04
B0C4   144 002 90 02 BCC 2 --> &B0C8
B0C6   230 005 E6 05 INC &05
B0C8 ' 165 039 A5 27 LDA &27
B0CA ` 096 60 RTS

[&B0CB] "Process the subroutine's arguments" disassembly

B0CB   165 027 A5 1B LDA &1B
B0CD H 072 48 PHA
B0CE   165 025 A5 19 LDA &19
B0D0 H 072 48 PHA
B0D1   165 026 A5 1A LDA &1A
B0D3 H 072 48 PHA
B0D4   032 174 152 20 AE 98 JSR &98AE Evaluate variable name & create it if it's a new variable
B0D7 R 240 082 F0 52 BEQ 82 --> &B12B Tidy up and issue 'Arguments' error
B0D9   165 027 A5 1B LDA &1B
B0DB   133 010 85 0A STA &0A
B0DD h 104 68 PLA
B0DE   133 026 85 1A STA &1A
B0E0 h 104 68 PLA
B0E1   133 025 85 19 STA &19
B0E3 h 104 68 PLA
B0E4   133 027 85 1B STA &1B
B0E6   250 FA PLX
B0E7 , 165 044 A5 2C LDA &2C
B0E9 H 072 48 PHA
B0EA + 165 043 A5 2B LDA &2B
B0EC H 072 48 PHA
B0ED * 165 042 A5 2A LDA &2A
B0EF H 072 48 PHA
B0F0   232 E8 INX
B0F1   218 DA PHX
B0F2   032 129 177 20 81 B1 JSR &B181 Load Variable & Push its value, address and type to the BASIC Stack
B0F5   032 229 140 20 E5 8C JSR &8CE5 Compare next non-space [PTR A] character with ','
B0F8   240 209 F0 D1 BEQ -47 --> &B0CB Process Subroutine Arguments
B0FA ) 201 041 C9 29 CMP#&29
B0FC - 208 045 D0 2D BNE 45 --> &B12B Tidy up and issue 'Arguments' error
B0FE   169 000 A9 00 LDA#&00
B100 H 072 48 PHA
B101   032 213 142 20 D5 8E JSR &8ED5 Get next non-space character (PTR B)
B104 ( 201 040 C9 28 CMP#&28
B106 # 208 035 D0 23 BNE 35 --> &B12B Tidy up and issue 'Arguments' error
B108 ; 032 059 157 20 3B 9D JSR &9D3B Evaluate expression at BASIC Text pointer B
B10B " 032 034 188 20 22 BC JSR &BC22 Push Variable to BASIC Stack (calls correct routine depending on flags)
B10E ' 165 039 A5 27 LDA &27
B110 - 133 045 85 2D STA &2D
B112 & 032 038 188 20 26 BC JSR &BC26 Push IWA value to the BASIC Stack [pushi]
B115   250 FA PLX
B116   232 E8 INX
B117   218 DA PHX
B118   032 235 142 20 EB 8E JSR &8EEB Get next non-space char (PTR B) & compare with ','
B11B   240 235 F0 EB BEQ -21 --> &B108 Process next actual parameter (call statement location)
B11D ) 201 041 C9 29 CMP#&29
B11F   208 010 D0 0A BNE 10 --> &B12B Tidy up and issue 'Arguments' error
B121 h 104 68 PLA
B122 h 104 68 PLA
B123 L 133 076 85 4C STA &4C
B125 M 133 077 85 4D STA &4D
B127 L 228 076 E4 4C CPX &4C
B129   240 021 F0 15 BEQ 21 --> &B140
B12B   162 251 A2 FB LDX#&FB
B12D   154 9A TXS
B12E h 104 68 PLA
B12F   133 012 85 0C STA &0C
B131 h 104 68 PLA
B132   133 011 85 0B STA &0B
B134   ...'Arguments' error...
B140   032 230 188 20 E6 BC JSR &BCE6 Retrieve IWA value from the BASIC Stack [popi]
B143 h 104 68 PLA
B144 * 133 042 85 2A STA &2A
B146 h 104 68 PLA
B147 + 133 043 85 2B STA &2B
B149 h 104 68 PLA
B14A , 133 044 85 2C STA &2C
B14C 0 048 031 30 1F BMI 31 --> &B16D
B14E - 165 045 A5 2D LDA &2D
B150   240 217 F0 D9 BEQ -39 --> &B12B Tidy up and issue 'Arguments' error
B152 ' 133 039 85 27 STA &27
B154 7 162 055 A2 37 LDX#&37
B156   032 198 189 20 C6 BD JSR &BDC6 Store Integer (IWA) to zero page location (specified by X)
B159 ' 165 039 A5 27 LDA &27
B15B   016 008 10 08 BPL 8 --> &B165
B15D   032 232 187 20 E8 BB JSR &BBE8 Pop Float from Stack and set argp (&4A-&4B) to point to the value
B160 A 032 065 165 20 41 A5 JSR &A541 Load FWA with Floating-Point variable (pointed to by argp)
B163   128 003 80 03 BRA 3 --> &B168
B165   032 230 188 20 E6 BC JSR &BCE6 Retrieve IWA value from the BASIC Stack [popi]
B168 8 032 056 179 20 38 B3 JSR &B338 Set numeric variable
B16B   128 010 80 0A BRA 10 --> &B177
B16D - 165 045 A5 2D LDA &2D
B16F   208 186 D0 BA BNE -70 --> &B12B Tidy up and issue 'Arguments' error
B171   032 210 188 20 D2 BC JSR &BCD2 Pop String (SWA) from the stack
B174   032 174 144 20 AE 90 JSR &90AE Set String variable
B177 L 198 076 C6 4C DEC &4C
B179   208 197 D0 C5 BNE -59 --> &B140
B17B M 165 077 A5 4D LDA &4D
B17D H 072 48 PHA
B17E L 076 128 176 4C 80 B0 JMP &B080 Start executing the subroutine

 


 Back to 8BS
Or