z80:Coding

From Learn @ Cemetech
Jump to navigationJump to search

Now that we have a basic idea of what we're going to do, it's time to actually write the code. Depending on what kind of program you're creating, your code will vary a great deal. However, it is possible to provide a few tips on coding:

Routines

If you don't know already, re-writing the same code multiple times is a waste of time and space. Instead, it is much more efficient to create routines. Here's how to create a routine:

  1. Create a label. This is the name of the routine, and should be specific for that routine.
  2. Put all the code you want that routine to do under that label.
  3. When you want to call the routine, just make sure you pass the correct arguments by loading the correct values into the inputs.
  4. To call a routine, use the call instruction, followed by the label name. Please note that you can also set the call routine up so that it can jump with similar arguments as jp/jr.

It is not necessary, but is highly recommended, that you include before the routine a description of the routine, the inputs, outputs, and other general information. See the comments section below.

General routine setup

Note that the stuff at the beginning is not necessary, but is recommended so that you know what the routine does.


   ;*****************
   ;_StringLength Inline
   ;*****************
   ;Description: the StrLength function inline
   ;
   ;Inputs: HL points to the start of a null-terminating string
   ;
   ;Outputs: String length (not including null term) in B
   ;             HL points to null term
   ;
   ;Destroyed: A, HL, B
   
   StrLength:
    ld B,0
   StrLength10:
    ld A,(HL)
    or A
    ret Z
    inc B
    inc HL
    jr StrLength10


Calling routines

A general way to call routines that you have written.


   ld HL,strData
    call StrLength
   strData:
    .db "Test String",0


Code Structure

It's important that you organize your code so that it is manage-able by you and others who see your code. Here are a few guidelines that you can follow:

Headers and Definitions/Equates

Headers must go at the top of the page. These are specific to the kind of program you are writing and what platform it is for. Definitions are those that make coding easier for you. They are equates that the compiler searches-and-replaces on compile, but allow you to understand what you are doing.

Sample Definitions/Equates

   #define shot 0
   #define shootFlags asmFlags1
   maxshots .equ 5

Jump Table

If your program is designed to offer subroutines, a jump table to specific routines will often be located at the beginning of the program or App. The first jump is to your main code, the rest are to specific routines. For example:

   <<header>>
   Start:
    jp Main
    jp PutSprite
    jp PutSpriteLarge
    jp BufToLCD
    jp SearchString
   Main:
    <<rest of code>

This way, other programs using your program for routines will know where to call, and if you update any of your routines, you and your users don't need to worry about changing addresses in other programs.

For the most part, this technique is only used by shells; Ion, MirageOS, and Doors CS all use it.

Routines

Routines generally go after the main code. Also be sure to denote where a certain routine starts and where it ends if using multiple labels.

Data

Data that your program uses is the last thing that should be in your program. Data includes strings that you display, saved high-scores, picture data, and anything else that you want to include in your program. Note that here data does not include equates to saferam areas.

Multiple files

Sometimes, if you're writing large programs are even large routines, you'll want to split your program up into multiple files. How you split them up depends on the code itself, but generally here's how I like to do it:

  • Create a separate file for all the headers and definitions stuff. Usually this file is denoted with a "*.inc" or "*.h" file type, but it's okay if you just make it a "*.asm"/"*.z80" file type.
  • Create a separate file for the main code. This does not have to include the data your using, but can.
  • Create a separate file for routines. If you have large routines, create separate files for those, too.
  • Create a separate file for data. This is not necessary, but is useful when trying to make animated sprites/greyscale pictures. Put each animated sprite/greyscale picture into it's own file so that you can edit them together and not get confused with other stuff. Sometimes, you may also want to include the routines that operate on that data with the data, too.

Getting it all together

So now that you have multiple files, you need to put them together in an orderly fashion. Using the #include directive and the guidelines above, you should be able to put your program together so that it will make sense and run correctly. Usually you use your main code file for this, so that way you don't have to create a separate file to put all the includes together.


   #include headers.inc
   
   main:
   ...    ;main code
   
   #include routines1.asm
   #include routines2.z80
   #include spriteData.h
   #include textData.asm


Comments

Although they aren't included in the program or affect the compilation of the code in any way shape or form, comments do provide a very useful perspective on the code at the time the code is being written. It also makes debugging easier, as you know what the code is supposed to do, as well as anyone else that is viewing your code.

To denote a line as a comment, put a semicolon (;) in front of the line. The comment will then continue until the end of that line.

   ld (hl),a        ;loads a to a very important location in memory
   ;the next section of code generates the world
   ...

Knowing when to use comments and when not to is an important aspect of programming. Here are some general pointers on how to use comments:

  • Do use to Describe routines that you have written, including information such as inputs, outputs, and what it does
  • Do use to Describe where the program is jumping to, and what it will do
  • Do use to Describe the conditions of a test, ex. if value is greater than 100, jump
  • Don't use to point out the obvious ex. loads a into (hl)
  • Don't use for every line, cluttering up your code. Instead, try to summarize small chunks of code

Pseudo Code

If you know any higher level languages (C(++),Java, Visual Basic, TI-Basic, etc.), then you can write pseudo code that may help you understand how the low-level assembly code is working. It doesn't even have to be 100% correct coding for a higher level language, so long as you understand what you're trying to do.

For example, you can think of djnz as for, call function as function(), etc.

Algorithm in higher level language

   for(int i=5;i>0;i--){
        display("HI");
   }

Translated to assembly

   ;assembly for-loop:
    ld b,4        ;loop 4 times
   loop:          ;don't use this label twice!
    push bc       ;save loop counter b
     ld hl,txtHI  ;load text
     bcall(_PutS) ;display
    pop bc        ;load loop counter b
    djnz loop     ;loop!
    ;...
   
   txtHI:
    .db "HI",0


Conclusion

Now that you have your code written, your done, right? Wrong. There are many other aspects to creating a successful program than just writing the code. If you wish, you may release your program at this point, but it probably won't get a good review by the program users. Instead, it is recommended that you read on to see what you need to do to finalize your program.