yes, you are right about the NMI. looks like looping is the only option.
Here is the ___sdcc_critical_enter by Sergey Belyashov. It is working correctly and there is no loop. But call/ret is slow, we need the same but inline, because on the SMS/MSX-like systems you are typically protecting only the couple of port writes. So we need to make it position-independent (that #>(l1+256) trick above). ___sdcc_critical_enter:: xor a push af pop af ld a, i di ret pe ;enabled interrupts dec sp dec sp pop af or a ;A = 0 if interrupts disabled jr NZ, 00100$ ;inetrrupts disabled sub...
well, is not user already pass his intention for z180 code with the -mz180 and there is no need for the additional flag --nmos-z80 neither its inverted version if you add one. so, my suggestion is that --nmos-z80(not the exact current call, but some optimized approach we discuss above!) should be the default behavior for the z80 systems, and the opposite behavior flag is needed instead, if the user is sure that his exact Z80 is 100% safe.
well, is not user already pass his intention for z180 code with the -mz180 and there is no need for the additional flag --nmos-z80 neither its inverted version if you add one. so, my suggestion is that --nmos-z80(not the exact current call, but some optimized approach we discuss above!) should be the default behavior for the z80 systems, and the opposite behavior flag is needed instead, if the user is sure that his exact Z80 is 100% safe.
Here is the ___sdcc_critical_enter by Sergey Belyashov. It is working correctly and there is no loop. But call/ret is slow, we need the same but inline, because on the SMS/MSX-like systems you are typically protecting only the couple of port writes. So we need to make it position-independent (that #>(l1+256) trick above). ___sdcc_critical_enter:: xor a push af pop af ld a, i di ret pe ;enabled interrupts dec sp dec sp pop af or a ;A = 0 if interrupts disabled jr NZ, 00100$ ;inetrrupts disabled sub...
Here is the ___sdcc_critical_enter by Sergey Belyashov. It is working correctly and there is no loop. But call/ret is slow, we need the same but inline, because on the SMS/MSX-like systems you are typically protecting only the couple of port writes. So we need to make it position-independent (that #>(l1+256) trick above). ___sdcc_critical_enter:: xor a push af pop af ld a, i di ret pe ;enabled interrupts dec sp dec sp pop af or a ;A = 0 if interrupts disabled jr NZ, 00100$ ;inetrrupts disabled sub...
actually, there is no much sense in knowing which z80 variants are affected from the point of writing the user code. because if you build for some target device, like ZX Spectrum, you never know which type of the CPU your code actually will run on, not even know if it is genuine Zilog or whatever obscure clones including something like the soviet Т34ВМ1. So more "strict" checking should probably be default.
As i get the problem, when doing ld a, i, PE condition, if met, is always correct, but PO condition may not reflect the real situation. By checking the byte below the SP, you are checking if PO condition above was wrong or not. So, you don't have to loop, you need to set PE condition in flags, if bytes not match, and set PO condition in flags, when they match. after that at the point of l2: PE flag indicate "interrupts enabled", PO indicate "interrupts disabled". You always DI just after l2:.