A call does not necessarily call a routine that you
made. The TI-86 has a large ROM that includes many predefined routines;
it is often advantageous to call these routines rather than writing the
calls yourself. ROM calls (any call for that matter) has both input
and output. You may, for instance, load a register with a
certain value before the call (input) and have the call perform an action
on that register, returning a value, manipulating variables or writing
text to the screen (output).
TI has released the equates for only some ROM calls,
and other have been discovered by hacking the ROM. Most of the known
equates have been collected into include files (extension .inc),
it is a good idea to look through the include files to see what calls you
have to work with; if a needed ROM call equate is defined in a certain
include file, then you must include that file by typing: <#include
“filename.inc”>. #include copies all the text from the included
file into your asm program. Both #includes and equates occupy no
memory once compiled, so don’t hesitate to use them. All current
include files can be found on my web page:
http://www.eden.rutgers.edu/~assets/ti86.htm
One of the most common ROM calls is _puts, which
takes the input of a string pointer in HL and gives the output of text
to the LCD (Liquid Crystal Display, or the calculator’s screen)
at the current cursor row and column. _curRow is a RAM address permanently
situated at $c00f; load this with any value between 0 and 7. _curCol
is similar; load it with a value between 0 and 20. <ld a,5 / ld
(_curRow),a / ld (_curCol),a / ld hl,string / call _puts> will put the
text labeled by “string”: to row 5, column 5 of the LCD. A special
kind of string is needed by call _puts, however, because the calculator
needs to know where the string ends. There are two methods used by
the calculator to find the string end; the two types of strings are: 1)
zero-terminated,
strings where the end is marked by zero (also called null-terminated) 2)
length-byte, strings that are lead by either a byte or a word whose
value is the string length. _puts inputs a zero-terminated string.
A second useful call is _clrLCD, which clears the
screen, taking void input and giving the output of a cleared screen.
<call _homeup> loads the cursor locations with 0,0; <call _putc>
puts a character addressed by HL to the LCD at cursor row / col; <call
_runidicoff> will remove the run indicator from the upper left of the screen;
<call _getkey> will pause until a key is pressed, also returning the
keycode in A.
A flag is a bit that indicates a certain system state depending on whether that bit is set or reset. Set usually means that a certain kind of function is enabled. TI-86 has a block of bytes from $c3e5 to $c409 used for system flags. IY always points to $c3e5, meaning that you can access this block using IY offsets from (IY) to (IY+$24). There are three main instructions you can use to manipulate the bits of system flags. Set will set the bit at the given bit number: set bit #,operand. Operand must be a register or an memory location indirectly addressed by a register. Reset has the same format: res bit #,operand. <set 7,a> sets bit 7 of a. <res 0,(iy+18)> is another way of turning off the run indicator; bit 0 of $c3e5+18 is the system flag that controls the run indicator. Not many system flags are known to asm programmers, TI only released knowledge of a very few, and very, very few system flags have been discovered independently. Look at ti86asm.inc for the flags TI released.
It’s often useful to employ calls, returns and jumps
only if a certain condition is met. The F register is called the
flag register because it contains the bits indicating Z80 system states.
Because a programmer can test these bits to look for a set condition, they’re
also called condition bits. Most instructions affect the condition
bits in some way or another; the instructions you have seen so far, however,
do not. There are four condition bits that can be checked (more that
can’t) by the control flow instructions: call, ret, jp and jr.
From this point forward, as an instruction is introduced, the affected
condition bits will be explained as well.
The zero flag is the most common flag, which can
be tested with the condition codes Z and NZ. If you have within
your code <call z,is_zero>, then is_zero will be called iff the zero
flag is set, otherwise it will execute the following instruction.
<ret nz> will return iff the zero flag is reset. Z is set,
in most cases, when the operand becomes zero.
Condition codes C and NC indicate a carry,
a set bit displaced to a position outside the operate byte or borrowed
from an inoperate byte (a better definition will come with experience).
<jr c,has_carried> will make a relative jump to has_carried iff
the carry flag is set.
The other two condition codes can only be used with call, ret
and jp (not jr). The sign flag is usually set if the operand is negative
and reset if the operand is positive. P tests for positivity and
M tests for negativity of the sign flag. <jp m,is_negative> will
make an absolute jump to is_negative iff the sign flag is set. PO
and PE test for parity in most cases, but also has more varied uses.
Use PO to test if the parity is odd (reset) and PE to test if the parity
is even (set). This flag is called P/V (the parity / overflow flag).