Search code examples
machine-codez80gameboy

GBZ80 - Code shortcomings


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.


Solution

  • 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.