CALL

Instruction: Jump to address with intention to return to next instruction.

CALL #Symbol


Result: PC + 1 is written to the s-field of the register indicated by the d-field.

  • Symbol (s-field) is a 9-bit literal whose value is the address to jump to. This field must contain a DAT symbol specified as a literal (#symbol) and the corresponding code should eventually execute a RET instruction labeled with the same symbol plus a suffix of "_ret" (Symbol_ret RET).

Opcode Table:

–INSTR–  ZCRI  –CON–     –DEST–        –SRC–

Z Result

C Result

Result

Clocks

 010111    0011    1111     ?????????    sssssssss

Result = 0

unsigned carry

Written

4

Concise Truth Table:

In

Out

Destination

Source

Z

C

Effects

Destination1

Z2

C3

$----_----; -

$----_----; -

-

-

wz wc

31:9 unchanged, 8:0 = PC+1

0

0

1 The Destination register's s-field (lowest 9 bits) are overwritten with the return address (PC+1) at run-time.
2 The Z flag is effectively always cleared. Having it set would require PC+1 to be 0. This is only the case for code execution from $1FF which is always aborted.
3 The C flag follows unsigned carry which means that for a CALL it is cleared given that a 9bit literal (source) is compared against a jump instruction (destination).

Explanation

CALL records the address of the next instruction (PC + 1) then jumps to Symbol. The routine at Symbol should eventually execute a RET instruction to return to the recorded address (PC+1; the instruction following the CALL). For the CALL to compile and run properly, the Symbol routine's RET instruction must be labeled in the form Symbol with "_ret" appended to it. The reason for this is explained below.

Propeller Assembly does not use a call stack, so the return address must be stored in a different manner. At compile time the assembler locates the destination routine as well as its RET instruction (labeled Symbol and Symbol_ret, respectively) and encodes those addresses into the CALL instruction's s-field and d-field. This provides the CALL instruction with the knowledge of both where it's going to jump to and exactly where it will return from.

At run time the first thing the CALL instruction does is store the return address (PC+1) into the location where it will return from; the "Symbol_ret RET" instruction location. The RET instruction is really just a JMP instruction without a hard-coded destination address, and this run-time action provides it with the "return" address to jump back to. After storing the return address, CALL jumps to the destination address; Symbol.

The diagram below uses a short program example to demonstrate the CALL instruction's run-time behavior; the store operation (left) and the jump-execute-return operation (right).

Run-Time Call Procedure

Store operation

Jump, execute and return operation

In this example, the following occurs when the CALL instruction is reached at run time:

  1. The cog stores the return address (PC+1; that of <next instruction>) into the source (sfield) of the register at Routine_ret (see left image).
  2. The cog jumps to Routine (see right image).
  3. Routine's instructions are executed, eventually leading to the Routine_ret line. 
  4. Since the Routine_ret location contains a RET instruction with an updated source (sfield), which is the return address written by step 1, it returns, or jumps, back to the <next instruction> line.

This nature of the CALL instruction dictates the following:

  • The referenced routine must have only one RET instruction associated with it. If a routine needs more than one exit point, make one of those exit points the RET instruction and make all other exit points branch (i.e., JMP) to that RET instruction (an indirect jump works as well and is faster, e.g. jmp Routine_ret vs jmp #Routine_ret).
  • The referenced routine can not be recursive. Making a nested call to the routine will overwrite the return address of the previous call.The return address (PC + 1) is written to the source (s-field) of the Symbol_ret register unless the NR effect is specified. Of course, specifying NR is not recommended for the CALL instruction since that turns it into a JMP, or RET, instruction. 

CALL is really a subset of the JMPRET instruction; in fact, it is the same opcode as JMPRET but with the i-field set (since CALL uses an immediate value only) and the d-field set by the assembler to the address of the label named Symbol_ret.

Unless otherwise noted, content on this site is licensed under the
Creative Commons Attribution-ShareAlike 4.0 International License.