How did the 1802 call and return instructions work?
Clash Royale CLAN TAG#URR8PPP
up vote
3
down vote
favorite
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?
rca-1802
add a comment |Â
up vote
3
down vote
favorite
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?
rca-1802
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
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?
rca-1802
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?
rca-1802
rca-1802
asked 3 hours ago
paxdiablo
286213
286213
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
2
down vote
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 byR2
); - load the address (pointed at by
R3
) intoR3
; 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 the call or return function and then jumping to that as the final step of that function. This would auto-magically leave R4
(or R5
) set to the correct value for next time.
Similarly, a SEP R5
in your code (the SCRT return) would start running the return function which would:
- pull the return address off the stack at
R2
, intoR3
, and adjust it to skip over the address. - do
SEP R3
(using the same trickery mentioned above) 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 call %address:
sep r4
dw address
endmacro
macro ret:
sep r5
endmacro
Then, in terms of what you would see in your code, it would be as simple as:
call subfunc
; do other stuff then return
subfunc:
; do sub-function stuff
ret
(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 :-)
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
13 mins ago
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
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 byR2
); - load the address (pointed at by
R3
) intoR3
; 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 the call or return function and then jumping to that as the final step of that function. This would auto-magically leave R4
(or R5
) set to the correct value for next time.
Similarly, a SEP R5
in your code (the SCRT return) would start running the return function which would:
- pull the return address off the stack at
R2
, intoR3
, and adjust it to skip over the address. - do
SEP R3
(using the same trickery mentioned above) 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 call %address:
sep r4
dw address
endmacro
macro ret:
sep r5
endmacro
Then, in terms of what you would see in your code, it would be as simple as:
call subfunc
; do other stuff then return
subfunc:
; do sub-function stuff
ret
(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 :-)
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
13 mins ago
add a comment |Â
up vote
2
down vote
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 byR2
); - load the address (pointed at by
R3
) intoR3
; 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 the call or return function and then jumping to that as the final step of that function. This would auto-magically leave R4
(or R5
) set to the correct value for next time.
Similarly, a SEP R5
in your code (the SCRT return) would start running the return function which would:
- pull the return address off the stack at
R2
, intoR3
, and adjust it to skip over the address. - do
SEP R3
(using the same trickery mentioned above) 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 call %address:
sep r4
dw address
endmacro
macro ret:
sep r5
endmacro
Then, in terms of what you would see in your code, it would be as simple as:
call subfunc
; do other stuff then return
subfunc:
; do sub-function stuff
ret
(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 :-)
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
13 mins ago
add a comment |Â
up vote
2
down vote
up vote
2
down vote
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 byR2
); - load the address (pointed at by
R3
) intoR3
; 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 the call or return function and then jumping to that as the final step of that function. This would auto-magically leave R4
(or R5
) set to the correct value for next time.
Similarly, a SEP R5
in your code (the SCRT return) would start running the return function which would:
- pull the return address off the stack at
R2
, intoR3
, and adjust it to skip over the address. - do
SEP R3
(using the same trickery mentioned above) 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 call %address:
sep r4
dw address
endmacro
macro ret:
sep r5
endmacro
Then, in terms of what you would see in your code, it would be as simple as:
call subfunc
; do other stuff then return
subfunc:
; do sub-function stuff
ret
(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 :-)
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 byR2
); - load the address (pointed at by
R3
) intoR3
; 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 the call or return function and then jumping to that as the final step of that function. This would auto-magically leave R4
(or R5
) set to the correct value for next time.
Similarly, a SEP R5
in your code (the SCRT return) would start running the return function which would:
- pull the return address off the stack at
R2
, intoR3
, and adjust it to skip over the address. - do
SEP R3
(using the same trickery mentioned above) 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 call %address:
sep r4
dw address
endmacro
macro ret:
sep r5
endmacro
Then, in terms of what you would see in your code, it would be as simple as:
call subfunc
; do other stuff then return
subfunc:
; do sub-function stuff
ret
(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 :-)
edited 2 hours ago
answered 2 hours ago
paxdiablo
286213
286213
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
13 mins ago
add a comment |Â
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
13 mins ago
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
13 mins ago
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
13 mins ago
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fretrocomputing.stackexchange.com%2fquestions%2f7968%2fhow-did-the-1802-call-and-return-instructions-work%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password