The RCA 1802 processor was used in a number of systems such as the ELF and COMX-35, and also apparently in the US space program (with its hardened variant).

From memory, it had a rather unusual set of instructions for doing function calls and returns. Can anyone detail how this actually worked in practice?

up vote 14 down vote accepted

The 1802 used a method known as SCRT, the standard call and return technique. The chip was actually endowed with a full complement of sixteen 16-bit general-purpose registers(a), but no dedicated stack pointer or program counter. The SCRT was one method for doing calls using this limitation.

You could actually use any register as the program counter with the SEP Rn instruction (where n was a value 0..F indicating which of the registers was to be used). This basically said to start using that register for the program counter, leaving whatever register was previously being used with its last contents (one byte beyond the SEP instruction that switched the program counter over).

So, by using some of those sixteen registers in a dedicated manner, you could easily "emulate" the more conventional instructions found on other processors.

Note that the details below are from rather distant memories, they may not be exact (in terms of what registers were used for what, for example), but they should give you the basic idea.


There was a "usual" program counter (R3), and the R4 and R5 registers were set respectively to the addresses of the SCRT call and return functions. R2 was used as a stack pointer.

In order to call another function, you therefore encoded a SEP R4 followed by the address that you wanted to call. This immediately started using R4 as the program counter, leaving R3 pointing at the memory containing the address that you were calling.

The SCRT call code running at R4 would:

  • store the return address (R3, to be adjusted on return to skip over the address) onto the stack (controlled by R2);
  • load the address you wanted to call (pointed at by R3) into R3; then finally
  • execute SEP R3 to continue execution at that new address.

It would, of course, have to ensure R4 was set back to the start of the SCRT call function and, from memory, this was done by placing the SEP R3 instruction immediately before that function and then jumping to that as the final step. This would auto-magically leave R4 set to the correct value for next time.


Similarly, a SEP R5 (return) in your code would start running the return function which would:

  • pull the return address off the stack at R2, into R3, and adjust it to skip over the address.
  • do SEP R3 (using the same jump trickery mentioned above to ensure R5 once again pointed to the return function) to return to the original code.

So, in terms of implementation, the set-up was something like:

ScrtCallDone:
    sep r3
ScrtCall:
    ; code for doing reg/mem manipulations for call
    br ScrtCallDone

ScrtRetDone:
    sep r3
ScrtRet:
    ; code for doing reg/mem manipulations for ret
    br ScrtRetDone

macro fcall %address:
    sep    r4
    dw     address
endmacro

macro fret:
    sep    r5
endmacro

Then, in terms of what you would see in your code, it would be as simple as:

    fcall subfunc
    ; do other stuff then return

subfunc:
    ; do sub-function stuff
    fret

(a) This rather massive (at the time) register bank was actually one of the big selling features of the chip, despite the fact you immediately lost a large chunk of them (SCRT, DMA and interrupts, from memory). Truly the triumph of marketing over reality :-)

  • 1
    Ha! That's a beautiful hack. I designed a processor earlier this year that has its PC in a general purpose register and copied the last PC into another register whenever that register is modified, but if I'd thought of doing it this way it would have saved the need to update the register file twice in a single cycle! Although a call+return on my system is two instructions shorter... – Jules Oct 15 at 6:31
  • 2
    This description seems pretty similar to the IBM S/360 "Branch and link" and "Branch and link register" instructions, which used the same basic idea for subroutine calls. S/360 did have a program counter, but it didn't have a stack pointer, so the BAL or BALR instructions had to save the program counter in a user-defined location - either in another register, or in memory. – alephzero Oct 15 at 9:36
  • 1
    @alephzero, it is very similar. The admittedly minor stuff I did on the System z at IBM SW Labs actually reminded me of the 1802. See stackoverflow.com/questions/664744/… (the answer of mine that I sourced for this) for detail. – paxdiablo Oct 15 at 9:54
  • Would you really define a macro and then name it ret? ret is also a mnemonic for instruction 0x70 which is "return" and seems to do some kind of pop. ittybittycomputers.com/IttyBitty/ShortCor.htm – Wilson Oct 18 at 14:25
  • @Wilson, probably not, I haven't actually used my old COMX-35 for about 30 years so my memory won't be perfect :-) Adjusted to use different macro name. – paxdiablo Oct 19 at 0:23

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.