Karma Universe - demuynck.org Lesson 18
TI-82 ASM Corner :: Programming Guide :: Lesson 18 Back | Home | Search
Lesson 18 : Block instructions

This lesson will handle about some more instructions that we haven't talked about before: Block instructions. This are instructions that combine a bunch of other instructions into one handy operation. This results in byte savings and faster execution.

LDI and LDIR | LDD and LDDR | CPI and CPIR | CPD and CPDR | More block instructions

LDI and LDIR

The LDI instruction is equivalent to the following structure:

 PUSH	AF
 LD	A,(HL)
 LD	(DE),A
 POP	AF
 INC	DE
 INC	HL
 DEC	BC
 

But instead of 7 bytes (that's the ammount of bytes the previous piece of code takes in), LDI only takes 2 bytes and the execution speed of LDI is also a lot faster.

The LDI instruction affects the Parity/Overflow flag only. If the result of BC-1=0, then the P/V flag will be reset to zero, otherwise P/V will be set to 1.

LDIR is the same as LDI, but here the LDI instruction is repeated until BC=0. At the end of instruction, the P/V flag will be 0.

So what can LDIR be used for? Well, most of the time it is used to copy a series of bytes. Take for example that you want to copy the contents of the GRAPH_MEM to the APD_BUF. Then you'll use the piece of code below.

 LD	HL,GRAPH_MEM
 LD	DE,APD_BUF
 LD	BC,768            
 LDIR
 

Notice that we set BC to 768. This is the amount of bytes that we need to copy. The LDI instruction will be executed 768 times.

Another routine where the use of LDIR is very handy is the following:

 LD	HL,GRAPH_MEM
 LD	DE,GRAPH_MEM+1
 LD	(HL),0
 LD	BC,767
 LDIR
 

This routine will clear the GRAPH_MEM. It does this by first writing a zero to the first byte of GRAPH_MEM and then copying this byte one byte further every time. Think about it. Please note that BC needs to be set to 767 and NOT to 768 here!! When you would use 768, the last byte would be copied outside of the GRAPH_MEM. Many programmers make this mistake. Luckily the byte just behind GRAPH_MEM is not that important. If it was, using 768 as your BC could cause a crash on your calculator.

LDD and LDDR

The LDD instruction is very similar to the LDI instruction. The replacement code for LDD could be:

 PUSH	AF
 LD	A,(HL)
 LD	(DE),A
 POP	AF
 DEC	DE
 DEC	HL
 DEC	BC
 

As you see, instead of increasing both DE and HL registers, they are decreased. The settings of the flags are the same as with the LDI instruction. After LDD, the P/V flag will be 0 if BC-1=0 and P/V will be 1 otherwise.

As you can guess, LDDR will do the same as LDIR, but backwards. So if you want to clear the GRAPH_MEM with LDDR, you'll need to use the following code:

 LD HL,GRAPH_MEM+767
 LD DE,GRAPH_MEM+766
 LD BC,767
 LD (HL),0
 LDIR
 

Now you could ask yourself why you need LDDR is you already can use the LDIR instruction. Well, suppose you want to copy the data from $8000-$9000 to $8500-$9500. When you would do this with LDIR, the first $500 bytes will be OK, but the last $500 bytes will be wrong. You'll be copying $8000-$8500 to both $8500-$9000 and $9000-$9500.
When you use LDDR instead, you won't have this problem, because $8500-$9000 is already copied to $9000-$9500 before you overwrite it with $8000-$8500.

CPI and CPIR

The CPI instruction is equivalent to the following series of instructions:

 CP	(HL)
 INC	HL
 DEC	BC
 

So this means that the value of A is compared to the value at the memory location with the address stored in HL. After comparing, HL is increased and BC is decreased.

Accordingly to the LDI and LDD instructions, the P/V flag will be 0 if the resulot of BC-1 is 0 and 1 otherwise. The Z flag will also be affected: if A=(HL), the Z flag will be set to 1 and if A is not equal to (HL), the Z flag will be reset to zero.

Just like with LDI and LDD, you will not often use this instruction. Instead, you will want to use the CPIR instruction once in a while.

The CPIR instruction is almost the same as the CPI one. Thye only difference is that CPIR will keep looping until BC=0 or A=(HL). The Z and P/V flags are set in the same way as with CPI.

An example of CPIR: suppose HL points to the middle of a zero-terminated string and you want to find the address of the string that comes immediately after that string. Here's a way to do it (supposing the string is less than $10 bytes long):

 LD	HL,MiddleOfString
 XOR	A	; = LD A,0
 LD	BC,$10
 CPIR
 ..
.db "This is a "
MiddleOfString:
.db "string",0
.db "This is another string",0
 

This will look for the next zero byte. If the zero byte was found, HL will point to the byte immediately after that zero byte (and NOT to the zero byte itsself) and thus to the next string.

Another string: suppose you have a table of data with length stored in DE and beginning at GRAPH_MEM. Suppose you have received A from the input and you want to check if A is in the table.

 PUSH	DE
 POP	BC	; BC = DE = length of table
 LD	HL,GRAPH_MEM 
 CPIR
 JR	Z,FoundIt
NotFound:
 ...
FoundIt:
 ...
 

CPD and CPDR

The CPD instruction is equivalent to the following series of instructions:

 CP	(HL)
 DEC	HL
 DEC	BC
 

This means that the value of A is compared to the value at the memory location with the address stored in HL. After comparing, both HL and BC are is decreased.

Accordingly to the CPI instruction, the P/V flag will be 0 if the resulot of BC-1 is 0 and 1 otherwise. The Z flag is also affected: if A=(HL), the Z flag will be set to 1 and if A is not equal to (HL), the Z flag will be reset to zero.

CPDR is a repeating CPD instruction that will continue until A=(HL) or BC=0. The flags are set in the same way as the CPD instruction.

An example: Suppose HL points to the middle of a string (which is not the first one in a series of strings) and you want HL to point to the beginning of that string. What will you do?

 LD	HL,MiddleOfString
 XOR	A	; = LD A,0
 LD	BC,$10
 CPDR
 INC	HL	; point to zero byte
 INC	HL	; point to 1st non zero byte
 ..
.db "This is a string",0
.db "This is"
MiddleOfString:
.db "another string",0
 

In this example, we supposed that there are not more than 10 bytes between HL and the beginning of the string and that there is a zero-terminated string immediately in front of the string we need.

Please note also that we still need to do INC HL twice after the CPDR instruction. Why? When we found the zero byte, we decreased HL once more, so increasing it again will make it point to the zero byte. Once more will make HL point to the frist byte of our string.

More block instructions

Yes, there are some more block instructions, but they are almost never used when doing TI-82 Z-80 Assembly. They can be useful for fast graphics, though. We give a listing anyway to be complete.

OUTI, OTIR: used for sending output from the memory to ports and moving downwards in memory (increasing HL).
OUTD, OTDR: used for sending output from the memory to ports and moving upwards in memory (decreasing HL).
INI, INIR: used to get input from a port to the memory (increasing HL every time)
IND, INDR: used to get input from a port to the memory (decreasing HL every time)

Previous lesson | Contents | Next lesson