info-mac@uw-beaver (12/22/84)
From: winkler@harvard.ARPA (Dan Winkler) Here is a little assembly language i/o package developed for our assembly language courses that use the Mac. It was written by Jeff Miller and is used by his QuickPrint and MacMelody programs. We were using an early version of the assembler then, but this should work just fine with the newer versions. The only difference I know of is that the new assembler names its linker files .link but the old one named them .ld. Dan. (winkler@harvard) ; io.asm ; "Frame" program and I/O subroutines for general purpose assembly language ; programs. To use this package: ; 1. The first line in your file should be "include iodefs.txt". ; 2. Your main program must begin with the label "main" and end with rts. ; 3. Your .ld file should look like this, if your source file is called ; myprog.asm: ; !start ; io ; myprog ; $ ; 4. Pass arguments to subroutines in this package, and receive return ; values, in D0 or A0 as specified. All registers are preserved (but ; subroutine rdchar does not preserve A0). ; 5. Always call subroutine makewindow at the beginning of your main ; program, passing the address of your title string in A0. ; Include all necessary traps files include m68klib.d include systraps.txt include quicktraps.txt include tooltraps.txt WINDWIDTH equ 492 ; window dimensions WINDHEIGHT equ 280 X1 equ 8 ; upper-left and lower-right coordinates Y1 equ 48 ; for bounds rectangle for window X2 equ X1+WINDWIDTH Y2 equ Y1+WINDHEIGHT LMARG equ 6 ; text margins - left, RMARG equ WINDWIDTH-10 ; right, TMARG equ 15 ; top, BMARG equ WINDHEIGHT-15 ; bottom CR equ 13 ; ascii carriage return BS equ 8 ; ascii backspace DASH equ 45 ; ascii minus sign ZERO equ 48 ; ascii character for digit zero NINE equ 57 ; ascii character for digit nine PROGFONT equ 4 ; Monaco font code ASCENT equ 0 ; offsets of fields in fontinfo record DESCENT equ 2 WIDMAX equ 4 LEADING equ 6 BUFSIZE equ 256 ; size of input buffer xdef start xref main ; Preserve registers in safe place; initialize graphics, font manager, ; windows, cursor, and textedit; call main program; restore registers ; and exit. start: movem.l D0-D7/A0-A6, -(SP) ; save all registers lea saveregs, A0 move.l A6, (A0) move.l A7, 4(A0) move.l A5, D0 ; set up quickdraw sub.l #4, D0 move.l D0, -(SP) _INITGRAF _INITFONT _INITWINDOW _INITCURSOR _TEINIT bsr main ; call the main program lea saveregs, A0 move.l (A0), A6 move.l 4(A0), A7 movem.l (SP)+, D0-D7/A0-A6 _EXITTOSHELL ; Subroutine makewindow ( StringAddress ) ; Receives argument in A0 ; Creates and displays a desk-accessory style window with title ; specified by string whose address is passed; flushes event queue ; and initializes cursor position for text I/O xdef makewindow makewindow: movem.l D0-D2/A0-A1, -(SP) ; save registers clr.l -(SP) ; space for return window pointer clr.l -(SP) ; nil wstorage pointer - window ; record storage will be allocated ; on heap pea boundsrect ; determines window size and loc move.l A0, -(SP) ; window title st -(SP) ; visible flag true - draw window move #16, -(SP) ; procid - desk accessory type window move.l #-1, -(SP) ; behind pointer -1 means in front ; of all other windows sf -(SP) ; goaway flag false - no goaway box clr.l -(SP) ; refcon (not used) _NEWWINDOW move.l (SP), window(A5) _SETPORT clr.l -(SP) _NEWRGN ; create a region lea scrollrgnh, A0 move.l (SP), (A0) pea scrollrect ; with same bounds as boundsrect _RECTRGN ; (required later for scrolling) move.w #PROGFONT, -(SP) ; set font to Geneva (monofont) _TEXTFONT pea fontinfo ; get information on font _GETFONTINFO ; dimension parameters clr.w D0 ; accumulate line height in D0 add.w fontinfo+ASCENT, D0 add.w fontinfo+DESCENT, D0 add.w fontinfo+LEADING, D0 lea lnht, A0 move.w D0, (A0) ; store in lnht move.l D0, -(SP) ; flush event queue move.l #$0000FFFF, D0 _FLUSHEVENTS move.l (SP)+, D0 move #LMARG, -(SP) ; initialize cursor position move #TMARG, -(SP) _MOVETO movem.l (SP)+, D0-D2/A0-A1 ; restore registers rts ; Subroutine clearwindow ; Erases contents of window and 'homes' pen to original position in ; upper left corner. xdef clearwindow clearwindow: movem.l D0-D2/A0-A1, -(SP) ; save registers pea scrollrect ; erase window contents _ERASERECT move.w #LMARG, -(SP) ; home pen move.w #TMARG, -(SP) _MOVETO movem.l (SP)+, D0-D2/A0-A1 ; restore registers rts ; Subroutine rdchar ; Returns single character result in D0. ; Waits for next keyboard character from event queue, echoes it on ; screen and returns it in D0. If character is CR or right margin has ; been reached, moves cursor to left margin one line down. xdef rdchar rdchar: lea regbufe, A0 movem.l D1-D2/A1, -(A0) ; save registers (but not A0) move.w #40, -(SP) ; mask for key-down or auto-key event pea evbuf ; pass address of event buffer _GETNEXTEVENT lea evbuf, A0 ; any characters? tst.w (A0) beq rdchar ; if not, keep waiting clr.l D0 move.b 5(A0), D0 ; pass character to wrtchar jsr wrtchar lea regbuf, A0 movem.l (A0)+, D1-D2/A1 ; restore registers rts ; Subroutine wrtchar ( character ) ; Receives single character argument in D0 ; Draws character on screen; if character is CR or right margin has ; been reached, moves pen to left margin one line down; if bottom ; has been reached, scrolls up one line. xdef wrtchar wrtchar: movem.l D1-D2/D5-D7/A0-A1, -(SP) ; save registers move.l D0, D5 ; store character in D5 pea penloc ; check pen location _GETPEN move.w penloc+2, D7 ; store x value of pen in D7 move.w penloc, D6 ; store y value of pen in D6 cmp.b #BS, D5 ; backspace typed? bne wrtchar1 ; if not, skip code to erase char. cmp.w #LMARG, D7 ; already at left margin? beq wrtchar4 ; if so, skip code to erase char. lea fontinfo, A0 ; compute and push inverse of move.w WIDMAX(A0), D0 ; character width neg.w D0 move.w D0, -(SP) move.w #0, -(SP) ; don't change pen's y coord _MOVE ; move pen back one character pos. move.w D7, -(SP) ; push x coord for lower right corner move.w D6, D0 ; add descent amount to y coord add.w fontinfo+DESCENT, D0 ; of lower right corner move.w D0, -(SP) ; of erase rect. sub.w fontinfo+ASCENT, D6 ; compute coords for upper left sub.w fontinfo+WIDMAX, D7 ; corner of erase rect move.w D7, -(SP) ; and push them move.w D6, -(SP) move.l SP, A0 ; push addr of erase rect move.l A0, -(SP) _ERASERECT ; erase deleted character add #8, SP ; remove rectangle coords from stack bra wrtchar4 ; skip ahead to return backspace wrtchar1: cmp.b #CR, D5 ; carriage return? beq wrtchar2 ; if so, skip to new-line generation cmp.w #RMARG, D7 ; past right margin? blt wrtchar3 ; if not, skip new-line generation wrtchar2: ; generate new line sub.w #LMARG, D7 ; compute delta x neg.w D7 move.w D7, -(SP) lea lnht, A0 move.w (A0), -(SP) _MOVE ; position cursor for new line cmp.w #BMARG, D6 ; past bottom margin? blt wrtchar3 ; if not, skip past code for scroll pea scrollrect move.w #0, -(SP) lea lnht, A0 move.w (A0), -(SP) neg.w (SP) lea scrollrgnh, A0 move.l (A0), -(SP) ; else, scroll up by one _SCROLLRECT ; line height move.w #0, -(SP) lea lnht, A0 move.w (A0), -(SP) ; move pen up accordingly neg.w (SP) _MOVE wrtchar3: move.w D5, -(SP) _DRAWCHAR ; display character wrtchar4: move.l D5, D0 ; return character in D0 movem.l (SP)+, D1-D2/D5-D7/A0-A1 ; restore registers rts ; Subroutine wrtdec ( num: integer ) ; Receives integer argument in D0. ; If argument is negative, negates it and outputs a minus sign; calls ; subroutine prtdec to output digits of number xdef wrtdec wrtdec: movem.l D0-D2/A0-A1, -(SP) ; save registers tst.w D0 ; negative? bge wrtdec1 neg.w D0 ; if so, negate num move.w D0, -(SP) ; save num ;clr.w D0 move.b #DASH, D0 ; output minus sign jsr wrtchar move.w (SP)+, D0 ; restore num to D0 wrtdec1: swap D0 clr.w D0 swap D0 bsr prtdec ; output num movem.l (SP)+, D0-D2/A0-A1 ; restore registers rts ; Subroutine prtdec (num: integer) ; Receives integer argument in D0. ; Recursively outputs digits of integer in decimal to terminal. prtdec: divs #10, D0 ; num <- num DIV 10 tst.w D0 ; result equals zero? beq prtdec1 move.l D0, -(SP) ; if not, call prtdec recursively swap D0 clr.w D0 ; (first getting rid of remainder) swap D0 bsr prtdec ; with num DIV 10 move.l (SP)+, D0 prtdec1: swap D0 ; num MOD 10 add.b #ZERO, D0 ; compute ascii code for digit jsr wrtchar ; output digit rts ; Subroutine rddec ; Returns integer result in D0. ; Inputs signed word integer value (decimal), ignores all non-numeric ; characters except for minus sign, returns result on encountering ; CR. xdef rddec rddec: movem.l D1-D5/A0-A1, -(SP) ; save registers lea inbuf, A0 jsr rdstrz ; input line to buffer clr.w D0 ; sum = 0 clr.w D3 ; character holder = 0 clr.b D4 ; digits read = false move.w #1, D5 ; sign = + rddec1: move.b (A0)+, D3 ; end of input line? beq rddec3 ; if so, return result cmp.b #DASH, D3 ; minus sign? bne rddec2 tst.b D4 ; if so, any digits read yet? bne rddec1 ; if so, ignore minus sign neg.w D5 ; else, sign = - bra rddec1 rddec2: cmp.b #ZERO, D3 ; less than '0'? blt rddec1 ; if so, ignore cmp.b #NINE, D3 ; greater than '9'? bgt rddec1 ; if so, ignore move.b #1, D4 ; digits read = true muls #10, D0 ; sum = sum * 10 sub.w #ZERO, D3 ; subtract ascii code for 0 from char ; to get digit value add.w D3, D0 ; sum = sum + digit bra rddec1 ; get next character rddec3: muls D5, D0 ; sum = sum * sign movem.l (SP)+, D1-D5/A0-A1 ; restore registers rts ; Subroutine rdstrz ( BufferAddress ) ; Receives address of destination buffer in A0. ; Inputs characters to buffer specified by destination address ; until CR is read; terminates string with zero byte; if backspace ; encountered, deletes last character in buffer, backspace not stored. ; Inputs maximum of 255 characters to buffer (plus zero byte), flushes ; excessive input until next CR encountered (for buffers less than ; 256 bytes long, buffer overflow is a possibility). xdef rdstrz rdstrz: movem.l D0-D3/A0-A2, -(SP) ; save registers clr.w D3 ; initialize counter movea.l A0, A2 ; save addr of buffer in A2 rdstrz1: jsr rdchar ; input next character cmp.b #CR, D0 ; CR? beq rdstrz5 ; if so, terminate string cmp.b #BS, D0 ; backspace? bne rdstrz2 tst.w D3 ; if so, is buffer empty? beq rdstrz1 ; if so, get next character clr.b -(A2) ; else, delete last character sub.w #1, D3 ; decrement counter bra rdstrz1 ; input another character rdstrz2: cmp.w #BUFSIZE-1, D3 ; buffer full? bne rdstrz4 rdstrz3: jsr rdchar ; if so, cmp.b #CR, D0 ; discard input characters till bne rdstrz3 ; CR found bra rdstrz5 ; and terminate string rdstrz4: add.w #1, D3 ; else, increment character count move.b D0, (A2)+ ; and move input character to ; next buffer position bra rdstrz1 ; input another character rdstrz5: clr.b (A2) ; zero terminate movem.l (SP)+, D0-D3/A0-A2 ; restore registers rts ; Subroutine wrtstrz ( BufferAddress ) ; Receives address of zero-terminated string in A0. ; Outputs characters of string on screen until zero byte is reached. xdef wrtstrz wrtstrz: movem.l D0/A0, -(SP) ; save registers wrtstrz1: move.b (A0)+, D0 ; pass char to wrtchar beq wrtstrz2 ; return when zero byte reached jsr wrtchar ; output character bra wrtstrz1 ; get next byte wrtstrz2: movem.l (SP)+, D0/A0 ; restore registers rts ; Subroutine rdstrc ( BufferAddress ) ; Receives address of destination buffer in A0. ; Inputs characters to buffer specified by destination address ; until CR is read; places count byte at start of string; if backspace ; encountered, deletes last character in buffer, backspace not stored. ; Inputs maximum of 255 characters to buffer (plus count byte), flushes ; excessive input until next CR encountered (for buffers less than ; 256 bytes long, buffer overflow is a possibility). xdef rdstrc rdstrc: movem.l D0-D3/A0-A3, -(SP) ; save registers movea.l A0, A2 ; save addr of buffer in A2 movea.l A0, A3 ; and A3 tst.b (A2)+ ; increment pointer past count byte clr.b D3 ; initialize counter rdstrc1: jsr rdchar ; input next character cmp.b #CR, D0 ; CR? beq rdstrc5 ; if so, terminate string cmp.b #BS, D0 ; backspace? bne rdstrc2 tst.b D3 ; if so, is buffer empty? beq rdstrc1 ; if so, get next character clr.b -(A2) ; else, delete last character sub.b #1, D3 ; decrement counter bra rdstrc1 ; input another character rdstrc2: cmp.b #BUFSIZE-1, D3 ; buffer full? bne rdstrc4 rdstrc3: jsr rdchar ; if so, cmp.b #CR, D0 ; discard input characters till bne rdstrc3 ; CR found bra rdstrc5 ; and terminate string rdstrc4: add.b #1, D3 ; else, increment character count move.b D0, (A2)+ ; and move input character to ; next buffer position bra rdstrc1 ; input another character rdstrc5: move.b D3, (A3) ; insert count byte movem.l (SP)+, D0-D3/A0-A3 ; restore registers rts ; Subroutine wrtstrc ( BufferAddress ) ; Receives address of count string in A0. ; Outputs number of characters specified by count-byte. xdef wrtstrc wrtstrc: movem.l D0/D3/A0, -(SP) ; save registers move.b (A0)+, D3 ; store count in D3 wrtstrc1: tst.b D3 ; all characters output? beq wrtstrc2 ; then quit move.b (A0)+, D0 ; pass char to wrtchar jsr wrtchar ; output character sub.b #1, D3 ; decrement counter bra wrtstrc1 ; get next byte wrtstrc2: movem.l (SP)+, D0/D3/A0 ; restore registers rts ; data for shell program saveregs: dcb.l 2, 0 ; space for storing saved registers evbuf: dcb.l 4, 0 ; event buffer ; data for subroutine makewindow boundsrect: dc.w Y1, X1, Y2, X2 ; the window rectangle in ; global coordinates scrollrect: dc.w 0, 0, WINDHEIGHT, WINDWIDTH ; the window rectangle ; in local coordinates scrollrgnh: dc.l 0 ; handle for scroll region fontinfo: dcb.w 4, 0 ; buffer for record returned ; by _GETFONTINFO lnht: dc.w 0 ; buffer for height of line ; of text ; data for subroutine rdchar penloc: dc.l 0 ; storage for pen location coordinates regbuf: dcb.l 3, 0 ; storage for saved registers regbufe: ; data for subroutine rddec inbuf: dcb.b BUFSIZE, 0 ; input buffer ; global storage window: ds.l 1 end
info-mac@uw-beaver (12/22/84)
From: winkler@harvard.ARPA (Dan Winkler) Here is a little assembly language i/o package developed for our assembly language courses that use the Mac. It was written by Jeff Miller and is used by his QuickPrint and MacMelody programs. We were using an early version of the assembler then, but this should work just fine with the newer versions. The only difference I know of is that the new assembler names its linker files .link but the old one named them .ld. Dan. (winkler@harvard) [filed on <info-mac>io.asm]