this kind of stems of gbz80 - IF statements
I have a code that loops 0x167 times, writing to the screen. What I'd like to happen is for the script to loop three times.
My script:
d322 21A0C3 LD HL,C3A0h
d323 016801 LD BC,0168h
d324 110300 LD DE,0003h
d325 00 NOP
.
.
.
d330 0B DEC BC
d331 75 LD (HL),L
d332 00 NOP
d333 23 INC HL
d334 00 NOP
.
.
.
d33f 78 LD A,B
d340 B1 OR C
d341 C22BD3 JP NZ,D32Bh
d344 7A LD A,D
d345 B3 OR E
d346 1B DEC DE
d347 00 NOP
d348 00 NOP
d349 C22BD3 JP NZ,D32B
d34c C9 RET
Now, instead of stopping where it should, it goes on to corrupt memory further until it reaches d325 and causes the script to crash. As you might be able to tell, I attempted to use DE as the counter for loops.
Please explain your answer, I'm still quite dull towards this.
The problem is that you decrement DE
after setting the flags. The critical bit of code reads:
LD A,D
OR E
DEC DE
JP NZ,D32B
Change that to:
DEC DE
LD A,D
OR E
JP NZ,D32B
And the outer loop will run 3 times instead of 4. Note that the BC
loop is handled correctly and will execute 0x168 times, not 0x167 so you may want to change that.
16 bit counters on the Z-80 are awkward as the 16 bit decrements don't set any flags. That's why you need the code to OR the two registers together as a way to set the Z flag when the 16 bit pair is equal to zero.
Since you only need 3 iterations you can use a single 8 bit register and write:
LD E,3
...
DEC E
JP NZ,D32B
As noted in Tommy's response, you also need to have BC
reloaded in the inner loop say by moving the LD BC,0x168
to D32B.