,ll 6.6
,cs 10
,pl 66
,lm 0.2,0.5
,pn 1
,ju
,hd
,ce
OmegaSoft 6809 Cross Pascal Language Handbook (V1.0)
,,
,ft

,ce 1
6-##
,,
,ce
OmegaSoft 6809 Cross Pascal Language Handbook (V1.0)

,ce
PROCEDURES AND FUNCTIONS

Procedures and functions are program units that a similar to the main program block. They may have parameters that are passed on the stack, they may have all of the declaration sections that a program can have, and they have an execution section.

Procedures and functions are used for two reasons. They allow you to build a routine that can be called many different places and thus reduce redundant code. They also allow you to isolate related code and variables into a separate section, reducing the probability of undesired side-effects and allowing re-usability of code.

Procedures and functions are similar in nature and the term "procedure" in this chapter is meant to refer to either a procedure or function. Where there is a difference between the two, it will be pointed out.

,ce
FORMAT OF A PROCEDURE OR FUNCTION

procedure-declaration = procedure identifier parameter-list ;
       (block | entry ; block | interrupt ; block | firq ; block |
        task ; block | external | forward | at address) ;
parameter-list = ( | (parameter-element {; parameter-element}) )
parameter-element = [var] identifier {, identifier} : type
address = integer-constant-expression | hex-constant-expression |
          longinteger-constant-expr. | longhex-constant-expr.
procedure-call = procedure-identifier [( (expression | variable)
                 {,(expression | variable)} )]

 
  procedure       identifier       parameter list       


 
              ;          entry          ;       Block       ;

                         task

                         firq

                       interrupt

                       external

                       forward
 
                       at        address

 
  Parameter list:

 
      (       var       identifier       :       type       )
       
                             ,
          
                             ;

,pg
,ce
FORMAT OF A PROCEDURE OR FUNCTION


function-declaration = function identifier parameter-list : type
                    ; (block | entry ; block | 
                    external | forward | at address) 


  function    identifier    parameter list    :    type

 
              ;         entry         ;       Block          ;

                      external

                      forward

                      at        address


,ce
PARAMETERS
 
FORMAL PARAMETER LIST

The formal parameter list specifies what parameters are to be passed to the procedure from the caller and how they are to be passed : by value or by address (variable). The identifiers in the parameter list and local variables in the procedure are allocated at the time of the procedure call.  At the end of the procedure execution they disappear (de-allocated). Variables defined global to a procedure may also be used by the procedure. An exception to this is local variables defined in data or varib sections.

The total size of the parameter list and function return value cannot exceed 32K bytes.

VALUE PARAMETERS

A value parameter has its value copied to a local variable created by the procedure at the time of the procedure call.  Any changes made to this parameter within the procedure does not affect the original variable passed. This is evident by the fact that an expression may be passed as a value parameter. Devices may not be passed by value. 

VARIABLE PARAMETERS
 
A variable parameter (definition in parameter list prefixed by a "var") actually has its address passed to the procedure at the time of the procedure call.  Therefore, any changes made to the parameter within the procedure does change the original variable passed. Only a variable (not an expression) may be passed as a variable parameter.

Variable parameters are essentially pointers to values and therefore can also be expressed as passing pointers by value. The two sections of code that follow are similar in operation :
,pg
,ce
PARAMETERS

program variable_parameter ;
  var
    x : integer ;
  procedure a (var y : integer) ;
    begin
      write (y)
    end ;
  begin
    a (x)
  end.

program pointer_parameter ;
  var
    x : ^integer ;
  procedure a (y : ^integer) ;
    begin
      write (y^)
    end ;
  begin
    a (x)
  end.

There is one important difference between the above two sections of code, type checking. Using variable parameters allows the compiler to check the type of the actual parameter against the parameter declaration. Since any pointer is compatible with any other pointer, there is no type checking and a real could have been passed just as easy as an integer. This can be used where such tricks are desired - such as processing a record as an array but it also can get you into big trouble if you are not careful.

FUNCTION RETURN TYPE

The function return type may be any type other than device. The function name must be assigned to from within the function, this sets the function return value. The function return type may not exceed 126 bytes in length.

TYPE COMPATIBILITY

When a procedure call is compiled the actual parameters used are compared against the procedure declaration to verify that the types are correct.

declaration type      acceptable parameter                       

boolean               boolean
character             character
enumerated            enumerated (any)
integer               integer
hex                   hex
subrange              subrange (same base type)
longinteger           longinteger or integer*
longhex               longhex or hex*
real                  real, longinteger*, or integer*
string                string or character*
array                 array (same size - see dynamic arrays)
record                record (same size)
set                   set (any)
devices and files     devices and files (variable only)
pointer               pointer, longhex, and hex*
,ce
PARAMETERS

NOTE : The acceptable parameters marked with an asterisk "*" may only be used if they are to be passed by value, not by variable.

DYNAMIC ARRAY PARAMETERS

When arrays or records are passed as parameters to a procedure or function only the size of the array or record is checked, not it's element types. If the array or record is being passed by value then the size of the actual parameter must match that of the parameter declaration. If the array or record is being passed by address (declared as VAR) then the size of the actual parameter may be equal to or smaller than that of the parameter declaration. This is possible because only the address of the array or record is pushed on the stack, which is 2 bytes regardless of what it is pointing to.

Using this feature it is possible to write general purpose procedures and functions that operate on array parameters of various sizes. In the following example the procedure is provided to add a vector array that may contain up to 10 elements. The integer parameter specifies to the procedure the size of the actual parameter.

Note that this feature must be used with caution, and only elements of the arrays should be accessed, never an entire array.

program dynamic_demo ;
  var
  va, vb, vc : array [1..4] of real ;
  ya, yb, yc : array [1..2] of real ;

  procedure vadd (var a,b,c : array[1..10] of real; x : integer);
    var
      count : integer 
    begin
      for count := 1 to x do
        c[count] := a[count] + b[count]
    end ;

  begin
    .
    .
    vadd (va, vb, vc, 4) ;
    vadd (ya, yb, yc, 2) ;
    .
  end.

,ce
SIDE EFFECTS

A side effect is the modification of a non-local variable in a procedure. This may take the form of an assignment to a non-local variable or as an assignment to a parameter that is declared as a variable parameter. Side effects should be avoided since their use will cause a procedure to modify its environment in ways that are difficult to document. Some side effects may cause non-portable code to be produced, as in :
,pg
,ce
SIDE EFFECTS

program test (input,output) ;
  var
    x : integer ;

  function b (y, z : integer) ;
    begin
      b := z + x * y ;
      x := y    
    end ;

  begin
    read (x) ;
    a := b (b(3,5),b(2,7)) ;
    writeln (a)
  end.

In the OmegaSoft compiler procedure parameters are evaluated left to right but this is left to the implementor in the ISO standard. If you were to transport this code to a compiler that evaluates right to left then the result would be different.

,ce
DECLARATION OPTIONS

If none of the declaration options are used then the procedure block must immediately follow the declaration part and the procedure name will not be known outside of this compilation. The Declaration options provide for mutually recursive routines, assembly language procedures, interrupt handling, and modular compilation.

FORWARD

Since every procedure must be declared before it is referenced a problem is created when two or more procedures call each other recursively. The forward declaration is included in the language to get around this problem :

procedure a (j : integer) ; forward ;

procedure b (k : integer) ;
  begin
    a (k)
  end ;

procedure a ;
  begin
    b (j)
  end ;

Note that in the forward declaration the full parameter list is used but that when the procedure block is going to be presented that only the procedure name is used.
,pg
,ce
DECLARATION OPTIONS

EXTERNAL

If a procedure is declared as external then its name is used to access the corresponding procedure declared as "entry" in another module and there is no block. The external option can only be used for lexical level two procedures (non-nested). Only the first 8 characters of the procedure name are used, so entry/external procedure names must be unique within the first 8 characters. Example :

  function minimum (x, y : integer) : integer ; external ;

ENTRY

If a procedure has the word "entry" placed between the declaration and its block then the procedure name will be made available as an entry point. The entry option can only be used on lexical level 2 procedures (non-nested). Only the first 8 characters of the procedure name are used, so entry/external procedure names must be unique within the first 8 characters. Example :

  function minimum (x, y : integer) : integer ; entry ;
    begin
      if x < y
        then
          minimum := x
        else
          minimum := y
    end ;
,pg
,ce
DECLARATION OPTIONS

ABSOLUTE

This option is similar in use to the external option but instead of using the name of the procedure, an absolute address is provided. For the procedure :

  function minimum (x, y : integer) : integer ; at $F004 ;

This is useful for placing commonly used Pascal or assembly language routines at fixed addresses, such as in an EPROM, and calling them from Pascal programs. There is no block that follows, and this option does not place a procedure at the specified address.

TASK

This is designed for multi-tasking applications and is very dependent on the actual multi-tasking used. The compiler does no parameter checking! When compiling a task the compiler modifies which routines it calls for various functions :

Function                Normal Task  Parameters                  
Procedure setup         INT50  INT52 D = param size X = local size
Procedure end           INT22  INT53 none                   
Nested procedure start  INT21  INT54 same
Memavail function       FNC13  FNC06 same
New procedure           PRC36  PRC70 same
Dispose procedure       PRC39  PRC71 same
Mark procedure          PRC37  PRC72 same
Release procedure       PRC38  PRC73 same

INTERRUPT

This option allows a procedure to handle 6809 interrupts directly without having to use any assembly language interface. Note this is only usable when you have access to the vector directly, not when processed by an operating system.

The following procedure declaration :

procedure timer ; interrupt ;
  begin
    .
  end ;

Will generate the following code :

timer equ *       {is an entry pointer, similar to entry}
 xref global
 ldy global
 pshu s,y
 ldx -8,y
 pshu y,x,d
 leay 10,u
   .
   .
 rti
,pg
,ce
EXCEPTION PROCEDURES

This results in the following stack frame for the procedure :

+-------------------+ +10 <- Y
|    GARBAGE        |                {stack link}
+-------------------+ +8
|   GLOBAL BASE     |                {dynamic link}
+-------------------+ +6
|   GLOBAL BASE     |
+-------------------+ +4
|   ERROR MASK      |
+-------------------+ +2
|    GARBAGE        |
+-------------------+ <- U

Local variables are then allocated on the stack if needed, just as in a regular procedure. What has been created on the stack is a valid local stack frame, with access to global variables in addition to local variables.

As an example, suppose we have a 6821 PIA that has a 10ms square wave going into one of the interrupt input lines, to be used as a delay counter.

  var
    delay1, delay2 : integer ;
    irqvect : hex at <$40 ; {alternate vector location}

  procedure timer ; interrupt ;
    var
      piaa : byte at $f004 ; {byte to read to clear interrupt}
      dummy : byte ;
    begin
      dummy := piaa ; {clear interrupt}
      if delay1 <> 0
        then
          delay1 := delay1 - 1 ;
      if delay2 <> 0
        then
          delay2 := delay2 - 1
    end ;

 begin
   irqvect := addr(timer) ;
   .
   .

This will provide two delay counters. The variable "global" referenced in the code is defined in the stack setup file (.ps file) and is setup to contain the address of the global stack mark.

FIRQ

This is identical to INTERRUPT except it is designed to be used for the fast interrupt handler of the 6809. It saves the U,Y,X, and D registers before modifying any registers, and then restores them before doing the RTI.

