CALLD PA/PB/PTRA/PTRB,#\A syntax question
CALLD PA/PB/PTRA/PTRB,#\A Call to A by writing {C, Z, 10'b0, PC[19:0]} to
PA/PB/PTRA/PTRB (per W). If R = 1 then PC += A, else PC = A. "\" forces R = 0. (406)
Looked through documentation couldn't really find anything discussing CALLD trired using RET with
CALLD (Nope) found following:
$1F6 RAM / PA CALLD-imm return, CALLPA parameter, or LOC address
$1F7 RAM / PB CALLD-imm return, CALLPB parameter, or LOC address
RESI3 = CALLD $1F0,$1F1 WCZ
RESI2 = CALLD $1F2,$1F3 WCZ
RESI1 = CALLD $1F4,$1F5 WCZ
RESI0 = CALLD INA,INB WCZ
RETI3 = CALLD INB,$1F1 WCZ
RETI2 = CALLD INB,$1F3 WCZ
RETI1 = CALLD INB,$1F5 WCZ
RETI0 = CALLD INB,INB WCZ
Can someone point me in the right direction no idea what this is.
Regards and Thanks
Bob (WRD)
Comments
As CALLD PA/PB/PTRA/PTRB doesn't write the return address to the stack, a RET won't work.
As odd as it may seem, the way to return from this is a CALLD D with D set to either a scratch register, or a read only register like INB, and S set to the relevant register (PA/PB/PTRA/PTRB) for the CALLD you are returning from.
This will fetch the return address from that register, restore the C & Z flags that were stored before the call, and discard the 'return address' from this CALLD.
This might help to explain the difference between the RESIx and RETIx: In RESIx the address of the next instruction in the ISR is stored in the relevant register ($1F0, $1F2, $1F4, or the shadow register behind INA), while in RETIx that address is thrown away by 'writing' it to the read-only INB register.
Yeah, it's a not a regular "call" because it doesn't use any stack. It is an odd-ball - the naming of the instruction changed a couple of times before CALLD was settled on. It was named JMPRET in the Prop1. LINK, JMPL and BL (branch and link) are some other names used in other CPUs. Others have a specific Link Register but Propellers just use any general register to store the link address.
The list you've posted is some special uses of CALLD. In the case of interrupts, entering and exiting the Interrupt Service Routines are entirely dealt with through some crafted cases of CALLD.
Btw, there is two versions of that instruction. The one in the topic title contains an immediate 20-bit branch address. As such it doesn't have S or D fields, so only has four link registers to choose from. The other version has both S and D fields and so can use any general register to place the link address in.
evanh
Do you have any simple examples of both versions. I checked again the documentation can't seem to find anything .
Never would have guessed to use CALLD D as a return. I would assume since there is no info the use of this call must be lower in priority. Just trying to have some sort
of complete notes on code instructions. Details of RESx RETx can be left for another day.
Regards and Thanks
Bob (WRD)
Technically, it doesn't ever "return". The CALLD doesn't perform any stacking itself. It's really a jump, that copies the address of where it branched from - the link. It's up to the software as to how that might be used further along.
Compilers will use it when optimising for what's known as leaf routines. Such routines don't call further compiled routines. As such these routines often don't need certain "stack frame" baggage that is normally provided by the compiler. Once the stack use drops down to zero, the last thing left is the caller return address. Well, that too can be eliminated from the stack with the use of a couple of link instructions replacing the usual call and return.
The Prop1 will have many examples. It didn't have a stack, nor a CALL instruction.
Here's a Prop1 example where two routines, Receive and Transmit, are cooperatively time slicing by using JMPRET. The RESIx aliases of CALLD serve a similar job, albeit interrupt based, in the Prop2.
Yes, evanh responded initially with a description of the other CALLD type (with D & S fields) that behaves much like the JMPRET of the original Propeller (P1).
D is the RetInstAddr and S is the DestAddr
The version you first asked about uses a 20-bit immediate allowing branching to anywhere, while storing the return address in one of those four registers. To return from the 20-bit immediate version requires use of the the D/S version.
Just looking at the Prop1 datasheet and note it does list both a CALL and RET. But they are the same opcode as JMPRET. And so is the JMP instruction. So JMP, RET and CALL are all aliases of JMPRET. But there is still no stack. So the CALL and RET are using what would be equivalent to a 1-level deep stack. EDIT: Oh, now I remember, CALL relied on self-modification to run-time insert the return address into the RET instruction. It had its caveats.
A simple example:
You just get the return address in a register instead of pushed onto the stack. So you can handle the return address by yourself. This subroutine would also work:
Andy
Thanks . In the first form of CALLD CALLD PA/PB/PTRA/PTRB,#\A the key to this is to remember that PA/PB/PTRA/PTRB contains the Instruction address of CaLLD +1. The (per W) term means : PA/PB/PTRA/PTRB = CALLD instruction address + 1 for the address following CALLD Instruction address. Is there some background to where (per W) comes from? What does that mean? I realize
what it is doing but why would I Know (per W) means this? Is there some sort of legend of terms? Or is this a common term I am just not aware of?
Regards
Bob (WRD)
Dunno why W as a name. I'd say it'll mainly to be unique naming so as not to be confused with any other lettering in the instruction sheet. That group of instructions with 20bit immediate addresses are distinct from most because their encodings don't fit the regular OPCODE+D+S encoding. And the two AUGx's are different again.
EDIT: The letterings used in the instruction sheet evolved as Chip added more and people made susgestions. If you look at the EEEE conditional execution field, the letter used for the Prop1 was CCCC instead.
I don't know where you have found this description, but I think there must be an instruction bit encoding with W bits beside it.
From the instructions.txt:
The two w bits define to which register the return address gets written.
Andy
Andy,
Where did you find that? It must be very old, it has the CCCC I was just referring to.
Is it right that the JMPRET way doesn't restore the CZ flags, but that way @AJL described in post #2 does?
When you say JMPRET way, do you mean on the Prop1 itself? Looking at the Prop1 datasheet ... sounds right, looks like C is untouched and Z normally always reset.
Whereas the Prop2 CALLD options are just like RET. Flags are restored from the link register according to WC/WZ/WCZ options.
I found it on my harddisk ;-)
I see in the newer versions it changed a bit:
I kind of wish CALLD were CALLS... Wouldn't that make more sense as you are calling the subroutine at address S?
But that's what all the CALL*s do. Only CALLD and CALLPA/CALLPB even have a D register
BL is too terse for my liking. JMPL looks fine although could be mistaken for meaning some kind of long jump. LINK is certainly distinctive but also not obvious what a link might be. But that isn't hard to get over so I guess I favour LINK.
EDIT: JMPRET wasn't so bad I didn't think. JMPLK wouldn't be bad either.
Ok, so this really is the equivalent of the P1 JMPRET, except that it now has the option to restore CZ flags, right?
Not quite P1 JMPRET, because that is able to patch a JMP in place, whereas CALLD overwrites the entire long with return address + CZ
It could do that because the code address range was only 9 bits on the Prop1.
You could totally patch a 20 bit address into a JMP
Good point, but it would be rough in comparison ... with relative encodings ... and loss of flags ... and hubexec ...