CPCWiki forum

General Category => Programming => Topic started by: IndyUK on 21:58, 09 May 25

Title: Pushing/Popping to the Stack
Post by: IndyUK on 21:58, 09 May 25
Hi Folks,

I've been experimenting with the technique of using the SP as a source of writing bytes and have come across something which is baffling me. I'm using the following test code but, cannot figure out why this causes the screen to get corrupted.

org &1000


ld (spbakog),sp
di

ld sp,&4000
pop bc : pop de : pop hl
exx
pop bc : pop de : pop hl
exx

ei
ld sp,(spbakog)

ret

spbakog dw 0

It seems to happen when I use the shadow registers, the text on the screen gets corrupted. I haven't included the second part of the code, which is basically the opposite i.e. push the data somewhere.

Can someone please offer some advice as to what I'm doing wrong?

Thanks,
Title: Re: Pushing/Popping to the Stack
Post by: Jean-Marie on 22:39, 09 May 25
Shadow registers should not be overwritten when the Firmware is active.
Unless you turn off the interrupts and push/pop them to their initial state.
Title: Re: Pushing/Popping to the Stack
Post by: lightforce6128 on 04:38, 10 May 25

exx
pop bc : pop de : pop hl
exx

If you want to use the second register set, then you need to backup them like the stack pointer and restore them before reenabling interrupts. E.g. register bc' is used to page rom in and out of memory and to remember what the last state was. If this is altered, bad things will happen.

ei
ld sp,(spbakog)

This (maybe) has strange side effects. This reenables interrupts before the stack address is restored. There can be pending (waiting) interrupts that will occur immediately after the 'ei' command. On the other hand I remember that 'ei' extends to one more command to enable 'ei : ret' in interrupt handling routines without unwanted recursion. But I'm not sure if this only applies to a subsequent 'ret' command or also to multi-byte commands like 'ld sp,(nnnn)'.
Title: Re: Pushing/Popping to the Stack
Post by: andycadley on 07:59, 10 May 25
EI doesn't enable interrupts until one command later, it doesn't matter that it is multi byte because the Z80 will never process an interrupt mid way through decoding or executing an instruction.

So that is technically safe.
Title: Re: Pushing/Popping to the Stack
Post by: IndyUK on 12:06, 10 May 25
Quote from: andycadley on 07:59, 10 May 25EI doesn't enable interrupts until one command later, it doesn't matter that it is multi byte because the Z80 will never process an interrupt mid way through decoding or executing an instruction.

So that is technically safe.
Thanks for confirming this. I did read somewhere (maybe on this forum) that upon issuing an EI, the next command will actually fire that, not the EI command. I did have a HALT immediately after but removed it as I didn't know if that was causing my issue so, luckily got away with what I've done.

Quote from: lightforce6128 on 04:38, 10 May 25If you want to use the second register set, then you need to backup them like the stack pointer and restore them before reenabling interrupts. E.g. register bc' is used to page rom in and out of memory and to remember what the last state was. If this is altered, bad things will happen.
What would you suggest is the best approach for backing up the shadow registers? To memory or to SP (before I repoint it)?

Thanks
Title: Re: Pushing/Popping to the Stack
Post by: McArti0 on 16:57, 10 May 25
org &1000

di
exx
push bc
push de
push hl
push AF
exx

ld (spbakog),sp

ld sp,&4000
pop bc : pop de : pop hl
exx
pop bc : pop de : pop hl
exx

ei
ld sp,(spbakog)

exx
push AF
push hl
push de
push bc
exx

ret

spbakog dw 0
Title: Re: Pushing/Popping to the Stack
Post by: Longshot on 18:09, 10 May 25
I'm not a firmware expert but I think you only need to backup BC'.
Title: Re: Pushing/Popping to the Stack
Post by: Urusergi on 18:29, 10 May 25
Quote from: Longshot on 18:09, 10 May 25I'm not a firmware expert but I think you only need to backup BC'.

Exactly, and also alternative flags (af')

https://cpctech.cpcwiki.de/docs/manual/s968ap11.pdf
Title: Re: Pushing/Popping to the Stack
Post by: lightforce6128 on 23:32, 10 May 25
Quote from: McArti0 on 16:57, 10 May 25ei
ld sp,(spbakog)

exx
push AF
push hl
push de
push bc
exx


Something got mixed here at the end of the block. Because we have multiple commands here, 'ei' should be clearly the last one, not the first one. Also we want to restore the registers ('pop' instead of 'push'). Should be:

ld sp,(spbakog)
exx
pop af
pop hl
pop de
pop bc
exx
ei
Title: Re: Pushing/Popping to the Stack
Post by: McArti0 on 00:51, 11 May 25
Yes good point! But POP order must be exactly opposite to PUSH.
Title: Re: Pushing/Popping to the Stack
Post by: IndyUK on 08:58, 11 May 25
Quote from: Urusergi on 18:29, 10 May 25
Quote from: Longshot on 18:09, 10 May 25I'm not a firmware expert but I think you only need to backup BC'.

Exactly, and also alternative flags (af')

That's really useful to know. Saved a few bytes. 
Title: Re: Pushing/Popping to the Stack
Post by: BSC on 19:42, 11 May 25
Quote from: lightforce6128 on 23:32, 10 May 25exx

push AF
AF is not affected when using EXX. It has it's own instruction. EX AF,AF'

So if you want to fully save the 2nd register set you'd have to:

EXX
PUSH BC: PUSH DE: PUSH HL
EXX
EX AF, AF'
PUSH AF
EX AF,AF'

to have all 2nd register values on the stack. Before returning from your
code, POP them back in reverse order.
Title: Re: Pushing/Popping to the Stack
Post by: GUNHED on 22:17, 11 May 25
My two Pfennige (Pennies) about all that...  :) :) :)

Sadly most OS for the CPC use the 2nd register set for interrupts - or lets say they waste them.
So basically the CPC works in 8080 mode and can't use the power of the enhanced 2nd registers. This slows the computer down my approx. 30%

The origin of this evil is that the coders of the firmware came from the 8080 (that's what they told by themselves actually). There is some article somewhere (google it).

The CPC has 300 interrupts per second. This means roughly, between two interrupts there are 3300 us or NOPs. Wasting the 2nd register set for interrupts only gains one of two dozens of NOPs. Not even 1%!!!

Of course some users will (like usually) completely disagree, but just calculate for yourself and think about it for yourself  ;) :)
Title: Re: Pushing/Popping to the Stack
Post by: Bread80 on 18:28, 13 May 25
Quote from: GUNHED on 22:17, 11 May 25The origin of this evil is that the coders of the firmware came from the 8080 (that's what they told by themselves actually). There is some article somewhere (google it).

The CPC has 300 interrupts per second. This means roughly, between two interrupts there are 3300 us or NOPs. Wasting the 2nd register set for interrupts only gains one of two dozens of NOPs. Not even 1%!!!
1. There's plenty of Z80 code in both the firmware and BASIC. And it's very skillfully done.

2. The alt registers cache video mode and ROM enable states (plus the I/O port). ROM enable states get changed every time you call into the firmware. That could be happening thousands of times per second. They've actually made very clever use of niche features of the Z80 (which *aren't* in the 8080) to make the machine faster.

PS. Happy to have a polite discussion. If this starts an argument I'll avoid the thread.
Title: Re: Pushing/Popping to the Stack
Post by: andycadley on 18:57, 13 May 25
These things are always a trade off. Zilog intended the alt registers to be a kind of early version of "supervisor" mode, so an OS could be more isolated. It's not surprising people used it like that.
Powered by SMFPacks Menu Editor Mod