CW PROG4MAC.S

From Atari Wiki
Revision as of 13:16, 13 October 2011 by Admin (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
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.
;-------------------------------------------------------------------- 
.macro tedinfo_str
        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.
;-------------------------------------------------------------------- 
.macro alert
        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