ticalc.org
Basics Archives Community Services Programming
Hardware Help About Search Your Account
   Home :: Programming :: Columns and Tutorials :: Usgard Programming: Lesson 2
Usgard Programming: Lesson 2

by Terry Peng

  • CP (Compare)
  • Conditionals Table
  • Loops
    • Crashes
    • DJNZ (Decrease and jump if not zero)
  • Rotations
    • RL,RLA (Rotate left)
    • RLC,RLCA (Rotate left branch carry)
    • RR,RRA (Rotate right branch carry)
    • RRC,RRCA (Rotate right branch carry)
  • Shifts
    • SRL (Shift right logical)
    • SRA (Shift right arithmatic)
    • SLA (Shift left arithmatic)
  • 16-bit rotate and shift
  • Single Bit Instructions
    • BIT (test bit)
    • SET (set bit)
    • RES (reset bit)
  • Logical operators
    • AND (Logical AND)
    • OR (Logical OR)
    • XOR (Logical Exclusive OR)
  • General Purpose Instructions
    • CPL (Complement)
    • NEG (Negate)
    • CCF (Complement Carry Flag)
    • SCF (Set Carry Flag)
  • Calls outside of your program
  • Some shell history
  • Comments on your first program

CP (Compare)

Well, I left off the last lesson talking about using math operations to affect the flags, and thereby make conditional jumps or calls. Well, the problem with this is, you change the accumulator, which you won't always want to do. So there is a command specifically used with flags, CP (Compare). CP is exactly the same as SUB except that CP doesn't affect the acc, only the flags.


Now we can easily do all kinds of conditionals without having to change back the accumulator.

Instructions Result
cp b \ jr z,lbl jump to lbl if a = b
cp b \ jr nz,lbl jump to lbl if a != b
cp b \ jr c,lbl jump to lbl if a=a
cp b+1 \ jr c,lbl jump to lbl if a<=b, ie b>a
cp b+1 \ jr nc,lbl jump to lbl if a>b, ie b<=a
cp b \ jr nc,lbl jump to lbl if a<=b, ie b


Loops

One of the most powerful things in programming is a loop. Loops can be good, if you know how to use them. Note that we would never want to have a loop that goes on forever, because then the program could never exit! You can't simply press [on] and quit like in ti-basic.


Crashes

This brings up the subject of crashes: there are a few main causes of crashes most of which I won't go into detail about just yet, but one of them is an infinite loop. When this happens, don't fret; take out ONE AAA battery and press [on] ten times.

Back to Loops

So how would you do a loop? Lets say you wanted to go through the loop 6 times. You should load a variable with 6, decrease it 6 times, and then jump back to the beginning if the z flag isn't set, like so:

        ld a,6     ;number of times to loop
Loop:
        -code-
        -code-
        -code-
        -code-
        dec a      ;decrease a once
        jr nz,Loop ;if it isn't 0, go to loop

But there is an even easier way to do this! A special instruction djnz, decreases b, and then does a relative jump if b is not zero. It always works on register b.

       ld b,6   ;number of times to loop
Loop:
       -code-
       -code-
       -code-
       -code-
       djnz Loop  ;decrease a once
                  ;if it isn't 0, go to loop

So why would we even want to do it the first way (not DJNZ?) well, that is a good way to do a FOR loop. You can choose whether you want the register to go up or down, and by how much. You can end it with a CP so that the loop doesn't end at zero!

       ld a,3     ;start number
Loop:
       -code-
       -code-
       -code-
       -code-
       add a,4    ;the change you want each loop
       cp 23      ;the value that ends the loop

I believe this is equivalent to For(a,3,23,4) in ti-basic and for( a = 3; a != 23; a = a + 4 ) in C/C++. Note that whenever you do a loop, be careful not to change the register inside the loop!


Rotations

Require a parameter (register)  BIT (CF= carry flag)
=========================================================
RL		      CF <- b7 b6 b5 b4 b3 b2 b1 b0 <- CF
RR		      CF -> b7 b6 b5 b4 b3 b2 b1 b0 -> CF
RLC		      CF <- b7 b6 b5 b4 b3 b2 b1 b0 <- b7
RRC		      b0 -> b7 b6 b5 b4 b3 b2 b1 b0 -> CF

RL = Rotate Left	  RLC = Rotate Left Branch Carry
RR = Rotate Right	  RRC = Rotate Right Branch Carry

Do not require a parameter
=========================================================
RLA-Rotate Left on the Acc
RRA-Rotate Right on the Acc
RLCA-Rotate Left Branch Carry on the Acc
RRCA-Rotate Right Branch Carry on the Acc
The chart is self explanatory. Each bit is basically rotated to the next bit.
Shifts (all require a parameter register)
=========================================================
SRL		    zero -> b7 b6 b5 b4 b3 b2 b1 b0 -> CF
SRA		    b7   -> b7 b6 b5 b4 b3 b2 b1 b0 -> CF
SLA		    CF   <- b7 b6 b5 b4 b3 b2 b1 b0 <- zero

SRL = Shift Right Logical
SRA = Shift Right Arithmetic
SLA = Shift Left Arithmetic

SRL

Shifts the bits right Logically. B7 is replaced by a zero. Don't use this for math. Use for graphics and general stuff.

SRA

Shifts the bits right Arithmatically. Use this to divide by two. B7 is saved so that the register will keep its negativity.

SLA

Shifts the bits left. Use to multiply by two, or for work with graphics.


Bit instructions

Bit has two parameters: the bit, and the register.

  bit    7,a
would test bit 7 of register a. BIT works on all registers (not pairs). BIT copies the bit in question to the zero flag. So if the bit=1 then the zero flag=1. WATCH OUT! if the bit=0 the zero flag is RESET! don't think that because it=0, the zero flag is set.

SET has two parameters: the bit, and the register.

  set    7,a
would set bit 7 of register a. SET works on all registers (not pairs).

RES has two parameters: the bit, and the register.

  bit    7,a
would reset bit 7 of register a. RES works on all registers (not pairs).


16 bit rotate and shift

The shift and rotate instructions are only for 8 bit registers. So how do you shift/rotate a 16 bit register? Well, you have to put instructions together.

to SRL BC:
   srl b
   rr c
to SRA BC:
   sra b
   rr c
to SLA BC:
   sla c
   rl b
to RR BC:
   rr b
   rr c
to RL BC:
   rl c
   rl b
to RRC BC:
   srl b
   rr c
   jr nc,label1
   set 7,b
label1:
to RLC BC:
   sla c
   rl b
   jr nc,label2
   set 0,c
label2:
If you study the bits, you will see that those combinations work.
Logical operators - AND

     and b

This instruction takes the bits of the accumulator, and the bits of the parameter, and it sees which bits are common to BOTH. The accumulator is loaded with a new byte, with only the common bits set. Note that all logical operators have the same possible parameters, and will change the flags.

      a = %01010101
      b = %11110000
      =============
new   a = %01010000
You can also use it on straight data:
      and  5

      a = %01010101
      5 = %00000101
      =============
new   a = %00000101
Remember that anytime the register b,c,d, or e can be used, so can (hl)
      a = %01010101
   (hl) = %10101010
      =============
new   a = %00000000

Uses

What use is AND? Well, there are many uses, but a common one is called a MASK. Let's say that, you only want the three low bits of the acc. You can AND %111 (same as %00000111), and only the bottom three bits will be preserved! This would be called MASKING out the top five bits.

       a = %qrstuwxyz
    %111 = %000000111
       ==============
new    a = %000000xyz


Logical operators - OR

OR is simialar to AND. OR takes the bits that are present in either register, and it puts all those bits in the acc.

      a = %01010101
      b = %11110000
      =============
new   a = %11110101

      a = %01010101
      5 = %00000101
      =============
new   a = %01010101

      a = %01010101
   (hl) = %10101010
      =============
new   a = %11111111
Uses

Most uses of OR are in graphics, which you will learn about later.


Logical operators - XOR (exclusive or)

XOR is simialar to AND. XOR takes the bits that are present in either register, but not both and it puts all those bits in the acc. So in other words, the two bits being compare must a a 0 and a 1 for the new bit to be set. An example illustrates best:

       a = %01010101
       b = %11110000
       =============
new    a = %10100101

       a = %01010101
       5 = %00000101
       =============
new    a = %01010000

       a = %01010101
    (hl) = %10101010
       =============
new    a = %11111111

Uses

One interesting use of XOR is crude encryption! Did you notice that if you XOR the acc with a value, then XOR it again with the same value, the acc goes back to normal? Because if the bit in the value is 0, then the acc's bit won't be changed both times. But if the bit in the value is one, then if the acc bit is 1, then 1 XOR 1 = 0 XOR 1 = 1 if the acc bit is 0, then 0 XOR 1 = 1 XOR 1 = 0

                a = %01010101
Arbitrary value   = %11100111
=============================
        new     a = %10110010
Arbitrary value   = %11100111
=============================
        new     a = %01010101 matches the original value!


General Purpose Instructions

CPL (complement)

This reverses all the bits in the acc.

     cpl

before:  a=%11010101
after:   a=%00101010

NEG (negate)

This negates the acc.

     neg

before: a=  20
after:	a= -20,duh

SCF (set carry flag)

This sets the carry flag. One good use for this is during a routine, to specify an error, you could set the carry flag and return.

   call  &routine
   jp    c,&error_handler

CCF (complement carry flag)

I can only think of one good use for this (there must be more though). Let's say that, during a routine, you have made a comparison. If the carry flag isn't set, then you know there has been an error (in this specific routine).

Well, if you put ret nc, then it would return, but with the carry flag reset, signifying no error! So you can put

  ccf
  ret c
Note that you shouldn't use
  scf
  ccf
to reset the carry flag, use
  or a
instead. It has no effect on the acc, but it resets the carry flag.


Calls outside your program

Now, you may be thinking, "OK, I know lots of instructions, and I know how to use conditionals, form loops, etc. But how do I do stuff like graphics, and other things (even simple things like clearing the screen) ?!" Well, now is the time to do some research on your own. There are several documents about certain calls named ROM CALLS. These are, calls to the ROM (duh). Since the routines are not contained within your program, they do not take up any extra space. There are also some special Usgard routines. These are routines stored within Usgard, the shell.

Look in the C:\Usgard\docs\prgm directory. Carefully read over the following docs:

zsfnlib.txt- A description of all the original zshell ROM CALLS
usgardfn.txt- A description of all Usgard routines and new ROM CALLS

You make a ROM CALL by typing

   call ROM_ROUTINE
...don't use &.

One excellent source of information is ZShell40.hlp- This is a windows help file. Just run it from Explorer/File Manager, or even make a shortcut. You can find all sorts of good information at www.ticalc.org, if you search the archives.


Some shell history

Well, as you probably know, the first ASM shell ever released for a TI calc was Zshell. Zshell was great for its time, but lets face it, it is completely obsolete with all the new shells (especially Usgard). Something you might want to know about Zshell is that it had a different way of doing ROM CALLS, CALLs, and JPs, and that is:

ROM_CALL(routine)
CALL_(label)
JUMP_(label)

Usgard also has extra features like libraries, interrupts, TSRs, more ROM CALLS, routines inside Usgard, RELOCATION!, TI-OS variable access, user selected interface, and even more that I probably can't remember right now. You'll learn about all this good stuff later.

Zshell was much less effecient and powerful than Usgard, but it was an amazing accomplishment for its time. Zshell 4.0, btw, was made by: (in no particular order)

  • Magnus Hagander
  • Rob Taylor
  • Dan Eble

Usgard 1.1 (the latest at the time of this writing) was(is) made by

  • Andreas Ess
  • Jimmy Mardell
  • Sam Davies
  • Austin Butler
  • Mel Tsai

Comments on your first program

Finally, that sample program, explained!

#include "usgard.h"
                                ;include all of the useful aliases
.org 0                          ;put this at the beginning of program
.db "My first program",0        ;a description string, zero-terminated

     call CLEARLCD      ;this is a ROM CALL, that, you
                        ;guessed it, clears the screen
     ld hl,0		;loads hl with 0
     ld (CURSOR_ROW),hl ;loads 0 into the CURSOR_ROW and
     ld hl,&Text        ;hl now is "pointing at" the text string
     call D_ZT_STR      ;ROM CALL, display zero terminated string
Wait_4_key:             ;a label
     call GET_KEY       ;load the code of last keypress into the acc
     cp	0               ;is it 0? (0 means no key pressed)
     ret nz             ;if not, then return to usgard
     jr	Wait_4_key      ;if so, then goto the Wait_4_Key label
Text:                   ;another label
.db "Hello World!",0    ;the string

.end                    ;end of program
                        ;be sure to leave several blank lines after
                        ;.end

  Copyright © 1996-2012, the ticalc.org project. All rights reserved. | Contact Us | Disclaimer