Re: A simple ASM request (hopefully ti-86, but any will do)
[Prev][Next][Index][Thread]
Re: A simple ASM request (hopefully ti-86, but any will do)
On Mon, 10 Nov 1997 18:38:55 -0500, Tim Brierley <brierley@erols.com>
wrote:
>Right now, i only know the ti-BASIC, and would like to learn ASM. I am
>a pretty good basic programmer, and have been trying to teach myself ASM
>by just looking at sample code (it didn't work, but i am still trying
>:-) If someone out there could write a program (in ASM) that is a
>high-low guessing game, I would be very greateful. The program is
>simple, and used by most people as a first program for it's use of if's
>loop's, random, input, and output all in a very simple program. If you
>sont know what i am talking about, here it is:
>
>The calc picks a number between 1 and 100.
>The person guesses a number.
>The calc will say "higher" if the person is too low and should guess
>higher.
>The calc will say "lower" if the person is too high and should guess
>lower.
>The calc will say "correct" if the person guesses correctly.
>If the person was not right ("higher" or "lower") then the program will
>repeat with the same random number.
>If the person was right, then the calc will tell the person how many
>turns it took and will exit.
>
>That is it.
>If you do decide to help me, please do not add anything to the program
>to make it easier to follow. Comments would be greatly appreciated
>also. Thanks ahead of time :-)
>
>you can either post the code here, or (preferably) send it to me at
>brierley@erols.com
>
>Tim Brierley
>brierley@erols.com
>
>
Here's an example. Some background on this. It was about a year and
half ago a friend let me know that the TI-85 used the Z-80 processor
and people were writing in assembly language with it. Since I did a
bunch of programming on CP/M boxes 15 years ago, this got me excited
and I started porting some of my old toys, including my own port of
Ron Cain's small C Compiler. Ron Cain's Small C Compiler and Aztec C
were the compilers under CP/M that I used to learn C. Anyhow as one of
my test programs I wrote a HILO game. This runs under Z-Shell 4.0 on a
TI-85. Here's the C program and the resulting assembly language from
the compiler:
----- HILO.C -----
#include <zshell.h>
/* cheap implementation of rand() */
int lastRand;
int numToGuess;
/* K_3 =$12 ;3 W */
/* K_6 =$13 ;6 S */
/* K_9 =$14 ;9 N */
/* K_2 =$1A ;2 V */
/* K_5 =$1B ;5 R */
/* K_8 =$1C ;8 M */
/* K_0 =$21 ;0 Y */
/* K_1 =$22 ;1 U */
/* K_4 =$23 ;4 Q */
/* K_7 =$24 ;7 L */
/* 0 1 2 3 4 5 6 7 8
9 */
int keys[] = { 0x21, 0x22, 0x1a, 0x12, 0x23, 0x1b, 0x13, 0x24, 0x1c,
0x14 };
rand()
{
lastRand = abs((lastRand * 16388 + 1) % 16387);
return(lastRand);
}
getDigit()
{
int key;
int a;
int i;
char *s;
char b[2];
key = 10;
while (key == 10)
{
a = waitKey();
for (i=0; i<10; i++)
{
if (keys[i] == a)
{
key = i;
}
}
}
s = "0123456789*";
b[0] = *(s + key);
b[1] = 0;
puts(b);
return(key);
}
getNum()
{
return(getDigit() * 10 + getDigit());
}
main()
{
int i;
int guess;
int count;
clearLCD();
puts("The High - Low Game ");
puts("=====================");
puts("I'm thinking of a ");
puts("number between 1 and ");
puts("100. Press enter when");
puts("ready................");
while (!chkEnter())
{
numToGuess = 999;
while (numToGuess > 100)
{
numToGuess = rand() / 100; /* keep running random numbers
*/
}
/* numToGuess = 50; */
}
/* 123456789.123456789.1 */
/* putw(numToGuess); */
guess = 1000;
count = 0;
while (guess != numToGuess)
{
puts("What's your guess? ");
guess = getNum();
count++;
if (guess == numToGuess)
{
puts(" You Win!!!! ");
puts("It only took");
putw(count);
puts(" tries.");
}
if (guess < numToGuess)
{
puts(" Too Low... ");
}
if (guess > numToGuess)
{
puts(" Too High ... ");
}
}
puts("Press Exit ");
waitExit();
}
----- HILO.ASM -----
;* * * Small-C/Plus Version 1.00 * * *
; Cain, Van Zandt, Hendrix, Yorston
; 25th February 1988
;
; Modified by Edward Thompson for TI-85
; Send Comments to edt@infinet.com
#include "ti.h"
.org 0
.db "hilo",0
CALL_(InitEmXX)
JUMP_(qmain)
.export qclearLCD
qclearLCD:
ROM_CALL(CLEARLCD)
ld hl,0
ld ($800C),hl ; reset XY position to top of screen
RET
.export qwaitExit
qwaitExit:
WaitKey:
ld a,0
call GET_KEY
cp K_EXIT
jr nz,WaitKey
RET
qwaitKey:
LD A,0
CALL GET_KEY
CP 0
JR Z,qwaitKey
LD H,0
LD L,A
RET
qchkEnter:
CALL GET_KEY
CP K_ENTER
JR NZ,qchEn2
LD HL,1
RET
qchEn2:
LD HL,0
RET
qchkExit:
CALL GET_KEY
CP K_EXIT
JR NZ,qchkE2
LD HL,1
RET
qchkE2:
LD HL,0
RET
qbusyOn:
ROM_CALL(BUSY_ON)
RET
qbusyOff:
ROM_CALL(BUSY_OFF)
RET
qputw:
LD HL,2
ADD HL,SP
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
ROM_CALL(D_HL_DECI)
RET
; void putPixel(int x, int y)
qputPixel:
LD HL,4 ; first arg == x coordinate (just beyond
ret adr)
ADD HL,SP
LD B,(HL)
LD HL,2 ; second arg = y coordinate
ADD HL,SP
LD C,(HL)
LD A,63
SUB C
LD C,A ; Pixel now in B,C in preperation for
FindPixel
LD A,4
OUT (5),A ; select ROM page
ROM_CALL(FIND_PIXEL)
LD DE,$FC00
ADD HL,DE ; HL holds the offset to the byte of memory
XOR (HL) ; A holds the pixel bit set.
LD (HL),A
RET
qputs:
LD HL,2
ADD HL,SP
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
ROM_CALL(D_ZT_STR)
RET
;
;Test if DE >= HL (unsigned)
CCUGE:
CALL_(CCUCMP)
RET NC
DEC HL
RET
;
;Test if DE < HL (unsigned)
CCULT:
CALL_(CCUCMP)
RET C
DEC HL
RET
;
;Test if DE > HL (unsigned)
CCUGT:
EX DE,HL
CALL_(CCUCMP)
RET C
DEC HL
RET
;
;Test if DE <= HL (unsigned)
CCULE:
CALL_(CCUCMP)
RET Z
RET C
DEC HL
RET
;
;Common routine to perform unsigned compare
;carry set if DE < HL
;zero/nonzero set accordingly
CCUCMP: LD A,D
CP H
JR NZ,CUCMP1
LD A,E
CP L
CUCMP1: LD HL,1
RET
;
;Shift DE arithmetically right by HL and return in HL
CCASR: EX DE,HL
DEC E
RET M ; 7/2/82 jrvz
LD A,H
RLA
LD A,H
RRA
LD H,A
LD A,L
RRA
LD L,A
JR CCASR+1
;Shift DE arithmetically left by HL and return in HL
CCASL: EX DE,HL
CCASL4: DEC E
RET M ; jrvz 7/2/82
ADD HL,HL
JR CCASL4
;Subtract HL from DE and return in HL
CCSUB:
EX DE,HL
OR A
SBC HL,DE
RET
;return absolute value of argument on stack (under return address)
QABS:
POP BC
POP HL
PUSH HL
PUSH BC
LD A,H
AND A
RET P
;Form the two's complement of HL
CCNEG: CALL_(CCCOM)
INC HL
RET
;Form the one's complement of HL
CCCOM: LD A,H
CPL
LD H,A
LD A,L
CPL
LD L,A
RET
;Multiply DE by HL and return in HL
CCMULT:
LD B,H
LD C,L
LD HL,0
CCMLT1: LD A,C
RRCA
JR NC,CMLT2
ADD HL,DE
CMLT2: XOR A
LD A,B
RRA
LD B,A
LD A,C
RRA
LD C,A
OR B
RET Z
XOR A
LD A,E
RLA
LD E,A
LD A,D
RLA
LD D,A
OR E
RET Z
JR CCMLT1
;Divide DE by HL and return quotient in HL, remainder in DE
CCDIV: LD B,H
LD C,L
LD A,D
XOR B
PUSH AF
LD A,D
OR A
BIT 7,A
CALL_NZ(CCDENEG)
LD A,B
OR A
BIT 7,A
CALL_NZ(CCBCNEG)
LD A,16
PUSH AF
EX DE,HL
LD DE,0
CCDIV1: ADD HL,HL
LD A,E
RLA
LD E,A
LD A,D
RLA
LD D,A
OR E
JR Z,CCDIV2
CALL_(CCPBCDE)
BIT 7,A
JUMP_NZ(CCDIV2)
LD A,L
OR 1
LD L,A
LD A,E
SUB C
LD E,A
LD A,D
SBC A,B
LD D,A
CCDIV2: POP AF
DEC A
JR Z,CCDIV3
PUSH AF
JR CCDIV1
CCDIV3: POP AF
RET P
CALL_(CCDENEG)
EX DE,HL
CALL_(CCDENEG)
EX DE,HL
RET
CCDENEG: LD A,D
CPL
LD D,A
LD A,E
CPL
LD E,A
INC DE
RET
CCBCNEG: LD A,B
CPL
LD B,A
LD A,C
CPL
LD C,A
INC BC
RET
CCRDEL: LD A,E
RLA
LD E,A
LD A,D
RLA
LD D,A
OR E
RET
CCPBCDE: LD A,E
SUB C
LD A,D
SBC A,B
RET
;logical negation
CCLNEG:
LD A,H
OR L
JR NZ,$+5
LD L,1
RET
LD HL,0
RET
;
; EXECUTE SWITCH STATEMENT
;
; HL = SWITCH VALUE
;(SP) -> SWITCH TABLE
; DW ADDR1, VALUE1
; DW ADDR2, VALUE2
; ...
; DW 0
; [JMP DEFAULT]
;
CCSWITCH:
EX DE,HL ;DE = SWITCH VALUE
POP HL ;HL -> SWITCH TABLE
SWLOOP:
LD C,(HL)
INC HL
LD B,(HL) ;BC -> CASE ADDR, ELSE 0
INC HL
LD A,B
OR C
JR Z,SWEND ;DEFAULT OR CONTINUATION CODE
LD A,(HL)
INC HL
CP E
LD A,(HL)
INC HL
JR NZ,SWLOOP
CP D
JR NZ,SWLOOP
LD H,B ;CASES MATCHED
LD L,C
SWEND:
LD DE,(PROGRAM_ADDR)
ADD HL,DE
JP (HL)
;
;Fetch a single byte from the address in HL and
; sign extend into HL
CCGCHAR: LD A,(HL)
Q_ARGCNT:
CCSXT: LD L,A
RLCA
SBC A,A
LD H,A
RET
;Fetch integer from (HL+2)
CCCDR: INC HL
INC HL
;Fetch a full 16-bit integer from the address in HL
CCCAR:
CCGINT: LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET
;Store a 16-bit integer in HL at the address in TOS
CCPINT: POP BC
POP DE
PUSH BC
LD A,L
LD (DE),A
INC DE
LD A,H
LD (DE),A
RET
;Inclusive "or" HL and DE into HL
CCOR:
LD A,L
OR E
LD L,A
LD A,H
OR D
LD H,A
RET
;Exclusive "or" HL and DE into HL
CCXOR:
LD A,L
XOR E
LD L,A
LD A,H
XOR D
LD H,A
RET
;"And" HL and DE into HL
CCAND:
LD A,L
AND E
LD L,A
LD A,H
AND D
LD H,A
RET
;Test if HL = DE and set HL = 1 if true else 0
CCEQ:
CALL_(CCCMP)
RET Z
DEC HL
RET
;Test if DE ~= HL
CCNE:
CALL_(CCCMP)
RET NZ
DEC HL
RET
;Test if DE > HL (signed)
CCGT:
EX DE,HL
CALL_(CCCMP)
RET C
DEC HL
RET
;Test if DE <= HL (signed)
CCLE:
CALL_(CCCMP)
RET Z
RET C
DEC HL
RET
;Test if DE >= HL (signed)
CCGE:
CALL_(CCCMP)
RET NC
DEC HL
RET
;Test if DE < HL (signed)
CCLT:
CALL_(CCCMP)
RET C
DEC HL
RET
;Common routine to perform a signed compare
; of DE and HL
;This routine performs DE - HL and sets the conditions:
; Carry reflects sign of difference (set means DE < HL)
; Zero/non-zero set according to equality.
CCCMP: LD A,E
SUB L
LD E,A
LD A,D
SBC A,H
LD HL,1 ;preset true condition
BIT 7,A
JUMP_NZ(CCCMP1) ; If bit is set, then we have minus
; or together E (low result) and A (high result) to detect 0
OR E ;"OR" resets carry and detects 0
RET
CCCMP1: OR E
SCF ;set carry to signal minus
RET
;*******
;*******
;*******
;******* End of Zshell include
;*******
;*******
;*******
qlastRand: .EQU $80FD
litaa: .byte 2
.export qlastRand
qnumToGue: .EQU $80FF
litab: .byte 2
.export qnumToGue
qkeys: .EQU $8101
litac: .word 33,34,26,18,35,27,19,36,28,20
.export qkeys
.export qrand
qrand:
.export qabs
LD HL,(qlastRand)
PUSH HL
LD HL,16388
POP DE
CALL_(ccmult)
INC HL
PUSH HL
LD HL,16387
POP DE
CALL_(ccdiv)
EX DE,HL
PUSH HL
CALL_(qabs)
POP BC
LD (qlastRand),HL
LD HL,(qlastRand)
RET
.export qgetDigit
qgetDigit:
LD HL,-10
ADD HL,SP
LD SP,HL
LD HL,8
ADD HL,SP
PUSH HL
LD HL,10
CALL_(ccpint)
cc6:
LD HL,8
ADD HL,SP
CALL_(ccgint)
PUSH HL
LD HL,10
POP DE
CALL_(cceq)
LD A,H
OR L
JUMP_Z(cc7)
LD HL,6
ADD HL,SP
PUSH HL
.export qwaitKey
CALL_(qwaitKey)
CALL_(ccpint)
LD HL,4
ADD HL,SP
PUSH HL
LD HL,0
CALL_(ccpint)
cc10:
LD HL,4
ADD HL,SP
CALL_(ccgint)
PUSH HL
LD HL,10
POP DE
CALL_(cclt)
LD A,H
OR L
JUMP_Z(cc9)
JUMP_(cc11)
cc8:
LD HL,4
ADD HL,SP
PUSH HL
CALL_(ccgint)
INC HL
CALL_(ccpint)
DEC HL
JUMP_(cc10)
cc11:
LD HL,qkeys
PUSH HL
LD HL,6
ADD HL,SP
CALL_(ccgint)
ADD HL,HL
POP DE
ADD HL,DE
CALL_(ccgint)
PUSH HL
LD HL,8
ADD HL,SP
CALL_(ccgint)
POP DE
CALL_(cceq)
LD A,H
OR L
JUMP_Z(cc12)
LD HL,8
ADD HL,SP
PUSH HL
LD HL,6
ADD HL,SP
CALL_(ccgint)
CALL_(ccpint)
cc12:
JUMP_(cc8)
cc9:
JUMP_(cc6)
cc7:
LD HL,cc5+0
POP DE
POP BC
PUSH HL
PUSH DE
LD HL,0
ADD HL,SP
PUSH HL
LD HL,4
ADD HL,SP
CALL_(ccgint)
PUSH HL
LD HL,12
ADD HL,SP
CALL_(ccgint)
POP DE
ADD HL,DE
CALL_(ccgchar)
POP DE
LD A,L
LD (DE),A
LD HL,1
ADD HL,SP
PUSH HL
LD HL,0
POP DE
LD A,L
LD (DE),A
.export qputs
LD HL,0
ADD HL,SP
PUSH HL
CALL_(qputs)
POP BC
LD HL,8
ADD HL,SP
CALL_(ccgint)
EX DE,HL
LD HL,10
ADD HL,SP
LD SP,HL
EX DE,HL
RET
cc5: .EQU $8115
litad: .byte 48,49,50,51,52,53,54,55,56,57
.byte 42,0
.export qgetNum
qgetNum:
CALL_(qgetDigit)
PUSH HL
LD HL,10
POP DE
CALL_(ccmult)
PUSH HL
CALL_(qgetDigit)
POP DE
ADD HL,DE
RET
.export qmain
qmain:
PUSH BC
PUSH BC
PUSH BC
CALL_(qclearLCD)
LD HL,cc14+0
PUSH HL
CALL_(qputs)
POP BC
LD HL,cc14+22
PUSH HL
CALL_(qputs)
POP BC
LD HL,cc14+44
PUSH HL
CALL_(qputs)
POP BC
LD HL,cc14+66
PUSH HL
CALL_(qputs)
POP BC
LD HL,cc14+88
PUSH HL
CALL_(qputs)
POP BC
LD HL,cc14+110
PUSH HL
CALL_(qputs)
POP BC
cc15:
.export qchkEnter
CALL_(qchkEnter)
CALL_(cclneg)
LD A,H
OR L
JUMP_Z(cc16)
LD HL,999
LD (qnumToGue),HL
cc17:
LD HL,(qnumToGue)
PUSH HL
LD HL,100
POP DE
CALL_(ccgt)
LD A,H
OR L
JUMP_Z(cc18)
CALL_(qrand)
PUSH HL
LD HL,100
POP DE
CALL_(ccdiv)
LD (qnumToGue),HL
JUMP_(cc17)
cc18:
JUMP_(cc15)
cc16:
LD HL,1000
POP DE
POP BC
PUSH HL
PUSH DE
LD HL,0
POP BC
PUSH HL
cc19:
LD HL,2
ADD HL,SP
CALL_(ccgint)
PUSH HL
LD HL,(qnumToGue)
POP DE
CALL_(ccne)
LD A,H
OR L
JUMP_Z(cc20)
LD HL,cc14+132
PUSH HL
CALL_(qputs)
POP BC
CALL_(qgetNum)
POP DE
POP BC
PUSH HL
PUSH DE
LD HL,0
ADD HL,SP
PUSH HL
CALL_(ccgint)
INC HL
CALL_(ccpint)
DEC HL
LD HL,2
ADD HL,SP
CALL_(ccgint)
PUSH HL
LD HL,(qnumToGue)
POP DE
CALL_(cceq)
LD A,H
OR L
JUMP_Z(cc21)
LD HL,cc14+152
PUSH HL
CALL_(qputs)
POP BC
LD HL,cc14+174
PUSH HL
CALL_(qputs)
POP BC
.export qputw
LD HL,0
ADD HL,SP
CALL_(ccgint)
PUSH HL
CALL_(qputw)
POP BC
LD HL,cc14+187
PUSH HL
CALL_(qputs)
POP BC
cc21:
LD HL,2
ADD HL,SP
CALL_(ccgint)
PUSH HL
LD HL,(qnumToGue)
POP DE
CALL_(cclt)
LD A,H
OR L
JUMP_Z(cc22)
LD HL,cc14+195
PUSH HL
CALL_(qputs)
POP BC
cc22:
LD HL,2
ADD HL,SP
CALL_(ccgint)
PUSH HL
LD HL,(qnumToGue)
POP DE
CALL_(ccgt)
LD A,H
OR L
JUMP_Z(cc23)
LD HL,cc14+217
PUSH HL
CALL_(qputs)
POP BC
cc23:
JUMP_(cc19)
cc20:
LD HL,cc14+239
PUSH HL
CALL_(qputs)
POP BC
CALL_(qwaitExit)
POP BC
POP BC
POP BC
RET
cc14: .EQU $8641
litae: .byte 84,104,101,32,72,105,103,104,32,45
.byte 32,76,111,119,32,71,97,109,101,32
.byte 32,0,61,61,61,61,61,61,61,61
.byte 61,61,61,61,61,61,61,61,61,61
.byte 61,61,61,0,73,39,109,32,116,104
.byte 105,110,107,105,110,103,32,111,102,32
.byte 97,32,32,32,32,0,110,117,109,98
.byte 101,114,32,98,101,116,119,101,101,110
.byte 32,49,32,97,110,100,32,0,49,48
.byte 48,46,32,80,114,101,115,115,32,101
.byte 110,116,101,114,32,119,104,101,110,0
.byte 114,101,97,100,121,46,46,46,46,46
.byte 46,46,46,46,46,46,46,46,46,46
.byte 46,0,87,104,97,116,39,115,32,121
.byte 111,117,114,32,103,117,101,115,115,63
.byte 32,0,32,89,111,117,32,87,105,110
.byte 33,33,33,33,32,32,32,32,32,32
.byte 32,32,32,0,73,116,32,111,110,108
.byte 121,32,116,111,111,107,0,32,116,114
.byte 105,101,115,46,0,32,84,111,111,32
.byte 76,111,119,46,46,46,32,32,32,32
.byte 32,32,32,32,32,32,0,32,84,111
.byte 111,32,72,105,103,104,32,46,46,46
.byte 32,32,32,32,32,32,32,32,0,80
.byte 114,101,115,115,32,69,120,105,116,32
.byte 32,32,32,32,32,32,32,32,0
InitEmXX:
LD DE,litaa
LD HL,(PROGRAM_ADDR)
ADD HL,DE
LD DE,$80FD
LD BC,2
LDIR
LD DE,litab
LD HL,(PROGRAM_ADDR)
ADD HL,DE
LD DE,$80FF
LD BC,2
LDIR
LD DE,litac
LD HL,(PROGRAM_ADDR)
ADD HL,DE
LD DE,$8101
LD BC,20
LDIR
LD DE,litad
LD HL,(PROGRAM_ADDR)
ADD HL,DE
LD DE,$8115
LD BC,12
LDIR
LD DE,litae
LD HL,(PROGRAM_ADDR)
ADD HL,DE
LD DE,$8641
LD BC,259
LDIR
RET
; --- End of Compilation ---
.end
Not a very efficient implementation of the HILO game, but it works.
Ed
References: