Examples

  GOSUB Label ... RETURN { Value }

Function
Store the address of the next instruction after GOSUB, then go to the point in the program specified by Label; with the intention of returning to the stored address.

Quick Facts
  SX18, SX20, SX28, SX48, SX52
 Maximum Nested GOSUBs 8

Explanation
GOSUB is a close relative of GOTO, in fact, its name means, "GO to a SUBroutine". When a program reaches a GOSUB, the program executes the code beginning at the specified Label. Unlike GOTO, GOSUB also stores the address of the instruction immediately following itself. When the program encounters the RETURN instruction, it interprets it to mean, "go to the instruction that follows the most recent GOSUB." In other words, a GOSUB makes the program do a similar operation as you do when you see a table or figure reference in this manual; 1) you remember where you are, 2) you go to the table or figure and read the information there, and 3) when you've reached the end of it, you "return" to the place you were reading originally.

GOSUB is mainly used to execute the same piece of code from multiple locations. If you have, for example, a block of three lines of code that need to be run from 10 different locations in your entire program you could simple copy and paste those three lines to each of those 10 locations. This would amount to a total of 30 lines of repetitive code (and extra space wasted in the program memory). A better solution is to place those three lines in a separate routine, complete with it's own label and followed by a RETURN instruction, then just use a GOSUB instruction at each of the 10 locations to access it. Since SX/B compiles instructions inline (no optimization) this technique can save a lot of program space.

SX/B simplifies subroutine use and error trapping with the declararing of subroutines (SUB directive) and required/possible parameters. When a subroutine is declared, the GOSUB keyword is no longer required and any parameters passed with be checked against the user declaration. The following examples demonstrate the differences in code style.

Version 1.1 (This style is still valid but not recommended)

Get_Char:
  SERIN Sio, Baud, char                         ' wait for character
  RETURN

' ------------------------------

Start:
  TRIS_B = %00000000                            ' make RB pins outputs

Main:
  GOSUB Get_Char
  IF char <> "!" THEN Main                      ' wait for "!"

Version 1.2+ (applies to SUB and FUNC)

GET_CHAR         SUB                            ' subroutine (no parameters)

' ------------------------------

Start:
  TRIS_B = %00000000                            ' make RB pins outputs

Main:
  char = GET_CHAR                               ' no "GOSUB" required
  IF char <> "!" THEN Main                      ' wait for "!"

  END

' ------------------------------

GET_CHAR:
  SERIN Sio, Baud, temp1                        ' wait for character
  RETURN temp1                                  ' return character to caller

Declared subroutines simplify SX/B programming by removing the necessity of the GOSUB keyword (which, in effect, allows the programmer to extend the language by creating new commands), it allows the compiler to validate the number of parameters being passed, and -- most valuable to the programmer -- it allows subroutine code to be placed anywhere in memory without concern of code page boundaries (now handled automatically).


Passing Parameters To/From a Subroutine
SX/B allows the programmer to pass up to four parameters to subroutines. The parameter may hold a value (bit or byte) or the address of a byte-variable (when prefaced with '@'). When used in subroutines, passed parameters must be saved before any SX/B instructions are called.

For example:

TX_BYTE         SUB                             ' subroutine with no parameters
SEND_CHAR       SUB     2                       ' subroutine with 2 parameters

' ------------------------------

Main:
  ' less convenient
  theChar = "*"                                 ' byte to send
  idx = 10                                      ' times to send
  TXBYTE
  theChar = 13
  idx = 1
  TXBYTE

  ' much more convenient
  SENDCHAR "*", 10                              ' **********
  SENDCHAR 13, 1                                ' <CR>
  PAUSE 1000
  GOTO Main

' ------------------------------

SEND_CHAR:
  theChar = __PARAM1                            ' save character to send
  idx = __PARAM2                                ' times to send character

TX_BYTE:
  DO WHILE idx > 0
    SEROUT Sio, Baud, theChar                   ' send the character
    DEC idx                                     ' update count, exit if 0
  LOOP
  RETURN

This subroutine (SEND_CHAR) expects two parameters: the character to transmit (using SEROUT), and the number of times to send the character.

A subroutine can be constructed to modify any variable that is passed to it (by address using '@'). For example:

INVERT_BITS     SUB     1                       ' subroutine with 1 parameter

' ------------------------------

Start:
  TRIS_B = %00000000                            ' make RB pins outputs

Main:
  myBits = $A5                                  ' myBits = %10100101
  INVERT_BITS @myBits                           ' pass address of variable
  RB = myBits                                   ' RB = %01011010 ($5A)
  END

' ------------------------------

INVERT_BITS:
  regAddr = __PARAM1                            ' save address
  GET rtnAddr, regVal                           ' get value from address
  regVal = ~regVal                              ' invert bits
  PUT rtnAddr, regVal                           ' update passed variable
  RETURN

An easier method, however, is to allow the subroutine to pass a value directly back to the caller. This update to the program above performs the same function, yet is easier to understand and prevents possible errors resulting is missing '@' headers.

INVERT_BITS     SUB     1                       ' subroutine with 1 parameter

' ------------------------------

Start:
  TRIS_B = %00000000                            ' make RB pins outputs

Main:
  myBits = $A5                                  ' myBits = %10100101
  myBits = INVERT_BITS myBits                   ' pass value, get one back
  RB = myBits                                   ' RB = %01011010 ($5A)
  END

' ------------------------------

INVERT_BITS:
  regVal = __PARAM1                             ' get value from caller
  regVal = ~regVal                              ' invert bits
  RETURN regVal                                 ' return value to caller

Notice that this style eliminates the need for a variable that holds the address of the target variable and simplifies the subroutine code. By using a defined function (with FUNC) the subroutine can return a word value.


Passing Strings
SX/B allows the programmer to pass a literal or stored (with DATA) string to a subroutine. String passing requires at least two parameters to handle the base and offset address bytes to the string (these values are used by READ). See READ for an example of string use in SX/B.


related instruction: GOTO