z80:Control Structures

From Learn @ Cemetech
Jump to navigationJump to search

Existing tutorials

If you still don't understand, here's some more information that may help you.

Control structures help you determine the flow of the program. It would be really boring if the code executed each line once from the beginning of the program to the end. We need some variation. Control structures allow you to perform certain actions found elsewhere in the program, allow you to repeatedly perform that action, and also give you control of what conditions must be satisfied before the action is performed.

If-then-else

The idea here is this: test a condition. If it is true, then do something. Else, do something else.

Example

   If it is sunny,
   then go for a walk.
   Else do homework.


As you can see, you have a choice of either going on a walk or doing homework. You can't do both at the same time.

Extension

It is also possible to chain if-then-else statements. There are a few ways you can chain, or expand the conditions:

Provide extra conditions

Self-explanatory, just add on extra conditions that must test to be true.


   If it is sunny and I have no homework,
   then go for a walk.
   Else, do homework.


Else-If

Similar to tacking on extra conditions, except Else-If tacks on conditions if the initial statement is false.


   If it is sunny,
   then go for a walk.
   Else if I have homework,
   then do homework.


Then without Else

Sometimes, you don't need an else. This is because the other course of action is to do nothing.


   If I'm hungry,
   then eat something
   (else, don't eat)


The stuff in parenthesis is optional, but as you can tell, unnecessary.

It is important to note that there is not an Else without a Then.

Programming Connection

Obviously, testing conditions are a vital part to programming code. If a piece of code is continually run from start to finish without conditions, it's usually not useful in the real world. So, we need to apply this idea of conditions into programming. Z80 has 2 uses conditions:

Directives (compiler instruction)

These tell the compiler what to do under certain conditions. A common use is to compile a program for many platforms.


   #If 83p
   .include "ti83plus.inc"
   #Else
   #If 83
   .include "ti83.inc"
   #EndIf


Program use

Much more important is the use of conditions in programs. The z80 processor can handle conditions in 2 fundamental ways. One is to test the accumulator for a certain value. This is done through the Z80:Opcodes:CP instruction.


   CP 5		;compare the accumulator to 5
   CP B		;compare the accumulator to the B register


The Z80:Opcodes:CP instruction is telling the processor to subtract the value of the argument (5, or B) from the accumulator. Note that the actual value of the accumulator is not changed, but there are a series of flags that are set, depending on the result of the Z80:Opcodes:CP instruction.

After you have set/reset certain flags with the Z80:Opcodes:CP instruction, you must do something with these flags. Unfortunately, the z80 processor doesn't directly support If-Else, so we need to create or own little work-around.

To do this, we'll use jump instructions. The jump instructions are Z80:Opcodes:JP and Z80:Opcodes:JR. Jump instructions jump to a location in memory, and execute the code at that point. The good part is that jump instructions can also take conditions, based on the flags we have changed with the CP instruction.

We can also use call instructions. Call instructions are similar to jump instructions with one key difference: you can easily jump back. Call instructions include Z80:Macros:BCALL, Z80:Opcodes:CALL, and Z80:Opcodes:RET. Note that Z80:Macros:BCALL is not actually an instruction directly recognized by the z80 processor. Instead, it is a macro that allows the programmer to call certain functions that the manufacturer (Texas Instruments) has coded into the calculator for the Operating System's use, as well as any programs' use.

Another way to test conditions is through Bit-Masking. This is a topic that will be discussed later, but if you want click on the link and it will explain the basics of bit-masking.

Loops

What if you want to perform an action repeatedly? You could type the code for the action over and over.

   ;repeatedly add a number 10 times, aka multiplication
   
    xor a			;initial value
    ld b,5			;what to repeatedly add
   
    add a,b		;add a and b 10 times
    add a,b
    add a,b
    add a,b
    add a,b
    add a,b
    add a,b
    add a,b
    add a,b
    add a,b


However, this presents some problems. One, it's a waste of space if you need to add, say, two numbers together 100 times. It would also be a problem if you want to make the code so that it can add numbers any number of times in the program without having to change the code, only the inputs. Luckily, there are loops. Loops perform a certain action over and over again until certain conditions are met. These are the loop conditions. There are two kinds of loops: for loops, and while loops. They are be discussed in greater detail below.

While

While loops perform an action until a condition is fulfilled, whether a certain key is pressed, a counter reaches a certain number, or any other sort of condition possible.


   keyloop:		;keep getting key presses until the enter key is pressed
    bcall(_GetKey)
    cp kenter
    jr nz,keyloop


See the last line of this code? It jumps to a label that gets key presses if the enter key was not pressed. As with regular control statements, it is possible to have multiple conditions for exiting the loop:


   keyloop:		;keep getting key presses until either 2nd or enter is pressed
    bcall(_GetCSC)
    cp skenter
    jr z,endloop
    cp sk2nd
    jr z,endloop
    jr keyloop
   
   endloop:


For

A special kind of while loops, for loops are while loops that run on a counter. Lucky for us, the z80 processor has an instruction set specially built in for for loops (not a typo). This instruction is the Z80:Opcodes:DJNZ instruction. Z80:Opcodes:DJNZ does these things (in this order):

  1. Decreases B
  2. Checks if B is zero
    • If it is, continue on in code
    • Else, jump to specified label

Remember, Z80:Opcodes:DJNZ decrements first, then jumps if not zero, so if B=0, Z80:Opcodes:DJNZ will make it equal $FF (256), and since this isn't zero, it will repeat 256 times.

So, let's create a loop! Please note that this in not how you should multiply two numbers together, but for our purposes will demonstrate for loops. To learn the more efficient method of multiplication, see this page.


   ;multiply
   ;
   ;inputs:	accumulator=number1
   ;		b=number2
   ;
   ;output: accumulator=number1*number2
   ;
   ;note: this routine is NOT how you should multiply. It also does not check if the 2nd operand is 0
   ;
   multiply:
    ld c,a
    xor a
   mLoop:
    add a,c
    djnz mLoop

Routines/Procedures

So, let's say you want a program that performs a certain action at different parts of the code. You could re-type the code, but that's a waste of space, and if you jump to it, how will you know were to jump back to? This creates the idea of routines. A routine is a bunch of code that is called somewhere in the program, and then when it's done running, jumps back. For this, we'll use the Z80:Opcodes:CALL instruction.

What CALL does:

  1. Pushes the program counter (where the processor is executing code from) onto the stack
  2. Jumps to a point in memory

However, at this point we've finished running the routine and want to get back. To get back, we'll use the Z80:Opcodes:RET instruction.

What RET does:

  1. Pops the stack
  2. Jumps to the address stored in the stack

Don't worry if you don't know what the stack is for now, but if you want, see this page.

So, let's put it all together now:


   ;Calling a routine
    call testRoutine
    ...
   
   ;The routine
   testRoutine:
    inc a
    dec b
    ret


Review

Time to test your knowledge. See if you can answer these questions.

  1. Create code for a while loop that:
    • Checks if the accumulator is bigger than B
      • If it is, increase the accumulator and C (use the Z80:Opcodes:INC instruction)
      • If it isn't, decrease the accumulator and C (use the Z80:Opcodes:DEC instruction)
    • Keeps doing this until the accumulator equals B

Identify the Error(s)

Find the error(s), if any, in each piece of code. They can either be run-time errors or logic errors.

2.

   loop:
    inc b
    add a,b
    djnz loop


3.

   keyloop:
    bcall(_GetKey)
   
    cp kUp
    jp mUp			;assume mUp exists somewhere
   
    cp kDown
    jp mDown		;assume mDown exists somewhere
   
    jr keyloop


4.

   mUp:
    inc a
    cp 6
    jp c,maxUp		;assume maxUp exists somewhere
    ret


5.

   ;
    ld b,0			;Let's repeat 256 times
    ld a,6
   loop:
    dec a
    djnz loop


For answers, see here.

Conclusion

Possible the most powerful thing in programming, control structures will allow you to dictate how to handle events and provide you with a powerful tool that can not be replaced by anything else. There are other parts to control structures, but they require knowledge of advanced topics not discussed here.