|
|
Sample Program
Assembled Program: bounce.89z
Source Code: bounce.s
When programming in assembly language, the hardest part can be getting
started. We have written a sample program in TI-89 assembly, using
TIGCC. This program simply makes a small ball bounce around the screen, taking 179 lines of code to
do so. In this program, we demonstrate how to push and pop data to and from the stack, how to draw
to the LCD screen, and how to call functions already in the TI-89's operating system, among other
things.
To run this program, you may download the file from
here, or you can copy the following code and paste it into an open TIGCC
GNU Assembly Source File. The ball is easier to see on Virtual TI than it is on a real TI-89.
| Assembly Source File
|-----------------------------------------------------------------------------------------
| External Symbol Exports
|
.xdef _ti89 | create TI-89 program file
|-----------------------------------------------------------------------------------------
| Variables
|
.equ AMS_jumptable,0xC8
.equ kbhit,4*0x52 | Check for button press, returns keycode
.equ GKeyFlush,4*0x180 | "Forgets" any keys already pressed
.equ ClrScr,4*0x19e | Erases contents of the screen
.equ memcpy,4*0x26a
.equ LCD_MEM, 0x4c00
.equ AMAXX, 154 | The maximum X for the ball anchor (true max 159)
.equ AMAXY, 95 | The maximum Y for the ball anchor (true max 99)
.equ MASK, 0x6FF6 | Ball pattern mask
|-----------------------------------------------------------------------------------------
| 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 %d3-%d7/%a2-%a6,-(%sp) | save registers
lea (%sp,-3840),%sp | grab some memory on the stack
pea 3840 | save 3,840 bytes
pea 0x4C00 | address of LCD
pea (%sp,8) | where to save the screen memory to
move.l 0xC8.w,%a0 | load the AMS jumptable into a0
move.l (%a0,memcpy),%a2 | load the memcpy function
jsr (%a2) | execute the memcpy function to save the LCD
jbsr _main | start the program
pea 3840 | restore 3,840 bytes
pea (%sp,16) | address of screen memory saved on the stack
pea 0x4C00 | address of LCD
move.l 0xC8.w,%a0 | load AMS jumptable into a0
move.l (%a0,memcpy),%a2 | load memcpy function
jsr (%a2) | execute memcpy function to restore the LCD
lea (%sp,3864),%sp | restore the stack pointer
movem.l (%sp)+,%d3-%d7/%a2-%a6 | restore registers
rts | leave the program
|-----------------------------------------------------------------------------------------
| _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 | Find the start of the LCD screen
link.w %a6,#0 | preserve the stack pointer location
move.l AMS_jumptable,%a5 | load the jumptable
move.l ClrScr(%a5),%a4 | load the ClrScr function
jbsr (%a4) | execute the ClrScr function
move.l kbhit(%a5),%a4 | load the kbhit function
move.w #0, %d3 | Set initial x value
move.w #0, %d4 | Set initial y value
move.w #1, %d5 | Set initial dx value
move.w #1, %d6 | Set initial dy value
move.w #MASK, %d7 | Store ball mask
loop:
move.l #0x00001FFF,%d0 | Increase this to slow down program, decrease
| to speed up
timewastingloop:
sub.l #1,%d0 | Loop does nothing but slow the program down
jne timewastingloop
move.l kbhit(%a5),%a4 | load the kbhit function
jbsr (%a4) | execute the kbhit function
tst.w %d0 | Check if key was pressed
jne endp | End if user pressed any key
tst %d5 | Check dx
jgt posx
| 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
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 %d6 | Check dy
jgt posy
| 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
moveimg:
movem.l %d3-%d6,-(%sp) | Save registers
move.w #0x8000,%d5 | Masker
move.w #0,%d6 | Loop counter
clearimg:
add.w #1,%d6 | Increment loop counter
and %d5,%d7 | Check mask
jeq clearimgshortloop | Do not change if not masked
cmp.w #5,%d6 | Separate X and Y components
jlt noswap
sub.w #4,%d6 | Subtract 4 X units
swap %d6
add.w #1,%d6 | Add 1 Y unit
swap %d6
noswap:
add.w %d6,%d3 | Add X offset
swap %d6
add.w %d6,%d4 | Add Y offset
swap %d6
clr.l %d0 | clear for temp calculations
clr.l %d1
| 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 | Copy (remainder + quotient)
clr.w %d2 | Clear quotient
swap %d2 | Move remainder to lower word
add.w %d1,%d0 | %d0 = Pixel byte offset (%d1 now useless)
moveq.l #7,%d1 | Bits are numbered backwards
sub.w %d2,%d1 | Invert remainder (%d2)
| %a3 + %d0 now contains the absolute location of the selected bit.
bclr.b %d1,(%d0,%a3) | Clear bit
sub.w %d6,%d3 | Reset anchor point
swap %d6
sub.w %d6,%d4
swap %d6
clearimgshortloop:
move.w #MASK, %d7 | Replace ball mask
lsr #1,%d5 | Shift %d5 to next position
jcs changeanchorx | If the set bit shifted into the carry, exit
jra clearimg | Loop
changeanchorx:
movem.l (%sp)+,%d3-%d6 | restore used registers
tst %d5 | Check dx
jgt moveimgright | Move right if positive
| Negative dx
sub.w #1,%d3 | Move drawing anchor left
jra changeanchory
moveimgright:
add.w #1,%d3 | Move drawing anchor right
changeanchory:
tst %d6 | Check dy
jgt moveimgdown | Move down if positive
| Negative dy
sub.w #1,%d4 | Move anchor up
jra drawimage
moveimgdown:
add.w #1,%d4 | Move anchor down
drawimage:
movem.l %d3-%d6,-(%sp) | Save registers
move.w #0x8000,%d5 | Masker
move.w #0,%d6 | Loop counter
drawimgloop:
add.w #1,%d6 | Increment loop counter
and %d5,%d7 | Check mask
jeq drawimgshortloop | Do not change if not masked
cmp.w #5,%d6 | Separate X and Y components
jlt noswaptwo
sub.w #4,%d6 | Subtract 4 X units
swap %d6
add.w #1,%d6 | Add 1 Y unit
swap %d6
noswaptwo:
add.w %d6,%d3 | Add X offset
swap %d6
add.w %d6,%d4 | Add Y offset
swap %d6
clr.l %d0 | clear for temp calculations
clr.l %d1
| 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 | Copy (remainder + quotient)
clr.w %d2 | Clear quotient
swap %d2 | Move remainder to lower word
add.w %d1,%d0 | %d0 = Pixel byte offset (%d1 now useless)
moveq.l #7,%d1 | Bits are numbered backwards
sub.w %d2,%d1 | Invert remainder (%d2)
| %a3 + %d0 now contains the absolute location of the selected bit.
bset.b %d1,(%d0,%a3) | Clear bit
sub.w %d6,%d3 | Reset anchor point
swap %d6
sub.w %d6,%d4
swap %d6
drawimgshortloop:
move.w #MASK, %d7 | Replace ball mask
lsr #1,%d5 | Shift %d5 to next position
jcs resetloop | If the set bit shifted into the carry, exit
jra drawimgloop | Loop
resetloop:
movem.l (%sp)+,%d3-%d6 | Restore used registers
jra loop | Loop
endp:
move.l GKeyFlush(%a5),%a4 | load the GKeyFlush function
jbsr (%a4) | execute the GKeyFlush function
unlk %a6 | restore the stack pointer
movem.l (%sp)+,%d3-%d7/%a3-%a5 | restore used registers
rts | exit our program
|-----------------------------------------------------------------------------------------
| Common Symbol Definitions
|
.comm _nostub,2 | create a nostub (non-kernel) program
|