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,
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.
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)'.
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.
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
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
I'm not a firmware expert but I think you only need to backup BC'.
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
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
Yes good point! But POP order must be exactly opposite to PUSH.
Quote from: Urusergi on 18:29, 10 May 25Quote 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.
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.
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 ;) :)
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.
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.