home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-10-23 | 112.1 KB | 2,536 lines |
- Atari ST Machine Specific Programming In Assembly
-
-
- Chapter 10: AES Initialization Algorithms
-
-
- Tired of typing file names on TTP input parameter lines? I
- assumed as much. Fortunately, the designers of the ST's
- operating system have provided an easier way to deal with such
- trivia. And the system that alleviates file selections also
- contains many other tools with which a programmer can design
- sophisticated interfacing algorithms. The user-interface
- features are provided by the Application Environment Services
- (AES) segment of the ST's operating system. Although the AES
- appears to be unreasonably complex during a first study of its
- repertoire, I intend to prove to you that using its routines is
- one of the easier operating system manipulations. But I'm not
- going to try to do the job alone; I sincerely recommend that you
- obtain at least one of two books and read it carefully, several
- times, if necessary. Because it is not possible for me to
- anticipate your every need and desire. Therefore, I want to show
- you methods, not canned routines; you'll find lots of those in
- other books. Magazine articles are another valuable source of
- AES information. The more you read about the ST's operating
- system, the less intimidated you will feel by its structure.
- Of the two books, Atari ST GEM Programmer's Reference, by
- Norbert Szczepanowski and Bernd Gunther, published by Abacus
- Software; and COMPUTE!'s Technical Reference Guide--Atari ST,
- Volume Two: GEM AES, by Sheldon Leemon; I feel that I must
- recommend Leemon's. The Abacus book omits too many AES
- functions, and it hardly mentions assembly language; however, it
- is just better than no book at all. I should have more
- enthusiastically recommended the Leemon book in chapter one. My
- enthusiasm had been dampened because Leemon did not include
- assembly setups in the function reference section, Appendix A of
- his book; but, then, neither does the Abacus book. Nevertheless,
- the assembly setups can more readily be inferred from the data
- given in the Leemon book. Furthermore, the Leemon book's
- assembly language examples are more comprehensive than are those
- in the Abacus book.
-
- Initializing Programs With AES Subroutines
-
- The initialization algorithms that have been used in the
- programs presented up to this point have been those that invoked
- GEMDOS functions. Incorporated into the design of those programs
- were some BIOS and XBIOS function invocations also. The AES
- subroutines are invoked with a trap #2 exception generating
- instruction. When the GEMDOS, BIOS and XBIOS functions are
- invoked, parameters are passed to the functions via the stack;
- and returned parameters are passed in one or more registers.
- Parameters are passed between invoking programs and AES
- subroutines via arrays. The arrays must be declared in the data
- section of an assembly language program.
- It is the descriptions concerning these arrays which
- probably cause much of the confusion associated with the AES.
- For example, on page 275 of the Abacus GEM book, the discussion
- of AES functions and the associated arrays begins, just at the
- conclusion of a VDI discussion. The array descriptions begin on
- the following page. The first problem in the Abacus book is that
- the authors omitted the int_out array in the list at the top of
- page 276. The second problem, although it is not immediately
- obvious that the information there is less accurate than that
- presented elsewhere, is that the functions assigned to the
- elements of the control array listed at the bottom of that page
- do not agree with other references.
- The Abacus book states that the parameters passed to contrl
- (sometimes called control) elements 1 and 2 are the size of the
- intin (sometimes called int_in or sintin) and intout (sometimes
- called int_out or sintout) arrays, respectively, in bytes. Atari
- documentation declares the information to be the same as does the
- Abacus book, however, that documentation reports that the size of
- the data must be specified in words. The COMPUTE! book insists
- that the items of information stored in those control array
- elements are the number of integer inputs passed in int_in and
- the number of integer results returned in int_out (see page 11).
- The Peel book (page 3-59) states the parameter values to be the
- length of i/p coor table and length of o/p coor table, where
- table length is in words; then, in tables under the AES function
- headings, indicates that the values are the number of particular
- parameter items passed. It seems prudent to suspect that the
- information given in the COMPUTE! book is the most consistent,
- even though the parameter specifications are also given there in
- both sets of terminology; because the information given on pages
- 10 through 13 leads one to conclude that, if the size of each
- parameter is one word long, and if it is the number of parameters
- that is specified via the pertinent element of array control,
- then the number of parameters, times the size of each parameter,
- equals the length of the array portion, in words, that is being
- passed. Notice that I said array portion, not the entire size of
- the declared array, as the references indicate. That is, if the
- number of int_in parameters is 2, then the size of the portion of
- the int_in array being passed is 2 words.
- There is a neat list of the applicable arrays on page 12 of
- the COMPUTE! book; unfortunately, the ordering of the list is not
- as it should be for storage of the addresses of the listed items
- in the application parameter block (apb) structure. The apb
- structure is a pointer array in which the addresses to other
- major AES structures are stored. That ordering is shown on page
- 13. I hope to be able to prove to you that it is more the
- inconsistency of data presentation in the references with which
- we must contend than it is with AES function intricacy. As you
- will see if you look at page 46 of the COMPUTE! book, that
- inconsistency is carried over into programming examples. There
- you see that not only have the names initially given for the
- arrays been changed, but also the values used in the array
- declarations: ds.w 8 for int_out (aintout), not ds.w 7 as
- indicated on page 12; ds.w 18 for int_in (aintin), not ds.w 16 as
- indicated on page 12; ds.l 3 for addr_in (addrin), not ds.l 2 as
- indicated on page 12; and ds.l 2 for addr_out (addrout), not ds.l
- 1 as indicated on page 12. I shall begin the unraveling with
- figure 10.1, in which I present the structure of the major AES
- variables under discussion.
-
- Figure 10.1. Major AES structures. The apb structure is a
- pointer array containing the addresses of the other structures;
- each address requires one longword of storage, therefore, the
- space occupied by the pointer array is 6 longwords. Within each
- structure, the digits indicate the element of the structure. The
- order in which the other 6 major AES structures are shown below
- is the order in which the addresses of these structures must be
- stored in the apb structure.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Within the figure, I have indicated a specific length for
- each structure; previously, I have spoken of array portions;
- congruency is provided by the following statement: the size
- declared for the int_in, int_out, addr_in and addr_out arrays
- must be commensurable with the number of parameters required by
- the specific AES functions invoked within a program. For
- example, when invoking the appl_init function (AES opcode $A), no
- parameters are passed, and only one parameter is returned--via
- the int_out array; therefore, the size declared for the int_out
- array must be at least one word; the size declared for each of
- the int_in, addr_in and addr_out arrays is irrelevant. On the
- other hand, when invoking the form_dial function (AES opcode $33
- dec 51), 9 parameters are passed to the function via the int_in
- array, and one parameter is returned via the int_out array. That
- function requires a declared size of at least 18 words for the
- int_in array and at least 1 word for the int_out array. In the
- figure, you can see that the int_in array is illustrated as a 16
- word length structure. That's because I used the structure
- lengths indicated on page 12 of the COMPUTE! book.
- What all of this means is that, in order to declare arrays
- of sufficient size for the functions to be invoked within a
- program, you must look under the function headings in your
- reference book for each of the functions to be used; determine
- which function requires the most parameters to be passed and
- which requires the most to be returned (these values may not
- coincide for a particular function); then declare sizes that meet
- the needs of the functions with the greatest number of
- parameters. If the form_dial function is not to be invoked
- within a program, then the size of the int_in array need not be
- sufficient to contain 9 word size integers.
- The sizes declared for the apb, control and global
- structures are constant for every application. Notice that the
- structure shown for global is constructed of both word size and
- longword size elements. I should also mention that, since the
- addresses of the four arrays for which the sizes need not be
- constant must still be stored in the apb array, even if no
- parameter exchange takes place, I would consider it prudent to
- declare a size of at least 1 element for each of those four. One
- other point; when declaring space for variables, a declaration of
- ds.w 8 reserves 16 bytes, as does a declaration of ds.b 16, or a
- declaration of ds.l 4, or a declaration of ds.w 4 followed by
- ds.l 2. We use one method or another simply to satisfy our human
- sense of structure--the machine does not give a damn. The values
- that are to be stored in each of the array elements are specified
- under the function headings in each reference book. I find the
- presentations in the Leemon book to be the easiest to decipher.
- It is time for an example program. But before that, let me
- stress a point. The structure element digits shown in figure
- 10.1 are not the numbers by which we reference those elements in
- assembly language programming. That's because the addressing
- modes we use require byte size offsets. Suppose that the
- appl_init function is being invoked. Preparatory to the trap #2
- invocation, 5 values must be stored in the control array. One
- method of accomplishing the required storage is to load the
- address of the array in a register, say A4. The function opcode
- would then be stored in control array element 0 with the
- instruction move.w #$A, (A4), where the digit 0 can be assumed to
- exist in front of (A4). But this 0 does not reference element 0
- of the array; it references a memory location that is at offset 0
- from the base address stored in register A4. If we know that the
- other control array elements contain the value 0, then we would
- not have to store that value in control array elements 1, 3 and
- 4; but we would have to store the value 1 in element 2. That
- would be accomplished with the instruction move.w #1, 4(A4)
- because element 2 of the control array is located in memory at an
- offset of 4 bytes from the base address of the array. When the
- length of each element of a structure is identical, an element's
- offset, in bytes, is calculated by multiplying the element number
- by the element length; hence, 2 (for element 2) times 2 bytes
- (the element length) equals 4 bytes offset.
- There is another method of passing parameters in the control
- array, which some programmers find attractive. For each function
- to be invoked within a program, an array bearing the function's
- name and containing all required parameters is declared within
- the data section. Then, before the trap #2 call, the address of
- the function being invoked is stored within the apb at the slot
- reserved for array control. You may see that method used in
- magazine articles. You can try each method and choose the one
- that suits you best.
-
- AES Structure Volatility
-
- Although this chapter is the official introduction to
- programs which utilize AES functions, I included program 57
- (REG_TST5.S) in chapter eight because it seemed to fit there more
- naturally. Using that program, I showed that the ST's operating
- system protects the registers which are being used by a desk
- accessory while it is waiting for a message event. In this
- chapter I will concentrate on programs that investigate the
- volatility of AES arrays during AES function invocation. Because
- the primary, investigatory, algorithm does not vary much from
- example to example within the chapter, I will introduce ancillary
- functions selected from the other segments of the operating
- system at relevant locations, so that you may become familiar
- with their usage.
-
-
- Program 76. A program that investigates AES array corruption
- during AES function invocation and saves the results in a disk
- file.
-
- ; Program Name: PRG_8AR.S
- ; Version: 1.005
-
- ; Assembly Instructions:
-
- ; Assemble in Relocatable mode and save with a PRG extension. From
- ; the desktop, change the extension to ACC. Programs that are to function
- ; as desk accessories MUST be assembled in Relocatable mode. If you design
- ; a desk accessory so that it can be assembled in PC-relative mode, and if
- ; you attempt to load that accessory via MultiDesk, you will receive an
- ; error pertaining to the attempt to read in the accessory. If you place
- ; that accessory in the boot directory, the system will reset every time
- ; it attempts to load the accessory. Sei gewarnt!
-
- ; Function:
-
- ; This program is used to observe system corruption of AES arrays
- ; during the execution of AES functions. Data is output into a file which
- ; assumes the name declared at the variable "filename". You may wish to
- ; alter the file's path to something like "A:\PRG_8DR.DAT" if you decide to
- ; assemble and execute the program.
-
- ; The program's output data is written with GEMDOS function $9, the write
- ; string to screen function. But the data is redirected to the file with
- ; GEMDOS function $46, the f_force function.
-
- ; Execution Instructions:
-
- ; Place PRG_8AR.ACC in the root directory of your boot disk. During
- ; the next power-up cycle, the program will be installed in memory as a desk
- ; accessory; assuming that it is not blocked by a program that permits desk
- ; accessory loading selections. Of course, if you use MultiDesk, you need
- ; not power up to use PRG_8AR.ACC immediately.
-
- ; The desk accessory is identified as a menu selection by the name
- ; Accessory Arrays. Choose the desk accessory twice so that the contents
- ; of the arrays will be printed twice from within the message handler. The
- ; message handler is disabled after it has been invoked twice.
-
- ; MAJOR NOTE:
-
- ; Although accessories such as MultiDesk add significant power to a ST
- ; system; and although initial testing of a desk accessory program can be
- ; accomplished via MultiDesk loading of the program, thereby alleviating the
- ; the testing process, the program under test cannot be pronounced correct
- ; until it has been permitted to load normally from the boot disk.
-
- ; For example, if the first statement of this program, which loads the
- ; stack's address into A7, is moved to a location following any instruction
- ; that requires stack usage, the accessory will function perfectly when it is
- ; loaded and executed via MultiDesk; but it will bomb during boot because, at
- ; that time, no default stack has yet been assigned by the system.
-
- ; REMEMBER: Programs executed during boot MUST provide their own stacks.
-
- ; NOTE: Within the program, registers are used as variables as much as
- ; possible to speed things up.
-
- lea stack(pc), a7 ; This must be the first instruction.
-
- create_output_file: ; COMPUTE! TOS book page 270.
- move.w #0, -(sp) ; File attribute = read/write.
- pea filename(pc)
- move.w #$3C, -(sp) ; Function = f_create = GEMDOS $3C.
- trap #1 ; File handle is returned in D0.
- addq.l #8, sp
- move.w d0, handle
-
- redirect_output_bound_for_screen:
-
- ; NOTE: If the output file's handle is exchanged with the video screen's
- ; handle, then the printline function = GEMDOS $9 can be used to
- ; write to the file.
-
- redirect_output: ; Exchange file handle with screen's handle.
- move.w handle(pc), -(sp) ; This is the disk file's handle.
- move.w #1, -(sp) ; This is the video screen's handle.
- move.w #$46, -(sp) ; Function = f_force = GEMDOS $46.
- trap #1
- addq.l #6, sp
-
- initialize_register_variables:
- move.w #$C8, d3 ; *** D3 is variable for AES call number.
- lea aes_pb(pc), a5 ; A5 is pointer to array address block.
- lea control(pc), a4 ; A4 is pointer for array 'control'.
- lea hex_table(pc), a3 ; A3 points to hexadecimal ASCII digits.
-
- ; For each test point, the contents of each AES array are printed.
-
- ;
- ; TEST POINT 0: Before appl_init
- ;
- bsr print_arrays
-
- initialize_application: ; COMPUTE! AES book page 223.
-
- ; Application identification = apid returned in int_out[0] and global[2].
-
- move.w #$A, (a4) ; Function = appl_init = AES $A.
- move.w #0, 2(a4) ; Input no 16-bit integer parameters.
- move.w #1, 4(a4) ; Return one 16-bit integer parameter.
- move.w #0, 6(a4) ; Input no 32-bit pointer parameters.
- move.w #0, 8(a4) ; Return no 32-bit pointer parameters.
- bsr aes ; Invoke trap #2 AES exception.
-
- ;
- ; TEST POINT 1: After appl_init, before menu_register
- ;
- bsr print_arrays
-
- menu_installation: ; COMPUTE! AES book page 248.
-
- ; Menu identification number returned in int_out[0].
-
- move.w #$23, (a4) ; Function = menu_register = AES $23.
- move.w #1, 2(a4) ; Input one 16-bit integer parameter.
- move.w #1, 4(a4) ; Return one 16-bit integer parameter.
- move.w #1, 6(a4) ; Input one 32-bit pointer parameter.
- move.w #0, 8(a4) ; Return no 32-bit pointer parameters.
- lea global(pc), a0 ; Fetch address of global array.
- move.w 4(a0), int_in ; Application identification to int_in[0].
- move.l #menu_text, addr_in ; Menu text address to addr_in[0].
- bsr aes
- move.w int_out(pc), menu_id ; Store menu identification number.
-
- ; MAIN ACCESSORY LOOP
-
- ;
- ; TEST POINT 2: After menu_register, before evnt_mesag
- ;
- bsr print_arrays
-
- move.l #message, addr_in ; Address of message array to addr_in.
- wait_for_message: ; COMPUTE! AES book page 235.
- move.w #$17, (a4) ; Function = evnt_mesag = AES $17.
- move.w #0, 2(a4) ; Input one 16-bit integer parameter.
- move.w #1, 4(a4) ; Return one 16-bit integer parameter.
- move.w #1, 6(a4) ; Input one 32-bit pointer parameter.
- move.w #0, 8(a4) ; Return no 32-bit pointer parameters.
- bsr aes
-
- ; When a message is received it is placed in array 'message'.
-
- ; ****************************************************************************
- ; ****************************************************************************
-
- message_handler: ; Entrance point when message is received.
- lea message(pc), a0 ; Fetch address of array 'message'.
- cmpi.w #$28, (a0) ; Compare ACCESSORY OPEN code with message[0].
- bne.s wait_for_message ; Execute the evnt_mesag function.
- move.w 8(a0), d0 ; The menu item selected is stored in element
- ; four (message[4]) of array 'message'. This
- ; application's id # is in menu_id.
- cmp.w menu_id(pc), d0 ; Was this application selected.
- bne.s wait_for_message ; Execute the evnt_mesag function.
-
- ; ****************************************************************************
- ; ****************************************************************************
-
- ; Execution proceeds past this point only when this application has been
- ; selected from the menu.
-
- cmpi.w #5, test ; Have five array groups been printed?
- beq wait_for_message ; Disable message handler if true.
- ;
- ; TEST POINT 3: In message handler, before evnt_mesag
- ;
- bsr print_arrays
- cmpi.w #5, test ; Branch after 2nd entrance in message handler.
- beq.s close_file
- bra wait_for_message ; Execute the evnt_mesag function.
-
- close_file:
- move.w handle(pc), -(sp)
- move.w #$3E, -(sp) ; Function = GEMDOS $3E = f_close.
- trap #1
- addq.l #4, sp
- redirect_screen_output:
- move.w #1, -(sp) ; This is the screen's handle.
- move.w handle(pc), -(sp) ; This is the file's handle.
- move.w #$46, -(sp) ; Function = f_force = GEMDOS $46.
- trap #1
- addq.l #6, sp
- bra wait_for_message
-
- ;
- ; SUBROUTINES
- ;
-
- print_arrays:
- lea newline(pc), a0
- bsr print_line
- lea test_header(pc), a0 ; Setup to fetch test point header.
- move.w test(pc), d0 ; Load test point number into D0.
- lsl.w #2, d0 ; Multiply by 4 to reach next pointer slot.
- movea.l 0(a0,d0.w), a0 ; Print test point header.
- bsr print_line
- lea pre_spaces(pc), a0 ; Print spaces before column headers.
- bsr print_line
- lea aes_names(pc), a0 ; Print AES array column headers.
- bsr print_line
- lea pre_spaces(pc), a0 ; Print spaces before underline.
- bsr print_line
- lea aes_underline(pc), a0; Print AES underline.
- bsr print_line
- moveq.l #0, d7 ; D7 is up counter to print 5 rows.
- moveq.l #4, d6 ; D6 is down counter to print 5 elements.
- put_row:
- lea buffer(pc), a0 ; Buffer is an 80 byte line buffer.
- movea.l a5, a6 ; Copy aes parameter block address.
- move.w #5, d5 ; D5 is array counter for 6 arrays.
- move.w #11, d0 ; Print beginning spaces to line up columns.
- put_space:
- move.b #$20, (a0)+
- dbra d0, put_space
- put_element: ; Print contents of array element.
- move.w d7, d0 ; Print array element number.
- andi.b #$F, d0 ; Mask most significant nibble.
- move.b 0(a3,d0.w), d0 ; Store appropriate hex character in D0.
- move.b d0, (a0)+
- move.b #$3A, (a0)+ ; A colon.
- move.b #$20, (a0)+ ; A space.
- move.w d7, d0 ; Multiply contents of D7 by 2 in D0 to
- lsl.w #1, d0 ; obtain offset for next array element.
- movea.l (a6)+, a1 ; Copy array address into A1 and increment
- ; A6 to point to next array address.
- move.w 0(a1,d0.w), d0 ; Fetch contents of array element.
- moveq #3, d2 ; D2 is loop counter for ASCII conversion.
- convert_digit: ; Convert a nibble, then print it.
- rol.w #4, d0 ; Rotate most significant nibble to the
- ; least significant nibble position.
- move.b d0, d1 ; Copy least significant byte of D0 to D1.
- andi.b #$F, d1 ; Mask out most significant nibble of D1.
- ext.w d1 ; Extend to word length.
- move.b 0(a3,d1.w), d1 ; Fetch ASCII hex digit to D1.
- put_digit:
- move.b d1, (a0)+
- dbra d2, convert_digit ; Loop until D2 = -1.
- _put_spaces:
- move.b #$20, (a0)+
- move.b #$20, (a0)+
- dbra d5, put_element
- move.b #0, (a0) ; Store NULL at end of string.
- lea buffer(pc), a0
- bsr print_line
- lea newline(pc), a0 ; Print a newline.
- bsr print_line
- addi.w #1, d7 ; Increment up counter.
- dbra d6, put_row
- add.w #1, test ; Increment test for next test point.
- rts
-
- aes: ; COMPUTE! AES book page 13,
- move.l a5, d1 ; Address of aes_pb.
- move.w d3, d0 ; AES identifier = $C8.
- trap #2
- rts
-
- print_line:
- move.l a0, -(sp) ; Push string onto stack.
- move.w #9, -(sp) ; Function = c_conws.
- trap #1
- addq.l #6, sp
- rts
-
- data
- aes_pb: dc.l control,global,int_in,int_out,addr_in,addr_out
- test_header: dc.l zero,one,two,three,four
- zero:
- dc.b $D,$A,'TEST POINT 0: Before appl_init',$D,$A,$D,$A,0
- one:
- dc.b $D,$A,'TEST POINT 1: After appl_init, before menu_register',$D,$A,$D,$A,0
- two:
- dc.b $D,$A,'TEST POINT 2: After menu_register, before evnt_mesag',$D,$A,$D,$A,0
- three:
- dc.b $D,$A,'TEST POINT 3: In message handler, before evnt_mesag',$D,$A,$D,$A,0
- four:
- dc.b $D,$A,'TEST POINT 4: In message handler second time',$D,$A,$D,$A,0
-
- hex_table: dc.b '0123456789ABCDEF'
- newline: dc.b $D,$A,0
- aes_header: dc.b ' AES ARRAYS',$D,$A,0
- aes_names: dc.b 'CONTROL GLOBAL INT_IN INT_OUT ADDR_IN '
- dc.b 'ADDR_OUT',$D,$A,0
- aes_underline:dc.b '------- ------- ------- ------- ------- '
- dc.b '--------',$D,$A,0
- pre_spaces: dc.b ' ',0
- spaces: dc.b ' ',0
- menu_text: dc.b ' Accessory Arrays ',0
- filename: dc.b 'E:\PRG_8\PRG_8AR.DAT',0
-
- bss
- align
-
- ;
- ; AES ARRAYS:
- ;
-
- ; The addresses of the arrays declared below will be stored in the pointer
- ; array 'aes_pb'. That happens because the program is assembled in Relocatable
- ; mode. The sizes declared for the arrays are identical simply because I am
- ; making it easy to line up the program's output.
-
- control: ds.w 5 ; Control parameters.
- global: ds.w 5 ; Global parameters.
- int_in: ds.w 5 ; Input parameters.
- int_out: ds.w 5 ; Output parameters.
- addr_in: ds.w 5 ; Input addresses.
- addr_out: ds.w 5 ; Output addresses.
-
- ;
- ; APPLICATION VARIABLES
- ;
-
- handle: ds.w 1
- test: ds.w 1
- message: ds.l 4 ; 16 byte array.
- menu_id: ds.w 1
- buffer: ds.b 80
- ds.l 300 ; Program stack.
- stack: ds.l 0 ; Address of program stack.
- end
-
-
- Execution Results
-
- TEST POINT 0: Before appl_init
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0000 0: 0000 0: 0000 0: 0000 0: 0000 0: 0000
- 1: 0000 1: 0000 1: 0000 1: 0000 1: 0000 1: 0000
- 2: 0000 2: 0000 2: 0000 2: 0000 2: 0000 2: 0000
- 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 1: After appl_init, before menu_register
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 000A 0: 0120 0: 0000 0: 0003 0: 0000 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0000 1: 0000 1: 0000
- 2: 0001 2: 0003 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 2: After menu_register, before evnt_mesag
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0023 0: 0120 0: 0003 0: 0001 0: 0003 0: 0000
- 1: 0001 1: 0001 1: 0000 1: 0000 1: D341 1: 0000
- 2: 0001 2: 0003 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 3: In message handler, before evnt_mesag
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0017 0: 0120 0: 0003 0: 0001 0: 0003 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0000 1: D3AA 1: 0000
- 2: 0001 2: 0003 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 4: In message handler second time
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0017 0: 0120 0: 0003 0: 0001 0: 0003 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0000 1: D3AA 1: 0000
- 2: 0001 2: 0003 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- Execution Results Discussion
-
- Looking at the contents of the AES structures displayed in
- the test point tables produced by program 76, you should be able
- to spot relevant values passed to the AES system and returned
- therefrom. At test point 1, the second element of global
- (global[2]) contains the application identification number, 3.
- Identical data can be found in the first element of int_out
- (int_out[0]). At test point 2, the menu identification number,
- 1, is evident in int_out[0]. Of particular interest is the fact
- that there is no structure content corruption beyond that
- purposely imposed by the program involved. We will be able to
- use this information to simplify function invocation in future
- programs. Note especially that the contents of addr_in[0] remain
- stable between evnt_mesag invocations; that is the address of the
- message buffer. Remember that this stability is constant only as
- long as no other AES function invocation disturbs the contents of
- addr_in[0].
-
- Storing Data in the File With GEMDOS $40
-
- It is always advantageous to understand several methods of
- accomplishing a task, especially when the system is as complex as
- is the ST, therefore, I want to present a method of storing data
- in the file which does not rely on GEMDOS function $9 and output
- redirection. Program 77 stores data in a buffer of sufficient
- size, then it writes the contents of that buffer to disk using
- GEMDOS function $40. I have chosen a particular directory path
- for the data file; if you decide to experiment with the program,
- you may want to alter that path.
- Since we have learned that we can rely on the stability of
- AES structures during AES function invocation, several short cuts
- have been taken in program 77's 'control' array setups. Program
- 78 accomplishes the same task as does program 77, but it permits
- the data file's directory path to be chosen via the AES file
- selector function. In addition, program 78 uses a group of
- predeclared, function named arrays that are substituted for
- 'control' in the aes parameter block array, as each AES function
- is invoked.
-
- Program 77. Writing data to the desk accessory's data file using
- a buffer and GEMDOS function $40 .
-
- ; Program Name: PRG_8BR.S
- ; Version: 1.002
-
- ; Assembly Instructions:
-
- ; Assemble in Relocatable mode and save with a PRG extension. From
- ; the desktop, change the extension to ACC. Programs that are to function
- ; as desk accessories MUST be assembled in Relocatable mode. If you design
- ; a desk accessory so that it can be assembled in PC-relative mode, and if
- ; you attempt to load that accessory via MultiDesk, you will receive an
- ; error pertaining to the attempt to read in the accessory. If you place
- ; that accessory in the boot directory, the system will reset every time
- ; it attempts to load the accessory. Sei gewarnt!
-
- ; Function:
-
- ; This program is used to observe system corruption of AES arrays
- ; during the execution of AES functions, as does PRG_8AR.S, and this program
- ; also creates a file in which to store its output data, but this program
- ; does not write its data via GEMDOS function $9 and redirection; instead it
- ; stores the data in a buffer, then writes the contents of the buffer to the
- ; file using GEMDOS function $40.
-
- ; Also note some of the short cuts taken to prepare the control array
- ; for each AES function.
-
- ; Execution Instructions:
-
- ; Place PRG_8BR.ACC in the root directory of your boot disk. During the
- ; next power-up cycle, the desk accessory will be installed. From the desktop
- ; select 'Accessory Arrays' two times in order to store the pertinent data in
- ; the file buffer. After the second selection, the file will be created and
- ; the buffer's contents will be written thereto. You can execute the desk
- ; accessory from within MultiDesk if you desire. You may want to change the
- ; path for the file so that it is created on another disk or partition.
-
- lea stack, a7 ; This must be the first instruction.
-
- initialize_register_variables:
- lea buffer(pc), a5 ; A5 is pointer to buffer.
- lea control(pc), a4 ; A4 is pointer for array 'control'.
- lea hex_table(pc), a3 ; A3 points to hexadecimal ASCII digits.
-
- ; For each test point, the contents of each AES array are printed.
-
- ;
- ; TEST POINT 0: Before appl_init
- ;
- bsr print_arrays
-
- initialize_application: ; COMPUTE! AES book page 223.
-
- ; Application identification = apid returned in int_out[0] and global[2].
-
- move.w #$A, (a4) ; Function = appl_init = AES $A.
- move.w #1, 4(a4) ; Return one 16-bit integer parameter.
- bsr aes ; Invoke trap #2 AES exception.
-
- ;
- ; TEST POINT 1: After appl_init, before menu_register
- ;
- bsr print_arrays
-
- menu_installation: ; COMPUTE! AES book page 248.
-
- ; Menu identification number returned in int_out[0].
-
- move.w #$23, (a4) ; Function = menu_register = AES $23.
- move.w #1, 2(a4) ; Input one 16-bit integer parameter.
- move.w #1, 6(a4) ; Input one 32-bit pointer parameter.
- lea global(pc), a0 ; Fetch address of global array.
- move.w 4(a0), int_in ; Application identification to int_in[0].
- move.l #menu_text, addr_in ; Menu text address to addr_in[0].
- bsr aes
- move.w int_out(pc), menu_id ; Store menu identification number.
-
- ; MAIN ACCESSORY LOOP
-
- ;
- ; TEST POINT 2: After menu_register, before evnt_mesag
- ;
- bsr print_arrays
-
- move.l #message, addr_in ; Address of message array to addr_in.
- move.w #$17, (a4) ; Function = evnt_mesag = AES $17.
- move.w #0, 2(a4) ; Input one 16-bit integer parameter.
- move.w #1, 4(a4) ; Return one 16-bit integer parameter.
- move.w #1, 6(a4) ; Input one 32-bit pointer parameter.
- wait_for_message: ; This simplification is not always
- bsr aes ; appropriate.
-
- ; When a message is received it is placed in array 'message'.
-
- ; ****************************************************************************
- ; ****************************************************************************
-
- message_handler: ; Entrance point when message is received.
- lea message(pc), a0 ; Fetch address of array 'message'.
- cmpi.w #$28, (a0) ; Compare ACCESSORY OPEN code with message[0].
- bne.s wait_for_message ; Execute the evnt_mesag function.
- move.w 8(a0), d0 ; The menu item selected is stored in element
- ; four (message[4]) of array 'message'. This
- ; application's id # is in menu_id.
- cmp.w menu_id(pc), d0 ; Was this application selected.
- bne.s wait_for_message ; Execute the evnt_mesag function.
-
- ; ****************************************************************************
- ; ****************************************************************************
-
- ; Execution proceeds past this point only when this application has been
- ; selected from the menu.
-
- ;
- ; TEST POINT 3: In message handler, before evnt_mesag
- ;
- cmpi.w #5, test ; Have five array groups been printed?
- beq wait_for_message ; This effectively disables the handler.
- bsr print_arrays
- cmpi.w #5, test ; Branch after 2nd entrance in message handler.
- beq.s store_in_file ; Create file and store buffer contents.
- bra wait_for_message ; Execute the evnt_mesag function.
-
- store_in_file:
- lea buffer(pc), a6 ; Fetch start address.
- suba.l a6, a5 ; Calculate number of bytes stored in buffer.
-
- create_file: ; COMPUTE! TOS book page 270.
- move.w #0, -(sp) ; File attribute = read/write.
- pea filename(pc)
- move.w #$3C, -(sp) ; Function = f_create = GEMDOS $3C.
- trap #1 ; File handle is returned in D0.
- addq.l #8, sp
- move.w d0, d4 ; Save file handle in D4.
-
- write_buffer_to_file: ; Function = f_write. COMPUTE! TOS p.274.
- pea (a6) ; Push buffer's address.
- move.l a5, -(sp) ; Push byte count length.
- move.w d4, -(sp) ; COMPUTE!'s TOS book incorrectly specifies
- move.w #$40, -(sp) ; a longword operation here; see page 274.
- trap #1
- lea $C(sp), sp
-
- close_output_file: ; COMPUTE! TOS book page 272.
- move.w d4, -(sp) ; Push file handle.
- move.w #$3E, -(sp) ; Function = GEMDOS $3E = f_close.
- trap #1
- addq.l #4, sp
- bra wait_for_message ; Execute the evnt_mesag function.
-
- ;
- ; SUBROUTINES
- ;
-
- print_arrays:
- lea newline(pc), a0
- bsr store_line
- lea test_header(pc), a0 ; Setup to fetch test point header.
- move.w test(pc), d0 ; Load test point number into D0.
- lsl.w #2, d0 ; Multiply by 4 to reach next pointer slot.
- movea.l 0(a0,d0.w), a0 ; Print test point header.
- bsr store_line
- lea pre_spaces(pc), a0 ; Print spaces before column headers.
- bsr store_line
- lea aes_names(pc), a0 ; Print AES array column headers.
- bsr store_line
- lea pre_spaces(pc), a0 ; Print spaces before underline.
- bsr store_line
- lea aes_underline(pc), a0; Print AES underline.
- bsr store_line
- moveq.l #0, d7 ; D7 is up counter to print 5 rows.
- moveq.l #4, d6 ; D6 is down counter to print 5 elements.
- put_row:
- lea aes_pb(pc), a6 ; Fetch parameter block address.
- move.w #5, d5 ; D5 is array counter for 6 arrays.
- move.w #11, d0 ; Print beginning spaces to line up columns.
- put_space:
- move.b #$20, (a5)+
- dbra d0, put_space
- put_element: ; Print contents of array element.
- move.w d7, d0 ; Print array element number.
- andi.b #$F, d0 ; Mask most significant nibble.
- move.b 0(a3,d0.w), d0 ; Store appropriate hex character in D0.
- move.b d0, (a5)+
- move.b #$3A, (a5)+ ; A colon.
- move.b #$20, (a5)+ ; A space.
- move.w d7, d0 ; Multiply contents of D7 by 2 in D0 to
- lsl.w #1, d0 ; obtain offset for next array element.
- movea.l (a6)+, a1 ; Copy array address into A1 and increment
- ; A6 to point to next array address.
- move.w 0(a1,d0.w), d0 ; Fetch contents of array element.
- moveq #3, d2 ; D2 is loop counter for ASCII conversion.
- convert_digit: ; Convert a nibble, then print it.
- rol.w #4, d0 ; Rotate most significant nibble to the
- ; least significant nibble position.
- move.b d0, d1 ; Copy least significant byte of D0 to D1.
- andi.b #$F, d1 ; Mask out most significant nibble of D1.
- ext.w d1 ; Extend to word length.
- move.b 0(a3,d1.w), d1 ; Fetch ASCII hex digit to D1.
- put_digit:
- move.b d1, (a5)+
- dbra d2, convert_digit ; Loop until D2 = -1.
- _put_spaces:
- move.b #$20, (a5)+
- move.b #$20, (a5)+
- dbra d5, put_element
- lea newline(pc), a0 ; Print a newline.
- bsr store_line
- addi.w #1, d7 ; Increment up counter.
- dbra d6, put_row
- add.w #1, test ; Increment test for next test point.
- rts
-
- aes: ; COMPUTE! AES book page 13,
- move.l #aes_pb, d1 ; Address of aes_pb.
- move.w #$C8, d0 ; AES identifier = $C8.
- trap #2
- rts
-
- store_line:
- move.b (a0)+, d0
- beq.s end_of_string
- move.b d0, (a5)+ ; Store byte in buffer.
- bra.s store_line
- end_of_string:
- rts
-
- data
- aes_pb: dc.l control,global,int_in,int_out,addr_in,addr_out
- test_header: dc.l zero,one,two,three,four
- zero:
- dc.b $D,$A,'TEST POINT 0: Before appl_init',$D,$A,$D,$A,0
- one:
- dc.b $D,$A,'TEST POINT 1: After appl_init, before menu_register',$D,$A,$D,$A,0
- two:
- dc.b $D,$A,'TEST POINT 2: After menu_register, before evnt_mesag',$D,$A,$D,$A,0
- three:
- dc.b $D,$A,'TEST POINT 3: In message handler, before evnt_mesag',$D,$A,$D,$A,0
- four:
- dc.b $D,$A,'TEST POINT 4: In message handler second time',$D,$A,$D,$A,0
-
- hex_table: dc.b '0123456789ABCDEF'
- newline: dc.b $D,$A,0
- aes_header: dc.b ' AES ARRAYS',$D,$A,0
- aes_names: dc.b 'CONTROL GLOBAL INT_IN INT_OUT ADDR_IN '
- dc.b 'ADDR_OUT',$D,$A,0
- aes_underline: dc.b '------- ------- ------- ------- ------- '
- dc.b '--------',$D,$A,0
- pre_spaces: dc.b ' ',0
- spaces: dc.b ' ',0
- menu_text: dc.b ' Accessory Arrays ',0
- filename: dc.b 'E:\PRG_8\PRG_8BR.DAT',0
-
- bss
- align
- ;
- ; AES ARRAYS:
- ;
-
- ; The addresses of the arrays declared below will be stored in the pointer
- ; array 'aes_pb'. That happens because the program is assembled in Relocatable
- ; mode. The sizes declared for the arrays are identical simply because I am
- ; making it easy to line up the program's output.
-
- control: ds.w 5 ; Control parameters.
- global: ds.w 5 ; Global parameters.
- int_in: ds.w 5 ; Input parameters.
- int_out: ds.w 5 ; Output parameters.
- addr_in: ds.w 5 ; Input addresses.
- addr_out: ds.w 5 ; Output addresses.
-
- ;
- ; APPLICATION VARIABLES
- ;
-
- file_handle: ds.w 1
- test: ds.w 1
- message: ds.l 4 ; 16 byte array.
- menu_id: ds.w 1
- buffer: ds.l $2000
- ds.l 300 ; Program stack.
- stack: ds.l 0 ; Address of program stack.
- end
-
-
- Execution Results
-
- TEST POINT 0: Before appl_init
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0000 0: 0000 0: 0000 0: 0000 0: 0000 0: 0000
- 1: 0000 1: 0000 1: 0000 1: 0000 1: 0000 1: 0000
- 2: 0000 2: 0000 2: 0000 2: 0000 2: 0000 2: 0000
- 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 1: After appl_init, before menu_register
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 000A 0: 0120 0: 0000 0: 0005 0: 0000 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0000 1: 0000 1: 0000
- 2: 0001 2: 0005 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 2: After menu_register, before evnt_mesag
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0023 0: 0120 0: 0005 0: 0001 0: 0003 0: 0000
- 1: 0001 1: 0001 1: 0000 1: 0000 1: 0DCD 1: 0000
- 2: 0001 2: 0005 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 3: In message handler, before evnt_mesag
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0017 0: 0120 0: 0005 0: 0000 0: 0003 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0000 1: 0E36 1: 0000
- 2: 0001 2: 0005 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 4: In message handler second time
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0017 0: 0120 0: 0005 0: 0000 0: 0003 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0000 1: 0E36 1: 0000
- 2: 0001 2: 0005 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- Predeclaring AES Control Structures
-
- In program 78, no space is reserved for the control
- structure, and control array values are not stored just before
- each AES function invocation. Instead, four function structures
- are declared in the data section of the program. Each of these
- function structures serves as array control when the particular
- function is invoked. Initially, the address of the first
- function structure is stored in the aes_pb slot reserved for
- array control. Then, when it is time to invoke the other AES
- functions, the address of the relevant function is inserted in
- that slot.
-
-
- Program 78. Illustrates the use of predefined AES control
- structures and the AES file selector function.
-
- ; Program Name: PRG_8CR.S
- ; Version: 1.003
-
- ; Assembly Instructions:
-
- ; Assemble in Relocatable mode and save with a PRG extension. From
- ; the desktop, change the extension to ACC.
-
- ; Function:
-
- ; Identical to that of PRG_8BR.S, but this program uses a group of
- ; predeclared, function named arrays that are substituted for 'control' in
- ; the aes_pb, as each AES function is invoked. In addition, a path for the
- ; data file is chosen via the AES file selector function. An additional
- ; array set is provided after the fsel_input function is invoked, then a
- ; final set is printed when the message handler is entered the second time.
-
- ; Execution Instructions:
-
- ; Place PRG_8CR.ACC in the root directory of your boot disk. During the
- ; next power-up cycle, the desk accessory will be installed. From the desktop
- ; select 'Accessory Arrays' two times in order to store the pertinent data in
- ; the file buffer. At the first selection, the file selector will appear so
- ; that a path and filename can be chosen for the data file; the buffer contents
- ; are written to the file when the accessory is chosen the second time.
-
- lea stack, a7 ; This must be the first instruction.
-
- initialize_register_variables:
- move.w #$C8, d3 ; *** D3 is variable for AES call number.
- lea buffer(pc), a5 ; A5 is pointer to buffer.
- lea aes_pb(pc), a4 ; A4 is pointer for aes pointer array.
- lea hex_table(pc), a3 ; A3 points to hexadecimal ASCII digits.
-
- ; For each test point, the contents of each AES array are printed.
-
- ;
- ; TEST POINT 0: Before appl_init
- ;
- bsr print_arrays
-
- initialize_application: ; COMPUTE! AES book page 223.
-
- ; Application identification = apid returned in int_out[0] and global[2].
-
- ; Since the address of the predeclared appl_init array is already stored in
- ; aes_pb, only the trap 2 invocation need be done here.
-
- bsr aes ; Invoke trap #2 AES exception.
- ;
- ; TEST POINT 1: After appl_init, before menu_register
- ;
- bsr print_arrays
-
- menu_installation: ; COMPUTE! AES book page 248.
-
- ; Menu identification number returned in int_out[0].
-
- move.l #menu_register, (a4) ; Store address of next 'control' array.
- lea global(pc), a0 ; Fetch address of global array.
- move.w 4(a0), int_in ; Application identification to int_in[0].
- move.l #menu_text, addr_in ; Menu text address to addr_in[0].
- bsr aes
- move.w int_out(pc), menu_id ; Store menu identification number.
-
- ; MAIN ACCESSORY LOOP
-
- ;
- ; TEST POINT 2: After menu_register, before evnt_mesag
- ;
- bsr print_arrays
-
-
- wait_for_message: ; Relinquish processor control.
- move.l #evnt_mesag, (a4) ; Store address of next 'control' array.
- move.l #message, addr_in ; Address of message array to addr_in.
-
- ; The above instruction must be executed each time evnt_mesag is invoked
- ; because the fsel_input function must store addresses in addr_in also.
- ; Furthermore, the evnt_mesag "control" array must be restored in aes_pb
- ; because it is replaced by the fsel_input "control" array whenever that
- ; function is invoked. If these alterations did not take place, then the
- ; evnt_mesag setup could be simplified as was done in PRG_8BR.S.
-
- bsr aes
-
- ; When a message is received it is placed in array 'message'.
-
- ; ****************************************************************************
- ; ****************************************************************************
-
- message_handler: ; Entrance point when message is received.
- lea message(pc), a0 ; Fetch address of array 'message'.
- cmpi.w #$28, (a0) ; Compare ACCESSORY OPEN code with message[0].
- bne.s wait_for_message ; Execute the evnt_mesag function.
- move.w 8(a0), d0 ; The menu item selected is stored in element
- ; four (message[4]) of array 'message'. This
- ; application's id # is in menu_id.
- cmp.w menu_id(pc), d0 ; Was this application selected.
- bne.s wait_for_message ; Execute the evnt_mesag function.
-
- ; ****************************************************************************
- ; ****************************************************************************
-
- ; Execution proceeds past this point only when this application has been
- ; selected from the menu.
-
- ;
- ; TEST POINT 3: In message handler, before fsel_input
- ;
- cmpi.w #5, test ; Have six array groups been printed?
- beq wait_for_message ; This effectively disables the handler.
- bsr print_arrays
-
- cmpi.w #5, test ; Is this 2nd entrance into message handler?
- bne.s get_current_drive
-
- store_in_file:
- lea buffer(pc), a6 ; Fetch start address.
- suba.l a6, a5 ; Calculate number of bytes stored in buffer.
-
- create_file: ; COMPUTE! TOS book page 270.
- move.w #0, -(sp) ; File attribute = read/write.
- pea path(pc) ; Push address of path.
- move.w #$3C, -(sp) ; Function = f_create = GEMDOS $3C.
- trap #1 ; Path handle is returned in D0.
- addq.l #8, sp
- move.w d0, d4 ; Save path handle in D4.
-
- write_buffer_to_file: ; Function = f_write. COMPUTE! TOS p.274.
- pea (a6) ; Push buffer's address.
- move.l a5, -(sp) ; Push byte count length.
- move.w d4, -(sp) ; COMPUTE!'s TOS book incorrectly specifies
- move.w #$40, -(sp) ; a longword operation here; see page 274.
- trap #1
- lea $C(sp), sp
-
- close_output_file: ; Actually, close the path.
- move.w d4, -(sp) ; Push path handle.
- move.w #$3E, -(sp) ; Function = GEMDOS $3E = f_close.
- trap #1
- addq.l #4, sp
- bra wait_for_message ; Execute the evnt_mesag function.
-
- get_current_drive: ; Current drive = last drive accessed.
- move.w #$19, -(sp) ; Function = c_getdrv.
- trap #1 ; Current drive number returned in D0.
- addq.l #2, sp
-
- ; Here we begin to construct the path that will be displayed when the
- ; file selector function is invoked. Below, I indicate the data that
- ; is actually being extracted from the system. Most references do not
- ; accurately describe what is being done with these functions.
-
- add.w #$41, d0 ; Convert drive number to drive letter.
- lea path(pc), a6 ; Fetch address of array 'path'.
- move.b d0, (a6)+ ; Store drive letter in 'path' array.
- move.b #$3A, (a6)+ ; Store a colon in 'path' array.
-
- get_sub_directories: ; The drive is the main directory.
- move.w #0, -(sp) ; See Internals page 135 for other values.
- pea (a6) ; Push address of next 'path' array element.
- move.w #$47, -(sp) ; Function = d_getpath = get subdirectories.
- trap #1 ; Subdirectories are returned in the array
- addq.l #8, sp ; 'path'.
-
- add_extension:
-
- ; The extension '\*.*' is added to complete the path. This string must be
- ; NULL terminated. For example, assume that the get_current_drive routine
- ; returns #6; adding 41 would convert this to ASCII F. After the drive
- ; letter and the colon are stored in the path array, the elements of the
- ; array would contain:
-
- ; F:____________________________________,etc.
-
- ; Whatever the get_sub_directories routine returns will be placed in the path
- ; array; the first character will be stored in element 3. Assume that the
- ; routine returns \FILE_SEL as a subdirectory. The path array would contain:
-
- ; F:\FILE_SEL___________________________,etc.
-
- ; The extension is then added to the array contents to yield:
-
- ; F:\FILE_SEL\*.*O______________________,etc.
-
- ; where the O represents the NULL character. This is the path. At this
- ; time there is no file name in the path.
-
- ; When the file selector is displayed, the contents of array 'path' will
- ; appear on the path = directory line. The selection line will be blank
- ; because the program does not write anything to that line.
-
- find_path_end: ; Find NULL at end of returned string.
- tst.b (a6)+
- bne find_path_end ; Branch back till NULL is found.
- subq.l #1, a6 ; Back up to overwrite the NULL.
- move.b #$5C, (a6)+ ; Add '\'.
- move.b #$2A, (a6)+ ; Add '*'.
- move.b #$2E, (a6)+ ; Add '.'.
- move.b #$2A, (a6)+ ; Add '*'.
- move.b #0, (a6) ; Add NULL.
-
- display_file_selector: ; COMPUTE!'s AES book page 282.
-
- ; Returns the drive name and subdirectories selected by the user in the
- ; array 'path', and, if a file was selected, it is returned in the array
- ; 'file'.
-
- move.l #fsel_input, (a4) ; Store address of next 'control' array.
- initialize_address_in_array:
- lea addr_in(pc), a1 ; Fetch address of array 'addr_in'.
- lea path(pc), a6 ; Fetch address of array 'path'.
- move.l a6, (a1) ; Store address of 'path' in 'addr_in'.
- move.l #file, 4(a1) ; Store address of 'file' in 'addr_in'.
- bsr aes
-
- ;
- ; TEST POINT 4: In message handler, after fsel_input
- ;
- bsr print_arrays
-
- analyze_returns: ; Look at returns for File Selector box.
- tst.w int_out + 2 ; CANCEL button => 0.
- beq wait_for_message ; Go there if CANCEL was selected.
- tst.b file ; NO FILE CHOSEN => 0.
- beq wait_for_message ; Go there if no file was chosen.
-
- find_selected_path_end: ; Search for first asterisk.
-
- ; At this point, the selected path does not include the file name, so
- ; it is only a "partial" path.
-
- cmp.b #$2A, (a6)+
- bne find_selected_path_end
- subq.l #1, a6 ; Back up to overwrite the asterisk.
-
- ; Here we add the file name to the path by appending it to the "partial"
- ; path. Then we will have constructed the complete path.
-
- lea file(pc), a0
- add_filename_to_path:
- move.b (a0)+, (a6)+
- bne.s add_filename_to_path ; Now we have a true path.
- bra wait_for_message ; Execute the evnt_mesag function.
-
- ;
- ; SUBROUTINES
- ;
-
- print_arrays:
- lea newline(pc), a0
- bsr store_line
- lea test_header(pc), a0 ; Setup to fetch test point header.
- move.w test(pc), d0 ; Load test point number into D0.
- lsl.w #2, d0 ; Multiply by 4 to reach next pointer slot.
- movea.l 0(a0,d0.w), a0 ; Print test point header.
- bsr store_line
- lea pre_spaces(pc), a0 ; Print spaces before column headers.
- bsr store_line
- lea aes_names(pc), a0 ; Print AES array column headers.
- bsr store_line
- lea pre_spaces(pc), a0 ; Print spaces before underline.
- bsr store_line
- lea aes_underline(pc), a0; Print AES underline.
- bsr store_line
- moveq.l #0, d7 ; D7 is up counter to print 5 rows.
- moveq.l #4, d6 ; D6 is down counter to print 5 elements.
- put_row:
- lea aes_pb(pc), a6 ; Fetch parameter block address.
- move.w #5, d5 ; D5 is array counter for 6 arrays.
- move.w #11, d0 ; Print beginning spaces to line up columns.
- put_space:
- move.b #$20, (a5)+
- dbra d0, put_space
- put_element: ; Print contents of array element.
- move.w d7, d0 ; Print array element number.
- andi.b #$F, d0 ; Mask most significant nibble.
- move.b 0(a3,d0.w), d0 ; Store appropriate hex character in D0.
- move.b d0, (a5)+
- move.b #$3A, (a5)+ ; A colon.
- move.b #$20, (a5)+ ; A space.
- move.w d7, d0 ; Multiply contents of D7 by 2 in D0 to
- lsl.w #1, d0 ; obtain offset for next array element.
- movea.l (a6)+, a1 ; Copy array address into A1 and increment
- ; A6 to point to next array address.
- move.w 0(a1,d0.w), d0 ; Fetch contents of array element.
- moveq #3, d2 ; D2 is loop counter for ASCII conversion.
- convert_digit: ; Convert a nibble, then print it.
- rol.w #4, d0 ; Rotate most significant nibble to the
- ; least significant nibble position.
- move.b d0, d1 ; Copy least significant byte of D0 to D1.
- andi.b #$F, d1 ; Mask out most significant nibble of D1.
- ext.w d1 ; Extend to word length.
- move.b 0(a3,d1.w), d1 ; Fetch ASCII hex digit to D1.
- put_digit:
- move.b d1, (a5)+
- dbra d2, convert_digit ; Loop until D2 = -1.
- _put_spaces:
- move.b #$20, (a5)+
- move.b #$20, (a5)+
- dbra d5, put_element
- lea newline(pc), a0 ; Print a newline.
- bsr store_line
- addi.w #1, d7 ; Increment up counter.
- dbra d6, put_row
- add.w #1, test ; Increment test for next test point.
- rts
-
- aes: ; COMPUTE! AES book page 13,
- move.l a4, d1 ; Address of aes_pb.
- move.w d3, d0 ; AES identifier = $C8.
- trap #2
- rts
-
- store_line:
- move.b (a0)+, d0
- beq.s end_of_string
- move.b d0, (a5)+ ; Store byte in buffer.
- bra.s store_line
- end_of_string:
- rts
-
- data
- aes_pb: dc.l appl_init,global,int_in,int_out,addr_in,addr_out
- test_header: dc.l zero,one,two,three,four,five
- zero:
- dc.b $D,$A,'TEST POINT 0: Before appl_init',$D,$A,$D,$A,0
- one:
- dc.b $D,$A,'TEST POINT 1: After appl_init, before menu_register',$D,$A,$D,$A,0
- two:
- dc.b $D,$A,'TEST POINT 2: After menu_register, before evnt_mesag',$D,$A,$D,$A,0
- three:
- dc.b $D,$A,'TEST POINT 3: In message handler, before fsel_input',$D,$A,$D,$A,0
- four:
- dc.b $D,$A,'TEST POINT 4: In message handler, after fsel_input',$D,$A,$D,$A,0
- five:
- dc.b $D,$A,'TEST POINT 5: In message handler second time',$D,$A,$D,$A,0
-
- hex_table: dc.b '0123456789ABCDEF'
- newline: dc.b $D,$A,0
- aes_header: dc.b ' AES ARRAYS',$D,$A,0
- aes_names: dc.b 'CONTROL GLOBAL INT_IN INT_OUT ADDR_IN '
- dc.b 'ADDR_OUT',$D,$A,0
- aes_underline: dc.b '------- ------- ------- ------- ------- '
- dc.b '--------',$D,$A,0
- pre_spaces: dc.b ' ',0
- spaces: dc.b ' ',0
- menu_text: dc.b ' Accessory Arrays ',0
-
- align
-
- ;
- ; AES ARRAYS:
- ;
-
- ; PREDEFINED 'CONTROL' STRUCTURES
-
- appl_init: ; This one is prestored in aes_pb.
- dc.w 10
- dc.w 0
- dc.w 1
- dc.w 0
- dc.w 0
-
- menu_register:
- dc.w 35
- dc.w 1
- dc.w 1
- dc.w 1
- dc.w 0
-
- evnt_mesag:
- dc.w 23
- dc.w 0
- dc.w 1
- dc.w 1
- dc.w 0
-
- fsel_input:
- dc.w 90
- dc.w 0
- dc.w 2
- dc.w 2
- dc.w 0
-
- ; The addresses of the arrays declared below will be stored in the pointer
- ; array 'aes_pb'. That happens because the program is assembled in Relocatable
- ; mode. The sizes declared for the arrays are identical simply because I am
- ; making it easy to line up the program's output.
-
- ; Note that array 'control' is not declared below,.
-
- bss ; The location of this assembler directive is critical. It must
- ; not be placed before the predeclared 'control' structures.
-
- global: ds.w 5 ; Global parameters.
- int_in: ds.w 5 ; Input parameters.
- int_out: ds.w 5 ; Output parameters.
- addr_in: ds.w 5 ; Input addresses.
- addr_out: ds.w 5 ; Output addresses.
-
-
- ;
- ; FSEL_INPUT ARRAYS
- ;
-
- path: ds.b 120 ; Array for drive name and subdirectories.
- file: ds.b 14 ; Array for selected file.
-
- ;
- ; APPLICATION VARIABLES
- ;
-
- file_handle: ds.w 1
- test: ds.w 1
- message: ds.l 4 ; 16 byte array.
- menu_id: ds.w 1
- buffer: ds.l $2000
- ds.l 300 ; Program stack.
- stack: ds.l 0 ; Address of program stack.
- end
-
-
- Execution Results
-
- TEST POINT 0: Before appl_init
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 000A 0: 0000 0: 0000 0: 0000 0: 0000 0: 0000
- 1: 0000 1: 0000 1: 0000 1: 0000 1: 0000 1: 0000
- 2: 0001 2: 0000 2: 0000 2: 0000 2: 0000 2: 0000
- 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 1: After appl_init, before menu_register
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 000A 0: 0120 0: 0000 0: 0003 0: 0000 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0000 1: 0000 1: 0000
- 2: 0001 2: 0003 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 2: After menu_register, before evnt_mesag
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0023 0: 0120 0: 0003 0: 0001 0: 0003 0: 0000
- 1: 0001 1: 0001 1: 0000 1: 0000 1: D3D8 1: 0000
- 2: 0001 2: 0003 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 3: In message handler, before fsel_input
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0017 0: 0120 0: 0003 0: 0001 0: 0003 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0000 1: D4D0 1: 0000
- 2: 0001 2: 0003 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 4: In message handler, after fsel_input
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 005A 0: 0120 0: 0003 0: 0001 0: 0003 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0001 1: D446 1: 0000
- 2: 0002 2: 0003 2: 0000 2: 9C58 2: 0003 2: 0000
- 3: 0002 3: 0000 3: 0000 3: 0000 3: D4BE 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 5: In message handler second time
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0017 0: 0120 0: 0003 0: 0001 0: 0003 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0001 1: D4D0 1: 0000
- 2: 0001 2: 0003 2: 0000 2: 9C58 2: 0003 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: D4BE 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- Execution Results Discussion
-
- There is nothing unexpected in the test point tables
- produced by the program. Note that the first table does contain
- the values stored in the appl_init array since it was predeclared
- and its address was prestored in aes_pb. In the test point 5
- table, note that addr_in[0] contains the address of the message
- array, as it should, but that the fsel_input required address
- that was stored in addr_in[1] during that function's invocation
- has not been disturbed. The stability of that array element
- could be used to advantage if it was necessary to invoke
- fsel_input again.
-
- Spawning a Program to Create a Desk Accessory's File
-
- Each ST programmer tends to concentrate productivity in
- areas of personal interest and commitment; therefore, it is not
- unusual to find that information passed on to one programmer by
- another is not quite applicable to the second programmer's
- particular programming applications. For example, I am
- completely neglecting the concept of color monitor programming
- requirements in this book. In order to offset this neglect, I am
- inclined to illustrate several methods of accomplishing a task.
- In some cases, I am prompted to do so because of something I have
- heard or read; in other cases, I feel that readers may notice
- something of assistance within the additional material. It is
- with from this viewpoint that I include programs 79 and 80.
- This pair of programs also create a file and store the
- contents of the AES structures therein, but the desk accessory,
- program 79, does not create the file; instead, it stores its data
- in a buffer and spawns program 80 so that it can create the file,
- write the buffer contents therein and properly close the file. I
- have chosen particular directory paths for the programs and the
- data files; if you decide to experiment with the programs, you
- may want to alter those paths.
-
- Program 79. Spawning a program from within a desk accessory so
- that the spawned program can create a file in which to store data
- generated by the desk accessory.
-
- ; Program Name: PRG_8DR.S
- ; Version: 1.002
-
- ; Assembly Instructions:
-
- ; Assemble in Relocatable mode and save with a PRG extension. From
- ; the desktop, change the extension to ACC. Programs that are to function
- ; as desk accessories MUST be assembled in Relocatable mode. If you design
- ; a desk accessory so that it can be assembled in PC-relative mode, and if
- ; you attempt to load that accessory via MultiDesk, you will receive an
- ; error pertaining to the attempt to read in the accessory. If you place
- ; that accessory in the boot directory, the system will reset every time
- ; it attempts to load the accessory. Sei gewarnt!
-
- ; Function:
-
- ; Identical to that of PRG_8CR.S, but this program does not create a
- ; file and place data directly therein. Instead, another program is spawned
- ; to create the file and transfer the data from the buffer to the file. The
- ; name of the disk file to be created by PRG_8EP.TOS is passed as a parameter
- ; in an environmental string.
-
- ; Execution Instructions:
-
- ; Place PRG_8DR.ACC and PRG_8EP.TOS in the root directory of your boot
- ; disk. During the next power-up cycle, the desk accessory will be installed.
- ; From the desktop select 'Accessory Arrays' two times in order to store the
- ; pertinent data in the file buffer. After the second selection, PRG_8EP.TOS
- ; will be executed. PRG_8EP.TOS will create file PRG_8DR.DAT, write the
- ; contents of the buffer to the file and close the file properly. You can
- ; execute the desk accessory from within MultiDesk, but don't forget that
- ; PRG_8EP.TOS must be in the same directory as is PRG_8DR.ACC. You may want
- ; to change the path for the file so that it is created on another disk or disk
- ; partition.
-
- lea stack, a7 ; This must be the first instruction.
-
- ; Note that when the buffer is declared before the stack, pc-relative
- ; addressing can't be used in the instruction above, because of the distance
- ; between the instruction and the address of the stack.
-
- initialize_register_variables:
- move.w #$C8, d3 ; *** D3 is variable for AES call number.
- lea buffer(pc), a5 ; A5 is pointer to buffer.
- lea aes_pb(pc), a4 ; A4 is pointer for aes pointer array.
- lea hex_table(pc), a3 ; A3 points to hexadecimal ASCII digits.
-
- ; The file buffer's address must be converted to an ASCII hexadecimal string
- ; and stored in the variable "command_string" so that it can be passed in that
- ; form to the spawned process, PRG_8EP.TOS. Note that the 8 digit string can be
- ; passed in "pure" form when it is done in this manner; that is, no quotes nor
- ; NULL character is needed. Refer to COMPUTE!'s TOS book pages 100 - 102 for
- ; other important information concerning the spawning process.
-
- store_buffer_address_in_command_line:
- move.l a5, d0
- lea command_string, a0 ; Fetch address of command line string.
- moveq #7, d2 ; D2 is loop counter for ASCII conversion.
- _convert_digit: ; Convert a nibble, then store it.
- rol.l #4, d0 ; Rotate most significant nibble to the
- ; least significant nibble position.
- move.b d0, d1 ; Copy least significant byte of D0 to D1.
- andi.b #$F, d1 ; Mask out most significant nibble of D1.
- ext.w d1 ; Extend to word length.
- move.b 0(a3,d1.w), d1 ; Fetch ASCII hex digit to D1.
- _put_digit:
- move.b d1, (a0)+
- dbra d2, _convert_digit ; Loop until D2 = -1.
-
- ; For each test point, the contents of each AES array are printed.
-
- ;
- ; TEST POINT 0: Before appl_init
- ;
- bsr print_arrays
-
- initialize_application: ; COMPUTE! AES book page 223.
-
- ; Application identification = apid returned in int_out[0] and global[2].
-
- ; Since the address of the predeclared appl_init array is already stored in
- ; aes_pb, only the trap 2 invocation need be done here.
-
- bsr aes ; Invoke trap #2 AES exception.
- ;
- ; TEST POINT 1: After appl_init, before menu_register
- ;
- bsr print_arrays
-
- menu_installation: ; COMPUTE! AES book page 248.
-
- ; Menu identification number returned in int_out[0].
-
- move.l #menu_register, (a4) ; Store address of next "control" array.
- lea global(pc), a0 ; Fetch address of global array.
- move.w 4(a0), int_in ; Application identification to int_in[0].
- move.l #menu_text, addr_in ; Menu text address to addr_in[0].
- bsr aes
- move.w int_out(pc), menu_id ; Store menu identification number.
-
- ; MAIN ACCESSORY LOOP
-
- ;
- ; TEST POINT 2: After menu_register, before evnt_mesag
- ;
- bsr print_arrays
-
- move.l #message, addr_in ; Address of message array to addr_in.
- move.l #evnt_mesag, (a4) ; Store address of next "control" array.
- wait_for_message: ; COMPUTE! AES book page 235.
- bsr aes
-
- ; When a message is received it is placed in array 'message'. Note the
- ; short cuts taken above. Since the aes_pb and the addr_in structures remain
- ; uncorrupted after they have been initialized for the evnt_mesag function,
- ; only the trap 2 exception need be invoked each time that function is to be
- ; executed.
-
- ; ****************************************************************************
- ; ****************************************************************************
-
- message_handler: ; Entrance point when message is received.
- lea message(pc), a0 ; Fetch address of array 'message'.
- cmpi.w #$28, (a0) ; Compare ACCESSORY OPEN code with message[0].
- bne.s wait_for_message ; Execute the evnt_mesag function.
- move.w 8(a0), d0 ; The menu item selected is stored in element
- ; four (message[4]) of array 'message'. This
- ; application's id # is in menu_id.
- cmp.w menu_id(pc), d0 ; Was this application selected.
- bne.s wait_for_message ; Execute the evnt_mesag function.
-
- ; ****************************************************************************
- ; ****************************************************************************
-
- ; Execution proceeds past this point only when this application has been
- ; selected from the menu.
-
- ;
- ; TEST POINT 3: In message handler, before evnt_mesag
- ;
- cmpi.w #5, test ; Have five array groups been printed?
- beq wait_for_message
- bsr print_arrays
- cmpi.w #5, test ; Branch after 2nd entrance in message handler.
- beq.s store_in_file ; Spawn process to create file.
- bra wait_for_message ; Execute the evnt_mesag function.
-
- store_in_file:
- move.b #0, (a5) ; Store NULL at end of file buffer.
- pea environ_string
- pea command_string ; Contains address of file buffer.
- pea program ; Push address of program name string.
- move.w #0, -(sp)
- move.w #$4B, -(sp) ; Function = GEMDOS $4B = p_exec.
- trap #1
- lea $10(sp), sp
- bra wait_for_message ; Execute the evnt_mesag function.
-
- ;
- ; SUBROUTINES
- ;
-
- print_arrays:
- lea newline(pc), a0
- bsr store_line
- lea test_header(pc), a0 ; Setup to fetch test point header.
- move.w test(pc), d0 ; Load test point number into D0.
- lsl.w #2, d0 ; Multiply by 4 to reach next pointer slot.
- movea.l 0(a0,d0.w), a0 ; Print test point header.
- bsr store_line
- lea pre_spaces(pc), a0 ; Print spaces before column headers.
- bsr store_line
- lea aes_names(pc), a0 ; Print AES array column headers.
- bsr store_line
- lea pre_spaces(pc), a0 ; Print spaces before underline.
- bsr store_line
- lea aes_underline(pc), a0; Print AES underline.
- bsr store_line
- moveq.l #0, d7 ; D7 is up counter to print 5 rows.
- moveq.l #4, d6 ; D6 is down counter to print 5 elements.
- put_row:
- lea aes_pb(pc), a6 ; Fetch parameter block address.
- move.w #5, d5 ; D5 is array counter for 6 arrays.
- move.w #11, d0 ; Print beginning spaces to line up columns.
- put_space:
- move.b #$20, (a5)+
- dbra d0, put_space
- put_element: ; Print contents of array element.
- move.w d7, d0 ; Print array element number.
- andi.b #$F, d0 ; Mask most significant nibble.
- move.b 0(a3,d0.w), d0 ; Store appropriate hex character in D0.
- move.b d0, (a5)+
- move.b #$3A, (a5)+ ; A colon.
- move.b #$20, (a5)+ ; A space.
- move.w d7, d0 ; Multiply contents of D7 by 2 in D0 to
- lsl.w #1, d0 ; obtain offset for next array element.
- movea.l (a6)+, a1 ; Copy array address into A1 and increment
- ; A6 to point to next array address.
- move.w 0(a1,d0.w), d0 ; Fetch contents of array element.
- moveq #3, d2 ; D2 is loop counter for ASCII conversion.
- convert_digit: ; Convert a nibble, then print it.
- rol.w #4, d0 ; Rotate most significant nibble to the
- ; least significant nibble position.
- move.b d0, d1 ; Copy least significant byte of D0 to D1.
- andi.b #$F, d1 ; Mask out most significant nibble of D1.
- ext.w d1 ; Extend to word length.
- move.b 0(a3,d1.w), d1 ; Fetch ASCII hex digit to D1.
- put_digit:
- move.b d1, (a5)+
- dbra d2, convert_digit ; Loop until D2 = -1.
- _put_spaces:
- move.b #$20, (a5)+
- move.b #$20, (a5)+
- dbra d5, put_element
- lea newline(pc), a0 ; Print a newline.
- bsr store_line
- addi.w #1, d7 ; Increment up counter.
- dbra d6, put_row
- add.w #1, test ; Increment test for next test point.
- rts
-
- aes: ; COMPUTE! AES book page 13,
- move.l a4, d1 ; Address of aes_pb.
- move.w d3, d0 ; AES identifier = $C8.
- trap #2
- rts
-
- store_line:
- move.b (a0)+, d0
- beq.s end_of_string
- move.b d0, (a5)+ ; Store byte in buffer.
- bra.s store_line
- end_of_string:
- rts
-
- data
- aes_pb: dc.l appl_init,global,int_in,int_out,addr_in,addr_out
-
- ; PREDEFINED 'CONTROL' STRUCTURES
-
- appl_init: ; This one is prestored in aes_pb.
- dc.w 10
- dc.w 0
- dc.w 1
- dc.w 0
- dc.w 0
-
- menu_register:
- dc.w 35
- dc.w 1
- dc.w 1
- dc.w 1
- dc.w 0
-
- evnt_mesag:
- dc.w 23
- dc.w 0
- dc.w 1
- dc.w 1
- dc.w 0
-
- test_header: dc.l zero,one,two,three,four
- zero:
- dc.b $D,$A,'TEST POINT 0: Before appl_init',$D,$A,$D,$A,0
- one:
- dc.b $D,$A,'TEST POINT 1: After appl_init, before menu_register',$D,$A,$D,$A,0
- two:
- dc.b $D,$A,'TEST POINT 2: After menu_register, before evnt_mesag',$D,$A,$D,$A,0
- three:
- dc.b $D,$A,'TEST POINT 3: In message handler, before evnt_mesag',$D,$A,$D,$A,0
- four:
- dc.b $D,$A,'TEST POINT 4: In message handler second time',$D,$A,$D,$A,0
-
- hex_table: dc.b '0123456789ABCDEF'
- newline: dc.b $D,$A,0
- aes_header: dc.b ' AES ARRAYS',$D,$A,0
- aes_names: dc.b 'CONTROL GLOBAL INT_IN INT_OUT ADDR_IN '
- dc.b 'ADDR_OUT',$D,$A,0
- aes_underline: dc.b '------- ------- ------- ------- ------- '
- dc.b '--------',$D,$A,0
- pre_spaces: dc.b ' ',0
- spaces: dc.b ' ',0
- menu_text: dc.b ' Accessory Arrays ',0
- program: dc.b 'PRG_8EP.TOS',0
- environ_string: dc.b 'E:\PRG_8\PRG_8DR.DAT',0
-
- bss
- command_string: ds.b 30 ; Must contain address of buffer.
-
- align
- ;
- ; AES ARRAYS:
- ;
-
- ; The addresses of the arrays declared below will be stored in the pointer
- ; array 'aes_pb'. That happens because the program is assembled in Relocatable
- ; mode. The sizes declared for the arrays are identical simply because I am
- ; making it easy to line up the program's output.
-
- ; Note that array "control" is not declared below.
-
- global: ds.w 5 ; Global parameters.
- int_in: ds.w 5 ; Input parameters.
- int_out: ds.w 5 ; Output parameters.
- addr_in: ds.w 5 ; Input addresses.
- addr_out: ds.w 5 ; Output addresses.
-
- ;
- ; APPLICATION VARIABLES
- ;
-
- test: ds.w 1
- message: ds.l 4 ; 16 byte array.
- menu_id: ds.w 1
- buffer: ds.l $2000
- ds.l 300 ; Program stack.
- stack: ds.l 0 ; Address of program stack.
- end
-
-
- Program 80. The program that creates the file for program 79.
- This program accepts a file name as a passed parameter in an
- environmental string. Note that the data passed to this program
- via its command line is processed with an ASCII hexadecimal
- string to binary number conversion algorithm.
-
- ; Program Name: PRG_8EP.S
- ; Version: 1.001
-
- ; Assembly Instructions:
-
- ; Assemble in PC-relative mode and save with a TOS suffix.
-
- ; Execution Instructions:
-
- ; This program is spawned by PRG_8DR.ACC. Both programs must reside in
- ; the same directory.
-
- ; Function:
-
- ; This program creates disk file specified in the first environmental string
- ; and stores therein the data contained in PRG_8DR.ACC's buffer. The purpose
- ; of this exercise is to illustrate an alternate method of creating a disk file
- ; for a desk accessory, writing data to the file and invoking proper file
- ; closure.
-
- fetch_command_line_address:
- lea -$82(pc), a3
-
- fetch_environmental_string_address:
- lea -$54(a3), a4 ; Fetch address of string pointer.
- movea.l (a4), a4 ; Fetch address of string.
-
- ; The data in the command line is a string of eight ASCII hexadecimal digits
- ; passed from PRG_8DR.ACC when that program spawned this one. There are no
- ; characters before that string and none following. The string is the address
- ; of PRG_8DR.ACC's buffer, in which data that is to be written to a disk file
- ; has been stored. The address must be converted from an ASCII hexadecimal
- ; string to a binary longword.
-
- ; The data in the environmental string can be used as it exist.
-
- process_command_line: ; Convert ASCII hexadecimal string to binary.
- moveq.l #0, d0 ; Accumulator.
- moveq.l #7, d2 ; Loop counter.
- convert_string:
- move.b (a3)+, d1 ; D1 is used for each character conversion.
- cmpi.b #$39, d1 ; Character greater than 9 test.
- bgt not_decimal
- cmpi.b #$30, d1 ; Character less than 0 test.
- blt not_valid
- subi.b #$30, d1 ; Convert ASCII hex character to binary.
- bra.s accumulate
- not_decimal:
- cmpi.b #$41, d1 ; Character less than A test.
- blt not_valid
- cmpi.b #$46, d1 ; Character greater than F test.
- bgt not_valid
- subi.b #$37, d1 ; Convert ASCII hex character to binary.
- accumulate:
- lsl.l #4, d0 ; Shift one nibble = one hex character.
- add.b d1, d0
- dbra d2, convert_string
- move.l d0, a3 ; Address of buffer is in D0.
- movea.l a3, a0 ; Copy for buffer byte count.
-
- count_bytes_in_buffer:
- moveq.l #0, d0 ; NULL byte test register.
- moveq.l #0, d3 ; Byte count accumulator.
- count:
- move.b (a0)+, d0 ; Look at each character in buffer and
- beq create_file ; accumulate count until NULL is found at
- addq.l #1, d3 ; end of buffer.
- bra.s count
-
- create_file: ; COMPUTE! TOS book page 270.
- move.w #0, -(sp) ; File attribute = read/write.
- pea (a4) ; Environmental string has file's path.
- move.w #$3C, -(sp) ; Function = f_create = GEMDOS $3C.
- trap #1 ; File handle is returned in D0.
- addq.l #8, sp
- move.w d0, d4 ; Save file handle in D4.
-
- write_buffer_to_file: ; Function = f_write. COMPUTE! TOS p.274.
- pea (a3) ; Push buffer's address.
- move.l d3, -(sp) ; Push byte count length.
- move.w d4, -(sp) ; COMPUTE!'s TOS book incorrectly specifies
- move.w #$40, -(sp) ; a longword operation here; see page 274.
- trap #1
- lea $C(sp), sp
-
- close_output_file: ; COMPUTE! TOS book page 272.
- move.w d4, -(sp) ; Push file handle.
- move.w #$3E, -(sp) ; Function = GEMDOS $3E = f_close.
- trap #1
- addq.l #4, sp
-
- not_valid:
- terminate:
- move.w #0, -(sp)
- trap #1
-
- data
- align
- bss
- program_end: ds.l 0
- end
-
- Execution Results
-
- TEST POINT 0: Before appl_init
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 000A 0: 0000 0: 0000 0: 0000 0: 0000 0: 0000
- 1: 0000 1: 0000 1: 0000 1: 0000 1: 0000 1: 0000
- 2: 0001 2: 0000 2: 0000 2: 0000 2: 0000 2: 0000
- 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 1: After appl_init, before menu_register
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 000A 0: 0120 0: 0000 0: 0005 0: 0000 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0000 1: 0000 1: 0000
- 2: 0001 2: 0005 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 2: After menu_register, before evnt_mesag
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0023 0: 0120 0: 0005 0: 0000 0: 0003 0: 0000
- 1: 0001 1: 0001 1: 0000 1: 0000 1: 0DD5 1: 0000
- 2: 0001 2: 0005 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 3: In message handler, before evnt_mesag
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0017 0: 0120 0: 0005 0: 0000 0: 0003 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0000 1: 0E5C 1: 0000
- 2: 0001 2: 0005 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- TEST POINT 4: In message handler second time
-
- CONTROL GLOBAL INT_IN INT_OUT ADDR_IN ADDR_OUT
- ------- ------- ------- ------- ------- --------
- 0: 0017 0: 0120 0: 0005 0: 0000 0: 0003 0: 0000
- 1: 0000 1: 0001 1: 0000 1: 0000 1: 0E5C 1: 0000
- 2: 0001 2: 0005 2: 0000 2: 9C58 2: 0000 2: 0000
- 3: 0001 3: 0000 3: 0000 3: 0000 3: 0000 3: 0000
- 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000 4: 0000
-
- A Practical Example
-
- As a practical desk accessory example, I have chosen a
- program which represents a continuation of the linear print
- buffer discussion of the last chapter. You will be able to
- invoke this program from within any application permitting access
- to desk accessories. Furthermore, since you should be somewhat
- familiar with the program's purpose, you will be able to
- concentrate on the AES functions introduced to invoke the alert
- form. I suggest that you change the name of this program and put
- it to good use as a desk accessory. I call the source file
- PRTASCII.S and the object file PRTASCII.ACC in my system.
-
- Program 81. A desk accessory linear print buffer. The AES file
- selector function is invoked to obtain the path for the file to
- be printed. If the desk accessory is selected while it is busy
- with a file, the form_alert function is invoked.
-
- ; Program Name: PRG_8FR.S
- ; Version: 1.002
-
- ; Assembly Instructions:
-
- ; Assemble in Relocatable mode and save with a PRG extension. From
- ; the desktop, change the extension to ACC. Programs that are to function
- ; as desk accessories MUST be assembled in Relocatable mode.
-
- ; Function:
-
- ; A desk accessory that prints the file selector chosen ASCII file.
- ; The print buffer which is used by this program is linear, not circular.
- ; This program also installs a parallel interface interrupt handler. The
- ; handler is invoked each time that the logic level of pin 11 of the parallel
- ; port drops from high to low.
-
- ; This program initiates the interrupt controlled printing process by
- ; sending a NULL character to the printer (A BELL character could also be
- ; used, if that is desirable.).
-
- ; The default size of the linear print buffer is 32,768 bytes. You can
- ; alter the buffer size and assemble the program with the larger size if you
- ; desire.
-
- ; The program reads the file to be printed and stores it in the buffer
- ; very rapidly, but the speed with which the buffer is cleared depends on
- ; the particular system configuration: if there is an external hardware buffer
- ; between the computer and the printer, or if the printer has an internal
- ; buffer of significant size, then the linear buffer will transfer its
- ; information to the external buffers very rapidly also.
-
- ; If there are no such buffers to speed up the transfer rate from the
- ; buffer to the printer, then it is possible that you may interrupt a session
- ; in progress by selecting the desk accessory before the buffer is clear. If
- ; that event occurs, an alert box will be displayed indicating that the buffer
- ; is busy. You will be able to select OK to continue the printing session
- ; (a Return key press is sufficient), or you may select CANCEL to stop the
- ; session. If you do choose to cancel the session, the buffer will be cleared
- ; immediately; but remember that the printer will continue to print until its
- ; internal buffer, however small, is also cleared.
-
- ; Execution Instructions:
-
- ; Place PRG_8FR.ACC in the root directory of your boot disk. During
- ; the next power-up cycle, the program will be installed in memory as a desk
- ; accessory; assuming that it is not blocked by a program that permits desk
- ; accessory loading selections. Of course, if you use MultiDesk, you need
- ; not power up to use PRG_8FR.ACC immediately.
-
- ; The desk accessory is identified as a menu selection by the name
- ; PRINT ASCII.
-
- ; MAJOR NOTE:
-
- ; Although accessories such as MultiDesk add significant power to a ST
- ; system; and although initial testing of a desk accessory program can be
- ; accomplished via MultiDesk loading of the program, thereby alleviating the
- ; the testing process, the program under test cannot be pronounced correct
- ; until it has been permitted to load normally from the boot disk.
-
- ; For example, if the first statement of this program, which loads the
- ; stack's address into A7, is moved to a location following the routine that
- ; installs the interrupt handler, the accessory will function perfectly when
- ; it is loaded and executed via MultiDesk; but it will bomb during boot
- ; because, at that time, no default stack has yet been assigned by the system.
-
- ; REMEMBER: Programs executed during boot MUST provide their own stacks.
-
- ; NOTE: Within the program, registers are used as variables as much as
- ; possible to speed things up.
-
- lea stack(pc), a7 ; This must be the first instruction.
-
- install_interrupt_handler_vector:; Parallel port pin 11 interrupt handler.
- pea interrupt_handler(pc); Push interrupt handler address.
- move.w #0, -(sp) ; Interrupt level for MFP GPIP bit 0.
- move.w #$D, -(sp) ; Functon = XBIOS #13 decimal = mfpint.
- trap #14
- addq.l #8, sp
-
- install_desk_accessory:
- lea aes_pb(pc), a3 ; aes_pb = AES parameter block.
- move.l a3, d5 ; Use D5 as a variable for aes_pb address.
- lea control(pc), a4 ; A4 is pointer for array 'control'.
- move.w #$C8, d3 ; *** D3 is variable for AES call number.
-
- initialize_application:
- move.w #$A, (a4) ; Function = appl_init = AES $A.
- move.w #1, 4(a4) ; Return one int_out parameter.
- move.l d5, d1 ; D5 contains address of aes parameter block.
- move.w d3, d0 ; D3 contains AES call number.
- trap #2 ; apid returned in int_out[0] and global[2].
-
- menu_installation:
- move.w #$23, (a4) ; Function = menu_register = AES $23.
- move.w #1, 2(a4) ; Pass one int_in parameter.
- move.w #1, 6(a4) ; Pass one addr_in parameter.
- lea int_out(pc), a6 ; Fetch address of int_out array.
- move.w (a6), int_in ; Application identification to int_in[0].
- lea addr_in(pc), a5 ; Fetch address of addr_in array.
- move.l #menu_text, (a5) ; Menu text address to addr_in[0].
- move.l d5, d1 ; Address of aes parameter block to D1.
- move.w d3, d0 ; D3 contains AES call number.
- trap #2 ; Menu identification number returned
- ; in int_out[0].
- move.w (a6), d4 ; Store menu identification number in D4.
-
- ; MAIN ACCESSORY LOOP
-
- lea message(pc), a3 ; A3 is variable for message array address.
- wait_for_message: ; Relinquish processor control.
- move.w #$17, (a4) ; Function = evnt_mesag = AES $17.
- move.w #0, 2(a4) ; Input one 16-bit integer parameter.
- move.w #1, 4(a4) ; Return one 16-bit integer parameter.
- move.w #1, 6(a4) ; Input one 32-bit pointer parameter.
- move.w #0, 8(a4) ; Return no 32-bit pointer parameters.
- move.l a3, (a5) ; Address of message array to addr_in.
-
- ; The above instruction must be executed each time evnt_mesag is invoked
- ; because the form_alert and fsel_input functions must store addresses in
- ; addr_in also. If that were not so, then the evnt_mesag setup could be
- ; simplified; that is, the address of the message array could be stored in
- ; addr_in once, before the wait_for_message label.
-
- ; In addition, I have been successful with the following abbreviated
- ; implementation of the evnt_mesag function, even though the fsel_input
- ; function intervenes between evnt_mesag invocations:
-
- ; lea message(pc), a3
- ; wait_for_message:
- ; move.w #$17, (a4)
- ; move.w #0, 2(a4)
- ; move.l a3, (a5)
- ; move.l d5, d1
- ; move.w d3, d0
- ; trap #2
-
- ; Therefore, it does not seem to matter that the fsel_input function
- ; requires that the value 2 in 4(a4) and 6(a4), while the evnt_mesag
- ; function requires the value 1 in those control array elements. I have
- ; not used the abbreviated version in this program because I want to avoid
- ; any unexplained phenomenona in your implementation of the program. But
- ; you should be aware of this type of simplification technique because it
- ; permits shorter, faster programs.
-
- move.l d5, d1 ; Address of aes parameter block to D1.
- move.w d3, d0 ; AES call number to D0.
- trap #2
-
- ; When a message is received it is placed in array 'message'.
-
- ; ****************************************************************************
- ; ****************************************************************************
-
- ; Execution proceeds past this point only when a message is received.
- ; Preserve contents of registers A3, A4, A5, D3, D4, and D5 during the rest of
- ; the program.
-
- message_handler: ; Entrance point when message is received.
- lea message(pc), a0 ; Fetch address of array 'message'.
- cmpi.w #$28, (a0) ; Compare ACCESSORY OPEN code with message[0].
- bne.s wait_for_message ; Execute the evnt_mesag function.
- move.w 8(a0), d0 ; The menu item selected is stored in element
- ; four (message[4]) of array 'message'. This
- ; application's id # is in D4.
- cmp.w d4, d0 ; Was this application selected.
- bne.s wait_for_message ; Execute the evnt_mesag function.
-
- ; ****************************************************************************
- ; ****************************************************************************
-
- ; Execution proceeds past this point only when this application has been
- ; selected from the menu.
-
- ; Preserve contents of registers A3, A4, A5, D3, D4, and D5 during the rest of
- ; the program.
-
- busy_test: ; Printing session in progress test.
- move.l filesize, d0 ; Fetch file size.
- beq.s get_current_drive ; Display alert if buffer is busy.
- form_alert:
- move.w #$34, (a4) ; Function = form_alert = AES $34.
- move.w #1, 2(a4) ; Input one 16-bit integer parameter.
- move.w #1, 4(a4) ; Return one 16-bit integer parameter.
- move.w #1, 6(a4) ; Input one 32-bit pointer parameter.
- move.w #0, 8(a4) ; Return no 32-bit pointer parameters.
- move.w #1, int_in ; Default exit button to int_in[0].
- move.l #alert_text, addr_in ; Alert text address to addr_in[0].
- move.l d5, d1 ; Address of aes parameter block to D1.
- move.w d3, d0 ; AES call number to D0.
- trap #2
- cmp.w #1, int_out ; Button test.
- beq wait_for_message ; Continue printing.
- move.l #0, filesize ; Cancel printing session.
- move.l #buffer, extract_pointer
- bra wait_for_message
-
- get_current_drive: ; Current drive = last drive accessed.
- move.w #$19, -(sp) ; Function = c_getdrv.
- trap #1 ; Current drive number returned in D0.
- addq.l #2, sp
-
- ; Here we begin to construct the path that will be displayed when the
- ; file selector function is invoked. Below, I indicate the data that
- ; is actually being extracted from the system. Most references do not
- ; accurately describe what is being done with these functions.
-
- add.w #$41, d0 ; Convert drive number to drive letter.
- lea path(pc), a6 ; Fetch address of array 'path'.
- move.b d0, (a6)+ ; Store drive letter in 'path' array.
- move.b #$3A, (a6)+ ; Store a colon in 'path' array.
-
- get_sub_directories: ; The drive is the main directory.
- move.w #0, -(sp) ; See Internals page 135 for other values.
- pea (a6) ; Push address of next 'path' array element.
- move.w #$47, -(sp) ; Function = d_getpath = get subdirectories.
- trap #1 ; Subdirectories are returned in the array
- addq.l #8, sp ; 'path'.
-
- add_extension:
-
- ; The extension '\*.*' is added to complete the path. This string must be
- ; NULL terminated. For example, assume that the get_current_drive routine
- ; returns #6; adding 41 would convert this to ASCII F. After the drive
- ; letter and the colon are stored in the path array, the elements of the
- ; array would contain:
-
- ; F:____________________________________,etc.
-
- ; Whatever the get_sub_directories routine returns will be placed in the path
- ; array; the first character will be stored in element 3. Assume that the
- ; routine returns \FILE_SEL as a subdirectory. The path array would contain:
-
- ; F:\FILE_SEL___________________________,etc.
-
- ; The extension is then added to the array contents to yield:
-
- ; F:\FILE_SEL\*.*O______________________,etc.
-
- ; where the O represents the NULL character. This is the path. At this
- ; time there is no file name in the path.
-
- ; When the file selector is displayed, the contents of array 'path' will
- ; appear on the path = directory line. The selection line will be blank
- ; because the program does not write anything to that line.
-
- find_path_end: ; Find NULL at end of returned string.
- tst.b (a6)+
- bne find_path_end ; Branch back till NULL is found.
- subq.l #1, a6 ; Back up to overwrite the NULL.
- move.b #$5C, (a6)+ ; Add '\'.
- move.b #$2A, (a6)+ ; Add '*'.
- move.b #$2E, (a6)+ ; Add '.'.
- move.b #$2A, (a6)+ ; Add '*'.
- move.b #0, (a6) ; Add NULL.
-
- display_file_selector: ; COMPUTE!'s AES book page 282.
- move.w #$5A, (a4) ; Function = fsel_input.
- move.w #0, 2(a4) ; Returns the drive name and subdirectories
- move.w #2, 4(a4) ; selected by the user in the array 'path'
- move.w #2, 6(a4) ; and, if a file was selected, it is returned
- move.w #0, 8(a4) ; in the array 'file'.
- initialize_address_in_array:
- lea addr_in(pc), a1 ; Fetch address of array 'addr_in'.
- lea path(pc), a6 ; Fetch address of array 'path'.
- move.l a6, (a1) ; Store address of 'path' in 'addr_in'.
- move.l #file, 4(a1) ; Store address of 'file' in 'addr_in'.
- move.l d5, d1 ; Address of aes parameter block to D1.
- move.w d3, d0 ; D3 contains AES call number.
- trap #2
-
- analyze_returns: ; Look at returns for File Selector box.
- tst.w int_out + 2 ; CANCEL button => 0.
- beq wait_for_message ; Go there if CANCEL was selected.
- tst.b file ; NO FILE CHOSEN => 0.
- beq wait_for_message ; Go there if no file was chosen.
-
- find_selected_path_end: ; Search for first asterisk.
-
- ; At this point, the selected path does not include the file name, so
- ; it is only a "partial" path.
-
- cmp.b #$2A, (a6)+
- bne find_selected_path_end
- subq.l #1, a6 ; Back up to overwrite the asterisk.
-
- ; Here we add the file name to the path by appending it to the "partial"
- ; path. Then we will have constructed the complete path.
-
- lea file(pc), a0
- add_filename_to_path:
- move.b (a0)+, (a6)+
- bne.s add_filename_to_path ; Now we have a true path.
-
- set_dta:
- pea dta(pc) ; dta = address of 44 byte buffer.
- move.w #$1A, -(sp) ; GEMDOS function = set dta.
- trap #1
- addq.l #6, sp
-
- search_for_file:
- move.w #0, -(sp) ; Attribute = normal access.
- pea path(pc) ; Push address of path.
- move.w #$4E, -(sp) ; GEMDOS function = search first.
- trap #1
- addq.l #8, sp
- tst d0
- bne wait_for_message ; Do nothing if file not found.
-
- open_file: ; Function returns file handle in D0.
- move.w #0, -(a7) ; Open as read only.
- pea path(pc) ; Push address of path.
- move.w #$3D, -(a7) ; See Internals page 127.
- trap #1
- addq.l #8, a7
- move.w d0, d6 ; Store file handle in D6.
-
- read_file:
- pea buffer(pc) ; Push buffer address
- lea dta(pc), a0
- move.l $1A(a0), filesize ; Store file size in handler variable.
- move.l $1A(a0), -(sp) ; Number of bytes to read.
- move.w d6, -(sp) ; File's handle number.
-
- ; NOTE:
-
- ; While I use the terminology found in the references when I say that
- ; D6 contains the file's handle, the truth is that we are not dealing with
- ; "just" a file; we are dealing with a path, therefore, D6 actually contains
- ; a path handle, not a file handle.
-
- move.w #$3F, -(sp) ; GEMDOS function = read.
- trap #1
- lea $C(sp), sp ; Reposition stack pointer.
-
- close_file: ; Actually, close the path.
- move.w d6, -(sp) ; Push file (path) handle.
- move.w #$3E, -(sp) ; See Internals page 128.
- trap #1
- addq #4, sp
-
- initiate_interrupt_process: ; Execute in supervisor mode.
- pea send_null(pc)
- move.w #$26, -(sp)
- trap #14
- addq.l #6, sp
-
- bra wait_for_message ; Execute the evnt_mesag function.
-
- send_null: ; The printer will drop the logic level of
- moveq.l #0, d0 ; pin 11 from high to low after receiving this
- ; character, even though nothing will be
- ; printed.
- lea $FF8800, a1 ; Address of Programmable Sound Generator.
- move.b #$F, (a1) ; Select port B (register 17) of PSG.
- move.b d0, 2(a1) ; Write character to PSG register 17.
- move.b #$E, (a1) ; Select port A (register 16) of PSG.
- move.b (a1), d0 ; Get current register 16 value.
- andi.b #$DF, d0 ; Bit 5 to zero.
- move.b d0, 2(a1) ; Bit 5 of port A to zero.
- ori.b #$20, d0 ; Bit 5 to one.
- move.b d0, 2(a1) ; Bit 5 of port A to one.
- rts
-
- interrupt_handler: ; Parallel interface interrupt handler.
- movem.l d0/a0-a1, -(sp) ; Save content of registers used by handler.
- move.l filesize, d0 ; Fetch file size.
- beq.s clear_in_service_bit ; Exit if buffer is empty (filesize = 0).
- lea io_buffer, a0 ; Fetch address of io_buffer pointer.
- movea.l 4(a0), a1 ; Fetch content of extract pointer.
- subq.l #1, d0 ; Decrement filesize.
- move.l d0, 8(a0) ; Store new filesize value.
- bne.s print_character ; Stop printing if filesize is 0.
- move.l (a0), 4(a0) ; Put buffer start address in extract pointer.
- bra.s clear_in_service_bit
-
- print_character:
- move.b (a1)+, d0 ; Fetch character. Increment extract pointer.
- move.l a1, 4(a0) ; Store location of next character.
- lea $FF8800, a1 ; Address of Programmable Sound Generator.
- move.b #$F, (a1) ; Select port B (register 17) of PSG.
- move.b d0, 2(a1) ; Write character to PSG register 17.
- move.b #$E, (a1) ; Select port A (register 16) of PSG.
- move.b (a1), d0 ; Get current register 16 value.
-
- strobe_low:
- andi.b #$DF, d0 ; Bit 5 to zero.
- move.b d0, 2(a1) ; Bit 5 of port A to zero.
-
- strobe_high:
- ori.b #$20, d0 ; Bit 5 to one.
- move.b d0, 2(a1) ; Bit 5 of port A to one.
-
- clear_in_service_bit:
- movem.l (sp)+, d0/a0-a1 ; Restore registers used by handler.
- bclr #0, $FFFA11 ; Clear MFP in service bit.
- rte
-
- data
- menu_text: dc.b ' PRINT ASCII ',0
- alert_text: dc.b '[3][ | | | Print buffer is busy.][OK|CANCEL]',0
-
- ; In the above declaration, each blank space followed by a vertical bar
- ; inserts a blank line in the alert box. I have used this method of
- ; formatting the line of text so that it is where I want it in the box.
-
- align
- io_buffer: dc.l buffer ; Pointer to buffer's starting address.
- extract_pointer: dc.l buffer ; Buffer character output pointer.
- filesize: dc.l 0 ; filesize = 0 when buffer is empty.
- aes_pb: dc.l control,global,int_in,int_out,addr_in,addr_out
-
- bss
-
- ;
- ; AES ARRAYS: The addresses of the arrays declared below will be stored in
- ; the pointer array 'aes_pb'. That happens because the program
- ; is assembled in Relocatable mode. Note that minimum space
- ; has been reserved for the int_in, int_out, addr_in and
- ; addr_out structures. It is the fsel_input function which
- ; requires the 2 words for int_out and the 2 longwords for
- ; addr_in.
- ;
-
- control: ds.w 5 ; Control parameters.
- global: ds.w 15 ; Global parameters.
- int_in: ds.w 1 ; Input parameters.
- int_out: ds.w 2 ; Output parameters.
- addr_in: ds.l 2 ; Input addresses.
- addr_out: ds.l 1 ; Output addresses.
-
- ;
- ; FSEL_INPUT ARRAYS
- ;
-
- path: ds.b 120 ; Array for drive name and subdirectories.
- file: ds.b 14 ; Array for selected file.
-
- ;
- ; APPLICATION VARIABLES
- ;
-
- message: ds.l 4 ; 16 byte array.
- dta: ds.l 11 ; 44 byte array.
- ds.l 300 ; Program stack.
- stack: ds.l 0 ; Address of program stack.
- buffer: ds.l $2000 ; Linear print buffer.
- end
-
-
- Other AES Functions
-
- Of the 11 AES libraries discussed on pages 8 and 9 of
- COMPUTE!'s AES book, I have briefly explored the Application
- Library, the Event Library, the Menu Library, the Form Library
- and the File Selector Library. I am going to delay discussions
- concerning the other libraries until I have introduced VDI
- Initialization Algorithms and Resource Construction. Once again,
- I want to mention that many of these other functions are
- discussion in magazines, such as ST Log and Atari Explorer.
- Also, these subjects are discussed in COMPUTE!'s AES book. If
- the xdef and xref assembler directives seen in programs designed
- for assemblers other than AssemPro seem foreign to you, then you
- should consult those subjects in references such as the Ford and
- Topp or Stan Kelly-Bootle books.
-
- Conclusion
-
- I have kept this chapter short and uncomplicated; it
- contains enough information about the AES to permit further
- explorations using the COMPUTE! AES book if you are impatient,
- but it is not cluttered with so much information that it bogs you
- down. In addition, I have introduced some of the more
- interesting TOS functions. I suggest that you explore these
- further using the COMPUTE! TOS book. Sheldon Leemon has written
- three excellent books for the ST; each seems better than the
- last; and I hope he continues his superior work. His references
- are valuable resources for both C language and assembly language
- programmers.
- I will continue the discussion of desk accessories in the
- next chapter, but it will be from a shifted viewpoint. Enough
- material has been covered to permit excursions into the subject
- of alterations to software packages produced by others, which you
- purchase or obtain via public domain, but which do not perform
- entirely to your personal satisfaction.
-
-