CW PROG4.S
Jump to navigation
Jump to search
;---------------------------------------------------------------------
; THE ST ASSEMBLY LANGUAGE WORKSHOP, VOLUME 2
; PROGRAM 4
;
; COPYRIGHT 1992 BY CLAYTON WALNUM
;---------------------------------------------------------------------
include SAMPLE.H
FINGER equ 3
PTERM0 equ 0
MSHRINK equ 74
AES_OPCODE equ 200
FMD_START equ 0
FMD_GROW equ 1
FMD_SHRINK equ 2
FMD_FINISH equ 3
;--------------------------------------------------------------------
; MACROS
;--------------------------------------------------------------------
;--------------------------------------------------------------------
; This macro gets the address of an object's string. It requires two
; parameters: the address of the resource tree and the object's
; number. The string address is returned in a5.
;--------------------------------------------------------------------
tedinfo_str macro
ifc '','\2'
fail Missing parameter!
mexit
endc
move.l \1,a5 ; Get address of dialog.
add.l #(\2*24)+12,a5 ; Calc. addr of ob_spec.
move.l (a5),a5 ; Get address of tedinfo.
endm
;--------------------------------------------------------------------
; This macro calls up a simple, one-button GEM alert box, using the
; form_alert AES function. It requires two parameters: the default
; button number and the address of the alert-box string. Because this
; alert box will have only one button, the value for the default
; button must be 0 for no default or 1 for button 1.
;--------------------------------------------------------------------
alert macro
ifc '','\2'
fail Missing parameter!
mexit
endc
move.l #form_alert,apb
move #\1,int_in
move.l #\2,addr_in
bsr aes
endm
;--------------------------------------------------------------------
; MAIN PROGRAM
;--------------------------------------------------------------------
text
; Calculate the size of the program area.
move.l a7,a5 ; Save addr of TPA.
lea stack,sp ; Load addr of our stack.
move.l 4(a5),a5 ; Get addr of TPA.
move.l 12(a5),d0 ; Get len of text segment.
add.l 20(a5),d0 ; Add len of data segment.
add.l 28(a5),d0 ; Add len of BSS segment.
add.l #$100,d0 ; Add len of TPA.
; Release unused memory back to the system.
move.l d0,-(sp) ; Push size of program on stack.
move.l a5,-(sp) ; Push program addr on stack.
clr -(sp) ; Clear dummy word on stack.
move #MSHRINK,-(sp) ; Push Mshrink opcode.
trap #1 ; Call GEMDOS.
add.l #12,sp ; Reset stack pointer.
; Clear some fields of the global array.
clr.l ap_ptree
clr.l ap_1resv
clr.l ap_2resv
clr.l ap_3resv
clr.l ap_4resv
; Call appl_init to initialize application.
move.l #appl_init,apb
bsr aes
cmpi #$FFFF,ap_id ; Error?
beq end ; Yep. Outta here.
; Load resource file.
move.l #rsrc_load,apb
move.l #rsrc_file,addr_in ; Addr of resource file name.
bsr aes
tst int_out ; Did the resource load okay?
bne rsrc_okay ; Yep.
alert 1,alert1 ; "Resource load error!"
bra exit
; Get resource address.
rsrc_okay:
move.l #rsrc_gaddr,apb
move #R_TREE,int_in ; Type number of data.
move #SAMPLE,int_in+2 ; Array index of data.
bsr aes
tst int_out ; Was there an error?
bne addr_okay ; Nope.
alert 1,alert2 ; "Resource address error!"
bra exit
addr_okay:
move.l addr_out,dialog_addr ; Save dialog's address.
; Center dialog for screen.
move.l #form_center,apb ; form_center control array.
move.l dialog_addr,addr_in ; Dialog's address.
bsr aes
move int_out+2,dial_x ; Save dialog's X coordinate.
move int_out+4,dial_y ; Save dialog's Y coordinate.
move int_out+6,dial_w ; Save dialog's width.
move int_out+8,dial_h ; Save dialog's height.
; Get coordinates of the NUMBERS object.
move.l #objc_offset,apb ; objc_offset control array.
move #NUMBERS,int_in ; Object to find.
move.l dialog_addr,addr_in ; Dialog's address.
bsr aes
move int_out+2,num_x ; Save object's X coordinate.
move int_out+4,num_y ; Save object's Y coordinate.
; Replace old dialog string with new dialog string.
tedinfo_str dialog_addr,NUMBERS ; Get pointer to dialog string.
move.l #number_str,(a5) ; Point tedinfo to new string.
; Reserve screen space for dialog box.
move.l #form_dial,apb ; form_dial control array.
move #FMD_START,int_in ; Operation type.
move #0,int_in+2 ; Small rectangle X.
move #0,int_in+4 ; Small rectangle Y.
move #10,int_in+6 ; Small rectangle width.
move #10,int_in+8 ; Small rectangle height.
move dial_x,int_in+10 ; Dialog's X.
move dial_y,int_in+12 ; Dialog's Y.
move dial_w,int_in+14 ; Dialog's width.
move dial_h,int_in+16 ; Dialog's height.
bsr aes
; Animate expanding rectangle.
move #FMD_GROW,int_in ; Operation type.
bsr aes
; Draw dialog box on screen.
move.l #objc_draw,apb ; objc_draw control array.
move #0,int_in ; First object to draw.
move #2,int_in+2 ; Depth of draw.
move dial_x,int_in+4 ; Clipping rectangle X.
move dial_y,int_in+6 ; Clipping rectangle Y.
move dial_w,int_in+8 ; Clipping rectangle width.
move dial_h,int_in+10 ; Clipping rectangle height.
move.l dialog_addr,addr_in ; Dialog's address.
bsr aes
; Change mouse to finger pointer.
move.l #graf_mouse,apb ; graf_mouse control array.
move #FINGER,int_in ; Pointer type.
clr.l addr_in ; Dummy mouse address.
bsr aes
; Activate dialog to accept user input.
do_dialog:
move.l #form_do,apb ; form_do control array.
move #NAME,int_in ; First edit field.
move.l dialog_addr,addr_in ; Dialog's address.
bsr aes
; Determine which exit button clicked.
cmpi #RADIO1,int_out ; Was RADIO1 clicked?
bne chk_but1 ; Nope.
move.b #'1',alert3+9 ; Yes. Prepare alert string.
alert 1,alert3 ; Show alert.
chk_but1:
cmpi #RADIO2,int_out ; Was RADIO2 clicked?
bne chk_but2 ; No.
move.b #'2',alert3+9 ; Yes. Prepare alert string.
alert 1,alert3 ; Show alert.
chk_but2:
cmpi #RADIO3,int_out ; Was RADIO3 clicked?
bne chk_but3 ; Nope.
move.b #'3',alert3+9 ; Yep. Prepare alert string.
alert 1,alert3 ; Show alert.
chk_but3:
cmpi #RADIO4,int_out ; Was RADIO4 clicked?
bne chk_but4 ; No.
move.b #'4',alert3+9 ; Yes, Prepare alert string.
alert 1,alert3 ; Show alert.
chk_but4:
cmpi #RADIO5,int_out ; Was RADIO5 clicked?
bne chk_but5 ; No.
move.b #'5',alert3+9 ; Yes, Prepare alert string.
alert 1,alert3 ; Show alert.
chk_but5:
cmpi #RADIO6,int_out ; Was RADIO6 clicked?
bne chk_but6 ; Nope.
move.b #'6',alert3+9 ; Yes. Prepare alert string.
alert 1,alert3 ; Show alert.
chk_but6:
cmpi #OPTION1,int_out ; Was OPTION1 clicked?
bne chk_but7 ; No.
move.b #'1',alert4+10 ; Yes. Prepare alert string.
alert 1,alert4 ; Show alert.
chk_but7:
cmpi #OPTION2,int_out ; Was OPTION2 clicked?
bne chk_but8 ; No.
move.b #'2',alert4+10 ; Yes. Prepare alert string.
alert 1,alert4 ; Show alert.
chk_but8:
cmpi #UPARROW,int_out ; Was UPARROW clicked?
bne chk_but9 ; No.
cmpi #9999,num ; Yes. Check if num maxed.
beq num_at_max ; Num at max value. Skip add.
addi #1,num ; Increment num.
num_at_max:
bsr change_number ; Change number in dialog.
chk_but9:
cmpi #DWNARROW,int_out ; Was DWNARROW clicked?
bne chk_but10 ; No.
tst num ; Yes. Is num already 0?
beq num_at_min ; If 0, skip decrement.
subi #1,num ; Decrement num.
num_at_min:
bsr change_number ; Change number in dialog.
chk_but10:
cmpi #CANCEL,int_out ; Was CANCEL clicked?
bne chk_but11 ; No.
bra dialog_done ; Yes. Close dialog.
chk_but11:
cmpi #OK,int_out ; Was OK clicked?
bne do_dialog ; No. Reactivate dialog.
dialog_done:
move.l #form_dial,apb ; form_dial control array.
move #FMD_SHRINK,int_in ; Operation code.
move #0,int_in+2 ; Small rectangle X.
move #0,int_in+4 ; Small rectangle Y.
move #10,int_in+6 ; Small rectangle width.
move #10,int_in+8 ; Small rectangle height.
move dial_x,int_in+10 ; Dialog's X.
move dial_y,int_in+12 ; Dialog's Y.
move dial_w,int_in+14 ; Dialog's width.
move dial_h,int_in+16 ; Dialog's height.
bsr aes
move #FMD_FINISH,int_in ; Operation Code.
bsr aes
quit:
; Release resource space.
move.l #rsrc_free,apb ; rsrc_free control array.
bsr aes
; Close down application.
exit:
move.l #appl_exit,apb ; appl_exit control array.
bsr aes
end:
move.w #PTERM0,-(sp) ; Back to desktop.
trap #1
;--------------------------------------------------------------------
; This subroutine changes the NUMBER object in the dialog box to a
; new value.
;--------------------------------------------------------------------
change_number:
; Restore dialog number string to '0000'.
lea number_str+4,a3 ; Get addr of 1st number character.
move.l #3,d3 ; Init loop counter.
place_zero:
move.b #'0',(a3)+ ; Put '0' in string.
dbra d3,place_zero ; Go place next '0'.
; Convert new value for dialog to ASCII string.
move num,d0 ; Get new value into work reg.
lea strg,a3 ; Get addr of string buffer.
bsr int2ascii16 ; Convert value to ASCII string.
; Count number of chars in new number string.
clr d3 ; Init counter.
.check_char:
tst.b (a3)+ ; Check for end of string.
beq .found_null ; if found null, branch.
addq #1,d3 ; Increment counter.
bra .check_char ; Go check next char.
.found_null:
; Move new number string into new dialog string.
subi #1,d3 ; Init loop counter.
sub.l #1,a3 ; Init string address.
lea number_str,a4 ; Get addr of new dialog string.
move #3,d4 ; Init addr index.
.move_char:
move.b -(a3),4(a4,d4) ; Move character into dialog string.
subi #1,d4 ; Decrement addr index.
dbra d3,.move_char ; Go move next character.
; Draw NUMBERS object so new string is displayed.
move.l #objc_draw,apb ; objc_draw control array.
move #NUMBERS,int_in ; First object to draw.
move #1,int_in+2 ; Depth of draw.
move num_x,int_in+4 ; Clipping rectangle X.
move num_y,int_in+6 ; Clipping rectangle Y.
move #96,int_in+8 ; Clipping rectangle width.
move #32,int_in+10 ; Clipping rectangle height.
move.l dialog_addr,addr_in ; Address of dialog.
bsr aes
rts
end_change_number:
;--------------------------------------------------------------------
; This subroutine converts a 16-bit unsigned integer into a
; null-terminated string.
;
; Input: Address of buffer in a3.
; Integer to convert in d0.
; Output: The buffer will contain the resultant null-terminated string.
; Registers changed: NONE.
;--------------------------------------------------------------------
int2ascii16:
movem.l a0-a7/d0-d7,-(sp) ; save registers.
clr.l d3 ; init leading-zero flag.
move.l #10000,d1 ; init divisor.
.convrt:
divu d1,d0 ; calculate place value.
cmpi.l #1,d1 ; are we at the one's place?
beq .zero_ok ; if so, "0" always ok.
tst.w d3 ; already have a non-zero char?
bne .zero_ok ; yes, so zeroes okay.
tst.w d0 ; is result zero?
beq .next_digit ; yes.
moveq #1,d3 ; set leading-zero flag.
.zero_ok:
move.b d0,(a3) ; move result to buffer.
add.b #'0',(a3)+ ; change digit to ascii.
.next_digit:
divu #10,d1 ; calculate next divisor.
tst.w d1 ; are we done yet?
beq .add_null ; sure are.
move.w #0,d0 ; clear result from low word.
swap d0 ; put remainder in low word.
bra .convrt ; convert next digit.
.add_null:
move.b #0,(a3)+ ; add null to string.
movem.l (sp)+,a0-a7/d0-d7 ; restore registers.
rts
end_int2ascii16:
;--------------------------------------------------------------------
; This subroutine calls the AES. Before calling this subroutine, the
; program must have correctly initialized the AES control, int_in,
; and addr_in arrays.
;
; Input: Appropriate values in the int_in, addr_in, and
; control arrays.
; Output: Appropriate values in the int_out, addr_out, and
; global arrays.
; Regs changed: NONE
; Uses: apb, global, int_in, int_out, addr_in, addr_out
;--------------------------------------------------------------------
aes:
movem.l a0-a7/d0-d7,-(sp) ; Save registers.
move.l #apb,d1 ; Load addr of apb.
move.l #AES_OPCODE,d0 ; Load AES opcode.
trap #2 ; Call AES.
movem.l (sp)+,a0-a7/d0-d7 ; Restore registers.
rts
data
even
num: dc.w 0
apb: dc.l 0,global,int_in,int_out,addr_in,addr_out
appl_init: dc.w 10,0,1,0,0
appl_exit: dc.w 19,0,1,0,0
form_alert: dc.w 52,1,1,1,0
form_center: dc.w 54,0,5,1,0
form_dial: dc.w 51,9,1,0,0
form_do: dc.w 50,1,1,1,0
graf_mouse: dc.w 78,1,1,1,0
objc_draw: dc.w 42,6,1,1,0
objc_offset: dc.w 44,1,3,1,0
rsrc_free: dc.w 111,0,1,0,0
rsrc_gaddr: dc.w 112,2,1,0,1
rsrc_load: dc.w 110,0,1,1,0
rsrc_file: dc.b "SAMPLE.RSC",0
number_str: dc.b " 0000 ",0
alert1: dc.b "[0][Resource load error! ][ OK ]",0
alert2: dc.b "[0][Resource address error!][ OK ]",0
alert3: dc.b "[0][RADIO ][ OK ]",0
alert4: dc.b "[0][OPTION ][ OK ]",0
alert5: dc.b "[0][UP ARROW ][ OK ]",0
alert6: dc.b "[0][DOWN ARROW ][ OK ]",0
bss
even
dialog_addr: ds.l 1
num_x: ds.w 1
num_y: ds.w 1
dial_x: ds.w 1
dial_y: ds.w 1
dial_w: ds.w 1
dial_h: ds.w 1
strg: ds.w 10
global:
ap_version: ds.w 1
ap_count: ds.w 1
ap_id: ds.w 1
ap_private: ds.l 1
ap_ptree: ds.l 1
ap_1resv: ds.l 1
ap_2resv: ds.l 1
ap_3resv: ds.l 1
ap_4resv: ds.l 1
int_in: ds.w 9
int_out: ds.w 5
addr_in: ds.l 2
addr_out: ds.l 1
ds.l 255
stack: ds.l 1
Back to CW_CHAPTER_4