|
Wristapp Programming
Reference |
Wristapp Programming
Tutorials |
|
|
|
|
|
|
Random Numbers and Marquis - 3Ball example
Wayne Buttles contributed the first version of this Wristapp which gives
you a simple decision maker. It inspired me to make a few adjustments to
it and add a real random number generator that you can use. I've also included
a little busy wait Marquis while it is selecting a number to show off a use
of the time. This Wristap also illustrates that you don't always have to
put a JMP or RTS instruction in the entry point vectors.
;Name: 3BALL
;Version: 3BALL
;Description: An executive decision maker that will give a yes/no/maybe answer. Pressing Next will generate another answer and beep (since it will be the same answer sometimes).
;
;(c) 1997 Wayne Buttles (timex@fdisk.com). Compiled using tools and knowledge published by John A. Toebes, VIII and Michael Polymenakos (mpoly@panix.com).
; Some enhancements by John Toebes...
;
;HelpFile: watchapp.hlp
;HelpTopic: 100
;
; (1) Program specific constants
;
INCLUDE "WRISTAPP.I"
;
; Program specific constants
;
CURRENT_TIC EQU $27 ; Current system clock tic (Timer)
LAST_ANS EQU $61
RAND_SEED EQU $60
MARQ_POS EQU $62
START EQU *
;
; (2) System entry point vectors
;
L0110: jmp MAIN ; The main entry point - WRIST_MAIN
L0113: bclr 1,BTNFLAGS ; Called when we are suspended for any reason - WRIST_SUSPEND
rts
L0116: jmp FLASH ; Called to handle any timers or time events - WRIST_DOTIC
L0119: bclr 1,BTNFLAGS ; Called when the COMM app starts and we have timers pending - WRIST_INCOMM
rts
L011c: rts ; Called when the COMM app loads new data - WRIST_NEWDATA
nop
nop
L011f: lda STATETAB,X ; The state table get routine - WRIST_GETSTATE
rts
L0123: jmp HANDLE_STATE0
db STATETAB-STATETAB
;
; (3) Program strings
;
S6_MSG timex6 "3 BALL"
S6_MAYBE timex6 "MAYBE"
S6_YES timex6 " YES"
S6_NO timex6 " NO"
S6_MARQ timex6 " +O+ "
MARQ_SEL
DB S6_MARQ+2-START
DB S6_MARQ+3-START
DB S6_MARQ+2-START
DB S6_MARQ+1-START
DB S6_MARQ-START
DB S6_MARQ+1-START
MSG_SEL DB S6_YES-START
DB S6_NO-START
DB S6_MAYBE-START
DB S6_YES-START
;
; (4) State Table
;
STATETAB:
db 0
db EVT_ENTER,TIM2_16TIC,0 ; Initial state
db EVT_RESUME,TIM_ONCE,0 ; Resume from a nested app
db EVT_DNNEXT,TIM2_16TIC,0 ; Next button
db EVT_TIMER2,TIM_ONCE,0 ; Timer
db EVT_MODE,TIM_ONCE,$FF ; Mode button
db EVT_END
;
; (5) State Table 0 Handler
; This is called to process the state events.
; We see ENTER, RESUME, TIMER2 and NEXT events
;
HANDLE_STATE0:
bset 1,APP_FLAGS ; Indicate that we can be suspended
bclr 1,BTNFLAGS ; Turn off the MARQUIS tic event
lda BTNSTATE
cmp #EVT_DNNEXT ; Did they press the next button?
beq DOITAGAIN
cmp #EVT_ENTER ; Or did we start out
beq DOITAGAIN
cmp #EVT_RESUME
beq REFRESH
;
; (6) Select a random answer
;
SHOWIT
bsr RAND
and #3 ; go to a 1 in 4 chance
sta LAST_ANS
;
; (7) Display the currently selected random number
;
REFRESH
ldx LAST_ANS ; Get the last answer we had, and use it as an index
lda MSG_SEL,X ; And get the message to display
jsr PUT6TOP ; Put that on the top
BANNER
lda #S6_MSG-START
jsr PUT6MID
lda #SYS8_MODE ; And show the mode on the bottom
jmp PUTMSGBOT
;
; (8) This flashes the text on the screen
;
FLASH
lda CURRENT_APP ; See which app is currently running
cmp #APP_WRIST ; Is it us?
bne L0113 ; No, so just turn off the tic timer since we don't need it
ldx #5
lda MARQ_POS
jsr INCA_WRAPX
sta MARQ_POS
tax
lda MARQ_SEL,X
jmp PUT6TOP
;
; (9) They want us to do it again
;
DOITAGAIN ; Tell them we are going to do it again
clr MARQ_POS
bset 1,BTNFLAGS
bra BANNER
;
; (10) Here is a simple random number generator
;
RAND
lda RAND_SEED
ldx #85
mul
add #25
sta RAND_SEED
rola
rola
rola
rts
;
; (11) This is the main initialization routine which is called when we first get the app into memory
;
MAIN:
lda #$c0 ; We want button beeps and to indicate that we have been loaded
sta WRISTAPP_FLAGS
lda CURRENT_TIC
sta RAND_SEED
rts
-
Program specific constants - We have two variables
- RAND_SEED and CURRENT_TIC which we use for the random number routine.
RAND_SEED is used to keep track of the last random number returned
so that we continue to deliver random numbers. CURRENT_TIC is what
is set by the system when it reads the clock to keep the watch time up to
date. We use it once to provide a seed for the random number generator.
-
System entry point vectors - This one gets to be a
little fun. Notice for the
WRIST_SUSPEND and
WRIST_INCOMM routines that
we don't have a JMP instruction, but instead put the actual code in line.
This saves use a couple of bytes.
-
Program strings - We are pretty fruegal here in reusing
blanks at the end of the string very liberally. Also note the S6_MARQ
string which has blanks at the start and end so that it can shuffle left
and right on the display but always have blanks visible. The MARQ_SEL
and MSG_SEL tables are simply offsets that allow us to select the message
with a simple load instruction instead of having to caluclate the offset.
-
State Table - This is pretty vanilla here except for
the fact that we have a very long time interval after the DNNEXT and ENTER
events. It is during this time that the Marquis runss. We could
make it even longer, but this seems to be a good compromise between seeing
something happen and actually getting a result in a resonable time.
-
State Table 0 Handler - Extremely simple, there are
only four events that we want to see and this is the typical test and branch
one. THe only unique thing here is that we turn off the Marquis timer
as soon as we get any event.
-
Select a random answer - As if life weren't complicated
enough. This is where we go when it is time to make a decision. For
this we get a random number and limit it to 1 in four.
-
Display the currently selected random number - Given
a random number, we just get the message for it and put it on the display.
-
This flashes the text on the screen - This is the
cheap way to do a Marquis. Just have a string wider than the display
and change the offset from the start at which you start to display. For
this one, there are only 6 states and we select the starting offset from
the table based on our current cycle. Note that this routine is called
by the TIC timer which is enabled when they want a new random number.
Eventually the timer for the main event will run out and they will
simply stop calling us.
-
They want us to do it again - Whenever we want to
do a new random number, we just start the Marquis tic timer and set up the
display.
-
Here is a simple random number generator - This is
a random number generator that you might want to use. It is a derivative
of the typical calculation rand = (seed*25173 + 13849) MOD 65536 which I
have chopped down to fit in the 8 bit world as rand = (seed * 85 + 25) MOD
256. Because the low order bits do produce a pattern cycle which is
fairly predictable, we rotate through to get a few of the more randomly occuring
bits.
-
This is the main initialization routine which is called
when we first get the app into memory - Very boring stuff here, but we
do take a moment to initialize the random number seed with the current tic
count just to make it a little more variable.
|