Assembly Programming on the TI-89
Download
Report
Transcript Assembly Programming on the TI-89
Assembly Programming
on the TI-89
Created By:
Adrian Anderson
Trevor Swanson
TI-89 Calculator
• Released in 1998 as a more
portable version of the TI-92,
which was much larger and had
a QWERTY keyboard.
• Evaluates and performs
algebraic expressions
• Performs calculus functions
• Can graph in several
coordinate systems, including
3D
• Has “pretty print”, meaning it
draws algebraic expressions
(such as radicals and
exponents) in a mathematical
way
Assembly vs. TI-Basic
• TI-Basic is simpler, but more
restricted
- Quick access to high-level features
- Many ROM functions cannot be called
from TI-Basic
- Strict rules when calling other procedures
- Must use the graph screen for pixel work
in TI-Basic
• Assembly is much faster
• Assembly programs cannot be
edited on the calculator
Motorola 68K Processor
• Sixteen 32-bit registers and one 16-bit
Condition Code Register (CCR)
– The first 8 registers are data registers which can hold
values associated with the assembly program
– The next 8 are address registers which can serve as
software stack pointers, index registers, or base
address registers. The eighth of the address registers
is the user stack pointer, a register which always holds
the top value of the system stack
– The final register, the 16-bit CCR, holds the conditions
of the information from the most recent operation.
These include carry, overflow, extend, zero, and
negative.
Motorola 68K Processor
Assembly Length Modifiers
• Adding “.b” to the end of an instruction
will make the instruction move data in
bytes
• Adding ".w" to the end of an instruction
will cause the processor to treat the
arguments as words.
• Adding ".l" to the end of an instruction will
treat the arguments as long words (32
bits).
• Example: move.w #1,-(a7) .
Pushes the number 1 to the stack as a
word.
Assembly Commands
•
Movement Instructions
– move – Moves the data from one address to another
– movem – Moves data from multiple locations to adjacent memory
locations
– clr – Clears the contents of a register.
– lea – Loads an address to a register.
– pea – Pushes data to the stack.
•
Arithmetic Instructions
– add – Adds the source to the destination, and places it in
destination.
– addx – Like add, but adds 1 if the extend flag is set.
– sub – Subtracts the source from the destination, and places the
result in the destination
– neg – Subtracts the data in the address from 0.
– cmp – Subtracts the source from the destination, but does not store
the result. Used to change the CCR.
– muls.w – Multiplies the source by the destination, and places the
result in the destination.
– divs.w – Divides the destination by the source, and places the result
in the destination.
Branch Instructions
– bra – Sets the Program Counter (PC) ahead by a number of
bytes equal to the argument.
– b(cc) – Sets the PC forward by a number of bytes equal to the
argument if a certain condition is set.
– Condition Tests:
•
•
•
•
•
•
•
•
•
cs - True if the Carry bit is set
cc - True if the Carry bit is cleared
eq - "Equal to Zero" - True if the Zero bit is set
ne - "Not Equal to Zero" - True if the Zero bit is cleared
vs - True if the Overflow bit is set
vc - True if the Overflow bit is cleared
mi - "Minus" - True if the Negative bit is set
pl - "Plus" - True if the Negative bit is cleared
ge - "Greater than or Equal to Zero" - True if the Negative and
Overflow are both cleared, or if they are both set.
• lt - "Less than or Equal to Zero" - True if the Negative bit is set and the
Overflow bit is cleared, or vice versa.
• gt - "Greater than Zero" - As ge, but the Zero bit must also be cleared.
• le - "Less than Zero" - As lt, but true if the Zero bit is set, regardless of
the other conditions.
Rotate and Shift Instructions
– asl – "Arithmetic Shift Left" - Moves the Most Significant Bit
(MSB) into the Carry bit in the CCR, shifts each bit to the left, and
inserts a 0 into the Least Significant Bit (LSB).
– lsl – Works exactly as asl.
– asr – Moves the LSB into the Carry bit in the CCR, shifts each bit
to the right, and inserts a copy of the old MSB to the new MSB.
– lsr – As asl, but places a zero in the MSB.
– rol – Shifts each bit to the left, moves the MSB to the Carry flag in
the CCR, and moves the Carry flag into the LSB.
– roxl – As rol, but the Carry flag is then copied to the Extend bit.
– ror – Shifts each bit to the right, moves the LSB to the Carry flag
in the CCR, and moves the Carry flag into the MSB.
– roxr – As ror, but the Carry flag is then copied to the Extend bit.
– swap – Exchanges the high word in the specified register with the
low word.
Binary Logic
– not – Flips all bits in the destination
– and – Performs a bitwise AND (destination bit is true only if both
input bits are true) of the two values, and places the result in the
destination
– andi – As and, but the source is a constant
– or – Performs a bitwise OR (destination bit is true if either source
bit is true) of the two values, and places the result in the
destination
– ori – As or, but the source is a constant
– eor – Performs a bitwise exclusive OR (destination bit is true of
one source bit is true and one is false) of the two values, and
places the result in the destination
– eori – As eor, but the source is a constant
A Sample Program
• Bounce.89z
• A small ball continuously bounces
off of the edges of the screen
• Program flow:
–
–
–
–
–
–
–
Initialize variables and clear screen
Runs a loop to slow the program down
Check for keyboard press
Switch directions if ball hits a wall
Erase the ball
Moves the ball in the correct direction
Draws the ball
Advanced Techniques
• Masking
– A mask determines which bits
will be set and which will not be set
– Often uses and to erase unwanted bits
• Jumptable
– List of the locations of certain functions in
memory
– All functions can be called by addresses
Declarations
| Assembly Source File
|----------------------------------------------------------------------------------------| External Symbol Exports
|
.xdef _ti89
| create TI-89 program file
|----------------------------------------------------------------------------------------| Variables
|
.equ AMS_jumptable,0xC8
.equ
.equ
.equ
.equ
kbhit,4*0x52
GKeyFlush,4*0x180
ClrScr,4*0x19e
memcpy,4*0x26a
.equ
.equ
.equ
.equ
LCD_MEM, 0x4c00
AMAXX, 154
AMAXY, 95
MASK, 0x6FF6
| Check for button press, returns keycode
| "Forgets" any keys already pressed
| Erases contents of the screen
| The maximum X for the ball anchor (true max 159)
| The maximum Y for the ball anchor (true max 99)
| Ball pattern mask
Saving the Screen
|--------------------------------------------------------------------------------| ASM_loader - prepares the program to be run
|
saves and restores the LCD screen and executes the _main method
| Code originally from Techno-Plaza's tutorial routines:
|
http://www.technoplaza.net/assembly/
ASM_loader:
movem.l
lea
pea
pea
pea
move.l
move.l
jsr
jbsr
pea
pea
pea
move.l
move.l
jsr
lea
movem.l
rts
%d3-%d7/%a2-%a6,-(%sp)
(%sp,-3840),%sp
3840
0x4C00
(%sp,8)
0xC8.w,%a0
(%a0,memcpy),%a2
(%a2)
_main
3840
(%sp,16)
0x4C00
0xC8.w,%a0
(%a0,memcpy),%a2
(%a2)
(%sp,3864),%sp
(%sp)+,%d3-%d7/%a2-%a6
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
save registers
grab some memory on the stack
save 3,840 bytes
address of LCD
where to save the screen memory to
load the AMS jumptable into a0
load the memcpy function
execute the memcpy function to save the LCD
start the program
restore 3,840 bytes
address of screen memory saved on the stack
address of LCD
load AMS jumptable into a0
load memcpy function
execute memcpy function to restore the LCD
restore the stack pointer
restore registers
leave the program
Initializing
|----------------------------------------------------------------------| _main - Program starts at this label
|
| Basic Program Flow:
| • Clear screen and set variables
| • Slow-down loop
| • Check for keyboard press
| • Switch directions if ball hits a wall
| • Erase ball
| • Move the ball based on new directions
| • Draw ball
| • Return to "Slow-down loop"
_main:
movem.l
%d3-%d7/%a3-%a5,-(%sp)
| save used registers
| Clear the screen
move.l
#LCD_MEM,%a3
link.w
%a6,#0
move.l
AMS_jumptable,%a5
move.l
ClrScr(%a5),%a4
jbsr
(%a4)
move.l
kbhit(%a5),%a4
|
|
|
|
|
|
Find the start of the LCD screen
preserve the stack pointer location
load the jumptable
load the ClrScr function
execute the ClrScr function
load the kbhit function
move.w
move.w
move.w
move.w
move.w
|
|
|
|
|
Set initial x value
Set initial y value
Set initial dx value
Set initial dy value
Store ball mask
#0, %d3
#0, %d4
#1, %d5
#1, %d6
#MASK, %d7
Loops and Direction Testing
loop:
move.l
#0x00001FFF,%d0
timewastingloop:
sub.l
#1,%d0
jne
timewastingloop
| Increase this to slow down program, decrease
| to speed up
| Loop does nothing but slow the program down
move.l
jbsr
tst.w
jne
kbhit(%a5),%a4
(%a4)
%d0
endp
|
|
|
|
tst
jgt
%d5
posx
| Check dx
load the kbhit function
execute the kbhit function
Check if key was pressed
End if user pressed any key
| X is moving in a negative direction (to the left)
cmp
#-1,%d3
| Has X hit left wall?
jne
testy
| If it doesn't hit a wall, continue
| X is moving to the left and has hit the left wall
move.w
#1, %d5
| Switch direction
jra
testy
Direction Testing 2
posx:
| X is moving in a positive direction (to the right)
Cmp
#AMAXX, %d3
| Has X hit right wall?
jle
testy
| Continue if it doesn't hit a wall
| X is moving right and has hit the right wall
move.w
#0, %d5
| Switch direction
testy:
tst
jgt
%d6
posy
| Check dy
| Y is moving in a negative direction (up)
tst
%d4
| Has Y hit top?
jne
moveimg
| If it doesn't hit a wall, continue
| Y is moving up and has hit the top wall
move.w
#1, %d6
| Switch direction
jra
moveimg
posy:
| Y is moving in a positive direction (down)
cmp
#AMAXY, %d4
| Has Y hit bottom?
jle
moveimg
| Continue if it doesn't hit a wall
| Y is moving down and has hit the bottom wall
move.w
#0, %d6
| Switch direction
Moving and Clearing
moveimg:
movem.l
move.w
move.w
%d3-%d6,-(%sp)
#0x8000,%d5
#0,%d6
| Save registers
| Masker
| Loop counter
clearimg:
add.w
and
jeq
#1,%d6
%d5,%d7
clearimgshortloop
| Increment loop counter
| Check mask
| Do not change if not masked
#5,%d6
noswap
#4,%d6
%d6
#1,%d6
%d6
| Separate X and Y components
cmp.w
jlt
sub.w
swap
add.w
swap
noswap:
add.w
swap %d6
add.w
swap
clr.l
clr.l
| Subtract 4 X units
| Add 1 Y unit
%d6,%d3
| Add X offset
%d6,%d4
%d6
%d0
%d1
| Add Y offset
| clear for temp calculations
Moving and Clearing 2
| Convert X and Y to one dimension
| Y bytes = Y rows * 240 pixels/row / 8 pixels/byte
move.w %d4,%d0
mulu.w #30,%d0
| X bytes = X columns / 8 columns/row + Remainder
move.w %d3,%d1
divu.w #8,%d1
| Save remainder
move.l %d1,%d2
clr.w
%d2
swap
%d2
| Copy (remainder + quotient)
| Clear quotient
| Move remainder to lower word
add.w
%d1,%d0
moveq.l #7,%d1
sub.w
%d2,%d1
| %d0 = Pixel byte offset (%d1 now useless)
| Bits are numbered backwards
| Invert remainder (%d2)
| %a3 + %d0 now contains the absolute location of the selected bit.
bclr.b
%d1,(%d0,%a3) | Clear bit
sub.w
swap
sub.w
swap
%d6,%d3
%d6
%d6,%d4
%d6
clearimgshortloop:
move.w #MASK, %d7
lsr
#1,%d5
jcs
changeanchorx
jra
clearimg
| Reset anchor point
|
|
|
|
Replace ball mask
Shift %d5 to next position
If the set bit shifted into the carry, exit
Loop
Moving Image
changeanchorx:
movem.l (%sp)+,%d3-%d6
tst
%d5
jgt
moveimgright
| Negative dx
sub.w
#1,%d3
jra
changeanchory
moveimgright:
add.w
#1,%d3
changeanchory:
tst
%d6
jgt
moveimgdown
| Negative dy
sub.w
#1,%d4
jra
drawimage
moveimgdown:
add.w
#1,%d4
| restore used registers
| Check dx
| Move right if positive
| Move drawing anchor left
| Move drawing anchor right
| Check dy
| Move down if positive
| Move anchor up
| Move anchor down
Drawing Image
drawimage:
movem.l
move.w
move.w
%d3-%d6,-(%sp)
#0x8000,%d5
#0,%d6
drawimgloop:
add.w
#1,%d6
and
%d5,%d7
jeq
drawimgshortloop
cmp.w
jlt
sub.w
swap
add.w
swap
noswaptwo:
add.w
swap
add.w
swap
clr.l
clr.l
| Save registers
| Masker
| Loop counter
| Increment loop counter
| Check mask
| Do not change if not masked
#5,%d6
noswaptwo
#4,%d6
%d6
#1,%d6
%d6
| Separate X and Y components
%d6,%d3
%d6
%d6,%d4
%d6
%d0
%d1
| Add X offset
| Subtract 4 X units
| Add 1 Y unit
| Add Y offset
| clear for temp calculations
| Convert X and Y to one dimension
| Y bytes = Y rows * 240 pixels/row / 8 pixels/byte
move.w
%d4,%d0
mulu.w
#30,%d0
Drawing Image 2
| X bytes = X columns / 8 columns/row + Remainder
move.w
%d3,%d1
divu.w
#8,%d1
| Save remainder
move.l
%d1,%d2
clr.w
%d2
swap
%d2
| Copy (remainder + quotient)
| Clear quotient
| Move remainder to lower word
add.w
moveq.l
sub.w
| %d0 = Pixel byte offset (%d1 now useless)
| Bits are numbered backwards
| Invert remainder (%d2)
%d1,%d0
#7,%d1
%d2,%d1
| %a3 + %d0 now contains the absolute location of the selected bit.
bset.b
%d1,(%d0,%a3) | Clear bit
sub.w
swap
sub.w
swap
%d6,%d3
%d6
%d6,%d4
%d6
drawimgshortloop:
move.w
#MASK, %d7
lsr
#1,%d5
jcs
resetloop
jra
drawimgloop
| Reset anchor point
|
|
|
|
Replace ball mask
Shift %d5 to next position
If the set bit shifted into the carry, exit
Loop
Cleanup
resetloop:
movem.l
jra
endp:
move.l
jbsr
unlk
movem.l
rts
(%sp)+,%d3-%d6
loop
| Restore used registers
| Loop
GKeyFlush(%a5),%a4
(%a4)
%a6
(%sp)+,%d3-%d7/%a3-%a5
|
|
|
|
|
load the GKeyFlush function
execute the GKeyFlush function
restore the stack pointer
restore used registers
exit our program
|-----------------------------------------------------------------------------| Common Symbol Definitions
|
.comm
_nostub,2
| create a nostub (non-kernel) program
Resources
•
Motorola 68k Family Programmer's Reference
– http://www.freescale.com/files/archives/doc/ref_manual/M68000PR
M.pdf
•
Techno-Plaza's TIGCC Assembly Lessons
– http://www.technoplaza.net/assembly/
•
Virtual TI Emulator
– http://www.technoplaza.net/downloads/download.php?program=67
•
Ticalc.org
– http://www.ticalc.org/
•
TI-89/TI-92 Plus Developer's Guide
– http://education.ti.com/downloads/pdf/us/sdk8992pguide.pdf
•
The Official TIGCC Site
– http://tigcc.ticalc.org/
•
TI-89 Graphing Calculator Product Center
– http://education.ti.com/us/product/tech/89/features/features.html
Black Slide