EX (SP),HL

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Post Reply
User avatar
Cosmium
Berk
Posts: 28
Joined: Tue Dec 04, 2018 10:20 pm
Location: USA

EX (SP),HL

Post by Cosmium » Mon Aug 12, 2019 1:19 am

Over the past year I've occasionally perused the Z80 opcodes and timings ( :geek: ) to get reacquainted with - and programming inspiration for - little neat features of the Z80 I've forgotten or seldom used.

One such instruction is EX (SP),HL which appears to be quite powerful at 19T states considering it's a 16 bit register swap with what's on the stack.

I've never actually used it and was wondering when would be a good case to. Maybe tight loops when all the registers have already been used? I feel like it holds quite a bit of potential!
0 x

Ralf
Dynamite Dan
Posts: 1223
Joined: Mon Nov 13, 2017 11:59 am
Location: Poland

Re: EX (SP),HL

Post by Ralf » Mon Aug 12, 2019 9:51 am

I believe we had in the past a discussion about this particular instruction. Maybe on WOS yet, not here ;)

I don't remember details but people said it's useful when you write things like Basic interpreter or another high level
language compiler/interpreter. Something with fetching instructions and variables.

Personally I have a different experience. For me it's useless, I've never used it.
I would gladly trade it for EX SP,HL :) Exchanging register values, not register and value in memory,
0 x

Joefish
Manic Miner
Posts: 569
Joined: Tue Nov 14, 2017 10:26 am

Re: EX (SP),HL

Post by Joefish » Mon Aug 12, 2019 11:31 am

When used in the combination POP HL // EX (SP),HL it lets you get the 'top-but-one' value off the stack, and copies the top value of the stack down in its place. You can actually undermine the stack by one slot with these two instructions.

It's for programming C-type function calls, where parameters are pushed onto the stack before calling the subroutine. You don't really want to leave them there, but you've got the problem that (from your subroutine's point of view) the RETurn address is at the top of the stack, not the parameters.

So you first do POP HL, which gets the function return address in HL. Now the stack pointer points to the last parameter PUSHed before the CALL. Then you do EX (SP),HL which fetches that parameter into HL, and puts the return address back in that slot on the stack, so you can still do a RET at the end of the function.

If there's another parameter on the stack, then you copy H and L into other registers for later, and do the same trick again:
POP HL
EX (SP),HL
That gets another parameter off the stack into HL, but puts the return address down in its place ready for a RET.

If that wasn't possible then you'd either (a) waste a register preserving the RETurn address while you tidied up the stack or (b) in your main routine, have to tidy up the stack after every CALL to erase the parameters you put there.
3 x

User avatar
Ast A. Moore
Dynamite Dan
Posts: 1134
Joined: Mon Nov 13, 2017 3:16 pm

Re: EX (SP),HL

Post by Ast A. Moore » Mon Aug 12, 2019 12:49 pm

Yes, it’s not a very useful instruction for game programming. I think I remember Joffa using it in Cobra for some trivial printing routine. While it’s common to use the stack for fetching the address of the beginning of a text string, in many cases you can do it much simpler just using PUSH/POP.

Cf.:

Code: Select all

	ex (sp),hl
	call printer
	ex (sp),hl
	ret


printer	ld a,(hl)	;load char. into A
	inc hl		;next address
	or a
	ret z		;return if 0 (i.e. EOS)
vs.

Code: Select all

	call printer
string	defm "Text string",0
	ret

printer
	pop hl		;grab stack address (after CALL; beginning of string)
	ld a,(hl)	;load char. into A
	inc hl		;next address
	push hl		;back onto the stack
	or a
	ret z		;return to the address right after EOS
0 x
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.

User avatar
Einar Saukas
Manic Miner
Posts: 908
Joined: Wed Nov 15, 2017 2:48 pm

Re: EX (SP),HL

Post by Einar Saukas » Mon Aug 12, 2019 1:11 pm

Joefish wrote:
Mon Aug 12, 2019 11:31 am
When used in the combination POP HL // EX (SP),HL it lets you get the 'top-but-one' value off the stack, and copies the top value of the stack down in its place. You can actually undermine the stack by one slot with these two instructions.

It's for programming C-type function calls, where parameters are pushed onto the stack before calling the subroutine. You don't really want to leave them there, but you've got the problem that (from your subroutine's point of view) the RETurn address is at the top of the stack, not the parameters.

So you first do POP HL, which gets the function return address in HL. Now the stack pointer points to the last parameter PUSHed before the CALL. Then you do EX (SP),HL which fetches that parameter into HL, and puts the return address back in that slot on the stack, so you can still do a RET at the end of the function.

If there's another parameter on the stack, then you copy H and L into other registers for later, and do the same trick again:
POP HL
EX (SP),HL
That gets another parameter off the stack into HL, but puts the return address down in its place ready for a RET.

If that wasn't possible then you'd either (a) waste a register preserving the RETurn address while you tidied up the stack or (b) in your main routine, have to tidy up the stack after every CALL to erase the parameters you put there.
It's used extensively in z88dk exactly this way, for instance:

BIFROST*2
NIRVANA+
ULAplus
ZX7
1 x

User avatar
arkannoyed
Manic Miner
Posts: 363
Joined: Mon Feb 05, 2018 9:56 am

Re: EX (SP),HL

Post by arkannoyed » Mon Aug 12, 2019 5:19 pm

I used it to very good effect in 3D Chess. It’s used in the main routine to swap the screen address in HL with the address in IX that just got PUSHed into the stack.
0 x

Joefish
Manic Miner
Posts: 569
Joined: Tue Nov 14, 2017 10:26 am

Re: EX (SP),HL

Post by Joefish » Mon Aug 12, 2019 5:31 pm

Yes, you could also think of it as a way of swapping between two address values (one on the stack, one in HL), pulling one up from before and saving the current value for later. Much as you might use EX DE,HL or EXX, though obviously it's not as quick. So it's more about code space-efficiency rather than time-efficiency.
1 x

User avatar
Cosmium
Berk
Posts: 28
Joined: Tue Dec 04, 2018 10:20 pm
Location: USA

Re: EX (SP),HL

Post by Cosmium » Mon Aug 12, 2019 6:06 pm

Useful explanations, thanks :)

So if say you've got some time critical loop code. You've have run out of 16 bit registers and have a situation where you'll be swapping between the use of two addresses.

You could PUSH the address, put the other one in HL, then in the main loop use EX (SP),HL to alternate between them. In effect, you're using the stack's contents as a 'second shadow' HL, that just so happens to be held in memory, so naturally it will be slower than EXX and EX DE,HL, but faster than the traditional memory or stack-based alternatives that would normally be used to achieve the same thing?
0 x

Post Reply