SPLatco Knowledge Base

Subroutines: Passing arguments and results

Some subroutines, I dare say most subroutines in SPLat applications, will simply perform some fixed operation without any information passing between the subroutine and the calling program. In some cases, though, you may need some data to pass one way or the other. You may for example have a subroutine that reads a temperature, performing the analog reading and all the necessary calculations as a service to the “caller”.

There several ways of passing information back and forth:

  • As data held on the register stack (X, Y, Z and/or T)
  • As data held in the floating point registers W and/or Q
  • As data held in RAM

The information passed may be into the subroutine as arguments, or out of the subroutine as results.

The most common method will be in one of the registers, i.e. X, Y etc or W/Q. Avoid using RAM unless you need to pass more data than will fit in the registers. It is good programming practice to let a given RAM location “belong” only to one subroutine or another (or the top level “main” program), and not be accessible to others. This is an aspect of what is known as data hiding.

One interesting and useful technique is to use X to return an error signal from a subroutine that performs an operation that might go wrong. For example, an industrial cleaning machine may have a detergent pump driven by a subroutine called Squirt. Squirt attempts to dispense one dose of detergent. It returns a logical True value if the operation succeeds and False if it fails (say due to the detergent reservoir being empty). The calling program can the simply call Squirt and test the outcome, rather than having to first test the reservoir level:

      GoSub    Squirt      ;Squirt in a dose of soap
GoIfF Failed ;G/ something went wrong

This might in turn be part of a larger subroutine that carries out a complete sequence. In that case we might make it so it so the larger subroutine returns a zero in X if everything went OK, and a non-zero error number if something went wrong:

Cycle:
GoSub Step1 ;Returns False if it fails
LoadX Step1FailCode ;In case Step1 failed
Swap ;Get the Step1 result back to X
RetIfF

GoSub Step2 ;Returns False if it fails
LoadX Step2FailCode ;In case Step1 failed
Swap ;Get the Step2 result back to X
RetIfF
... etc ...
LoadX 0 ;Signal success
Return

The above subroutine can be called to perform the whole cycle, and when it is done the outcome is in X for evaluation. This may for example be to display a message on the LCD:

      GoSub    Cycle         ;Run a cycle, result code returned in X
      Branch                 ;Test the outcome
      Target   ItWorked      ;Return code = 0
      Target   NoSoap        ;Return code = 1
      Target   OverLoad      ;Return code = 2
      Target   NoFill        ;Return code = 3

ItWorked:
      OBLCD_Cls
      OBLCD_Text  "Cycle complete"
      GoTo     DoTheNextThing

NoSoap:
      OBLCD_Cls
      OBLCD_Text  "No detergent"
      GoTo     DoTheNextThing
.... etc ....