Flow-control structures: Difference between revisions
→{{header|Z80 Assembly}}
Puppydrum64 (talk | contribs) |
Puppydrum64 (talk | contribs) |
||
Line 3,021:
=={{header|Z80 Assembly}}==
===JP and JR===
This is the equivalent of <code>GOTO</code> in BASIC, in that after the jump takes place, the CPU has no way of knowing where it came from.
* <code>JP</code> takes three bytes, one for the jump itself, and two for the address. This instruction can jump conditionally based on the status of the zero, carry, sign, and overflow/parity flags. (On Game Boy, there are no sign or overflow/parity flags so those jumps won't work even for <code>JP</code>)
; next instruction.▼
* <code>JR</code> is a "short jump" that is program-counter relative. This instruction takes two bytes - one for the jump, and the second is an 8-bit signed offset. The offset represents how many bytes forward or backward to jump - <code>JR</code> can only travel forward 127 bytes and backward 128 bytes, and cannot branch based on the sign or overflow/parity flags - only zero and carry.
===Breaking out of a loop===
A subroutine that loops is often escaped with a conditional return, or, if it needs to unwind the stack frame, a conditional jump to an unconditional return.
</lang z80>PrintString:
ld a,(hl) ;HL is our pointer to the string we want to print
cp 0 ;it's better to use OR A to compare A to zero, but for demonstration purposes this is easier to read.
ret z ;return if accumulator = zero
call PrintChar ;prints accumulator's ascii code to screen - on Amstrad CPC for example this label points to memory address &BB5A
jr PrintString ;jump back to the start of the loop. RET Z is our only exit.</lang>
In the above example, the stack was never modified (besides the CALL pushing the return address) so <code>RET Z</code> was safe to use. Conditional returns are not safe to use if the stack needs to be unwound prior to exiting, since there's no way to conditionally unwind the stack without conditionally jumping to a section of code that does just that. In which case you don't need the return to be conditional anyway. This contrived example shows this in action.
<lang z80>foo:
push af
bar:
ld a,(hl)
cp 255
jr z,exit
inc hl
jr bar
exit:
pop af
ret</lang>
===DJNZ===
<code>DJNZ</code> stands for "decrement, jump if nonzero." This is the equivalent of x86's <code>LOOP</code> command - as it subtracts 1 from the B register (just B, not BC) and if it's nonzero, jumps to a specified signed 8-bit offset. (It's better to use a label and let the assembler compute the offset for you.) Although this is usually used for looping, it can also jump forward. The same distance limits of <code>JR</code> apply to <code>DJNZ</code> as well. <code>DJNZ</code> cannot be made conditional based on flags, and it doesn't actually change the flags the same way <code>DEC B</code> would.
(Game Boy doesn't have this instruction - you'll have to use a combination of <code>DEC B</code> and <code>JR NZ</code>)
<lang z80>loop:
;your code goes here
DJNZ loop</lang>
===Block Instructions===
These instructions repeat until <code>BC</code> equals zero. They're useful for doing the same thing in a row, but have one-off equivalents that are faster. However, you can often save space by using these, especially if you can't hardcode a fixed repetition count before using one.
<code>LDIR</code> is the equivalent of <code>memcpy()</code> in C and <code>rep movsb</code> in x86. It loads from the address stored in HL and stores in the address pointed to by DE, increments both HL and DE, decrements BC, and repeats if BC doesn't equal zero.
Essentially it's equivalent to the code below, except in the real <code>LDIR</code> the accumulator isn't actually altered in any way.
<lang z80>_LDIR:
ld a,(hl)
ld (de),a
inc hl
inc de
dec bc
ld a,b
or c ;compare BC to zero
jr nz,_LDIR ;Game Boy doesn't have LDIR so you'll have to use this code instead.</lang>
There are several others that work in a similar fashion, such as:
* <code>LDDR</code> - equivalent of x86's <code>REP MOVSB</code> with direction flag set
* <code>CPIR</code> - equivalent of x86's <code>REPNZ SCASB</code> with direction flag clear
* <code>CPDR</code> - equivalent of x86's <code>REPNZ SCASB</code> with direction flag set
* <code>OTIR</code> - equivalent of x86's <code>REP OUTSB</code> with direction flag clear
* <code>OTDR</code> - equivalent of x86's <code>REP OUTSB</code> with direction flag set
* <code>INIR</code> - equivalent of x86's <code>REP INSB</code> with direction flag clear
* <code>INDR</code> - equivalent of x86's <code>REP INSB</code> with direction flag set
=={{header|zkl}}==
|