From
Ivan Roshin
→
To
All
17 October 2000
Hello, All!
═══════════════════ z80_ln_1.W ══════════════════
(c) Ivan Roshchin, Moscow
Fido: 2:5020/689.53
ZXNet: 500:95/462.53
E-mail: asder_ffc@softhome.net
WWW: http://www.zx.ru/echo/roschin
Z80: optimization of loading constants into registers
────────────────────── ───────────────────────
(Radio amateur. Your computer 9/2000)
(under the pseudonym BV_Creator)
Expanded version.
The Z80 processor, manufactured by ZiLOG since 1976,
used, in addition to personal computers, and in many
other microprocessor devices. So this article will
useful not only for Spectrum owners. It is addressed
firstly, for those who are planning to write an optimizing compiler
any high level language (HLL) for the Z80, and secondly,
those who write programs for the Z80 in assembly language and optimize them
manually. The optimization techniques discussed here can be
are applied by analogy to other types of processors in which
load commands "register -> register" or other commands,
changing the contents of registers are faster and/or
take up fewer bytes than "memory -> register" load instructions.
Why is Spectrum the main programming language?
is an assembler, and compilers for Pascal, C and other languages
are practically not used? After all, in these languages it is much easierwrite programs! The answer is simple: the whole point is that the formed
during the compilation process, the program in machine code is obtained
longer and slower compared to similar
assembler program. And with a small amount of memory and low
the performance of the Spectrum is crucial.
Why is the program not optimal? Yes because
the compiler operates quite primitively. For example, he needs
in the program, place the number 0 in the accumulator - it will form
command LD A,0. And anyone with any knowledge of
In assembly language, the programmer will write the command in the same situation
XOR A, which will be both faster and shorter. Programmer also
takes into account and uses the fact that by the time the register
you need to load a constant, the contents may be known
some registers. For example, you need to load into the battery
the number is 1, and there is 0. Of course, instead of LD A,1 we write
INC A. Another example: you need to load 3 into the accumulator, and to this
moment in register H just turns out to be 3 - naturally, we write
command LD A,H.
It is clear that the compiler also needs to be taught such methods
optimization. Then, quite possibly, he will be able to form even
more optimal programs than a person - after all, the compiler
will consider all possible optimization options and choose the best one,
something a person, no matter how much he or she wants, is not capable of doing. Well who,for example, he will guess that if A=0, but it is necessary to obtain A=6, then, with
corresponding value of some flags, you can get by with one
only by the DAA team?
Yes, this is how we come close to the topic of this article. Speech
will talk about optimizing the loading of constants into registers and register
pairs of Z80s. Commands for loading constants are one of the most commonly used
encountered, and their optimization will bring good gains in
volume and speed.
So what do we have? Suppose that during the program it is necessary
put some constant into a register or register pair.
To do this, the processor provides the following commands:
one of which does not change the flags:
LD A,n ┐
LD B,n │
LD C,n │
LD D,n ├──> length: 2 bytes, execution time: 7 clock cycles
LD E,n │
LD H,n │
LD L,n ┘
LD XH,n ┐
LD XL,n ├──> length: 3 bytes, execution time: 11 clock cycles
LD YH,n │ (these are undocumented commands, however,
LD YL,n ┘ used in many programs)
LD BC,nn ┐
LD DE,nn ├──> length: 3 bytes, execution time: 10 clock cycles
LD HL,nn ┘
LD IX,nn ┐ ─> length: 4 bytes, execution time: 14 clock cycles
LD IY,nn ┘
Let by the moment when into a register or into a register pair
a constant must be placed, we know at least some of
the following:
- the contents of all or some processor registers;
- values of all or some flags;- the contents of which registers are no longer needed;
- the meaning of which flags are no longer needed.
So, knowing this, we can often replace the ones mentioned
above commands load constants to be shorter and/or faster
running commands. Naturally, the more we know, the
There will be more opportunities for optimization.
════════════════════════ ════════════════════════
Best regards, Ivan Roshchin.
[ZX] [BestView 3.0 - 26%]
From
Ivan Roshin
→
To
All
17 October 2000
Hello, All!
═══════════════════ z80_ln_2.W ══════════════════
Now we will analyze in detail in what cases and how exactly
it is possible to optimize how the gain in length and
speed.
1. If it is known that a register or register pair already contains
is the number that needs to be entered there, then no
no command is required, and we do not add anything to the object code.
The savings will be from 2 to 4 bytes/from 7 to 14 clock cycles, in
depending on the type of register/register pair.
2. If you need to place a constant in one of the registers A, B, C, D, E,
H,L (let's denote it R1) and it is known that this constant is already
contained in another register (also in one of A,B,C,D,E,H,
L - let's denote it R2), then we place the command in the object code
LD R1,R2. The savings will be 1 byte/3 clock cycles.
Example: you need to put #23 in register D; we know that
in register B also #23; put the command in the object code
LD D,B.
Note: under the words "place in object code
command..." we will mean placing it in object code
machine codes corresponding to this command. Note
also that the compiler can generate not an object, but
directly executable code.
3. If you need to place a constant in one of the registers XH, XL
(let's denote it R1) and it is known that this constant is alreadycontained in another register (in one of A,B,C,D,E,XH,XL -
let's denote it R2), then we place the LD command in the object code
R1,R2. The savings will be 1 byte/3 clock cycles.
Example 1: you need to put #76 in the XH register; we know that
in register A also #76; put the command in the object code
LD XH,A.
Example 2: you need to put #18 in the XL register; we know that
in register XH also #18; put the command in the object code
LD XL,XH.
4. If you need to place a constant in one of the YH,YL registers
(let's denote it R1) and it is known that this constant is already
contained in another register (in one of A,B,C,D,E,YH,YL -
let's denote it R2), then we place the LD command in the object code
R1,R2. The savings will be 1 byte/3 clock cycles.
Example 1: you need to put #29 in the YH register; we know that
in register E also #29; put the command in the object code
LD YH,E.
Example 2: you need to put #74 in the YL register; we know that
in YH register also #74; put the command in the object code
LD YL,YH.
5. If you need to place a constant in one of the BC register pairs,
DE,HL,IX,IY and it is known that one of the bytes of the constant is already
is in its place, let’s reformulate the problem
optimization: you need to place the remaining byte of the constant in
the corresponding register of the register pair, and so that
do not change the value of a byte already in place.We save at least 1 byte/3 clock cycles.
Example: you need to put #2574 in HL; we know that H=#25.
Let's try to solve the optimization problem of loading #74 into register L -
even if this does not work, there will be a command in the object code
LD L,#74, which is still shorter and faster than LD HL,#2574.
6. If you need to place a constant in one of the BC register pairs,
DE,HL (we denote this register pair RR) and it is known that
the value of the high byte of the constant is in one of the registers
A,B,C,D,E,H,L (let’s denote this register R1), and the value
the low byte of the constant is also in one of these
registers (let’s denote it as R2), then optimization can be
execute by placing the commands LD RRH,R1 in the object code:
LD RRL,R2 (where RRH and RRL are the high and low registers
register pair RR). The savings will be 1 byte/2 clock cycles.
Attention! It must be taken into account that after completing the first
LD command, the value of the RRH register will change, and if R2
matches RRH, then optimization cannot be performed. Sometimes in
In this case, reversing the LD commands helps.
Example 1: you need to put #1234 in HL; we know that A=#12,
E=#34; We place the commands LD H,A in the object code: LD L,E.
Example 2: you need to put #7536 in BC; we know that A=#75,
B=#36; put the commands LD C,B into the object code: LD B,A
(in that order!).Example 3: you need to put #8762 in DE; we know that D=#62,
E=#87. However, optimization cannot be performed.
7. If you need to place a constant in one of the BC register pairs,
DE,HL (we denote this register pair RR) and it is known that
the value of the AF register pair is exactly equal to this constant
(to establish this fact the compiler will have to
monitor the value of the flags register, including and
undocumented flags), then you can put it in an object
PUSH AF command code: POP RR. The savings will be 1 byte/-11
cycles (i.e. we lose speed due to a reduction in length).
This can be useful when a small program size is more important
speed of its implementation.
8. If you need to place a constant in register pair IX or IY
(we denote this pair RR1) and it is known that this constant is already
contained in one of the register pairs AF,BC,DE,HL (denote
its RR2), then you can put it in the object code of the PUSH command
RR2: POP RR1. As in the previous case, the gain in length
will be one byte, and the loss in speed will be 11 cycles.
════════════════════════ ════════════════════════
Best regards, Ivan Roshchin.
[ZX] [BestView 3.0 - 26%]
From
Ivan Roshin
→
To
All
17 October 2000
Hello, All!
═══════════════════ z80_ln_3.W ══════════════════
9. If you need to place a constant in a register pair HL (or
DE), and it is known that the contents of the register pair DE (or HL)
is no longer needed, then we do this: try to solve
the optimization problem of placing the required constant in DE (HL),
and if you can do it in less than 2 bytes and/or 6
cycles, then we place another EX DE command in the object code,
H.L. At the same time, it is possible to save in length and/or speed
(how much exactly depends on the specific case, maximum -
2 bytes/6 clock cycles).
Example 1: you need to place constant #1653 in HL. It is known
that DE=#1653 and DE will no longer be needed. Place in
object code command EX DE,HL. The savings will be 2 bytes/6
beats
Example 2: you need to place the constant #8736 in DE. It is known
that HL=#8735, HL will no longer be needed, change the flags
it is impossible. Solving the optimization problem of room #8736 in HL,
we find that this can be done with the INC HL command in 1 byte/6
beats This satisfies the 2 byte/6 clock limit.
We also add the EX DE,HL command to the object code. Savings
will be 1 byte/0 clock cycles.
10. If you need to place a constant in one of the BC register pairs,
DE,HL and it is known that the values of register pairs BC,DE,HL,BC
From
Ivan Roshin
→
To
All
17 October 2000
Hello, All!
═══════════════════ z80_ln_4.W ══════════════════
15. If you need to place a constant in one of the BC register pairs,
DE,HL,IX,IY (let’s denote it RR1), and in this register pair
the value is found to be one less (more) than the required one
(modulo 65536), then we place the INC command in the object code
(DEC) RR1. The savings will be 2 bytes/4 clock cycles.
Example: you need to place #13FF in BC, and there is
#1400. We place the DEC BC command in the object code.
16. If you need to place a constant in one of the registers C, E, L, XL,
YL (let's denote it R1, and the register pair into which it
included - RR1), the values of the flags cannot be changed, and it is known
that this register contains a value one less
(more) required (not modulo 256, but absolute
value!), then we place the INC (DEC) command in the object code
RR1. The savings will be 1 byte/1 clock cycle.
Example: you need to put #32 in C; we know that C=#31 and
Flag values cannot be changed. Place it in object code
INC BC team.
17. If you need to place a constant in one of the registers B, C, D, E, H,
L,XH,XL,YH,YL (let's denote it R1, the register pair into which
it enters - RR1, and the second register of the pair RR1 - R2), and if
the value of RR1 is known, then you can try to do this with
using the commands INC RR1, DEC RR1. If R1 is one of the registersH,L,XH,XL,YH,YL, then, in addition to INC/DEC, you can also try
commands ADD RR1,RR1; ADD RR1,BC; ADD RR1,DE; ADD RR1,SP,
if the flags allow it. At the same time, it must be taken into account that
the contents of R2 may be corrupted. The savings will be
1 byte/1 clock cycle when using INC/DEC and 1 byte/-4 clock cycles
when using ADD.
Example 1: you need to put #82 in D; we know that DE=#81FF,
the value of E is no longer needed, the flags cannot be changed.
We place the INC DE command in the object code.
Example 2: you need to place #40 in H; we know that HL=#2000 and
there is no need to save flags. Place the command in the object code
ADD HL,HL.
Example 3: you need to place #12 in XL; we know that IX=#5309,
the XH value will no longer be needed, there is no need to save the flags.
We place the ADD IX,IX command in the object code.
Example 4: you need to place #25 in H; we know that HL=#1000,
BC=#1500; you can change flags except Z. Place in
object code command ADD HL,BC.
18. If you need to place a constant in H (XH,YH), the current value
H (XH,YH) is known, and the value of L (XL,YL) is unknown, however
you cannot change it, you can (if the flags allow) use
the following fact: commands ADD HL,BC (ADD IX,BC; ADD IY,BC),
ADD HL,DE (ADD IX,DE; ADD IY,DE) and ADD HL,SP (ADD IX,SP; ADD
IY,SP) will not change the L register (XL,YL) if the low byteof the second term (BC, DE and SP, respectively) is equal to zero.
The savings will be 1 byte/-4 clock cycles.
Example: you need to place #70 in XH; we know that XH=#20,
SP=#5000; You can change the values of all flags except Z and S.
We place the ADD IX,SP command in the object code.
19. If you need to place a constant in L (XL,YL), the current value
L (XL,YL) is known, and the value of H (XH,YH) is unknown, however
you cannot change it, you can (if the flags allow) use
the following fact: commands ADD HL,BC (ADD IX,BC; ADD IY,BC),
ADD HL,DE (ADD IX,DE; ADD IY,DE) and ADD HL,SP (ADD IX,SP; ADD
IY,SP) will not change the register H (XH,YH), or if the high byte
of the second term (BC, DE and SP, respectively) is equal to zero and
there will be no transfer to the high byte during addition, or if
the most significant byte is #FF and when adding there will be a carry to
high byte. The savings will be 1 byte/-4 clock cycles.
Example 1: should be placed in L #26; we know that L=#10,
BC=#0016, no need to save flags. Place it in object code
team ADD HL,BC.
Example 2: should be placed in YL #70; we know that YL=#74,
DE=#FFFC, no need to save flags. Place in
object code command ADD IY,DE.
20. If in one of the register pairs HL,IX,IY (let’s denote it RR1)
you need to place a constant that can be obtained with
using one of the operations ADD RR1,RR1; ADD RR1,BC; ADD RR1,DE; ADD RR1,SP, then we place the corresponding
command (if the flags allow). The savings will be 2 bytes/-1
tact.
Example 1: should be placed in HL #AAAA; we know that
HL=#5555, no need to save flags. Place it in object code
command ADD HL,HL.
Example 2: should be placed in IX #7624; we know that
IX=#1211, DE=#6413, no need to save flags. Place in
object code command ADD IX,DE.
21. If you need to place a constant in a register pair HL, which
can be obtained using one of the ADC operations HL,HL;
ADC HL,BC; ADC HL,DE; ADC HL,SP; SBC HL,HL; SBC HL,BC; SBC
HL,DE; SBC HL,SP, then we put it in object code
the appropriate command (if the flags allow). Savings
will be 1 byte/-5 clock cycles.
Example 1: should be placed in HL 0; we know that CY=0 and
there is no need to save flags. Place the command in the object code
SBC HL,HL.
Example 2: should be placed in HL #2299; we know that
HL=#2266, BC=#0032, CY=1 and there is no need to save flags.
We place the ADC HL,BC command in the object code.
════════════════════════ ════════════════════════
Best regards, Ivan Roshchin.
[ZX] [BestView 3.0 - 26%]
From
Ivan Roshin
→
To
All
17 October 2000
Hello, All!
═══════════════════ z80_ln_5.W ══════════════════
22. Let's take two sets of commands: the first - (ADD HL,HL, ADD HL,
BC, ADD HL,DE), second - (ADD HL,HL, ADD HL,BC, ADD HL,DE,
INC H, DEC H, INC L, DEC L, INC HL, DEC HL). If in
register pair HL must be placed as a constant, then you can
try (if the flags allow) to do this with
two teams, one of which is taken from the first set, and
the other is from the second. The memory savings will be 1 byte, and
performance loss will depend on which command
was selected from the second set: INC H, DEC H, INC L or
DEC L - 5 cycles; INC HL or DEC HL - 7 bars; ADD HL,HL,
ADD HL,BC or ADD HL,DE - 12 clock cycles.
Example 1: should be placed in HL #8080; we know that HL=#2020
and there is no need to save flags. Place commands in object code
ADD HL,HL: ADD HL,HL.
Example 2: should be placed in HL #8081; we know that HL=#4040
and there is no need to save flags. Place commands in object code
ADD HL,HL: INC L.
Example 3: should be placed in HL #8082; we know that HL=#4040
and there is no need to save flags. Place commands in object code
INC L:ADD HL,HL.
Example 4: should be placed in HL #1234; we know that
HL=#1111, DE=#0111, BC = #0012 and there is no need to save the flags.
We place the ADD HL,DE commands in the object code: ADD HL,BC.23. If in one of the register pairs HL,IX,IY (let’s denote it RR1)
you need to place a constant that can be obtained with
using one of the operations ADD RR1,RR1; ADD RR1,BC; ADD RR1,
DE; ADD RR1,SP, and if it is known that the contents of the flag
transfer cannot be changed, and as a result of executing the command
ADD it will change to the opposite, then after placing in
object code of the ADD command we also place the CCF command (invert
transfer flag). The savings will be 1 byte/-5 clock cycles.
Example 1: should be placed in HL #1234; we know that
HL=#1123, DE=#0111, carry flag is set and change it
it is impossible. We place the ADD HL,DE: CCF commands in the object code.
Example 2: should be placed in IY 0; we know that IY=#FFF0,
BC=#0010, the carry flag is cleared and cannot be changed.
We place the ADD IY,BC: CCF commands in the object code.
When optimizing, you need to try to apply each of the
twenty-three rules listed above, and if they fit right away
several rules, choose the one that provides the best
result. If the program being optimized is required
maximum performance, you will have to discard such options
optimizations that reduce program length by
increasing constant loading time.
Pay attention to rules 9 and 10. When applying each
of these, we have to change the optimization problem (let's call thismodified problem by subtask) and solve it (to do this again
applying all the rules to it). When solving a subtask it is necessary
exclude that rule (9 or 10) from the list of rules when applying
which this subtask arose. This is necessary to avoid
looping.
While writing this article, I had some thoughts:
not directly related to its topic, but indirectly related to
her. I'll try to outline them.
Maybe someone would like to write a Java compiler for
Spectrum, but it is stopped by problems such as implementation
editor, user interface, etc.? I can advise
Here's what: the ZX ASM 3.10 assembler has an excellent interface, and
the compiler is made as a separate overlay. Thus,
no one is stopping you from writing a compiler for any other language (C,
Pascal, etc.) and connect it to the ZX ASM.
And I’ll also touch on the issue of optimization. I would like it to
There was a site on the Internet specifically dedicated to optimizing the Z80 code,
so that programmers from all over the world can use
information posted there (and add your own). I don't know -
perhaps something similar already exists? If not - maybe
will anyone do this?
════════════════════════ ════════════════════════
Best regards, Ivan Roshchin.
[ZX] [BestView 3.0 - 26%]
From
Kirill Frolov
→
To
All
23 October 2000
================================================================================
* Forwarded by Kirill Frolov (500:812/23.25)
* Area : ZX.SPECTRUM (Emulator people hanging out)
* From : Alex Letaev, 2:5020/689.53 (21 Oct 00 06:33)
* To : All
* Subj : Z80: optimization of loading constants into registers
================================================================================
Hi, All!
(c) Ivan Roshchin, Moscow
Fido: 2:5020/689.53
ZXNet: 500:95/462.53
E-mail: asder_ffc@softhome.net
WWW: http://www.zx.ru/echo/roschin
Z80: optimization of loading constants into registers
────────────────────── ───────────────────────
(Radio amateur. Your computer 9/2000)
(under the pseudonym BV_Creator)
Expanded version.
The Z80 processor, manufactured by ZiLOG since 1976,
used, in addition to personal computers, and in many
other microprocessor devices. So this article will
useful not only for Spectrum owners. It is addressed
firstly, for those who are planning to write an optimizing compiler
any high level language (HLL) for the Z80, and secondly,
those who write programs for the Z80 in assembly language and optimize them
manually. The optimization techniques discussed here can be
are applied by analogy to other types of processors in which
load commands "register -> register" or other commands,
changing the contents of registers are faster and/ortake up fewer bytes than "memory -> register" load instructions.
Why is Spectrum the main programming language?
is an assembler, and compilers for Pascal, C and other languages
are practically not used? After all, in these languages it is much easier
write programs! The answer is simple: the whole point is that the formed
during the compilation process, the program in machine code is obtained
longer and slower compared to similar
assembler program. And with a small amount of memory and low
the performance of the Spectrum is crucial.
Why is the program not optimal? Yes because
the compiler operates quite primitively. For example, he needs
in the program, place the number 0 in the accumulator - it will form
command LD A,0. And anyone with any knowledge of
In assembly language, the programmer will write the command in the same situation
XOR A, which will be both faster and shorter. Programmer also
takes into account and uses the fact that by the time the register
you need to load a constant, the contents may be known
some registers. For example, you need to load the battery
the number is 1, and there is 0. Of course, instead of LD A,1 we write
INC A. Another example: you need to load 3 into the accumulator, and to this
moment in register H just turns out to be 3 - naturally, we write
command LD A,H.
It is clear that the compiler also needs to be taught such methodsoptimization. Then, quite possibly, he will be able to form even
more optimal programs than a person - after all, the compiler
will consider all possible optimization options and choose the best one,
something a person, no matter how much he or she wants, is not capable of doing. Well who,
for example, he will guess that if A=0, but it is necessary to obtain A=6, then, with
corresponding value of some flags, you can get by with one
only by the DAA team?
Yes, this is how we come close to the topic of this article. Speech
will talk about optimizing the loading of constants into registers and register
pairs of Z80s. Commands for loading constants are one of the most commonly used
encountered, and their optimization will bring good gains in
volume and speed.
So what do we have? Suppose that during the program it is necessary
put some constant into a register or register pair.
To do this, the processor provides the following commands:
one of which does not change the flags:
LD A,n ┐
LD B,n │
LD C,n │
LD D,n ├──> length: 2 bytes, execution time: 7 clock cycles
LD E,n │
LD H,n │
LD L,n ┘
LD XH,n ┐
LD XL,n ├──> length: 3 bytes, execution time: 11 clock cycles
LD YH,n │ (these are undocumented commands, however,
LD YL,n ┘ used in many programs)
LD BC,nn ┐
LD DE,nn ├──> length: 3 bytes, execution time: 10 clock cycles
LD HL,nn ┘
LD IX,nn ┐ ─> length: 4 bytes, execution time: 14 clock cycles
LD IY,nn ┘Let by the moment when into a register or into a register pair
a constant must be placed, we know at least some of
the following:
- the contents of all or some processor registers;
- values of all or some flags;
- the contents of which registers are no longer needed;
- the meaning of which flags are no longer needed.
So, knowing this, we can often replace the ones mentioned
above commands load constants to be shorter and/or faster
running commands. Naturally, the more we know, the
There will be more opportunities for optimization.
Now we will analyze in detail in what cases and how exactly
it is possible to optimize how the gain in length and
speed.
1. If it is known that a register or register pair already contains
is the number that needs to be entered there, then no
no command is required, and we do not add anything to the object code.
The savings will be from 2 to 4 bytes/from 7 to 14 clock cycles, in
depending on the type of register/register pair.
2. If you need to place a constant in one of the registers A, B, C, D, E,
H,L (let's denote it R1) and it is known that this constant is already
contained in another register (also in one of A,B,C,D,E,H,
L - let's denote it R2), then we place the command in the object code
LD R1,R2. The savings will be 1 byte/3 clock cycles.
Example: you need to put #23 in register D; we know thatin register B also #23; put the command in the object code
LD D,B.
Note: under the words "place in object code
command..." we will mean placing it in object code
machine codes corresponding to this command. Note
also that the compiler can generate not an object, but
directly executable code.
3. If you need to place a constant in one of the registers XH, XL
(let's denote it R1) and it is known that this constant is already
contained in another register (in one of A,B,C,D,E,XH,XL -
let's denote it R2), then we place the LD command in the object code
R1,R2. The savings will be 1 byte/3 clock cycles.
Example 1: you need to put #76 in the XH register; we know that
in register A also #76; put the command in the object code
LD XH,A.
Example 2: you need to put #18 in the XL register; we know that
in register XH also #18; put the command in the object code
LD XL,XH.
4. If you need to place a constant in one of the YH,YL registers
(let's denote it R1) and it is known that this constant is already
contained in another register (in one of A,B,C,D,E,YH,YL -
let's denote it R2), then we place the LD command in the object code
R1,R2. The savings will be 1 byte/3 clock cycles.
Example 1: you need to put #29 in the YH register; we know that
in register E also #29; put the command in the object code
LD YH,E.Example 2: you need to put #74 in the YL register; we know that
in YH register also #74; put the command in the object code
LD YL,YH.
5. If you need to place a constant in one of the BC register pairs,
DE,HL,IX,IY and it is known that one of the bytes of the constant is already
is in its place, let’s reformulate the problem
optimization: you need to place the remaining byte of the constant in
the corresponding register of the register pair, and so that
do not change the value of a byte already in place.
We save at least 1 byte/3 clock cycles.
Example: you need to put #2574 in HL; we know that H=#25.
Let's try to solve the optimization problem of loading #74 into register L -
even if this does not work, there will be a command in the object code
LD L,#74, which is still shorter and faster than LD HL,#2574.
6. If you need to place a constant in one of the BC register pairs,
DE,HL (we denote this register pair RR) and it is known that
the value of the high byte of the constant is in one of the registers
A,B,C,D,E,H,L (let’s denote this register R1), and the value
the low byte of the constant is also in one of these
registers (let’s denote it as R2), then optimization can be
execute by placing the commands LD RRH,R1 in the object code:
LD RRL,R2 (where RRH and RRL are the high and low registers
register pair RR). The savings will be 1 byte/2 clock cycles.Attention! It should be taken into account that after completing the first
LD command, the value of the RRH register will change, and if R2
matches RRH, then optimization cannot be performed. Sometimes in
In this case, reversing the LD commands helps.
Example 1: you need to put #1234 in HL; we know that A=#12,
E=#34; We place the commands LD H,A in the object code: LD L,E.
Example 2: you need to put #7536 in BC; we know that A=#75,
B=#36; put the commands LD C,B into the object code: LD B,A
(in that order!).
Example 3: you need to put #8762 in DE; we know that D=#62,
E=#87. However, optimization cannot be performed.
7. If you need to place a constant in one of the BC register pairs,
DE,HL (we denote this register pair RR) and it is known that
the value of the AF register pair is exactly equal to this constant
(to establish this fact the compiler will have to
monitor the value of the flags register, including and
undocumented flags), then you can put it in an object
PUSH AF command code: POP RR. The savings will be 1 byte/-11
cycles (i.e. we lose speed due to a reduction in length).
This can be useful when a small program size is more important
speed of its implementation.
8. If you need to place a constant in register pair IX or IY
(we denote this pair RR1) and it is known that this constant is alreadycontained in one of the register pairs AF,BC,DE,HL (denote
its RR2), then you can put it in the object code of the PUSH command
RR2: POP RR1. As in the previous case, the gain in length
will be one byte, and the loss in speed will be 11 cycles.
9. If you need to place a constant in a register pair HL (or
DE), and it is known that the contents of the register pair DE (or HL)
is no longer needed, then we do this: try to solve
the optimization problem of placing the required constant in DE (HL),
and if you can do it in less than 2 bytes and/or 6
cycles, then we place another EX DE command in the object code,
H.L. At the same time, it is possible to save in length and/or speed
(how much exactly depends on the specific case, maximum -
2 bytes/6 clock cycles).
Example 1: you need to place constant #1653 in HL. It is known
that DE=#1653 and DE will no longer be needed. Place in
object code command EX DE,HL. The savings will be 2 bytes/6
beats
Example 2: you need to place the constant #8736 in DE. It is known
that HL=#8735, HL will no longer be needed, change the flags
it is impossible. Solving the optimization problem of room #8736 in HL,
we find that this can be done with the INC HL command in 1 byte/6
beats This satisfies the 2 byte/6 clock limit.
We also add the EX DE,HL command to the object code. Savings
will be 1 byte/0 clock cycles.10. If you need to place a constant in one of the BC register pairs,
DE,HL and it is known that the values of register pairs BC,DE,HL,BC