Lesson 10: String Operations
String operations? No, not stuff like D_ZT_STR, in fact, not calls at all. They are everyday commands like add, sub or ld. There are three basic 'branches' of string commands. They are LD, CP, and OUT.
First off, they are all different but are at tjhe same time very simalar. Let me just get this out of the way now: I have no idea why they are called String Operations. They have nothing to do with strings. Oh Well. This is just the name I learned them under.
LD
The string operation versions of LD are LDI,
LDD, LDIR, and LDDR. They
stand for Load and Increment,
Load and Decrement,
Load, Increment
and Repeat, and Load,
Decrement and Repeat. What they
do are basically the same: Load from one place to another, and
alter a lot of registers.
To set up (I think) all string opeations requires three register
pairs to be initilaized. DE is the location data is to be loaded
into. HL is the location of where the data comes from, and BC is
a counter. Lets look at LDI:
If we were to write out what LDI does, this is what it would look
like: (Also we are maiking up something: a magical
version of djnz that uses a 16 bit reg, meaing this code does not
actually work!)
ld de,$FC00
ld hl,GRAPH_MEM
ld bc,1024
FakeDJNZ:
ld a,(hl)
ld (de),a
inc hl
inc de
djnz FakeDJNZ
This would copy the GRAPH_MEM to the screen, that is if you could actually use djnz with bc. You would have to use another reg pair and CP_HL_DE'ing with it, which would be a huge mess with push and pop, not to metion another line for dec bc. There is a much easier way.
ld de,$FC00
ld hl,GRAPH_MEM
ld bc,1024
LDIR
Thats it. LDI puts (hl) into (de) and inc's hl and de. It also dec's bc. All LDIR does is that it repeats LDI until BC=0.
As for LDD, it does the opposite with the regs. It decreases all three register pairs, meaning you would have to point to the end of the graph mem and the end of the screen buffer. You can probably guess what LDDR does.
String commands, despite thieir weird name, are extremly useful.
CP
The CP string commands follow the same naming conventions as LD: CPI, CPD, CPIR, and CPDR.
CPI compares a and (hl), set flags, increments hl and decrements bc.
CPIR does the same thing as before: CPI's until BC=0 OR the Z flag is Set.
CPD does a cp (hl), dec hl and bc. CPDR has predicable results....
This may not seem very useful, so I will give you an actual
example!
In my game Wak-a-Skeeter, I used a CPIR. Heres a snippet of code:
ld hl,&PadTable
ld bc,10
cpir
ld a,c
cp 0
jr nz,UI
ret ;not really in the
code
PadTable:
.db K_3,K_2,K_1
.db K_6,K_5,K_4
.db K_9,K_8,K_7,0
First of all I pointed hl to the PadTable, which you see is a
table of the scancodes for the number pad.
I then set bc to 10, the maximum number of checks to make.
Then the cpir gets done. You mus remember at this point in the
code, a is a scancode from GET_KEY.
The cpir stoppes when it his a value identical to A. So if you
had pressed 6, a is going to be equivilent of K_6. Once (hl)=K_6,
the cpir stoppes and leaves bc alone, having never reached 0. I
now know what button was pressed, the number 6 is stored in bc,
more locally in c. So by putting c in a, then checking it against
0, I know if one of the number pad buttons have been pressed. If
so, it gets wisked away to the UI label. If not, go back to where
we came.
This method is way better than:
cp K_1
jr nz,Key1
cp K_2
jr nz,Key2
....
And so on...
Unforunatley, this is the extent of my knowledge of sting opeations. The third branch based on OUT I have never used. I can give you a technical version of the commands, but am unable to offer better: They seem to send a large quantity of data to a port, but I have never used it so if you really want to learn about these I suggest you ask around.
OTDR Perform an OUTD and repeat until B=0.
OTIR Perform an OTI and repeat until B=0.
OUTD Load output port (C) with (HL), decrement HL and B.
OUTI Load output port (C) with (HL), incr HL, decr B.