Equivalents to Z80 DJNZ instruction on other architectures?
-
22-09-2019 - |
문제
First a little background. The z80 CPU has an instruction called DJNZ which can be used in a similar manner as a for
loop. Basically DJNZ decrements the B register and jumps to a label if not zero. For example:
ld b,96 ; erase all of the line
disp_version_erase_loop:
call _vputblank ; erase pixels at cursor (uses b reg)
djnz disp_version_erase_loop ; loop
Of course you can do the same thing using regular comparison and jump instructions, but often it is handy to use the single instruction.
With that out of the way, my question is, do other CPU architectures include a similar control instruction?
해결책
That was a fairly common instruction on machines of that era, and occurs in many other places as well.
- Corewar supports it using the DJN instruction with the pre-decrement addressing mode.
- Likewise the m68k supports BNE with a pre-decrement addressing mode.
- The minimalist PDP-8 has a similar instruction
ISZ - increment operand and skip if result is zero.
And so on
다른 팁
Actualy in IA-32 direct equivalent for DJNZ is LOOPcc (LOOPZ). Remember the Z80 and 8086 have the same predecessor Intel 8080. So all x86 CPUs directly inherit DJNZ instruction!
IA-32 has various REP*
instructions which use CX as their counter
PowerPC has bdnz
and a special count-down register ctr
. Decrementing ctr
and conditionally branching is independent of the actual condition test, so you can add a condition on top of bdnz
, eg bdnzlt cr5, label
(if memory serves) will check if the less-than bit stored in cr5 and either AND or OR that with the condition of ctr
becoming 0.
Ironically, ctr
is also used to store any indirect function call destination. So it's possible to code the instruction "decrement ctr
and branch to its new value if not zero", but this is specifically forbidden. (It wouldn't check for a NULL pointer anyway.) Somewhat significantly, bdnz
becomes rather useless in a loop with an indirect call.
Some PIC microcontrollers like the PIC18 have a DECFSZ (Decrement File and Skip if Zero) instruction. I have often put a DECFSZ followed by branch.
There exist single instruction set computers, which aren't actually used. But one of the single instruction set machines is the "subtract and branch if less than or equal to zero" (subleq
) machine. Wikipedia has more on this
I'm not aware of any other real machines that have an instruction exactly like this though. I like RISC machines, and really don't see a need for it either.
The PDP-11 (circa 1970) predated the Z-80 by about 5 years, and at least some models (though probably not the early ones) had a subtract-one-and-branch instruction:
sob R, offset
On x86 there is the LOOP instruction that does exactly the same thing (with counter in ECX). There is also the JECXZ instruction (Jump if ECX is Zero) which is meant to be used together with LOOP - you place it BEFORE the loop so that you can skip the entire loop if the count was zero in the beginning.
Like this:
;number of iterations in ECX
JECXZ end
start:
;loop body
LOOP start
end:
But note that those instructions are horribly inefficient on contemporary CPUs. It's much better to use regular CMP/SUB and Jcc instructions. On a side note - the Intel Core2 CPUs are actually able to treat a compare+jump instruction pair as if it were a single instruction - they call it "macro-op fusion".
The Z80 was a CISC processor. DJNZ is a classic example of a complex instruction. The modern fashion is towards RISC instruction sets which prefer smaller, simpler, faster instructions but can process them more quickly - especially with advanced pipelining features. I don't think you get anything like this on the ARM family, for example.