| 
				   | 
				
| 1. sor: | 
1. sor: | 
 | AMIGA MACHINE LANGUAGE  |  | AMIGA MACHINE LANGUAGE  | 
 |  |  | 
 | Typed by DEE JAY  |  | Typed by DEE JAY  | 
 | 
  |  | 
  | 
 |  | Wiki-ified by Charlie / Singular Crew, (a.k.a [[User:Chain-Q|Chain-Q]])  | 
 | 
  |  | 
  | 
 |  | * [[Amiga_Machine_Language_(Chapter_1)|Chapter 1 - Introduction]]  | 
 |  | * [[Amiga_Machine_Language_(Chapter_2)|Chapter 2 - The MC68000 processor]]  | 
 |  | * [[Amiga_Machine_Language_(Chapter_3)|Chapter 3 - Working with assemblers]]  | 
 |  | * [[Amiga_Machine_Language_(Chapter_4)|Chapter 4 - Our first programs]]  | 
 |  | * [[Amiga_Machine_Language_(Chapter_5)|Chapter 5 - Hardware registers]]  | 
 |  | * [[Amiga_Machine_Language_(Chapter_6)|Chapter 6 - The Amiga operating system]]  | 
 |  | * [[Amiga_Machine_Language_(Chapter_7)|Chapter 7 - Working with Intuition]]  | 
 |  | * [[Amiga_Machine_Language_(Chapter_8)|Chapter 8 - Advanced programming]]  | 
 |  | * [[Amiga_Machine_Language_(Appendix_A)|Appendix A - Overview of library functions]]  | 
 |  | * [[Amiga_Machine_Language_(Appendix_B)|Appendix B - Overview of the MC68000 Instructions]]  | 
 | 
  |  | 
  | 
 |       Table of Contents.
  |  |    | 
 |       ------------------
  |  | Original contents table, will be gone as chapters will get Wiki formatting:  | 
 |         1.     Introduction
  |  | 
 |         1.1    Why machine code?
  |  | 
 |         1.2    A look into the Amiga's memory
  |  | 
 |         1.2.1  RAM,ROM,hardware register
  |  | 
 |         1.2.2  Bits,bytes and words
  |  | 
 |         1.2.3  Number systems
  |  | 
 |         1.3    Inside the Amiga
  |  | 
 |         1.3.1  Components and libraries
  |  | 
 |         1.3.2  Memory
  |  | 
 |         1.3.3  Multi-tasking
  |  | 
 | 
  |  | 
  | 
 |          2      The MC68000 processor  |  |          2      The MC68000 processor  | 
| 91. sor: | 
93. sor: | 
 |                 Overview of library functions  |  |                 Overview of library functions  | 
 |                 Overview of the MC68000 Instructions  |  |                 Overview of the MC68000 Instructions  | 
 |                
  |  | 
 | 
  |  | 
 | 
  |  | 
 | 
  |  | 
 | 
  |  | 
 |       Chapter 2.
  |  | 
 |       ---------
  |  | 
 |       2.The MC68000 Processor.
  |  | 
 |       -----------------------
  |  | 
 |         The Amiga`s MC68000 processor is a 16/32 bit processor,which means
  |  | 
 |         that while it can process data of 32 bits,it"only"has a 16 bit
  |  | 
 |         data bus and a 24 bit address bus.Thus,it can access 2^24=16777216
  |  | 
 |         bytes(or 16 Mbytes)of memory directly.
  |  | 
 |       7.1 Megaherz;
  |  | 
 |         The Amiga 68000 processor,running at 7.1 megaherz,is quite fast,
  |  | 
 |         which is required for a computor with a workload as heavy as the
  |  | 
 |         Amiga`s.The Amiga also processes a number of custom chips that
  |  | 
 |         greatly ease the workload of the processor.These custom chips
  |  | 
 |         manage sound in/output,graphics and animation,thus freeing the
  |  | 
 |         processor for calculations.
  |  | 
 |         
  |  | 
 |       2.1.Registers.
  |  | 
 |       -------------
  |  | 
 |         In addition to the standard RAM,the processor contains internal
  |  | 
 |         memory called registers.There are eight data registers(D0-D7),
  |  | 
 |         eight address registers(A0-A7),a status register(SR),two stack
  |  | 
 |         pointers,a user stack pointer,a system stack pointer(USP and SSP)
  |  | 
 |         and the program counter(PC).
  |  | 
 |       Register Sizes;
  |  | 
 |         The data registers,the address registers,and the program counter
  |  | 
 |         are all 32 bits,while the status register is 16 bits.These
  |  | 
 |         registers are located dirctly in the processor so they are not 
  |  | 
 |         accessed the same way memory would be accessed.There are special
  |  | 
 |         instructions for accessing these registers.
  |  | 
 |       Data Registers;
  |  | 
 |         The data registers are used for all kinds of data.They can handle
  |  | 
 |         operations with bytes(8 bits)words(16 bits)and longwords(32bits).
  |  | 
 |       Address Registers;
  |  | 
 |         The address registers are used for storing and processing
  |  | 
 |         addresses.This way they can be used as pointers to tables,in which
  |  | 
 |         case only words and longwords operations are possible.
  |  | 
 |       Stack Pointer;
  |  | 
 |         The address register A7 plays a special role:this register is
  |  | 
 |         utilized as the Stack Pointer(SR)by the processor,and thus is not
  |  | 
 |         recommended for normal use by the programmer.Which of the two
  |  | 
 |         possible stacks is being pointed to depends on the present mode of
  |  | 
 |         the processor,but more about that later.
  |  | 
 |         The stack,to whose actual position the stack pointer is pointing,
  |  | 
 |         is used to store temporary internal data.The stack works similar 
  |  | 
 |         to a stack of notes on your desk:the note that was added to the
  |  | 
 |         stack last is the first one to come off the stack.This type of
  |  | 
 |         stack is known as LIFO(Last in,First out).There is another type of
  |  | 
 |         stack,the FIFO(First in,First out)which is not used by the
  |  | 
 |         processor itself.
  |  | 
 |         How these registers and the SP can be manipulated,or how to work
  |  | 
 |         with the stack,is presented in the next chapter.Lets continue with
  |  | 
 |         the registers for now.
  |  | 
 |       Status Register;
  |  | 
 |         The status register plays an important role in machine language
  |  | 
 |         programming.This 16-bit quality(word)contains important
  |  | 
 |         information about the processor status in 10 of its bits.The word
  |  | 
 |         is divided into two bytes,the lower byte(the user byte)and the
  |  | 
 |         upper byte(the system byte).The bits that signify that certain
  |  | 
 |         conditions are refered to as flags.This means that when a certain
  |  | 
 |         condition is present,a particular bit is set.
  |  | 
 |         The user byte contains five flags,which have the following meaning
  |  | 
 | 
  |  | 
 |                 Bit     Name           Meaning
  |  | 
 |                 -----------------------------------------------
  |  | 
 |                  0      (C,Carry)      Carry bit,modified by math
  |  | 
 |                                        calculation,and shift instructions.
  |  | 
 |                  1      (V,Overflow)   Similar to carry,indicates a change
  |  | 
 |                                        of sign,in other words,a carry from
  |  | 
 |                                        bit six to bit seven.
  |  | 
 |                  2      (Z,Zero)       Bit is set when the result of an
  |  | 
 |                                        operation is zero.
  |  | 
 |                  3      (N,Negative)   Is set when the result of an
  |  | 
 |                                        operation  is negative.
  |  | 
 |                  4      (X,Extended)   Like carry,is set for arithmetic
  |  | 
 |                                        operations.
  |  | 
 |                  5-7                   Not used.
  |  | 
 | 
  |  | 
 |         The system byte contains five significant bits:
  |  | 
 | 
  |  | 
 |                 Bit     Nane           Meaning
  |  | 
 |                 -----------------------------------------------
  |  | 
 |                  8      I0             Interupt mask.Activates interupt
  |  | 
 |                  9      I1             levels 0 to 7,where 0 is the lowest
  |  | 
 |                  10     I2             and 7 is the highest priority.
  |  | 
 |                  11                    not used.
  |  | 
 |                  12                    not used.
  |  | 
 |                  13    (S,Supervisor)  This bit indicates the actual
  |  | 
 |                                        pocessor mode(0=User,1=Supervisor
  |  | 
 |                                        mode).
  |  | 
 |                  14                    not used.
  |  | 
 |                  15    (T,Trace)       If this bit is set,the processor is
  |  | 
 |                                        in single step mode.
  |  | 
 | 
  |  | 
 |         Here's an overview of the status word;
  |  | 
 |                  
  |  | 
 |                  bit  : 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
  |  | 
 |                  name :  T  -  S  -  - I2 I1 I0  -  -  -  X  N  Z  V  C
  |  | 
 |         
  |  | 
 |         Don't let the new terms,like mode and interupt confuse you.We'll
  |  | 
 |         talk about these in greater detail in the chapter dealing with the
  |  | 
 |         operating conditions of the processor.
  |  | 
 | 
  |  | 
 |       2.2.Addressing Memory.
  |  | 
 |       ---------------------
  |  | 
 |         In the standard Amiga 500's and 1000's,the processor has over 512k
  |  | 
 |         of RAM available.The Amiga 2000 has one mega-byte of RAM that can
  |  | 
 |         be accessed by the processor.How does the processor access all
  |  | 
 |         this memory?
  |  | 
 |         If you're programming in BASIC you don't have to worry about
  |  | 
 |         memory management.You can simply enter MARKER%=1,and the value is
  |  | 
 |         stored in memory by the BASIC interpreter.
  |  | 
 |         In assembler,there are two ways of accomplishing this task:
  |  | 
 |            1) Store the value in one of the data or address registers,or
  |  | 
 |            2)Write it directly into a memory location.
  |  | 
 |         To demonstrate these two methods let's get a little ahead and
  |  | 
 |         introduce a machine language instruction,which is probably the
  |  | 
 |         most common:MOVE.As its name states,this instruction moves values.
  |  | 
 |         Two parameters are required with the instruction:source and
  |  | 
 |         destination.
  |  | 
 |         Lets see what the example from above would look like if you
  |  | 
 |         utilize the MOVE instruction...
  |  | 
 |            1)  MOVE   #1,D0
  |  | 
 |         This instruction moves the value 1 into data register D0.As you
  |  | 
 |         can see,the source value is always entered before the destination.
  |  | 
 |         Thus,the instruction MOVE D0,#1 is not possible.
  |  | 
 |            2)  MOVE   #1,$1000
  |  | 
 |         deposits the value 1 in the memory location at $1000.This address
  |  | 
 |         was arbitrarily chosen.Usually addresses of this form won't be
  |  | 
 |         used at all in assembler programs,since labels that point to a 
  |  | 
 |         certain address are used instead.Thus,the more common way of
  |  | 
 |         writing this would be:
  |  | 
 |              ...
  |  | 
 |              MOVE  #1,MARKER
  |  | 
 | 
  |  | 
 |              ...
  |  | 
 |           MARKER:DC.W 1
  |  | 
 | 
  |  | 
 |         These are actually two pieces of program:the first part executes 
  |  | 
 |         the normal MOVE instruction whose destination is `MARKER`.This
  |  | 
 |         label is usually defined at the end of a program and specifies the
  |  | 
 |         address at which the value is stored.
  |  | 
 |         The paraneter DC.W 1 is a pseudo op,apseudo operation.This means
  |  | 
 |         that this isn`t an instruction for the processor,but an
  |  | 
 |         instruction for the assembler.The letters DC stand for`DeClare`and
  |  | 
 |         the suffix .W indicates that the data is a Word.The other two
  |  | 
 |         suffix alternatives would be .B for a byte(8 bits)and .L for a
  |  | 
 |         long word(32 bits).
  |  | 
 |         This suffix(.B.W or.L)is used with most machine language
  |  | 
 |         instructions.If the suffix is omitted,the assembler uses .W(word)
  |  | 
 |         as the default parameter.If you wanted a long word,you`d use an
  |  | 
 |         instruction that looks something like this:MOVE .L #$1234678,D0
  |  | 
 |         where as an instruction like MOVE.B #$12,D0 would be used for a
  |  | 
 |         byte of data.However,with this instruction there`s one thing you
  |  | 
 |         must be aware of...
  |  | 
 |         CAUTION:
  |  | 
 |         If the memory is accessed by words or long words,the address must
  |  | 
 |         be even(end digit must be 0,2,4,6,8,A,C,E)!
  |  | 
 |         Assemblers usually have a pseudo-op,`EVEN`or`ALIGN`,depending on
  |  | 
 |         the assembler,that aligns data to an even address.This becomes
  |  | 
 |         necessary in situations similar to this:
  |  | 
 |              ...
  |  | 
 |           VALUE1:    DC.B 1
  |  | 
 |           VALUE2:    DC.W 1
  |  | 
 | 
  |  | 
 |         If the VALUE1 is located at an even address,VALUE2 is automaticaly
  |  | 
 |         located at an odd one.If an ALIGN(EVEN)is inserted here,a fill
  |  | 
 |         byte(0)is inserted by the assembler,thus making the second address
  |  | 
 |         even.
  |  | 
 |              ...
  |  | 
 |           VALUE1:    DC.B 1
  |  | 
 |           ALIGN
  |  | 
 |           VALUE2:    DC.W 1
  |  | 
 | 
  |  | 
 |         Back to the different ways of addressing.The variations listed
  |  | 
 |         above are equivalent to the BASIC instruction MARKER%=1 where the
  |  | 
 |         % symbol indicates an integer value.
  |  | 
 |         Lets go a step further and translate the BASIC instruction MARKER
  |  | 
 |         %=VALUE% into assembler.You`ve probably already guessed the answer
  |  | 
 |         right?
  |  | 
 | 
  |  | 
 |                  MOVE VALUE,MARKER
  |  | 
 |                  ...
  |  | 
 |                  ...
  |  | 
 |           MARKER:      DC.W 1
  |  | 
 |           VALUE :      DC.W 1
  |  | 
 | 
  |  | 
 |         In this case,the contents in the address at VALUE are moved into
  |  | 
 |         the address at MARKER.
  |  | 
 |         With the help of these simple examples,you`ve already become
  |  | 
 |         familiar with four different ways of addressing,in other words,
  |  | 
 |         ways that the processor can access memory.The first is
  |  | 
 |         characterized by the number sign(#)and represents a direct value.
  |  | 
 |         Thus,this method is also known as direct addressing,and is legal
  |  | 
 |         only for the source parameter!
  |  | 
 |         A further method in which a direct address(in our case,`MARKER`and
  |  | 
 |         `VALUE`)can be specified is known as absolute addressing.This
  |  | 
 |         method is legal for the source parameter as well as for the
  |  | 
 |         destination parameter.
  |  | 
 |         This method can be divided into two different types,between which
  |  | 
 |         the programmer usually does'nt notice a difference.Depending on
  |  | 
 |         whether the absolute address is smaller or larger than $FFFF,in
  |  | 
 |         other words if it requires a long word,it is called absolute
  |  | 
 |         addressing(for addresses above $FFFF)or otherwise absolute short
  |  | 
 |         addressing.The assembler generally makes the distinction between
  |  | 
 |         these two types,and thus,only general knowledge of absolute
  |  | 
 |         addressing is required.
  |  | 
 |         The fourth method of addressing that you've encountered so far is
  |  | 
 |         known as DATA REGISTER DIRECT.It was the first one introduced(MOVE
  |  | 
 |         #1,D0)in conjunction with direct addressing,the only difference
  |  | 
 |         being that this type accesses a data register(such as D0).
  |  | 
 |         These four methods aren't the only ones available to the MC68000
  |  | 
 |         processor,in fact there are a total of 12.One other variation
  |  | 
 |         called ADDRESS REGISTER DIRECT,is almost identical to data
  |  | 
 |         register direct,except that it accesses the address register
  |  | 
 |         instead of the data register.Thus,you can use MOVE.L #MARKER,A0 to
  |  | 
 |         access the address register A0 directly.
  |  | 
 |         You now know five ways to address memory with which quite a bit
  |  | 
 |         can be accomplished.Now,lets tackle something more complicated and
  |  | 
 |         more interesting.
  |  | 
 |         Lets take another example from BASIC:
  |  | 
 |             
  |  | 
 |             10  A=1000
  |  | 
 |             20  POKE A,1
  |  | 
 | 
  |  | 
 |         In this example the first line assigns the value 1000 to the
  |  | 
 |         variable A.This can be done in assembler as well:MOVE.L #1000,A0.
  |  | 
 |         In the assembler version the absolute value of 1000 ia stored in
  |  | 
 |         the address register A0.
  |  | 
 |         Line 20 doesn't assign a value to the variable A itself,but rather
  |  | 
 |         to the memory location at the address stored in A.This is an
  |  | 
 |         indirect access,which is quite easy to duplicate in assembler:
  |  | 
 |              
  |  | 
 |             MOVE.L  #1000,A0       ;bring address in A0
  |  | 
 |             MOVE    #1,(A0)        ;write 1 into this address
  |  | 
 | 
  |  | 
 |         The parentheses indicates an addressing known as ADDRESS REGISTER
  |  | 
 |         INDIRECT.This method only works with address registers,since a
  |  | 
 |         'data register indirect' does not exist.
  |  | 
 |         There are several variations of this method.For instance,a
  |  | 
 |         distance value can be specified,which is added to the address
  |  | 
 |         presently located in the address register before the register is
  |  | 
 |         actually accessed.The instruction MOVE #1,4(A0),if applied to the
  |  | 
 |         example above,writes the value 1 into the memory cell at 1000+4=
  |  | 
 |         1004.This distance value can be positive or negative.Thus,values
  |  | 
 |         from -32768 to +32768 are accepted.This specific variation of
  |  | 
 |         addressing is called ADDRESS REGISTER INDIRECT WITH A 16 BIT
  |  | 
 |         DISPLACEMENT value.
  |  | 
 |         There is another very similar variation:ADDRESS REGISTER INDIRECT
  |  | 
 |         WITH AN 8 BIT INDEX value.While this variation is limited to 8
  |  | 
 |         bits,it also brings another register into play.This second
  |  | 
 |         register is also a distance value,except that it is a variable as
  |  | 
 |         well.
  |  | 
 |         We'll try to clarify this with an example.Lets assume that a
  |  | 
 |         program includes a data list that is structured like this:
  |  | 
 |            
  |  | 
 |                ...
  |  | 
 |             RECORD:         DC.W 2   ;number of entries -1
  |  | 
 |                    DC.W 1,2,3        ;elements of list
  |  | 
 |         
  |  | 
 |         We'll use MOVE.L #RECORD,A0 to load the list into the address
  |  | 
 |         register A0.Then you can use MOVE (A0),D0 to pull the number of
  |  | 
 |         in the list into the data register.To access the last element of
  |  | 
 |         the listonly one instruction is needed.The whole thing looks
  |  | 
 |         something like this:
  |  | 
 | 
  |  | 
 |                    CLR.L   D0            ;erase D0 completely
  |  | 
 |                    MOVE.L  #RECORD,A0    ;address of list in A0
  |  | 
 |                    MOVE    (A0),D0       ;number of elements -1 in D0
  |  | 
 |                    MOVE    1(A0,D0),D1   ;last element in D1
  |  | 
 |                    ...
  |  | 
 |            RECORD: DC.W 2                ;number of entries -1
  |  | 
 |                   DC.W 1,2,3             ;elements of list
  |  | 
 | 
  |  | 
 |         This last instruction accesses the byte that is located at 1+A0+D0
  |  | 
 |         in other words,the record +1 where the data begins plus the
  |  | 
 |         contents of D0(in this case 2).
  |  | 
 |         This method of accessing is very useful.It works exquisitely for
  |  | 
 |         the processing of tables and lists,as the example demonstrates.If 
  |  | 
 |         no distance value is needed,simply use a distance value of zero,
  |  | 
 |         which some assemblers automatically insert as the default value if
  |  | 
 |         for instance only MOVE (A0,D0)is entered.
  |  | 
 |         The latter two methods have a third variation,which as its own
  |  | 
 |         characteristic trait.It dosen't utilize an address register,but
  |  | 
 |         uses the Program Counter(PC)instead.The program counter with 
  |  | 
 |         displacement method proves useful when a program must function 
  |  | 
 |         without any changes in all address ranges.The following two
  |  | 
 |         statements(in the 15 bit limits)have the same effect:
  |  | 
 | 
  |  | 
 |                    MOVE  MARKER,D0
  |  | 
 | 
  |  | 
 |            and
  |  | 
 | 
  |  | 
 |                    MOVE  MARKER(PC),D0
  |  | 
 | 
  |  | 
 |         This method is actually rather imprecise,since the first
  |  | 
 |         instruction specifies the actual address of the marker with MARKER
  |  | 
 |         while the second line specifies the distance between the
  |  | 
 |         instruction and the marker.However since it would be quite
  |  | 
 |         cumbersome to constanly calculate the distance,the assembler takes
  |  | 
 |         this task off our hands and calculates the actual value automatic.
  |  | 
 |         Lets examine the difference between the two instructions.In a
  |  | 
 |         program they'll accomplish the same thing,although they are
  |  | 
 |         interpreted as two completely different things by the assembler.
  |  | 
 |         You'll assume a program being at the address $1000 and the marker
  |  | 
 |         is located at $1100.The generated program code looks something
  |  | 
 |         like this:
  |  | 
 | 
  |  | 
 |            $001000      30 39 00 00 11 00     MOVE  MARKER,D1
  |  | 
 | 
  |  | 
 |           or
  |  | 
 | 
  |  | 
 |            $001000      30 3A 00 FE           MOVE  MARKER(PC),D1
  |  | 
 | 
  |  | 
 |         As you can see,the generated code of the second line is two bytes
  |  | 
 |         shorter than the first line.In addition,if you were to shift this
  |  | 
 |         code to the address $2000,the first version still accesses the
  |  | 
 |         memory at $1100,while the second line using the PC indirect
  |  | 
 |         addressing accesses memory at $2000 correctly.Thus,the program can
  |  | 
 |         be transferred to almost any location.
  |  | 
 |         This,then,is PROGRAM COUNTER WITH 16 BIT DISPACEMENT value.As we
  |  | 
 |         mentioned,there is also PROGRAM COUNTER WITH 8 BIT INDEX value,
  |  | 
 |         which permits a second register as a distance value,also known as
  |  | 
 |         offset.
  |  | 
 |         There are two addressing modes left.These two are based on
  |  | 
 |         indirect addressing.They offer the capability of automatically
  |  | 
 |         raising or lowering the address register by one when memory is
  |  | 
 |         accessed with address register indirect.
  |  | 
 |         To automatically increase the register,you'd use ADDRESS REGISTER
  |  | 
 |         DIRECT WITH POST-INCREMENT.The address register raises this by the
  |  | 
 |         number of bytes used AFTER accessing memory.Thus if you write:
  |  | 
 |  
  |  | 
 |              MOVE.L  #1000,A0
  |  | 
 |              MOVE.B  #1,(A0)+
  |  | 
 | 
  |  | 
 |         the 1 is written in the address $1000 and then A0 is raised by one
  |  | 
 |         Instructions like this are very helpful when a memory range is to
  |  | 
 |         be filled with a specific value(for instance when the screen is
  |  | 
 |         cleared).For such purposes the instruction can be placed in a loop
  |  | 
 |         ...which we'll get to later.
  |  | 
 |         The counter part to post increment is ADDRESS REGISTER WITH PRE-
  |  | 
 |         DECREMENT.In this case the specified address register is lowered
  |  | 
 |         by one BEFORE the access to memory.The instructions:
  |  | 
 | 
  |  | 
 |              MOVE.L  #1000,A0
  |  | 
 |              MOVE.B  #1,-(A0)
  |  | 
 | 
  |  | 
 |         writes 1 in the address 999,since the contents of A0 is first 
  |  | 
 |         decremented and the 1 is written afterwards.
  |  | 
 |         These two methods of addressing are used to manage the stack
  |  | 
 |         pointer(SP).Since the stack is filled from top to bottom,the
  |  | 
 |         following is written to place a word(s.aD0)on the stack:
  |  | 
 | 
  |  | 
 |              MOVE.B  D0,-(SP)
  |  | 
 | 
  |  | 
 |         and to remove it from the stack,again in D0:
  |  | 
 | 
  |  | 
 |              MOVE.B  (SP)+,D0
  |  | 
 | 
  |  | 
 |         This way the stack pointer always points to the byte last
  |  | 
 |         deposited on the stack.Here,again,you'll have to be careful that
  |  | 
 |         an access to the stack with a word or a long word is always on an
  |  | 
 |         even address.Thus,if you're going to deposit a byte on the stack,
  |  | 
 |         either use a whole word or make sure the byte is not followed by a
  |  | 
 |         JSR or BSR.The JSR or BSR instructions deposit the addresses from
  |  | 
 |         which they stem on the stack in the form of a long word.
  |  | 
 |         In the code above,the SP is generally replaced by the address
  |  | 
 |         register A7 in the program code,since this register is always used
  |  | 
 |         as the SP.Thus,you can write A7 as well as S,the resulting program
  |  | 
 |         is the same.However,we recommend the use of SP,since this makes
  |  | 
 |         the code somewhat easier to read.After all,quite often you'll want
  |  | 
 |         to employ your own stacks,in which case the difference between the
  |  | 
 |         processor stack and your own stacks become very important.
  |  | 
 |         These are the twelve ways of addressing the MC68000 processor,Here
  |  | 
 |         is a summary:
  |  | 
 | 
  |  | 
 |         No  Name                                                Format
  |  | 
 |         --  ----                                                ------
  |  | 
 |          1  data register direct                                Dn
  |  | 
 |          2  address register direct                             An
  |  | 
 |          3  address register indirect                           (An)
  |  | 
 |          4  address register indirect with post-increment       (An)+
  |  | 
 |          5  address register indirect with pre-decrement        -(An)
  |  | 
 |          6  address register indirect with 16 bit displacement  d16(An)
  |  | 
 |          7  address register indirect with 8 bit index value    8(An,Rn)
  |  | 
 |          8  absolute short                                      xxxx.W
  |  | 
 |          9  absolute long                                       xxxxxxxx.L
  |  | 
 |         10  direct                                              #'data'
  |  | 
 |         11  program counter indirect with 16 bit displacement   d16(PC)
  |  | 
 |         12  program counter indirect with 8 bit index value     d8(PC,Rn)
  |  | 
 | 
  |  | 
 |         The abbreviations above have the following meanings:
  |  | 
 | 
  |  | 
 |              An      address registers A0-A7
  |  | 
 |              Dn      data registers D0-D7
  |  | 
 |              d16     16 bit value
  |  | 
 |              d8      8 bit value
  |  | 
 |              Rn      register D0-D7,A0-A7
  |  | 
 |              'data'  up to 32 bit value,(either .B .W .L)
  |  | 
 | 
  |  | 
 |         These are the addressing modes used by the MC68000 processor.The
  |  | 
 |         bigger brother of this processor,the 32 bit MC68020,has six more
  |  | 
 |         methods which we won't discuss here.
  |  | 
 |         Next you're going to see under what conditions the processor can
  |  | 
 |         operate.
  |  | 
 | 
  |  | 
 |       2.3.Operating Modes.
  |  | 
 |       -------------------
  |  | 
 |         In the previous section about registers you encountered the Status
  |  | 
 |         Register(SR).The individual bits of this register reflect the
  |  | 
 |         present operating condition of the processor.You differentiated
  |  | 
 |         between the system byte(bits 8-15)and the user byte(bits 0-7).Now,
  |  | 
 |         lets take a closer look at the system byte and its effects upon
  |  | 
 |         the operation of the processor.
  |  | 
 | 
  |  | 
 |       2.3.1.User and Supervisor Modes.
  |  | 
 |       -------------------------------
  |  | 
 |         Isn't it rather strange that the processor classifies you either
  |  | 
 |         as a'user'or a 'supervisor'?Both of these operating modes are
  |  | 
 |         possible,the user mode being the more common mode.In this mode it
  |  | 
 |         is impossible to issue some instructions,and that in your own
  |  | 
 |         computor!
  |  | 
 |         Don't worry though,you can get around that,as well.The Amiga's
  |  | 
 |         operating system contains a function that allows us to switch the
  |  | 
 |         processor from one mode to the other.
  |  | 
 |         The mode is determined by bit 13 of the Status Register.Usually
  |  | 
 |         this bit is cleared(0),indicating that the processor is in user
  |  | 
 |         mode.It is possible to write directly into the status register,
  |  | 
 |         although this is a privileged instruction that can only be
  |  | 
 |         executed from the supervisor mode.Thus,this instructioncould only
  |  | 
 |         be used to switch from the supervisor mode into the user mode,by 
  |  | 
 |         using AND #$DFFF,SR to clear the supervisor bit.However,it is
  |  | 
 |         quite preferable to let the operating system perform the switch
  |  | 
 |         between these two modes.
  |  | 
 |         Now what differentiates these two modes in terms of application?
  |  | 
 |         Well,we already mentioned the first difference:some instructions,
  |  | 
 |         such as MOVE xx,SR, are privileged and can only be executed from
  |  | 
 |         the supervisor mode.An attempt to do this in user mode would
  |  | 
 |         result in an exception and interruption of the program.Exceptions
  |  | 
 |         are the only way of switching to the supervisor mode,but more
  |  | 
 |         about later.
  |  | 
 |         A further difference is in the stack range used.Although A7 is
  |  | 
 |         still used as the stack pointer,another memory range is used for
  |  | 
 |         the stack itself.Thus,the SP is changed rach time you switch from
  |  | 
 |         one mode to the other.Because of this you differentiate between
  |  | 
 |         the User(USP)and the Supervisor SP(SSP).
  |  | 
 |         Accessing memory can also depend on these two modes.During such
  |  | 
 |         accessing,the processor sends signals to the peripheral components
  |  | 
 |         informing them of the current processor moce.This way a MC68000 
  |  | 
 |         computor can protect(privilege)certain memory ranges so they can't
  |  | 
 |         be accessed by the user.
  |  | 
 |         In the supervisor mode it is possible to execute all instructions
  |  | 
 |         and access all areas of memory.Because of this,operating systems
  |  | 
 |         usually run in the supervisor mode.This is accomplished through
  |  | 
 |         the use of Exceptions.
  |  | 
 | 
  |  | 
 |       2.3.2.Exceptions.
  |  | 
 |       ----------------
  |  | 
 |         Exceptions are similar to interupts on 6500 computors.This allows
  |  | 
 |         stopping a program,running a sub-program,and then restarting the
  |  | 
 |         stopped program.When an exception occurs the following seps are
  |  | 
 |         taken:
  |  | 
 | 
  |  | 
 |            1)   The status register is saved.
  |  | 
 |            2)   The S bit in SR is set(supervisor mode)and the T bit is
  |  | 
 |                 cleared(no trace).
  |  | 
 |            3)   The program counter and the user SP are saved.
  |  | 
 |            4)   The exception vector,which points to the needed exception
  |  | 
 |                 routine,is retrieved.
  |  | 
 |            5)   The routine is executed.
  |  | 
 | 
  |  | 
 |         The vectors mentioned,which contain the starting addresses for the
  |  | 
 |         various routines,are located at the very beginning of the memory.
  |  | 
 |         Here is an overview of the vectors and their respective addresses:
  |  | 
 | 
  |  | 
 |            Number   Address       Used for
  |  | 
 |            -----    ------        --------
  |  | 
 |             0       $000          RESET:starting SSP
  |  | 
 |             1       $004          RESET:starting PC
  |  | 
 |             2       $008          bus error
  |  | 
 |             3       $00C          address error
  |  | 
 |             4       $010          illegal instruction
  |  | 
 |             5       $014          division by zero
  |  | 
 |             6       $018          CHK instruction
  |  | 
 |             7       $01C          TRAPV instruction
  |  | 
 |             8       $020          privilege violation
  |  | 
 |             9       $024          trace
  |  | 
 |            10       $028          Axxx-instruction emulation
  |  | 
 |            11       $02C          Fxxx-instruction emulation
  |  | 
 |                     $030-$038     reserved
  |  | 
 |            15       $03C          uninitialed interrupt
  |  | 
 |                     $040-$05F     reserved
  |  | 
 |            24       $060          unjustified interrupt
  |  | 
 |            25-31    $064-$083     level 1-7 interrupt
  |  | 
 |            32-47    $080-$0BF     TRAP instructions
  |  | 
 |                     $0C0-$0FF     reserved
  |  | 
 |            64-255   $100-$3FF     user interrupt vectors
  |  | 
 |  
  |  | 
 |         The individual entries in the table above need detailed
  |  | 
 |         explanation.So lets go through them one by one...
  |  | 
 |       RESET:staring SSP;
  |  | 
 |         At reset,the long word stored at this location is used as the
  |  | 
 |         stack pointer for the supervisor mode(SSP).This way you can
  |  | 
 |         specify the stack for the RESET routine.
  |  | 
 |       RESET:starting PC;
  |  | 
 |         Again at reset,the value at this location is used as the program
  |  | 
 |         counter.In other words,the RESET routine is started at the address
  |  | 
 |         stored here.
  |  | 
 |       Bus Error;
  |  | 
 |         This exception is activated by a co-processor when,for instance,a
  |  | 
 |         reserved or non-existant memory range is accessed.
  |  | 
 |       Address Error;
  |  | 
 |         This error occurs when a word or long word access is atempted at
  |  | 
 |         an odd address.
  |  | 
 |       Illegal Instruction;
  |  | 
 |         Since all MC68000 instructions consist of one word,a total 65536
  |  | 
 |         different instructions are possible.However,since the processor
  |  | 
 |         doesn't that many instructions,there are a number of words that
  |  | 
 |         are invalid instructions.Should such a word occur,the exception is
  |  | 
 |         prompted.
  |  | 
 |       Division by Zero;
  |  | 
 |         Since the processor has a division function,and the division of
  |  | 
 |         anything by zero is mathematically undefined and thus illegal,this
  |  | 
 |         exception occurs when such an operation is attempted.
  |  | 
 |       CHK Instruction;
  |  | 
 |         This exception only occurs with the CHK instruction.This
  |  | 
 |         instruction tests that a data registers contents are within a
  |  | 
 |         certain limit.If this is not the case,the exception is activated.
  |  | 
 |       TRAPV Instruction;
  |  | 
 |         If the TRAPV instruction is executed and the V bit(bit 1)in the
  |  | 
 |         status word is set,this exception is prompted.
  |  | 
 |       Privilege Violation;
  |  | 
 |         If a privileged instruction is called from the user mode,this
  |  | 
 |         exception is activated.
  |  | 
 |       Trace;
  |  | 
 |         If the trace bit(bit 15)in the status word is set,this exception
  |  | 
 |         is activated after each instruction that is executed.This method
  |  | 
 |         allows you to employ a step by step execution of machine programs.
  |  | 
 |       Axxx-Instruction Emulation;
  |  | 
 |       Fxxx-Instruction Emulation;
  |  | 
 |         These two vectors can be used for a quite interesting trick.If an
  |  | 
 |         instruction beginning with $A or $F(such as $A010 or $F200)is
  |  | 
 |         called the,the routine to which the corresponding vector is
  |  | 
 |         pointing is accessed.In these routines you can create chains of
  |  | 
 |         other instructions,in effect expanding the processors instruction
  |  | 
 |         vocaulary!
  |  | 
 |       Reserved;
  |  | 
 |         These vectors are not used.
  |  | 
 |       Uninitialized Interrupt;
  |  | 
 |         This exception is activated when a peripheral component that was
  |  | 
 |         not initialized sends an interrupt.
  |  | 
 |       Unassigned Interrupt;
  |  | 
 |         Is activated when a BUS error occurs during the interrupt
  |  | 
 |         verification of the activating component.However,the interrupt is
  |  | 
 |         usually only by some type of disturbance.
  |  | 
 |       Level 1-7 Interrupt;
  |  | 
 |         These seven vectors point to the interrupt routines of the
  |  | 
 |         corresponding priority levels.If the level indicated in the status
  |  | 
 |         word is higher than the level of the occuring interrupt,the
  |  | 
 |         interrupt is simply ignored.
  |  | 
 |       TRAP Instructions;
  |  | 
 |         These 16 vectors are used when a corresponding TRAP instruction
  |  | 
 |         occurs.Thus,TRAP instructions from TRAP #0 to TRAP #15 are
  |  | 
 |         possible.
  |  | 
 |       User Interrupt Vectors;
  |  | 
 |         These vectors are used for interrupts which are activated by
  |  | 
 |         several peripheral components that generate their own vector
  |  | 
 |         number.
  |  | 
 |         
  |  | 
 |         At this point you don't want to delve any deeper into the secrets
  |  | 
 |         of exceptions,since we'd be expanding this book beyond its frame
  |  | 
 |         work.However,there's one last thing to say about exceptions:the
  |  | 
 |         exception routines are ended with the RTE(ReTurn from Exception)
  |  | 
 |         instruction,with which the original status is restored and the
  |  | 
 |         user program is continued.
  |  | 
 | 
  |  | 
 |       2.3.3.Interrupts.
  |  | 
 |       ----------------
  |  | 
 |         Interrupts are processed similarly to exceptions.They are breaks
  |  | 
 |         (or interruptions)in the program which are activated through
  |  | 
 |         hardware(such as a peripherical component or an external trigger).
  |  | 
 |         The interrupt level is stored in bits 8-10 of the status register.
  |  | 
 |         A value between 0 and 7 indicates the interrupt level.There are
  |  | 
 |         eight possible interrupts,each of which as a different priority.If
  |  | 
 |         the level of this interrupt happens to be higher than the value in
  |  | 
 |         the status register,the interrupt is executed,or else ignored.
  |  | 
 |         When a valid interrupt occurs,the computor branches to the
  |  | 
 |         corresponding routine whose address is indicated in the exception
  |  | 
 |         vector table above.
  |  | 
 |         The interrupts are very important if you're trying to synchronize
  |  | 
 |         a program with connected hardware.In this manner,a trigger(s.a the
  |  | 
 |         keyboard)which is to feed the computor data,can signal the request
  |  | 
 |         for a legal value using an interrupt.The interrupt routine then
  |  | 
 |         simply takes the value directly.This method is also employed for
  |  | 
 |         the operation of the serial interface(RS232).
  |  | 
 |         We'll talk about the use of interrupts at a later time.The last
  |  | 
 |         thing we want to mention about interrupts at this time is that,
  |  | 
 |         like exceptions,interrupt routines are terminated with the RTE
  |  | 
 |         instruction.
  |  | 
 | 
  |  | 
 |       2.3.4.Condition Codes.
  |  | 
 |       ---------------------
  |  | 
 |         When you write a program in any language,the need for a
  |  | 
 |         conditional operation arises quite often.For instance,in a BASIC
  |  | 
 |         program
  |  | 
 | 
  |  | 
 |             IF D1=2 THEN D2=0
  |  | 
 | 
  |  | 
 |         represents a conditional operation.To write the equivalent in
  |  | 
 |         machine language,you first need to make the comparison:
  |  | 
 | 
  |  | 
 |             CMP  #2,D1
  |  | 
 | 
  |  | 
 |         CMP stands for compare and compares two operands,in this case D1
  |  | 
 |         and D2.How is this operation evaluated?
  |  | 
 |         For this purpose you have condition codes(CC's),which exist in the
  |  | 
 |         branch instructions of machine language.Because of this,you must
  |  | 
 |         specify when and where the program is to branch.
  |  | 
 |         The simplest variation of the branch instruction is an
  |  | 
 |         unconditional branch.The corresponding instruction is 'BRA address
  |  | 
 |         ',although this won't help you here.After all,you need a
  |  | 
 |         conditional branch.
  |  | 
 |         To retain the result of the operation,in this case a comparrison
  |  | 
 |         (CMP),several bits are reserved in the status word.Lets look at
  |  | 
 |         bit 2 first,which is the zero flag.This flag is set when the
  |  | 
 |         result of the previous operation was zero.
  |  | 
 |         To explain the relationship between CMP and the Z flag,you must
  |  | 
 |         first clarify the function of the CMP instruction.Actually this
  |  | 
 |         instruction performs the subtraction of the source operand from
  |  | 
 |         the destination operand.In the example above,the number 2 is
  |  | 
 |         subtracted from the content of the memory cell at D1.Before the
  |  | 
 |         result of this subtraction is discarded,the corresponding flags
  |  | 
 |         are set.
  |  | 
 |         If the contents of D1 in our example above happened to be 2,the
  |  | 
 |         result of the subtraction would be 0.Thus,the Z flag would be set,
  |  | 
 |         which can then be evaluated through a corresponding branch
  |  | 
 |         instruction.Our example would then look like this:
  |  | 
 | 
  |  | 
 |                    ...
  |  | 
 |                   CMP   #2,D1      ;comparison,or subtraction
  |  | 
 |                   BNE   UNEQUAL    ;branch,if not equal(Z flag not set)
  |  | 
 |                   MOVE  #0,D2      ;otherwise execute D2=0
  |  | 
 |          
  |  | 
 |            UNEQUAL:
  |  | 
 | 
  |  | 
 |                    ...             ;program branches to here
  |  | 
 | 
  |  | 
 |         BNE stands for Branch if Not Equal.This means,that if the Z flag
  |  | 
 |         was cleared(=0)by the previous CMP,the program branches to the
  |  | 
 |         address specified by BNE(here represented by UNEQUAL).The counter
  |  | 
 |         part to the BNE instruction is the BEQ(Branch if EQual)instruction
  |  | 
 |         which is executed if Z=1.
  |  | 
 |         Here's a list of condition codes,which allow you to form
  |  | 
 |         conditional branches using the Bcc(cc=condition code)format:
  |  | 
 | 
  |  | 
 |            cc       Condition                     Bits
  |  | 
 |            ---------------------------------------------------
  |  | 
 |            T        true,corresponds to BRA
  |  | 
 |            F        false,never branches
  |  | 
 |            HI       higher than                   C'* Z'
  |  | 
 |            LS       lower or same                 C + Z
  |  | 
 |            CC,HS    carry clear,higher or same    C'
  |  | 
 |            CS,LO    carry set,lower               C
  |  | 
 |            NE       not equal                     Z'
  |  | 
 |            EQ       equal                         Z
  |  | 
 |            VC       overflow clear                V'
  |  | 
 |            VS       overflow set                  V
  |  | 
 |            PL       plus,positive
  |  | 
 |            MI       minus,negative
  |  | 
 |            GE       greater or equal              N*V+N'*V'
  |  | 
 |            LT       less than                     N*V'+N'*V
  |  | 
 |            GT       greater than                  N*V*Z'+N'*V'*Z'
  |  | 
 |            LE       less or equal                 Z + N*V' + N'*V
  |  | 
 | 
  |  | 
 |            *=logic AND, +=logic OR, '=logic NOT
  |  | 
 | 
  |  | 
 |         Here are a few examples to demonstrate how these numerous
  |  | 
 |         conditions can be utilized:
  |  | 
 | 
  |  | 
 |            CMP   #2,D1
  |  | 
 |            BLS SMALLER_EQUAL
  |  | 
 | 
  |  | 
 |         This branches if the contents of D1<=2,whether D1 is 0,1 or 2.In
  |  | 
 |         this example,the BLE instruction would allow the program to branch
  |  | 
 |         even if D1 is negative.You can tell this by the fact that the V
  |  | 
 |         bit is used in the evaluation of this expression(see chart above).
  |  | 
 |         When the sign is changed during the operation,this V bit is
  |  | 
 |         compared with the N bit.Should both bits be cleared(N bit=0 and V
  |  | 
 |         bit=0)after the CMP subtraction(D1-2),the result has remained
  |  | 
 |         positive:the condition as not been met.
  |  | 
 |         The conditions EQ and NE are quite important for other uses,as
  |  | 
 |         well.For instance,they can be used to determine if particular bits
  |  | 
 |         in a data word are set,by writing the following sequence...
  |  | 
 | 
  |  | 
 |             ...
  |  | 
 |             AND  #%00001111,D1       ;masks bits out
  |  | 
 |             BEQ SMALLER              ;branches when none of the four
  |  | 
 |         ;                            ;lower bits is set
  |  | 
 |             CMP  #%00001111,D1 
  |  | 
 |             BEQ ALL                  ;branches when all four bits set
  |  | 
 | 
  |  | 
 |         The AND instruction causes all bits of D1 to be compared with the 
  |  | 
 |         bits of the parameter(in this case #%00001111).If the same bits
  |  | 
 |         are set in both bytes,the corresponding bits are also set in the
  |  | 
 |         result.If one bit of the pair is cleared,the resulting bit is zero
  |  | 
 |         as well.Thus,in the result,the only bits that are set are those
  |  | 
 |         bits of the lowest four that were set in D1.
  |  | 
 |         The technique is known as masking.In the example above,only the
  |  | 
 |         lowest four bits were masked out,which meansthat in the resulting 
  |  | 
 |         byte,only the lowest four appear in their original condition.All
  |  | 
 |         other bits are cleared with the AND operand.Of course you can use
  |  | 
 |         any bit combination with this method.
  |  | 
 |         If no bit at all is set in the result,the zeroflag is set,thus
  |  | 
 |         fullfilling the BEQ condition and branching the program.Otherwise,
  |  | 
 |         the next instruction is processed,in which D1 is compared with
  |  | 
 |         %00001111.When both are equal,at leastall of the four lowest bits
  |  | 
 |         of the original byte have been set,in which case the following BEQ
  |  | 
 |         instruction branches.
  |  | 
 |         Aside from CMP,the CC and CS conditions can also be used to
  |  | 
 |         determine whether a HI bit was pushed out of the data word during
  |  | 
 |         data rotation with the ROL and ROR instructions.
  |  | 
 |         Before you move on the instruction vocabulary of the MC68000,we'd
  |  | 
 |         like to give you another tip:
  |  | 
 |         The AssemPro assembler makes it quite easy to try every command in
  |  | 
 |         posible situations.Take the CMP command which we've been talking
  |  | 
 |         about,for example.To test this command with various values and to
  |  | 
 |         receive the results of the comparisons directly via the flags,try
  |  | 
 |         the following.
  |  | 
 |         Type the following into the Editor.
  |  | 
 | 
  |  | 
 |             run:
  |  | 
 |             cmp  $10,d1
  |  | 
 |             bra run
  |  | 
 |             end
  |  | 
 | 
  |  | 
 |         Assemble it,save the resulting code and enter the debugger.After
  |  | 
 |         reloading the code you can then single step through the program
  |  | 
 |         observing the results the program has on the flags.Try changing
  |  | 
 |         the values in the register D1 and see how higher and lower values
  |  | 
 |         affect the flag.
  |  | 
 |         By the way,using the start command at this time causes it to run 
  |  | 
 |         forever.Well,at least until reset is hit,which isn't exactly
  |  | 
 |         desirable,either...
  |  | 
 |         This procedure isn't limited to just the CMP instruction.You can
  |  | 
 |         use it to try any other instructions you're interested in.
  |  | 
 | 
  |  | 
 |       2.4.The 68000 Instructions.
  |  | 
 |       --------------------------
  |  | 
 |         Its about time to explain the MC68000 instructions.You don't have
  |  | 
 |         room for an in-depth discussion of each instruction in this book;
  |  | 
 |         for that purpose we recommend PROGRAMMING THE 68000 from Sybex by
  |  | 
 |         Steve Williams.
  |  | 
 |         The following tables show the required parameters and arguments
  |  | 
 |         for each instruction.AssemPro have access to built in help tables
  |  | 
 |         covering effective addressing modes and many of the Amiga
  |  | 
 |         Intuition calls.The following notation is used for arguments:
  |  | 
 | 
  |  | 
 |            Label     a label or address
  |  | 
 |            Reg       register
  |  | 
 |            An        address register n
  |  | 
 |            Dn        data register n
  |  | 
 |            Source    source operand
  |  | 
 |            Dest      destination operand
  |  | 
 |            <ea>      address or register
  |  | 
 |            #n        direct value
  |  | 
 | 
  |  | 
 |         Here is a short list of the instructions for the MC68000 processor
  |  | 
 |         AssemPro owners can simply place the cursor at the beginning of
  |  | 
 |         the instruction and press the help key to see the addressing modes
  |  | 
 |         allowed:
  |  | 
 | 
  |  | 
 |         Mnemonic             Meaning
  |  | 
 |         ---------------------------------------------------
  |  | 
 |        Bcc     Label         conditional branch,depends on condition
  |  | 
 |        BRA     Label         unconditional branch(similar to JMP)
  |  | 
 |        BSR     Label         branch to subprogram.Return address is
  |  | 
 |                              deposited on stack,RTS causes return to that
  |  | 
 |                              address.
  |  | 
 |        CHK     <ea>,Dx       check data register for limits,activate the
  |  | 
 |                              CHK instruction exception.
  |  | 
 |        DBcc    Reg,Label     check condition,decrement and branch
  |  | 
 |        JMP     Label         jump to address(similar to BRA)
  |  | 
 |        JSR     Label         jump to subroutine.Return address is
  |  | 
 |                              deposited on stack,RTS causes return to that
  |  | 
 |                              address.
  |  | 
 |        NOP                   no operation
  |  | 
 |        RESET                 reset peripherals(caution!)
  |  | 
 |        RTE                   return from exception
  |  | 
 |        RTR                   return with loading of flags
  |  | 
 |        RTS                   return from subroutine(after BSR and JSR)
  |  | 
 |        Scc     <ea>          set a byte to -1 when condition is met
  |  | 
 |        STOP                  stop processing(caution!)
  |  | 
 |        TRAP #n               jump to an exception
  |  | 
 |        TRAPV                 check overflow flag,the TRAPV exception
  |  | 
 | 
  |  | 
 |         Here are a few important notes...
  |  | 
 |         When a program jumps(JSR)or branches(BSR)to subroutine,the return
  |  | 
 |         address to which the program is to return is placed on the stack.
  |  | 
 |         At the RTS instruction,the address is pulled back off the stack,
  |  | 
 |         and the program jumps to that point.
  |  | 
 |         Lets experiment a little with this procedure.Please enter the 
  |  | 
 |         following short program:
  |  | 
 | 
  |  | 
 |           run:
  |  | 
 |                  pea     subprogram   ;address on the stack
  |  | 
 |                  jsr     subprogram   ;subprogram called
  |  | 
 |                  move.l  (sp)+,d1     ;get a long word from stack
  |  | 
 |           ;      illegal              ;for assemblers without
  |  | 
 |                                       ;debuggers
  |  | 
 | 
  |  | 
 |           subprogram:
  |  | 
 |                  move.l  (sp),d0      ;return address in D0
  |  | 
 |                  rts                  ;and return
  |  | 
 |                  end
  |  | 
 | 
  |  | 
 |         The first instruction,PEA,places the address of the subprogram on
  |  | 
 |         the stack.Next,the JSR instruction jumps to the subprogram.The
  |  | 
 |         return address,or the address at which the main program is to
  |  | 
 |         continue after the completion of the subprogram,is also deposited
  |  | 
 |         on the stack at this point.
  |  | 
 |         In the subprogram,the long word pointed to by the stack pointer is
  |  | 
 |         now loaded into the data register D0.After that,the RTS
  |  | 
 |         instruction pulls the return address from the stack,and the
  |  | 
 |         program jumps to that address.
  |  | 
 |         Back in the main program,the long word which is on the top of the
  |  | 
 |         stack,is pulled from the stack and written in D1.Assemblers that
  |  | 
 |         do not have the debugging features of AssemPro may need the
  |  | 
 |         ILLEGAL instruction so they can break the program and allow you to
  |  | 
 |         view the register contents.
  |  | 
 |         Assemble the program and load the resulting code into the debugger
  |  | 
 |         Single step thru the program and examine the register contents.
  |  | 
 |         Here you can see that D0 contains the address at which the program
  |  | 
 |         is to continue after the RTS command.Also,D1 contains the address
  |  | 
 |         of the subprogram which you can verify by comparing the debugger
  |  | 
 |         listing.
  |  | 
 |         The STOP and RESET instructions are so powerful that they can only
  |  | 
 |         be used in supervisor mode.Even if you do switch to the supervisor
  |  | 
 |         mode,you should NOT use these instructions if there is any data in
  |  | 
 |         memory that has not been saved and you wish to retain.
  |  | 
 |         The TRAP instruction receives a number between 0 and $F,which
  |  | 
 |         determines the particular TRAP vector(addresses $0080-$00BF)and
  |  | 
 |         thus the corresponding exception routine.Several operating systems
  |  | 
 |         for the 68000 utilize this instruction to call operating system
  |  | 
 |         functions.You'll deal more with this instruction later.
  |  | 
 |         In the short sample program that compared two numbers,the CMP
  |  | 
 |         instruction performed an arithmetic function,namely a subtraction.
  |  | 
 |         This subtraction could be performed with an actual result as well
  |  | 
 |         using the SUB instruction.The counterpart to this is in addition,
  |  | 
 |         for which the ADD instruction is used.In 8 bit processors,like the
  |  | 
 |         6502,these arithmetic functions are the only mathematical
  |  | 
 |         operations.The MC68000 can also multiply,divide,and perform these
  |  | 
 |         operations with a variety of data sizes.
  |  | 
 |         Most of the functions require two parameters.For instance the ADD
  |  | 
 |         instruction...
  |  | 
 | 
  |  | 
 |             ADD source,destination
  |  | 
 | 
  |  | 
 |         where source and destination can be registers or memory addresses.
  |  | 
 |         Source can also be a direct value(#n).The result of the opoeration
  |  | 
 |         is placed in the destination register or the destination address.
  |  | 
 |         This is same for all operation of this type.These instructions can
  |  | 
 |         be tried out with the AssemPro assembler.In this case we recommend
  |  | 
 |         the use of a register as the destination.
  |  | 
 |         Heres an overview of the arithmetic operations with whole numbers:
  |  | 
 | 
  |  | 
 |         Mnemonic                   Meaning
  |  | 
 |         --------------------------------------------------------------
  |  | 
 |         ADD       source,dest      binary addition
  |  | 
 |         ADDA      source,An        binary addition to a address register
  |  | 
 |         ADDI      #n,<ea>          addition with a constant
  |  | 
 |         ADDQ      #n,<ea>          fast addition of a constant which can
  |  | 
 |                                    be only from 1-8
  |  | 
 |         ADDX      source,dest      addition with transfer in X flag
  |  | 
 |         CLR       <ea>             clear an operand
  |  | 
 |         CMP       source,dest      comparison of two operands
  |  | 
 |         CMPA      <ea>,An          comparison with an address register
  |  | 
 |         CMPI      #n,<ea>          comparison with a constant
  |  | 
 |         CMPM      source,dest      comparison of two memory operands
  |  | 
 |         DIVS      source,dest      sign-true division of a 32 bit
  |  | 
 |                                    destination by a 16 bit source operand.
  |  | 
 |                                    The result of the division is stored in
  |  | 
 |                                    the LO word of the destination,the
  |  | 
 |                                    remainder in the HI word.
  |  | 
 |         DIVU      source,dest      division without regard to sign,similar
  |  | 
 |                                    to DIVS
  |  | 
 |         EXT       Dn               sign-true expansion to twice original
  |  | 
 |                                    size(width)data unit
  |  | 
 |         MULS      source,dest      sign-true multiplication of two words
  |  | 
 |                                    into one long word
  |  | 
 |         MULU      source,dest      multiplication without regard to sign,
  |  | 
 |                                    similar to MULS
  |  | 
 |         NEG       <ea>             negation of an operand(twos complement)
  |  | 
 |         NEGX      <ea>             negation of an operand with transfer
  |  | 
 |         SUB       source,dest      binary subtraction
  |  | 
 |         SUBA      <ea>,An          binary subtraction from an address
  |  | 
 |                                    register
  |  | 
 |         SUBI      #n,<ea>          subtraction of a constant
  |  | 
 |         SUBQ      #n,<ea>          fast subtraction of a 3 bit constant
  |  | 
 |         SUBX      source,dest      subtraction with transfer in X flag
  |  | 
 |         TST       <ea>             test an operand and set N and Z flag
  |  | 
 | 
  |  | 
 |         For the processing of whole numbers,the processor can operate with
  |  | 
 |         BCD numbers.These are Binary Coded Decimal numbers,which means
  |  | 
 |         that the processor is working with decimals.In this method,each
  |  | 
 |         halfbyte contains only numbers from 0 to 9,so that these numbers
  |  | 
 |         can be easily processed.For this method,the following instructions
  |  | 
 |         are available:
  |  | 
 | 
  |  | 
 |         Mnemonic                   Meaning
  |  | 
 |         -----------------------------------------------------------------
  |  | 
 |         ABCD      source,dest      addition of two BCD numbers
  |  | 
 |         NBCD      source,dest      negation of a BCD number(nine
  |  | 
 |                                    complement)
  |  | 
 |         SBCD      source,dest      subtraction of two BCD numbers
  |  | 
 | 
  |  | 
 |         Again,we recommend that you try this out yourself.Although
  |  | 
 |         handling the BCD numbers is relatively easy,it can be rather
  |  | 
 |         awkward at first.Be sure that you enter only BCD numbers for
  |  | 
 |         source and destination,since the results are not correct
  |  | 
 |         otherwise.
  |  | 
 |         Next are the logical operations,which you might know from BASIC.
  |  | 
 |         With these functions,you can operate on binary numbers bit for
  |  | 
 |         bit.
  |  | 
 | 
  |  | 
 |         Mnemonic                   Meaning
  |  | 
 |         -----------------------------------------------------------------
  |  | 
 |         AND       source,dest      logic AND
  |  | 
 |         ANDI      #n,<ea>          logic AND with a constant
  |  | 
 |         EOR       source,dest      exclusive OR
  |  | 
 |         EORI      #n,<ea>          exclusive OR with a constant
  |  | 
 |         NOT       <ea>             inversion of an operand
  |  | 
 |         OR        source,dest      logic OR
  |  | 
 |         ORI       #n,<ea>          logic OR wuth a constant
  |  | 
 |         TAS       <ea>             check a byte and set bit 7
  |  | 
 | 
  |  | 
 |         Single bits can also be manipulated by the following set of
  |  | 
 |         instructions:
  |  | 
 | 
  |  | 
 |         Mnemonic                   Meaning
  |  | 
 |         ----------------------------------------------------------------
  |  | 
 |         BCHG      #n,<ea>          change bit n(0 is changed to 1 and vice
  |  | 
 |                                    versa)
  |  | 
 |         BCLR      #n,<ea>          clear bit n
  |  | 
 |         BSET      #n,<ea>          set bit n
  |  | 
 |         BTST      #n,<ea>          test bit n,result is displayed in Z
  |  | 
 |                                    flag
  |  | 
 | 
  |  | 
 |         These instructions are particularly important from the
  |  | 
 |         manipulation and evaluation of data from peripherals.After all,in
  |  | 
 |         this type of data,single bits are often very significant.You'll
  |  | 
 |         come across this more in later chapters.
  |  | 
 |         The processor can also shift and rotate an operand within itself
  |  | 
 |         ('n'indicates a register,'#'indicates a direct value which
  |  | 
 |         specifies the number of shiftings)...
  |  | 
 | 
  |  | 
 |         Mnemonic                   Meaning
  |  | 
 |         ----------------------------------------------------------------
  |  | 
 |         AS        n,<ea>           arithmetic shift to the left(*2^n)
  |  | 
 |         ASR       n,<ea>           arithmetic shift to the right(/2^n)
  |  | 
 |         LSL       n,<ea>           logic shift to the left
  |  | 
 |         LSR       n,<ea>           logic shift to the right
  |  | 
 |         ROL       n,<ea>           rotation left
  |  | 
 |         ROR       n,<ea>           rotation right
  |  | 
 |         ROXL      n,<ea>           rotation left with transfer in X flag
  |  | 
 |         ROXR      n,<ea>           rotation right with transfer in X flag
  |  | 
 | 
  |  | 
 |         All these instructions allow you to shift a byte,a word or a long
  |  | 
 |         word to the left or right.Its not too surprising that this is the
  |  | 
 |         equivalentof multipling(dividing)the number by a power of 2.Here's
  |  | 
 |         a little example to demonstrate why
  |  | 
 |         Lets take a byte containing the value 16 as an example.In binary,
  |  | 
 |         it looks like this:
  |  | 
 | 
  |  | 
 |             %00010000 =16
  |  | 
 |         
  |  | 
 |         Now,if you shift the byte to the left by inserting a 0 at the
  |  | 
 |         right,you'll get the following result...
  |  | 
 | 
  |  | 
 |             %00010000 shifted to the left equals
  |  | 
 |             %00100000 =32,in effect 16*2
  |  | 
 | 
  |  | 
 |         Repeated shifting results in repeated doubling of the number.Thus
  |  | 
 |         if you shift the number n times,the number is multiplied by 2^n.
  |  | 
 |         The same goes for shifting to the right.However,this operation as
  |  | 
 |         a slight quirk:here's a sample byte with the value 5:
  |  | 
 | 
  |  | 
 |             %00000101 =5,shifted once to the right equals
  |  | 
 |             %00000010 =2
  |  | 
 | 
  |  | 
 |         The answer in this case is not 2.5 as you might expect.The result
  |  | 
 |         such a division is always a whole number,since any decimal places
  |  | 
 |         are discarded.If you use the DIV instruction instead of shifting,
  |  | 
 |         you'll retain the digits to the right of the decimal point.However
  |  | 
 |         shifting is somewhat faster,and shifting can also receive long
  |  | 
 |         words as results.
  |  | 
 |         After explaining the principle of shifting,you still need to know
  |  | 
 |         why more than two instructions are required for the procedure.Well
  |  | 
 |         this is because there are several different types of shifting.
  |  | 
 |         First,you must differentiate between shifting and rotating.In
  |  | 
 |         shifting,the bit that is added to the left or the right side is
  |  | 
 |         always a zero.In rotating,it is always a specific value that is
  |  | 
 |         inserted.This means that with the ROR or the ROL instructions,the
  |  | 
 |         bit that is taken out on one side is the one that is inserted on
  |  | 
 |         the other.With the ROXR and the ROXL instructions this bit takes a
  |  | 
 |         slight detour to the X flag.Thus,the content of the flag is
  |  | 
 |         inserted into the new bit,while the old bit is loaded into the 
  |  | 
 |         flag.
  |  | 
 |         Shifting as well,has two variations:arithmetic and logical
  |  | 
 |         shifting.You've already dealt with logical shifting.In this
  |  | 
 |         variation,the inserted bit is always a zero,and the extracted bit
  |  | 
 |         is deposited in the C flag and in the X flag.
  |  | 
 |         Although the highest bit,which always represents the sign,is
  |  | 
 |         shifted in arithmetic shifting,the sign is still retained by ASR.
  |  | 
 |         This has the advantage that when these instructions are used for
  |  | 
 |         division,the operation retains the correct sign(-10/2 equals-5).
  |  | 
 |         However,should an overflow or underflow cause the sign to change,
  |  | 
 |         this change is noted in the V flag,which always indicates a change
  |  | 
 |         in sign.With logical shifting this flag is always cleared.
  |  | 
 |         Now to the instructions that allow you to move data.These are
  |  | 
 |         actually the most important instructions for any processor,for how
  |  | 
 |         else could you process data?
  |  | 
 | 
  |  | 
 |         Mnemonic                   Meaning
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |         EXG       Rn,Rn            exchange of two register contents(don't
  |  | 
 |                                    confuse with swap)
  |  | 
 |         LEA       <ea>,An          load an effective address in address
  |  | 
 |                                    register An
  |  | 
 |         LINK      An,#n            build stack range
  |  | 
 |         MOVE      source,dest      carry value over from source to dest
  |  | 
 |         MOVE      SR,<ea>          transfer the status register contents
  |  | 
 |         MOVE      <ea>,SR          transfer the status register contents
  |  | 
 |         MOVE      <ea>,CCR         load flags
  |  | 
 |         MOVE      USP,<ea>         transfer the user stack point
  |  | 
 |         MOVE      <ea>,USP         transfer the user stack point
  |  | 
 |         MOVEA     <ea>,An          transfer a value to the address
  |  | 
 |                                    register An
  |  | 
 |         MOVEM     Regs,<ea>        transfer several registers at once
  |  | 
 |         MOVEM     <ea>,Regs        transfer several registers at once
  |  | 
 |         MOVEP     source,dest      transfer data to peripherals
  |  | 
 |         MOVEQ     #n,Dn            quickly transfer a 8 bit constant to
  |  | 
 |                                    the data register Dn
  |  | 
 |         PEA       <ea>             deposit an address on the stack
  |  | 
 |         SWAP      Dn               swap the halves of the register(the
  |  | 
 |                                    upper 16 bits with the lower)
  |  | 
 |         UNLK      An               unlink the stack
  |  | 
 | 
  |  | 
 |         The LEA or PEA instructions are often used to deposit addresses in
  |  | 
 |         an address register or on the stack.The instruction
  |  | 
 | 
  |  | 
 |              LEA   label,A0
  |  | 
 | 
  |  | 
 |         loads the address of the label'label' into the address register
  |  | 
 |         A0.In practice,this corresponds to
  |  | 
 | 
  |  | 
 |              MOVE.L  #label,A0
  |  | 
 | 
  |  | 
 |         which is equivalent to
  |  | 
 | 
  |  | 
 |              PEA  label
  |  | 
 | 
  |  | 
 |         All these instructions deposit the address of 'label' on the stack
  |  | 
 |         The following instruction also does this:
  |  | 
 | 
  |  | 
 |              MOVE.L  #label,-(SP)
  |  | 
 | 
  |  | 
 |         The LEA instruction becomes much more interesting when the label
  |  | 
 |         is replaced by indirect addressing.Here's an example:
  |  | 
 | 
  |  | 
 |              LEA   1(A0,D0),A1
  |  | 
 | 
  |  | 
 |         The address that's produced by the addition of 1(direct value
  |  | 
 |         offset)+A0+D0 is located in A1.To duplicate this instruction with
  |  | 
 |         MOVE would be quite cumbersome.Take a look:
  |  | 
 | 
  |  | 
 |              MOVE.L  A0,A1
  |  | 
 |              ADD.L   D0,A1
  |  | 
 |              ADDQ.L  #1,A1
  |  | 
 | 
  |  | 
 |         As you can see,the LEA instruction offers you quite some
  |  | 
 |         interesting possibilities.
  |  | 
 |         Those are all the instructions of the MC68000.Through their
  |  | 
 |         combination using the diverse methods of addressing,you can create
  |  | 
 |         a great number of different instructions,in order to make a
  |  | 
 |         program as efficent as possible.
  |  | 
 |         The following table is an overview of all MC68000 instructions
  |  | 
 |         along with their possible addressing types and the influence of
  |  | 
 |         flags.The following abbreviations are used:
  |  | 
 | 
  |  | 
 |             x=legal          s=source only    d=destination only
  |  | 
 |             -=not effected   0=cleared        *=modified accordingly
  |  | 
 |             1=set            u=undermined     P=privileged
  |  | 
 | 
  |  | 
 |         Mnemonic     1  2  3  4  5  6  7  8  9 10 11 12  X N Z V C   P
  |  | 
 |         -----------------------------------------------------------------
  |  | 
 |         ABCD         x
  |  | 
 |         ADD          s  s  x  x  x  x  x  x  x  s  s  s  * * * * *
  |  | 
 |         ADDA         x  x  x  x  x  x  x  x  x  x  x  x  - - - - -
  |  | 
 |         ADDI         x     x  x  x  x  x  x  x           * * * * *
  |  | 
 |         ADDQ         x  x  x  x  x  x  x  x  x           * * * * *
  |  | 
 |         ADDX         x           x                       * * * * *
  |  | 
 |         AND          s     x  x  x  x  x  x  x  s  s  s  - * * 0 0
  |  | 
 |         ANDI         x     x  x  x  x  x  x  x           - * * 0 0
  |  | 
 |         ASL, ASR     x     x  x  x  x  x  x  x           * * * * *
  |  | 
 |         Bcc                                              - - - - -
  |  | 
 |         BCHG         x     x  x  x  x  x  x  x           - - * - -
  |  | 
 |         BCLR         x     x  x  x  x  x  x  x           - - * - -
  |  | 
 |         BRA                                              - - - - -
  |  | 
 |         BSET         x     x  x  x  x  x  x  x           - - * - - 
  |  | 
 |         BSR                                              - - - - -
  |  | 
 |         BTST         x     x  x  x  x  x  x  x  z  x  x  - - * - - 
  |  | 
 |         CHK          x     x  x  x  x  x  x  x  x  x  x  - * u u u
  |  | 
 |         CLR          x     x  x  x  x  x  x  x           - 0 1 0 0
  |  | 
 |         CMP          x  x  x  x  x  x  x  x  x  x  x  x  - * * * *
  |  | 
 |         CMPA         x  x  x  x  x  x  x  x  x  x  x  x  - * * * * 
  |  | 
 |         CMPI         x     x  x  x  x  x  x  x           - * * * *
  |  | 
 |         CMPM               x        x  x  x  x     x  x  - * * *
  |  | 
 |         cpGEN                                            - - - - -
  |  | 
 |         DBcc                                             - - - - -
  |  | 
 |         DIVS         x     x  x  x  x  x  x  x  x  x  x  - * * * 0
  |  | 
 |         DIVU         x     x  x  x  x  x  x  x  x  x  x  - * * * 0
  |  | 
 |         EOR          x     x  x  x  x  x  x  x           - * * 0 0
  |  | 
 |         EORI         x     x  x  x  x  x  x  x           - * * 0 0
  |  | 
 |         EORI CCR                                         * * * * *
  |  | 
 |         EORI SR                                          * * * * *
  |  | 
 |         EXG                                              - - - - -
  |  | 
 |         EXT                                              - * * 0 0
  |  | 
 |         EXTB                                             - * * 0 0
  |  | 
 |         ILLEGAL                                          - - - - -
  |  | 
 |         JMP                x        x  x  x  x     x  x  - - - - -
  |  | 
 |         JSR                x        x  x  x  x     x  x  - - - - -
  |  | 
 |         LEA                x        x  x  x  x     x  x  - - - - -
  |  | 
 |         LINK            x                                - - - - -
  |  | 
 |         LSL, LSR           x  x  x  x  x  x  x           * * * 0 *
  |  | 
 |         MOVE         x  s  x  x  x  x  x  x  x  s  s  s  - * * 0 0
  |  | 
 |         MOVEA        x  x  x  x  x  x  x  x  x  x  x  x  - - - - -
  |  | 
 |         MOVE to CCR  x     x  x  x  x  x  x  x  x  x  x  * * * * *
  |  | 
 |         MOVE from SR x     x  x  x  x  x  x  x           - - - - -   P
  |  | 
 |         MOVE to SR   x     x  x  x  x  x  x  x  x  x  x  * * * * *   P
  |  | 
 |         MOVE USP        x                                - - - - -   P
  |  | 
 |         MOVEM              x  s  d  x  x  x  x     s  s  - - - - -
  |  | 
 |         MOVEP        s  d                                - - - - -
  |  | 
 |         MOVEQ        d                                   - * * 0 0
  |  | 
 |         MULS         x     x  x  x  x  x  x  x  x  x  x  - * * 0 0
  |  | 
 |         MULU         x     x  x  x  x  x  x  x  x  x  x  - * * 0 0
  |  | 
 |         NBCD         x     x  x  x  x  x  x  x           * u * u *
  |  | 
 |         NEG          x     x  x  x  x  x  x  x           * * * * *
  |  | 
 |         NEGX         x     x  x  x  x  x  x  x           * * * * * 
  |  | 
 |         NOP                                              - - - - -
  |  | 
 |         NOT          x     x  x  x  x  x  x  x           - * * 0 0
  |  | 
 |         OR           s     x  x  x  x  x  x  x  s  s  s  - * * 0 0
  |  | 
 |         ORI          x     x  x  x  x  x  x  x           - * * 0 0
  |  | 
 |         PEA                x        x  x  x  x     x  x  - - - - -
  |  | 
 |         RESET                                            - - - - -   P
  |  | 
 |         ROL, ROR           x  x  x  x  x  x  x           - * * 0 *
  |  | 
 |         ROXL, ROXR         x  x  x  x  x  x  x           - * * 0 *
  |  | 
 |         RTE                                              - - - - -   P
  |  | 
 |         RTR                                              * * * * *
  |  | 
 |         RTS                                              - - - - - 
  |  | 
 |         SBCD         x           x                       * u * u *
  |  | 
 |         Scc          x     x  x  x  x  x  x  x           - - - - -
  |  | 
 |         STOP                                    x        - - - - -
  |  | 
 |         SUB          s  s  x  x  x  x  x  x  x  s  s  s  * * * * *
  |  | 
 |         SUBA         x  x  x  x  x  x  x  x  x  x  x  x  - - - - -
  |  | 
 |         SUBI         x     x  x  x  x  x  x  x           * * * * *
  |  | 
 |         SUBQ         x  x  x  x  x  x  x  x  x           * * * * *
  |  | 
 |         SUBX         x           x                       * * * * *
  |  | 
 |         SWAP         x                                   - * * 0 0
  |  | 
 |         TAS          x     x  x  x  x  x  x  x           - * * 0 0
  |  | 
 |         TRAP                                    x        - - - - -
  |  | 
 |         TRAPV                                            - - - - -
  |  | 
 |         TST          x     x  x  x  x  x  x  x           - * * 0 0
  |  | 
 |         UNLK            x                                - - - - -          
  |  | 
 |         
  |  | 
 | 
  |  | 
 | 
  |  | 
 | 
  |  | 
 |       Chapter 3.
  |  | 
 |       ---------
  |  | 
 |       3.Working With Assemblers.
  |  | 
 |       -------------------------
  |  | 
 |         The instructions that you've learned so far are incomprehensible
  |  | 
 |         to the MC68000 processor.The letters MOVE mean absolutely nothing
  |  | 
 |         to the processor-it needs the instructions in binary form.Every
  |  | 
 |         instruction must be coded in a word-which normally takes a lot of
  |  | 
 |         work.
  |  | 
 |         An assembler does this work for you.An assembler is a program that
  |  | 
 |         translates the instructions from text into the coresponding binary
  |  | 
 |         instructions.The text that is translated is called Mnemonic or
  |  | 
 |         Memcode.Its a lot easier working with text instructions-or does
  |  | 
 |         $4280 mean more to you than CLR.L D0?
  |  | 
 |         This chapter is about working with assemblers.We'll describe the
  |  | 
 |         following three:
  |  | 
 |       ASSEM;
  |  | 
 |         This is the assembler from the Amiga's development package.This
  |  | 
 |         assembler is quite powerful,but it is clearly inferior to its two
  |  | 
 |         fellow compilers in some areas.
  |  | 
 |       AssemPro;
  |  | 
 |         This is the Abacus assembler.It has a debugger in addition to the
  |  | 
 |         assembler.This lets you test and correct programs.In our opinion,
  |  | 
 |         it is the best one to use for writing and testing practice
  |  | 
 |         programs.For this reason,we wrote the programs in this book with
  |  | 
 |         this assembler.
  |  | 
 |       KUMA-SEKA;
  |  | 
 |         This is a popular assembler which also has a debugger.
  |  | 
 | 
  |  | 
 |         All assemblers perform a similar task-they translate memcode,so
  |  | 
 |         that you can write a runable program to disk.To test the program
  |  | 
 |         directly,you need a debugger which is something Assem doesn't
  |  | 
 |         have.
  |  | 
 |  
  |  | 
 |       3.1.The Development Assembler.
  |  | 
 |       -----------------------------
  |  | 
 |         This assembler is a plain disk assembler.That means that it can
  |  | 
 |         only assemble text files that are on disk and write the result
  |  | 
 |         back to disk.You can't make direct input or test run the new
  |  | 
 |         program.
  |  | 
 |         You can call ASSEM from the CLI by typing ASSEM followed by
  |  | 
 |         parameters that specify what you wish the assembler to do.
  |  | 
 |         In the simplest case,you call it like this:
  |  | 
 | 
  |  | 
 |              ASSEM Source -O Destination
  |  | 
 | 
  |  | 
 |         Source is the filename of the file containing the program text.
  |  | 
 |         Destination is the name of the file that contains the results of
  |  | 
 |         assembling after the process is over.The "-O"means that the
  |  | 
 |         following name is used for the object file.
  |  | 
 |         There are several other parameters that can be passed.These are
  |  | 
 |         written with their option(ie-O),so that the assembler knows what
  |  | 
 |         to do with the file that you've told it to use.The following
  |  | 
 |         possible options must be followed by a filename.
  |  | 
 | 
  |  | 
 |             -O    Object file
  |  | 
 |             -V    Error messages that occur during assembling are written
  |  | 
 |                   to a file.If this isn't given,the error messages appear
  |  | 
 |                   in the CLI window.
  |  | 
 |             -L    The output of the assembled program lines are sent to
  |  | 
 |                   this file.You can also use"PRT:"to have it printed.
  |  | 
 |             -H    This file is read in at the beginning of the assembled
  |  | 
 |                   file and assembled along with it.
  |  | 
 |             -E    A file is created that contains lines which have EQU
  |  | 
 |                   instructions.
  |  | 
 |             -C    This option isn't followed by a filename but by another
  |  | 
 |                   option.You can also use OPT to do this.The following
  |  | 
 |                   options are available:
  |  | 
 |                   
  |  | 
 |                   OPT S  A symbol table is created which contains all the
  |  | 
 |                          labels and their values.
  |  | 
 |                   OPT X  A cross reference list is created(where labels
  |  | 
 |                          are used).
  |  | 
 |                   OPT W  A number must follow this option.It sets the
  |  | 
 |                          ammount of workspace to be reserved.
  |  | 
 | 
  |  | 
 |         The assembler creates an object file.This is not runnable.To make
  |  | 
 |         it runnable,you need to call the linker,ALINK.This program can
  |  | 
 |         link several assembled or compiled object files together to make a
  |  | 
 |         runnable program.In the simplest case,you enter the following
  |  | 
 |         instruction in the CLI:
  |  | 
 | 
  |  | 
 |              ALINK Source TO Destination
  |  | 
 | 
  |  | 
 |         Source is the object file produced by the assembler.Destination is
  |  | 
 |         the name of the program.It can be started directly.
  |  | 
 | 
  |  | 
 |       3.2.AssemPro.
  |  | 
 |       ------------
  |  | 
 |         Abacus's AssemPro is a package which combines editor,assembler and
  |  | 
 |         debugger in an easy to use package.
  |  | 
 |         The AssemPro Program is divided into several windows-one for the
  |  | 
 |         assembler,the editor,the debugger and several help functions.
  |  | 
 |         Producing a program is very easy:
  |  | 
 |           
  |  | 
 |           1)  Write the program with the editor and then store it to disk.
  |  | 
 |           2)  Start the assembler,so that the program is translated.
  |  | 
 |           3)  If desired,start the debugger,load the program and test it.
  |  | 
 | 
  |  | 
 |         Within the debugger you can work through parts of the program or
  |  | 
 |         even through single commands.As after each one of these steps the
  |  | 
 |         debugger shows you the state of the registers and flags in the
  |  | 
 |         status register,you can easily try the programs presented in this
  |  | 
 |         book.
  |  | 
 |         You need to load AssemPro only once when working with machine
  |  | 
 |         language programs.Thus you don't need to save back and to between
  |  | 
 |         editor,assembler,linker and debugger.
  |  | 
 |         AssemPro has an especially interesting function:the reassembler.
  |  | 
 |         With this debugger function you are able to convert runnable
  |  | 
 |         programs into the source text of the program.Once you have made
  |  | 
 |         the source text,you can edit the program using the editor and
  |  | 
 |         assemble it again.AssemPro is equipped with functions other
  |  | 
 |         assemblers miss.There are however,some differences you should know
  |  | 
 |         about.As many programs you see were written for the K-SEKA,be
  |  | 
 |         aware of one difference:the EVEN command.AssemPro uses the ALIGN
  |  | 
 |         instruction.
  |  | 
 |         Note,that when entering and assembling one of the programs in
  |  | 
 |         AssemPro you must make sure that you place an END directive at the
  |  | 
 |         end of the source text.
  |  | 
 |         The following is an introduction into working with AssemPro and
  |  | 
 |         the programs in this book.
  |  | 
 |         
  |  | 
 |         Start AssemPro normally,next click on the editor window and start
  |  | 
 |         typing in your program.If the program is on disk already,load it
  |  | 
 |         by selecting the appropriate menu or by using the key combination
  |  | 
 |         right <AMIGA> key and <o>.To do this you only need to ckick on the
  |  | 
 |         filename in the displayed requester and click on the OK gadget.
  |  | 
 |         Once you have typed in or loaded the program into the editor,you
  |  | 
 |         can assemble it.It is best to save your source before assembling.
  |  | 
 |         You assemble your program by clicking on the assembler window
  |  | 
 |         displayed above the editor window and pressing <AMIGA> and <a>.You
  |  | 
 |         can then choose how to locate your program in the memory.Remember
  |  | 
 |         that data used by the co-processors must be located in CHIP RAM.
  |  | 
 |         By clicking OK you start the assembler process.If you additionally
  |  | 
 |         select "breakable",you can cancel the process by pressing both
  |  | 
 |         shift keys.If any error occurs during assembling,AssemPro uses a
  |  | 
 |         window to tell you this.Use this window to correct the error and
  |  | 
 |         continue with "Save and try again".
  |  | 
 |         Now the runnable program is located in the Amiga's memory.Use the
  |  | 
 |         menu item "Save as"to save it on disk.If you want to store it on
  |  | 
 |         RAM disk,click the given filename and enter RAM: in front of this
  |  | 
 |         name.In addition you can click on the menu item "ICON"and choose
  |  | 
 |         if you only want the program itself on disk but the icon too.Use
  |  | 
 |         this icon to start the program at a later time from Workbench.
  |  | 
 |         To test-run the program,you move the debugger window to the 
  |  | 
 |         foreground of the screen(for instance by clicking on the back
  |  | 
 |         gadget).Use "Load"in the debugger menu or <AMIGA> <o> to call the
  |  | 
 |         select file window,where you select the saved program.The program
  |  | 
 |         is then loaded into the memory and its shown disassembled.
  |  | 
 |         The highlighted line(orange)represents the current state of the 
  |  | 
 |         program counter.This is the line where the processor reads its
  |  | 
 |         next instruction,provided you tell the processor so.There are
  |  | 
 |         three ways to do so.
  |  | 
 |         The first one is to start the program with "Start".This
  |  | 
 |         alternative does not enable you to stop the program if anything
  |  | 
 |         goes wrong.
  |  | 
 |         The second possibility,"Start breakable"is better in this respect.
  |  | 
 |         After the program starts,it continuously displays the registers
  |  | 
 |         contents on the left side of the window.In addition to that you
  |  | 
 |         can cancel the process by pressing <ESC>.Note that this only works
  |  | 
 |         if your program doesn't use the <ESC>key itself.
  |  | 
 |         The third possibility enables you to only partly run your program.
  |  | 
 |         You can do this by stepping through the program or by placing
  |  | 
 |         breakpoints throughout the program.You place these by clicking on 
  |  | 
 |         the desired address and then pressing <AMIGA> <b>."BREAKPOINT"is
  |  | 
 |         displayed where the command was displayed before.If you start the
  |  | 
 |         program now,it stops whenever it comes across any breakpoints.
  |  | 
 |         You can start a small part of the program by moving the mouse
  |  | 
 |         pointer to the orange line,clicking the left button and holding it
  |  | 
 |         down while you drag the mouse pointer downward.If you release the
  |  | 
 |         button,the processor works through this part of the program,
  |  | 
 |         stopping at the line,where you positioned the mouse pointer.This
  |  | 
 |         is a very useful method to step by step test a program.
  |  | 
 |         AssemPro as another helpful window:the Table.This window lists the
  |  | 
 |         valid address methods for instructions and the parameters of Amiga
  |  | 
 |         functions.This is extremely helpful whenever you are not sure
  |  | 
 |         about one of the instructions.
  |  | 
 | 
  |  | 
 |       3.3.The K-SEKA Assembler.
  |  | 
 |       ------------------------
  |  | 
 |         The SEKA assembler,from KUMA,has a simple text editor and a
  |  | 
 |         debugger in addition to the assembler.This program is controlled
  |  | 
 |         by simple instructions and it is easy to use.It is also multi-
  |  | 
 |         functional and quick,so it is great for small test and example
  |  | 
 |         programs.You can use it to write bigger programs once you've got
  |  | 
 |         use to the editor.Now lets look at the editor.
  |  | 
 |         To load a program as source code(text)into the editor,enter"r"
  |  | 
 |         (read).The program asks you for the name of the file with the
  |  | 
 |         "<FILENAME>"prompt.You then enter the name of the text file.If you
  |  | 
 |         created the file with SEKA,the file is stored on disk with".s" on
  |  | 
 |         the end of its name.You don't need to include the".s"when you load
  |  | 
 |         the file.Thats taken care of automatically.("s"stands for source.)
  |  | 
 |         You can store programs you've just written or modified by using
  |  | 
 |         the"w"instruction.The program asks you for the name.If you enter
  |  | 
 |         "Test",the file is written to the disk with"Test.s"as its name.
  |  | 
 |         This is a normal text file in ASCII format.
  |  | 
 |         There are two ways to enter or change a programs:using the line
  |  | 
 |         editor or the screen editor.You can enter the second by hitting
  |  | 
 |         the <ESC>key.The upper screen section is then reserved for the
  |  | 
 |         editor.You can move with the cursor keys and change the text
  |  | 
 |         easily.The lines that you enter are inserted into the existing
  |  | 
 |         text and automatically numbered.By hitting the <ESC>key again,you
  |  | 
 |         leave the screen editor. 
  |  | 
 |         There's really not much to say about this editor.It's really just
  |  | 
 |         for simple insertions and changes.Other functions are called in
  |  | 
 |         normal instruction mode,the mode in which">"is the input prompt.
  |  | 
 |         The following instructions are available to you for text editing
  |  | 
 |         (<n>stands for a number.The meaning of the instructions is in
  |  | 
 |         parenthesis.)
  |  | 
 | 
  |  | 
 |         Instruction        Function
  |  | 
 |         ----------------------------------------------------------------
  |  | 
 |         t(Target)          Puts the cursor on the highest line in the
  |  | 
 |                            text.
  |  | 
 |         t<n>               Puts the cursor on line n.
  |  | 
 |         b(Bottom)          Puts the cursor on the last line in the text.
  |  | 
 |         u(Up)              Go up one line.
  |  | 
 |         u<n>               Go up n lines.
  |  | 
 |         d(Down)            Go down one line.
  |  | 
 |         d<n>               Go down n lines.
  |  | 
 |         z(Zap)             Deletes the current line.
  |  | 
 |         z<n>               Deletes n lines starting at the cursor line.
  |  | 
 |         e(Edit)            Lets you edit the current line(and only that
  |  | 
 |                            line).
  |  | 
 |         e<n>               Edit from line n.
  |  | 
 |         ftext(Find)        Searches for the text entered starting at the
  |  | 
 |                            current line.The case of a letter makes a
  |  | 
 |                            difference,so make sure to enter it correctly.
  |  | 
 |                            Blanks that appear after the f are looked for
  |  | 
 |                            as well!
  |  | 
 |         f                  Continues searching beyond the text that was
  |  | 
 |                            previously given.
  |  | 
 |         i(Insert)          Starts the line editor.Now you can enter a
  |  | 
 |                            program line by line.However,you can't use the
  |  | 
 |                            cursor to move into another line.Line numbers
  |  | 
 |                            are generated automatically.The lines that
  |  | 
 |                            follow are moved down,not erased.
  |  | 
 |         ks(Kill Source)    The source text is deleted if you answer"y"
  |  | 
 |                            when the program asks if you are sure.Otherwise
  |  | 
 |                            nothing happens.
  |  | 
 |         o(Old)             Cancels the "ks"function and saves the old text
  |  | 
 |         p(Print)           Prints the current line.
  |  | 
 |         p<n>               Prints n lines starting at cursor line.
  |  | 
 | 
  |  | 
 |         Those are the K-SEKA's editor functions.In combination with the
  |  | 
 |         screen editor,they allow for simple text editing.You can,for
  |  | 
 |         example,delete the current line(and other lines)while working in
  |  | 
 |         the screen editor by hitting <ESC> to get into instruction mode
  |  | 
 |         and then entering"z"(or "z<n>").
  |  | 
 |         If you'd like to edit all lines that contain "trap",for example,
  |  | 
 |         you can do the following:
  |  | 
 | 
  |  | 
 |            -Jump to the beginning of the text using "t"
  |  | 
 |            -Search for a "trap"instruction by entering "ftrap" in the
  |  | 
 |             first line.
  |  | 
 |            -Press <ESC> and edit the line.
  |  | 
 |            -Press <ESC> again to get into instruction mode.
  |  | 
 |            -Search using "f",<ESC>,etc.until you get to the end of the
  |  | 
 |             text.
  |  | 
 | 
  |  | 
 |         This sounds very clumsy,but in practise it works quite well and
  |  | 
 |         goes quickly.Experiment with the editor bit,so you can get use to
  |  | 
 |         it.
  |  | 
 |         Now here are the instructions for working with disks:
  |  | 
 | 
  |  | 
 |         Instruction             Function
  |  | 
 |         -----------------------------------------------------------------
  |  | 
 |         v(View files)           Look at the disk's directory.You can also
  |  | 
 |                                 include the disk drive or subdirectory
  |  | 
 |                                 that interests you.For example,"vc"causes
  |  | 
 |                                 the "c"subdirectory to be listed and makes
  |  | 
 |                                 it the current directory.
  |  | 
 |         kf(Kill file)           The program asks for the name of the file.
  |  | 
 |                                 The file is deleted(and you aren't asked
  |  | 
 |                                 if your sure either-so be careful).
  |  | 
 |         r(Read)                 After inputting this instruction,you'll be
  |  | 
 |                                 asked which file to load(FILENAME>).The
  |  | 
 |                                 file that you specify is then loaded.If
  |  | 
 |                                 only "r"is entered,a text file is loaded
  |  | 
 |                                 in the editor.
  |  | 
 |         ri(Read Image)          Loads a file into memory.After you've
  |  | 
 |                                 entered the filename,SEKA asks for the
  |  | 
 |                                 address the file should begin at in memory
  |  | 
 |                                 (BEGIN>)and the highest address that
  |  | 
 |                                 should be used for the file(END>).
  |  | 
 |         rx(Read from Auxillary) This works just like the "ri"function
  |  | 
 |                                 except that it reads from the serial port
  |  | 
 |                                 instead of from disk(You don't need a file
  |  | 
 |                                 name).
  |  | 
 |         rl(Read Link file)      This instruction reads in a SEKA created 
  |  | 
 |                                 link file.First you'll be asked if you are
  |  | 
 |                                 sure,because the text buffer is erased
  |  | 
 |                                 when the link file is loaded.
  |  | 
 |         w(Write)                After entering this instruction,you'll be 
  |  | 
 |                                 asked for the name of the file the text
  |  | 
 |                                 should be written to.A".s"is automatically
  |  | 
 |                                 appended to the name,so that it can be 
  |  | 
 |                                 recognized as a SEKA file.
  |  | 
 |         wi(Write Image)         Stores a block of memory to disk after the
  |  | 
 |                                 name,beginning and end are entered.
  |  | 
 |         wx(Write to Auxillary)  This is similar to"wi";the only difference
  |  | 
 |                                 is that the output is to the serial inter-
  |  | 
 |                                 face.
  |  | 
 |         wl(Write Link file)     Asks for the name and then stores a link 
  |  | 
 |                                 file that was assembled with the"I"option
  |  | 
 |                                 to disk.If this isn't available,the
  |  | 
 |                                 message "* * Link option not specified"
  |  | 
 |                                 appears.
  |  | 
 | 
  |  | 
 |         Once you've typed in or loaded a program,you can call the
  |  | 
 |         assembler and have the program translated.Just enter"a"to do so.
  |  | 
 |         You'll then be asked which options you want to use.If you enter a
  |  | 
 |         <RETURN>,the program is assembled normally-ie the results of
  |  | 
 |         translating a program in memory is stored in memory.Then the
  |  | 
 |         program can be executed straight away.
  |  | 
 |         You can enter one or more of the following options,however:
  |  | 
 | 
  |  | 
 |           v     The output of the results goes to the screen.
  |  | 
 |           p     or
  |  | 
 |           e     goes to the printer with a title line.
  |  | 
 |           h     The output stops after every page and waits for a key
  |  | 
 |                 stroke.This is useful for controlling output to the screen
  |  | 
 |                 or for putting new sheets of paper in the printer.
  |  | 
 |           o     This option allows the assembler to optimize all possible
  |  | 
 |                 branch instructions.This allows the program code to be
  |  | 
 |                 shorter than it would otherwise be.Several messages appear
  |  | 
 |                 but you can ignore them.
  |  | 
 |           l     This option causes linkable code to be produced.You can
  |  | 
 |                 save it with the"wl"instruction and read it with the "rl"
  |  | 
 |                 instruction.
  |  | 
 | 
  |  | 
 |         A symbol table is included at the end of the listing if desired.
  |  | 
 |         The table contains all labels and their values.It also contains
  |  | 
 |         macro names.A macro allows several instructions to be combined in
  |  | 
 |         to a single instruction.
  |  | 
 |         For example,suppose you wrote a routinethat outputs the text that 
  |  | 
 |         register A0 points to.Every time you need to use the routine,you
  |  | 
 |         must type:
  |  | 
 | 
  |  | 
 |             lea  text,a0      ;pointer to text in A0
  |  | 
 |             bsr  pline        ;output text
  |  | 
 | 
  |  | 
 |         You can simplify this by defining a macro for this function.To do
  |  | 
 |         this,put the following at the beginning of the program:
  |  | 
 | 
  |  | 
 |             print:macro     ;Macro with the name "Print"
  |  | 
 |              lea  ?1,a0     ;Parameter in A0
  |  | 
 |              bsr  pmsg      ;Output text
  |  | 
 |             endm            ;End of macro
  |  | 
 | 
  |  | 
 |         Now,you can simply write the following in your program:
  |  | 
 | 
  |  | 
 |             print text       ;Output text
  |  | 
 | 
  |  | 
 |         This line is replaced using the macro during assembly.The
  |  | 
 |         parameter "text"is inserted where "?1"appears in the macro.You can
  |  | 
 |         have several parameters in a macro.You give them names like "?2",
  |  | 
 |         "?3",etc...
  |  | 
 |         You can also decide whether you'd like to see the macros in the
  |  | 
 |         output listing of the assembler.This is one of the pseudo-ops that
  |  | 
 |         are available in the assembler.The SEKA assembler has the
  |  | 
 |         following pseudo-ops:
  |  | 
 | 
  |  | 
 |           dc      Defines one or more data items that should appear in
  |  | 
 |                   this location in the program.The word length can be
  |  | 
 |                   specified with .B,.W,or .L-and if this is left off, .B
  |  | 
 |                   is used.Text can be entered in question marks or
  |  | 
 |                   apostrophes.For example:dc.b "Hello",10,13,0
  |  | 
 |           blk     Reserves a number of bytes,words or long words,depending
  |  | 
 |                   on whether .B,.W,or .L is chosen.The first parameter
  |  | 
 |                   specifies the number of words to be reserved.The second
  |  | 
 |                   (which is optional)is used to fill the memory area.For
  |  | 
 |                   example:blk.w 10,0
  |  | 
 |           org     The parameter that follows the org instruction is the
  |  | 
 |                   address from which the (absolute) program should be
  |  | 
 |                   assembled.For example: org $40000
  |  | 
 |           code    Causes the program to be assembled in relative mode,the
  |  | 
 |                   mode in which a program is assembled starting at address
  |  | 
 |                   0.The Amiga takes care of the new addressing after the
  |  | 
 |                   program is loaded.
  |  | 
 |           data    This means that from here on only data appear.This can
  |  | 
 |                   be left out.
  |  | 
 |           even    Makes the current address even by sometimes inserting a
  |  | 
 |                   fill byte.
  |  | 
 |           odd     The opposite of even-it makes the address odd.
  |  | 
 |           end     Assembling ends here.
  |  | 
 |           equ or  Used for establishing the value of a label
  |  | 
 |           =       For example: Value=123 or Value:equ 123
  |  | 
 |           list    Turns the output on again(after nlist).You can use the
  |  | 
 |                   following parameters to influence the output:
  |  | 
 |                     c    Macro calls
  |  | 
 |                     d    Macro definitions
  |  | 
 |                     e    Macro expansion of the program
  |  | 
 |                     x    Code expansions
  |  | 
 |                   For example: list e
  |  | 
 |           nlist   Turns off output.You can use the same parameters here as
  |  | 
 |                   with "list".
  |  | 
 |           page    Causes the printer to execute a page feed,so that you'll
  |  | 
 |                   start a new page.
  |  | 
 |           if      The following parameter decides whether you should
  |  | 
 |                   continue assembling.If it is zero,you won't continue
  |  | 
 |                   assembling.
  |  | 
 |           else    If the "if"parameter is zero,you'll begin assembling
  |  | 
 |                   here.
  |  | 
 |           endif   End of conditional assembling.
  |  | 
 |           macro   Start of a macro definition.
  |  | 
 |           endm    End of macro definition.
  |  | 
 |           ?n      The text in the macro that is replaced by the nth
  |  | 
 |                   parameter in the calling line.
  |  | 
 |           ?0      Generates a new three digit number for each macro call-
  |  | 
 |                   this is very useful for local labels.
  |  | 
 |                   For example: x?0:bsr pmsg
  |  | 
 |           illegal Produces an illegal machine language instruction.
  |  | 
 |           globl   Defines the following label as globel when the "I"option
  |  | 
 |                   of the assembler is chosen.
  |  | 
 | 
  |  | 
 |         Once you've assembled your program,the program code is in memory.
  |  | 
 |         Using the "h"instruction,you can find out how large the program is
  |  | 
 |         and where it is located in memory.The beginning and end address is
  |  | 
 |         given in hex and the length in decimal(according to the last
  |  | 
 |         executed operations):
  |  | 
 | 
  |  | 
 |            Work   The memory area defined in the beginning
  |  | 
 |            Src    Text in memory
  |  | 
 |            RelC   Relocation table of the program
  |  | 
 |            RelD   Relocation table of the memory area
  |  | 
 |            Code   Program code produced
  |  | 
 |            Data   The program's memory area
  |  | 
 | 
  |  | 
 |         You'll find program in memory at the location given by Code.It's a
  |  | 
 |         pain to have to enter this address whenever you want to start the
  |  | 
 |         program.It make's good sense to mark the beginning of the program
  |  | 
 |         with a label(for example,"run:").You can use the "g"instruction to
  |  | 
 |         run the program as follows:
  |  | 
 | 
  |  | 
 |            g run
  |  | 
 | 
  |  | 
 |         The"g"(GO)instruction is one of SEKA's debugger instrucions.Heres
  |  | 
 |         an overview:
  |  | 
 | 
  |  | 
 |          x    Output all registers.
  |  | 
 |          xr   Output and change of registers(ie xd0)
  |  | 
 |          gn   Jump to address n.You`ll be asked for break points,addresses
  |  | 
 |               at which the program should be terminate.
  |  | 
 |          jn   This is similar to the one above-a JSR is used to jump into
  |  | 
 |               the program.The program must end with a RTS instruction.
  |  | 
 |          qn   Output the memory starting at address n.You can also specify
  |  | 
 |               the word length.For example: q.w $10000
  |  | 
 |          nn   Disassembled output starting at address n.
  |  | 
 |          an   Direct assembling starting at address n.Direct program
  |  | 
 |               instructions are entered.
  |  | 
 |          nn   Modify the contents of memory starting at address n.Here too
  |  | 
 |               the word length can be given.You can terminate input with
  |  | 
 |               the <ESC> key.
  |  | 
 |          sn   Executes the program instruction that the PC points to.After
  |  | 
 |               you enter this instruction,n program steps are executed.
  |  | 
 |          f    Fill a memory area.You can choose the word width.All the
  |  | 
 |               needed parameters are asked for individually.
  |  | 
 |          c    Copies one memory area to another.All the needed parameters
  |  | 
 |               are asked for individually.
  |  | 
 |          ?    Outputs the value of an expression or a label.
  |  | 
 |               For example: ?run+$1000-256
  |  | 
 |          a    Sets an instruction sequence that is passed to the program
  |  | 
 |               when it starts as if it were started from CLI with this
  |  | 
 |               sequence.
  |  | 
 |          !    Leaves the SEKA assembler after being asked if your sure.
  |  | 
 | 
  |  | 
 |         You saw some of the calculations like SEKA can make in the "?"
  |  | 
 |         example.You can also use them in programming.The folowing
  |  | 
 |         operations work in SEKA:
  |  | 
 | 
  |  | 
 |            +  Addition
  |  | 
 |            -  Subtraction
  |  | 
 |            *  Multiplication
  |  | 
 |            /  Division
  |  | 
 |            &  Logic AND
  |  | 
 |            !  Logic OR
  |  | 
 |            ~  EXclusive OR (XOR) 
  |  | 
 | 
  |  | 
 |         These operations can also be combined.You can choose the counting
  |  | 
 |         system.A "$"stands for hexadecimal,"@"for octal,and "%"for binary.
  |  | 
 |         If these symbols aren`t used,the number is interpreted as a
  |  | 
 |         decimal number.
  |  | 
 |         Lets go back to the debugger.As mentioned,after entering "g
  |  | 
 |         address",you`ll be asked for break points.You can enter up to 16
  |  | 
 |         addresses at which the program halts.If you don`t enter break
  |  | 
 |         points,but instead hit <RETURN>,the program must end with an
  |  | 
 |         ILLEGAL instruction.If it ends instead with a RTS,the next return
  |  | 
 |         address from the stack is retrieved and jumped to.This is usually
  |  | 
 |         address 4 which causes SEKA to come back with "**Illegal
  |  | 
 |         Instruction at $000004",but theres no guarantee that it will.Your
  |  | 
 |         computor can end up so confused that it can`t function.
  |  | 
 |         The SEKA program puts an ILLEGAL instruction in the place
  |  | 
 |         specified as break points after saving the contents of these
  |  | 
 |         locations.If the processor hits an illegal instruction,it jumps
  |  | 
 |         back to the debugger by using the illegal instruction vector that
  |  | 
 |         SEKA set up earlier.Then SEKA repairs the modified memory
  |  | 
 |         locations and then displays the status line.Here you can find out
  |  | 
 |         where the program terminated.
  |  | 
 |         Using break points is a good technique for finding errors in the
  |  | 
 |         program.You can,for example,put a break point in front of a
  |  | 
 |         routine that you`re not sure about and start the program.When the
  |  | 
 |         program aborts at this spot,you can go through the routine step by
  |  | 
 |         step using the "s"option.Then you can watch what happens to the
  |  | 
 |         status line after each instruction and find the mistake.
  |  | 
 |         Program errors are called bugs.That`s why the program that finds
  |  | 
 |         them is called a debugger.  
  |  | 
 | 
  |  | 
 | 
  |  | 
 | 
  |  | 
 | 
  |  | 
 |       Chapter 4.
  |  | 
 |       ---------
  |  | 
 |       4.Our First Programs.
  |  | 
 |       --------------------
  |  | 
 |         You`re getting pretty far along in your knowledge of machine
  |  | 
 |         language programming.In fact,you`re to the point where you can
  |  | 
 |         write programs,and not just programs for demonstration purposes,
  |  | 
 |         but ones that serve a real function.We`re assuming that you have
  |  | 
 |         the AssemPro assembler and have loaded it.
  |  | 
 |         If you`re using a different assembler,a few things must be done
  |  | 
 |         differently.We covered those differences already in the chapter on
  |  | 
 |         the different assemblers.
  |  | 
 |         We`ve written the example programs as subroutines so they can be
  |  | 
 |         tried out directly and used later.After assembling the program,you
  |  | 
 |         can put the desired values in the register.Then you can either
  |  | 
 |         single-step thru the programs or run the larger programs and
  |  | 
 |         observe the results in the registers directly.(using the SEKA
  |  | 
 |         assembler you can type "j program_name"to start the program.Then
  |  | 
 |         you can read the results from the register directly,or use "q
  |  | 
 |         address"to read it from memory.)
  |  | 
 |         Lets start with an easy example,adding numbers in a table.
  |  | 
 | 
  |  | 
 |       4.1.Adding Tables.
  |  | 
 |       -----------------
  |  | 
 |         Imagine that you have numbers in memory that you'd like to add.
  |  | 
 |         Lets assume that you have five numbers whose length is one word
  |  | 
 |         each.You want their sum to be written in register D0.The easiest
  |  | 
 |         way to do this is:
  |  | 
 | 
  |  | 
 |         ;(4.1A)
  |  | 
 |         adding1:
  |  | 
 |                clr.l  D0               ;Erase D0 (=0)
  |  | 
 |                move   table,d0         ;First entry in D0
  |  | 
 |                add    table+2,d0       ;Add second entry
  |  | 
 |                add    table+4,d0       ;Add third entry
  |  | 
 |                add    table+6,d0       ;Add fourth entry
  |  | 
 |                add    table+8,d0       ;add fifth entry
  |  | 
 |                rts                     ;Return to main program
  |  | 
 |         table: dc.w 2,4,6,8,10,
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         Try out the program using the debugger by single stepping thru the
  |  | 
 |         program until you get to the RTS instruction(left Amiga T).(SEKA
  |  | 
 |         owners use "j adding1").You see that data register D0 really
  |  | 
 |         contains the sum of the values.
  |  | 
 |         The method above only reads and adds numbers from a particular set
  |  | 
 |         of addresses.The Amigas processor has lots of different sorts of 
  |  | 
 |         addressing modes that give us a shorter and more elegant solution.
  |  | 
 |         Lets add a variable to the address of the table,so that the
  |  | 
 |         program can add different tables.
  |  | 
 |         Lets put the addresses of the table in an address register(for
  |  | 
 |         example, A0)instead.This register can be used as a pointer to the
  |  | 
 |         table.You must use move.l since only long words are relocatable.By
  |  | 
 |         using a pointer to a table you can use indirect addressing.You can
  |  | 
 |         change the expression "table+x" to"x(A0)".
  |  | 
 | 
  |  | 
 |         ;(4.1B)
  |  | 
 |         adding1:
  |  | 
 |                clr.l   D0            ;Erase D0 (=0)
  |  | 
 |                move.l  #table,a0     ;Put table addresses in A0
  |  | 
 |                move    0(a0),d0      ;Put first entry in d0
  |  | 
 |                add     2(a0),d0      ;Add second entry
  |  | 
 |                add     4(a0),d0      ;Add third entry
  |  | 
 |                add     6(a0),d0      ;Add forth entry
  |  | 
 |                add     8(a0),d0      ;Add fifth entry
  |  | 
 |                rts                   ;Return to main program]
  |  | 
 |         table: dc.w 2,4,6,8,10
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         Assemble this program,load it into the debugger.Then single step
  |  | 
 |         (left Amiga T)thru this program and you'll see that this program
  |  | 
 |         adds five numbers in order just like the last one.The reason you
  |  | 
 |         used a step size of two for the ofset is that words are two bytes
  |  | 
 |         long.AssemPro also defaults to relocate code so that you must move
  |  | 
 |         #table as a long word.
  |  | 
 |         Lets improve the program more by using "(a0)+"instead of "x(a)".
  |  | 
 |         This way,every time you access elements of the table,the address
  |  | 
 |         register A0 is automatically incremented by the number of bytes
  |  | 
 |         that are read(in this case two).The difference between this and
  |  | 
 |         the last example is that here the registers contents are modified.
  |  | 
 |         The pointer is to the next unused byte or word in memory.
  |  | 
 |         Lets make it even better.Lets make the number of words to be added
  |  | 
 |         to a variable.You'll pass the number in register D1.Now you need
  |  | 
 |         to do a different sort of programming,since you can't do it with
  |  | 
 |         the old methods.
  |  | 
 |         Lets use a loop.You need to add D1 words.You can use(a0)+ as the
  |  | 
 |         addressing method(address register indirect with post increment),
  |  | 
 |         since this automatically gets you to the next word.
  |  | 
 |         Now for the loop.You'll have D1 decremented by one every time the
  |  | 
 |         contents of the pointer are added.If D1 is zero,then you're done.
  |  | 
 |         Otherwise,you need another addition.The program looks like this:
  |  | 
 | 
  |  | 
 |         ;(4.1C)
  |  | 
 |         adding2:
  |  | 
 |                clr.l    d0            ;Erase D0
  |  | 
 |                move.l   #table,a0     ;Put table addresses in A0
  |  | 
 |                move     #$5,d1        ;Put number of entries in D1
  |  | 
 |                
  |  | 
 |         loop:                         ;Label for loop beginning
  |  | 
 |                add      (a0)+,d0      ;Add a word
  |  | 
 |                subq     #1,d1         ;Decrement counter
  |  | 
 |                bne      loop          ;Continue if non-zero
  |  | 
 |                rts                    ;Else done
  |  | 
 | 
  |  | 
 |         table: dc.w 2,4,6,8,10
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         Lets take a close look at this program.Load the pointer A0 with
  |  | 
 |         the addresses of the data and the counter D1 with the number of
  |  | 
 |         elements.Then you can single step thru the program and watch the
  |  | 
 |         results.Make sure not to run the final command,the RTS command,
  |  | 
 |         because otherwise a return address is popped from the stack,and
  |  | 
 |         the results of this are unpredictable.(SEKA owners can use"x pc"
  |  | 
 |         to point the program counter to "adding2".You can then step thru
  |  | 
 |         the program by using the "s"command and watch the results).
  |  | 
 |         To finish up this example,your assigning a little homework.Write
  |  | 
 |         the program so that it adds single bytes or long words.Try to
  |  | 
 |         write a program that takes the first value in a table and
  |  | 
 |         subtracts the following values.For example,the table
  |  | 
 | 
  |  | 
 |              table: dc.w 50,8,4,6
  |  | 
 | 
  |  | 
 |         should return the value 50-8-4-6, ie 32 ($20).
  |  | 
 | 
  |  | 
 |       4.2.Sorting a Table.
  |  | 
 |       -------------------
  |  | 
 |         Lets keep working with tables.You don't want to just read data
  |  | 
 |         from one this time.You want to change it.You'll assort the table
  |  | 
 |         in assending order.
  |  | 
 |         You need to decide how to do the sorting.The simplest method is to
  |  | 
 |         do the following.
  |  | 
 |         Compare the first and the second value.If the second value is
  |  | 
 |         larger than the first one,things are OK so far.Do the next step,
  |  | 
 |         compare the second and third values,and so on.If you come to the 
  |  | 
 |         final pair and in each case the preceding value was smaller than
  |  | 
 |         the following value,then the sorting is done(it was unnescessary).
  |  | 
 |         If you find a pair where the second value is smaller than the
  |  | 
 |         first,the two values are exchanged.You then get a flag(here let's
  |  | 
 |         use a register)that is checked once you're done going thru the
  |  | 
 |         table.If it is set,the table probably isn't completely sorted.You
  |  | 
 |         then erase the flag and start again from the beginning.If the flag
  |  | 
 |         is still zero at the end,the sorting is complete.
  |  | 
 |         Now let's write a program to do this.First let's figure out the
  |  | 
 |         variables you need.You'll use registers for the variables.You need
  |  | 
 |         a pointer to the table you're sorting(A0),a counter(D0)and a flag
  |  | 
 |         (D1).While the program is running,change these values,so you'll 
  |  | 
 |         need two more registers to store the starting values(address and
  |  | 
 |         the number of the table entries).You'll use A1 and D2.
  |  | 
 |         Let's start writing the program,each section will be written and
  |  | 
 |         then explained.Then the complete program will be given.You put the
  |  | 
 |         tables address in A1 and the number of entries in D2.
  |  | 
 | 
  |  | 
 |         ;(4.2A) part of sort routine
  |  | 
 |         sort:                       ;Start address of the program
  |  | 
 |                 move.l  #table,a1   ;Load pointer with address
  |  | 
 |                 move.l  a1,a0       ;Copy pointer to working register
  |  | 
 |                 move.l  #5,d2       ;Number in the counter
  |  | 
 |                 move.l  d2,d0       ;Copy number of elements
  |  | 
 |                 subq    #2,d0       ;Correct conter value
  |  | 
 |                 clr     d1          ;Erase flag
  |  | 
 | 
  |  | 
 |         table: dc.w 3,6,9,5
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         Now the preparations are complete.The pointer and the counter are
  |  | 
 |         ready and the flag is cleared.The counter is decremented by two
  |  | 
 |         because you want to use the DBRA command(take one off)and only X-1
  |  | 
 |         comparrisons are needed for X numbers(take off one more).
  |  | 
 |         Next let's write the loop that compares the values.You compare one
  |  | 
 |         word with another.It looks like this:
  |  | 
 | 
  |  | 
 |         loop:
  |  | 
 |               move   2(a0),d3   ;Next value in register D3
  |  | 
 |               cmp    (a0),d3    ;Compare values
  |  | 
 | 
  |  | 
 |         You need to use register D3 because CMP (A0),2(A0) isn't a legal
  |  | 
 |         choice.If the second value is greater than or equal to the first
  |  | 
 |         value,you can skip an exchange.
  |  | 
 | 
  |  | 
 |               bcc    noswap      ;Branch if greater than or equal
  |  | 
 |                                  ;to
  |  | 
 | 
  |  | 
 |         Now you need to do the exchanging(unfortunatly you can't use EXC
  |  | 
 |         2(a0),(a0) since this form of addressing does not exist).
  |  | 
 | 
  |  | 
 |         doswap:
  |  | 
 |                move   (a0),d1      ;Save first valus
  |  | 
 |                move   2(a0),(a0)   ;Copy second into first word
  |  | 
 |                move   d1,2(a0)     ;Move first into second
  |  | 
 |                moveq  #1,d1        ;Set flag
  |  | 
 |         noswap:
  |  | 
 | 
  |  | 
 |         Now increment the counter and continue with the next pair.You do
  |  | 
 |         this until the counter is negative.
  |  | 
 | 
  |  | 
 |                addq.l  #2,a0      ;Pointer+2
  |  | 
 |                dbra    d0,loop    ;Continuing looping until the end
  |  | 
 | 
  |  | 
 |         Now you'll see if the flag is set.You start again at the beginning
  |  | 
 |         if it is.
  |  | 
 | 
  |  | 
 |                tst     d1         ;Test flag
  |  | 
 |                bne     sort       ;Not finished sorting yet!
  |  | 
 |                rts                ;Otherwise done.Return
  |  | 
 | 
  |  | 
 |         If the flag is zero,you're done and the subroutine ends.You jump
  |  | 
 |         back to the main program using the RTS command.
  |  | 
 |         Now a quick overview of the complete program.
  |  | 
 | 
  |  | 
 |         ;(4.2B)
  |  | 
 |         sort:                      ;Start address of the program
  |  | 
 |               move.l  #table,a1    ;Load pointer with address
  |  | 
 |               move.l  a1,a0        ;Copy pointer to working register
  |  | 
 |               move.l  #5,d2        ;Number in the counter
  |  | 
 |               move.l  d2,d0        ;Copy number of elements
  |  | 
 |               subq    #2,d0        ;Correct counter value
  |  | 
 |               clr     d1           ;Erase flag
  |  | 
 | 
  |  | 
 |         loop:
  |  | 
 |               move    2(a0),d3     ;Next value in register D3
  |  | 
 |               cmp     (a0),d3      ;Compare values
  |  | 
 |               bcc     noswap       ;Branch if greater than or equal to
  |  | 
 | 
  |  | 
 |         doswap:
  |  | 
 |               move    (a0),d1      ;Save first value
  |  | 
 |               move    2(a0),(a0)   ;Copy second into first word
  |  | 
 |               move    d1,2(a0)     ;Move first into second
  |  | 
 |               moveq   #1,d1        ;Set flag
  |  | 
 | 
  |  | 
 |         noswap: 
  |  | 
 |               addq.l  #2,a0        ;Pointer+2
  |  | 
 |               dbra    do,loop      ;Continue looping until the end
  |  | 
 |               tst     d1           ;Test flag
  |  | 
 |               bne     sort         ;Not finished sorting yet!
  |  | 
 |               rts                  ;Otherwise done.Return
  |  | 
 | 
  |  | 
 |         table: 
  |  | 
 |               dc.w    10,8,6,4,2   ;When finished acceding
  |  | 
 | 
  |  | 
 |               end
  |  | 
 | 
  |  | 
 |         To test this subroutine,assemble the routine with AssemPro,save it
  |  | 
 |         and then load it into the debugger.The table is directly after the
  |  | 
 |         RTS,notice its order.Set a breakpoint at the RTS,select the
  |  | 
 |         address with the mouse and press left-Amiga-B sets a breakpoint in
  |  | 
 |         AssemPro.Start the program the redisplay the screen by selecting
  |  | 
 |         "Parameter-Display-Dissassem-bled"and examine the order of the
  |  | 
 |         numbers in the table,they should now be ascending order.
  |  | 
 |         You use several registers in this example for storing values.
  |  | 
 |         Usually in machine language programming your subroutines cannot
  |  | 
 |         change any register or can only change certain registers.For this
  |  | 
 |         reason,there is a machine language command to push several
  |  | 
 |         registers onto the stack at the same time.This is the MOVEM ("MOVE
  |  | 
 |         multiple")command.If you insert this command twice in your program
  |  | 
 |         then you can have the registers return to the main program with
  |  | 
 |         the values they had when the subroutine was called.To do this,you
  |  | 
 |         need one more label.Let's call it"start";the subroutine is started
  |  | 
 |         from here.
  |  | 
 | 
  |  | 
 |         start:
  |  | 
 |               movem.l  d0-d7/a0-a6,-(sp)    ;save registers
  |  | 
 |               
  |  | 
 |         sort:
  |  | 
 |               etc...
  |  | 
 |               ...
  |  | 
 |               ...
  |  | 
 |               bne      sort                 ;not finished sorting yet!
  |  | 
 | 
  |  | 
 |               movem.l  (sp)+,d0-d7/a0-a6    ;retrieve registers
  |  | 
 |               rts                           ;finished
  |  | 
 | 
  |  | 
 |         The powerful command moves several registers at the same time.You
  |  | 
 |         can specify which registers should be moved.If you want to move
  |  | 
 |         the D1,D2,D3,D7,A2 and A3 registers,just write 
  |  | 
 | 
  |  | 
 |               movem.l  d1-d3/d7/a2-a3,-(sp)
  |  | 
 | 
  |  | 
 |         Before you quit sorting,do one little homework assignment.Modify
  |  | 
 |         the program,so that it sorts the elements in descending order.
  |  | 
 | 
  |  | 
 |       4.3.Converting Number Systems.
  |  | 
 |       -----------------------------
  |  | 
 |         As we mentioned in the chapter on number systems,converting
  |  | 
 |         numbers from one base to another can be rather difficult.There is
  |  | 
 |         another form of numeric representation-as a string that can be
  |  | 
 |         entered via the keyboard or output on the screen.
  |  | 
 |         You want to look at some of the many conversions possible and
  |  | 
 |         write programs to handle the task.You'll start by converting a hex
  |  | 
 |         number into a string using binary numbers and then print the value
  |  | 
 |         in hex.
  |  | 
 | 
  |  | 
 |       4.3.1.Converting Hex To ASCII.
  |  | 
 |       -----------------------------
  |  | 
 |         First you need to set the start and finish conditions.In this
  |  | 
 |         example,let's assume that data register D1 contains a long word
  |  | 
 |         that should be converted into a 8-digit long string of ASCII
  |  | 
 |         characters.You'll write it to a particular memory location so that
  |  | 
 |         you can output it later.
  |  | 
 |         The advantage of using hex instead of decimal is pretty clear in
  |  | 
 |         this example.To find out the hexadecimal digit for a particular
  |  | 
 |         spot in the number,you just need to take the corresponting 4 bits
  |  | 
 |         (half byte)and do some work on it.A half byte(also called a
  |  | 
 |         nibble)contains one hex digit.
  |  | 
 |         You'll work on a half byte in D2.To convert this to a printable
  |  | 
 |         character,you need to use the correct ASCII code.The codes of the
  |  | 
 |         16 characters that are used as hex digits are the following:
  |  | 
 | 
  |  | 
 |           0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
  |  | 
 | 
  |  | 
 |         $30 $31 $32 $33 $34 $35 $36 $37 $38 $39 $41 $42 $43 $44 $45 $46
  |  | 
 | 
  |  | 
 |         To convert the digits 0-9,you just need to add $30.For the letters
  |  | 
 |         A-F that correspond to the values 10-15,you need to add $37.The
  |  | 
 |         program to evaluate a half byte must make a destinction between
  |  | 
 |         values between 0 and 9 and those between A and F and add either
  |  | 
 |         $30 or $37.
  |  | 
 |         Now let's write a machine language subroutine that you'll call for
  |  | 
 |         each digit in the long words hex representation.
  |  | 
 | 
  |  | 
 |         nibble:
  |  | 
 |                and    #$0f,d2     ;just keep low byte
  |  | 
 |                add    #$30,d2     ;add $30
  |  | 
 |                cmp    #$3a,d2     ;was it a digit?
  |  | 
 |                bcs    ok          ;yes:done
  |  | 
 |                add    #7,d2       ;else add 7
  |  | 
 | 
  |  | 
 |         ok:
  |  | 
 |                rts                ;done
  |  | 
 | 
  |  | 
 |         This routine converts the nibble in D2 to an ASCII character that
  |  | 
 |         corresponds to the hex value of the nibble.To convert an entire
  |  | 
 |         byte,you need to call the routine twice.Here is a program to do
  |  | 
 |         this.The program assumes that A0 contains the address of the
  |  | 
 |         buffer that the characters are to be put in and that D1 contains
  |  | 
 |         the byte that is converted.
  |  | 
 | 
  |  | 
 |         ;(4.3.1a) bin-hex
  |  | 
 |         ;                            ;your program
  |  | 
 |                  lea     buffer,a0   ;pointer to buffer
  |  | 
 |                  move    #$4a,d1     ;byte to be converted(example)
  |  | 
 |                  bsr     byte        ;and convert
  |  | 
 |                  rts
  |  | 
 |         ;        ...                 ;more of your program
  |  | 
 |         byte:
  |  | 
 |                  move    d1,d2       ;move value into d2
  |  | 
 |                  lsr     #4,d2       ;move upper nibble into lower nibble
  |  | 
 |                  bsr     nibble      ;convert d2
  |  | 
 |                  move.b  d2,(a0)+    ;put character into buffer
  |  | 
 |                  move    d1,d2       ;value in d2
  |  | 
 |                  bsr     nibble      ;convert lower nibble
  |  | 
 |                  move.b  d2,(a0)+    ;and put it in buffer
  |  | 
 |                  rts                 ;done
  |  | 
 |         nibble:
  |  | 
 |                  and     #$0f,d2     ;just keep low byte
  |  | 
 |                  add     #$30,d2     ;add $30
  |  | 
 |                  cmp     #$3a,d2     ;was it a digit?
  |  | 
 |                  bcs     ok          ;yes:done
  |  | 
 |                  add     #7,d2       ;else add 7
  |  | 
 |         ok:
  |  | 
 |                  rts                 ;done
  |  | 
 |         buffer:
  |  | 
 |                  blk.b   9,0         ;space for long word data
  |  | 
 | 
  |  | 
 |                  end
  |  | 
 | 
  |  | 
 |         To test this subroutine,use AssemPro to assemble the routine,save
  |  | 
 |         the program and load it intoi the debugger.Next set a breakpoint
  |  | 
 |         at the first RTS,to set the breakpoint in AssemPro select the
  |  | 
 |         correct address with the mouse and press the right-Amiga-B keys.
  |  | 
 |         Start the program and watch the contents of D2,it is first $34
  |  | 
 |         (ASCII 4)and finally $41(ASCII A).Select "Parameter-Display-HEX-
  |  | 
 |         Dump"and you'll see that 4A has been moved into the buffer.
  |  | 
 |         This is how the routine operates.First,you move the value that you
  |  | 
 |         wish to convert into D2.Then you shift the register four times to
  |  | 
 |         the right to move the upper nibble into the lower four bits.After
  |  | 
 |         the subroutine call,you use "move.b d2,(a0)+"to put the HI nibble
  |  | 
 |         in the buffer.Then the original byte is put in D2 again.It is 
  |  | 
 |         converted.This gives us the LO nibble as an ASCII character in D2.
  |  | 
 |         You put this in the next byte of the buffer.
  |  | 
 |         The buffer is long enough to hold a long word in characters and
  |  | 
 |         closing the null byte.The null byte is usually required by screen
  |  | 
 |         output routines.Screen output will be discussed in a later
  |  | 
 |         chapter.Now let's worry about converting a long word.
  |  | 
 |         When converting a long word,you need to be sure to deal with the
  |  | 
 |         nibbles in the right order.Before calling the "nibble"routine for
  |  | 
 |         the first time,you need to move the upper nibble into the lower 4
  |  | 
 |         bits of the long word.You need to do this without losing anything.
  |  | 
 |         The LSR command isn't very good for this application.If you use it
  |  | 
 |         you'll lose bits.Its better to use the rotation commands like ROR
  |  | 
 |         or ROL,since they move the bits that are shifted out,back in on
  |  | 
 |         the other side.
  |  | 
 |         If you shift the original long word in D1 four times to the left,
  |  | 
 |         the upper four bits are shifted into the lower four bits.Now you
  |  | 
 |         can use our "nibble"routine to evaluate it and then put the
  |  | 
 |         resulting ASCII character in the buffer.You repeat this eight
  |  | 
 |         times and the whole long word has been converted.You even have D1
  |  | 
 |         looking exactly the way it did before the conversion process began
  |  | 
 | 
  |  | 
 |         ;(4.3.1B) bin-hex-2
  |  | 
 |         hexlong:
  |  | 
 |                lea     buffer,a0      ;pointer to the buffer
  |  | 
 |                move.l  #$12345678,d1  ;data to convert
  |  | 
 |                move    #7,d3          ;counter for the nibbles:8-1
  |  | 
 | 
  |  | 
 |         loop:
  |  | 
 |                rol     #4,d1          ;move upper nibble into lower
  |  | 
 |                move    d1,d2          ;write in d2
  |  | 
 |                bsr     nibble         ;and convert it
  |  | 
 |                move.b  d2,(a0)+       ;character in buffer
  |  | 
 |                dbra    d3,loop        ;repeat 8 times
  |  | 
 |                rts                    ;finished!
  |  | 
 | 
  |  | 
 |         nibble:
  |  | 
 |                and     #$0f,d2        ;just keep low byte
  |  | 
 |                add     #$30,d2        ;add $30
  |  | 
 |                cmp     #$3a,d2        ;was it a digit?
  |  | 
 |                bcs     ok             ;yes:done
  |  | 
 |                add     #7,d2          ;else add 7
  |  | 
 | 
  |  | 
 |         ok:
  |  | 
 |                rts                    ;done
  |  | 
 | 
  |  | 
 |         buffer:
  |  | 
 |                blk.b   9,0            ;space for long word,null byte
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         To test this subroutine,use AssemPro to assemble the routine,save
  |  | 
 |         the program and load it into the debugger.Next set a breakpoint at
  |  | 
 |         the first RTS,to set the breakpoint in AssemPro select the correct
  |  | 
 |         address with the mouse and press the right-Amiga-B keys.Start the
  |  | 
 |         program and when it is finished redisplay the output by selecting
  |  | 
 |         "Parameter-Display-HEX-dump"so you can examine the new buffer
  |  | 
 |         contents.
  |  | 
 |         You'll find that there's an error in the program-the buffer
  |  | 
 |         contains the digits "56785678"instead of "12345678".Try to find
  |  | 
 |         the error.
  |  | 
 |         Have you found it?This is the sort of error that causes you to
  |  | 
 |         start pulling your hair out.This sort is hard to find.The
  |  | 
 |         assembler assumes that the rotation operation should be done on a
  |  | 
 |         word,because the ".l"was left off.As a result,only the lower word
  |  | 
 |         of D1 was rotated-so you get the same value twice.If you change
  |  | 
 |         the "rol.l",things work just right.
  |  | 
 |         The error shows how easy it is to convert the program above into
  |  | 
 |         one that converts four digit hex numbers into ASCII characters.
  |  | 
 |         Just leave off the ".l"on the "rol"command and change the counter
  |  | 
 |         from seven to three.The program is done.
  |  | 
 |         Now for a little homework:change the program so that it can handle
  |  | 
 |         six digit hex numbers(D1 doesn't nescessarily have to stay the
  |  | 
 |         same...)!
  |  | 
 |         Now lets look at a different conversion problem:converting a four
  |  | 
 |         digit decimal number.
  |  | 
 | 
  |  | 
 |       4.3.2.Converting Decimal To ASCII.
  |  | 
 |       ---------------------------------
  |  | 
 |         It's not quite as easy to convert decimal as hex.You can't group
  |  | 
 |         the bits to form individual digits.You need to use another method.
  |  | 
 |         Lets look at how a decimal number is constructed.In a four digit
  |  | 
 |         number,the highest place is in the thousands place,the next is the
  |  | 
 |         hundreds place,etc...
  |  | 
 |         If you have the value in a register and divide by 1000,you'll get
  |  | 
 |         the value that goes in the highest place in the decimal number.
  |  | 
 |         Since the machine language command DIV not only gives us the
  |  | 
 |         result of the division but also gives us the remainder,you can
  |  | 
 |         work out the remainder quite easily.You divide the remainder by
  |  | 
 |         100 to find the hundreds place,divide the remainder by 10 and get
  |  | 
 |         the tens place,and the final remainder is the ones place.
  |  | 
 |         This isn't so hard after all!Heres the program that follows the
  |  | 
 |         steps above to fill the buffer with D1's ASCII value.
  |  | 
 | 
  |  | 
 |         main:
  |  | 
 |                lea     buffer,a0    ;pointer to the buffer
  |  | 
 |                move    #1234,d1     ;number to convert
  |  | 
 |                jsr     deci_4       ;test subroutine
  |  | 
 |                illegal              ;room for breakpoint
  |  | 
 | 
  |  | 
 |         deci_4:                     ;subroutine-four digit numbers
  |  | 
 | 
  |  | 
 |                divu    #1000,d1     ;divide by 1000
  |  | 
 |                bsr     digit        ;evaluate result-move remainder
  |  | 
 | 
  |  | 
 |                divu    #100,d1      ;divide by 100
  |  | 
 |                bsr     digit        ;evaluate result and move
  |  | 
 | 
  |  | 
 |                divu    #10,d1       ;divide by 10
  |  | 
 |                bsr     digit        ;evaluate result-move remainder
  |  | 
 | 
  |  | 
 |                                     ;evaluate the remainder directly
  |  | 
 | 
  |  | 
 |         digit:
  |  | 
 |                add     #$30,d1      ;convert result into ASCII
  |  | 
 |                move.b  d1,(a0)+     ;move it into buffer
  |  | 
 |                clr     d1           ;erase lower word
  |  | 
 |                swap    d1           ;move the remainder down
  |  | 
 |                rts                  ;return
  |  | 
 | 
  |  | 
 |         buffer:blk.b 5,0            ;reserve bytes for result
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         To test this subroutine,use AssemPro to assemble the routine,save
  |  | 
 |         the program and load it into the debugger.Next set a breakpoint at
  |  | 
 |         the illegal instruction.To set the breakpoint in AssemPro select
  |  | 
 |         the correct address with the mouse and press the right-Amiga-B
  |  | 
 |         keys.This breakpoint stops the program.Start the program and when
  |  | 
 |         it is finished redisplay the output by selecting"Parameter-Display
  |  | 
 |         -HEX-dump"so you can examine the ASCII values now in the buffer.
  |  | 
 |         You use a little trick in this program that is typical for machine
  |  | 
 |         language programming.After calling"digit"three times from the sub-
  |  | 
 |         routine"deci_4",you go right into the"digit"subroutine.You don't 
  |  | 
 |         use a BSR or JSR command.Once the processor hits the RTS command,
  |  | 
 |         it returns to the main program,not the "deci_4"subroutine.Doing
  |  | 
 |         this,you save a fourth "bsr digit"command and an "rts"command for
  |  | 
 |         the "deci_4"routine.
  |  | 
 |         Try the program out.Make sure that you use values that are smaller
  |  | 
 |         than 9999,because otherwise strange things can happen.
  |  | 
 |         Now let's reverse what you've been doing and convert strings into
  |  | 
 |         binary numbers.
  |  | 
 | 
  |  | 
 |       4.3.3.Converting ASCII To Hex.
  |  | 
 |       -----------------------------
  |  | 
 |         In a string,each hex digit represents a half byte.You just need to
  |  | 
 |         write a program that exactly reverses what the hex conversion
  |  | 
 |         program did.
  |  | 
 |         You have two choices
  |  | 
 | 
  |  | 
 |           1.  The number of hex digits is known in advance
  |  | 
 |           2.  The number is unknown
  |  | 
 | 
  |  | 
 |         The first is easier to program,but has the disadvantage that if,
  |  | 
 |         you assume the strings are four digits in length and want to enter
  |  | 
 |         the value 1,you must enter 0001.That is rather awkward,so you'll
  |  | 
 |         use the second method.
  |  | 
 |         Let's convert a single digit first.You'll pass a pointer to this
  |  | 
 |         digit in address register A0.You want the binary value to come
  |  | 
 |         back in data register D0.
  |  | 
 |         The program looks like this:
  |  | 
 | 
  |  | 
 |                move.l  #string,a0    ;this example
  |  | 
 |                jsr     nibblein      ;test routine
  |  | 
 |                nop                   ;set breakpoint here
  |  | 
 | 
  |  | 
 |         nibblein:                    ;*convert the nibble from (A0)
  |  | 
 |                clr.l   d0            ;erase D0
  |  | 
 |                move.b  (a0)+,d0      ;get digit,increment A0
  |  | 
 |                sub     #'A',d0       ;subtract $41
  |  | 
 |                bcc     ischar        ;no problem:in the range A-F
  |  | 
 | 
  |  | 
 |                add     #7,d0         ;else correct value
  |  | 
 |         ischar:
  |  | 
 |                add     #10,d0        ;correct value
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         string:dc.b 'B',0            ;character to convert
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         To test this subroutine,use AssemPro to assemble the routine,save
  |  | 
 |         the program and load it into the debugger.Next set a breakpoint at
  |  | 
 |         the first NOP,to set the breakpoint in AssemPro select the correct
  |  | 
 |         address with the mouse and press the right-Amiga-B keys.Start the
  |  | 
 |         program and watch the contents of D0.
  |  | 
 |         Let's see how the program works.A0 points to a memory location
  |  | 
 |         that contains the character "B"that is represented by the ASCII
  |  | 
 |         value $42.This number is loaded into D0 right after this register
  |  | 
 |         is erased.
  |  | 
 |         After subtracting $41,you end up with the value $1.Now you're
  |  | 
 |         almost done.Before returning to the main program,you add 10 to get
  |  | 
 |         the correct value 11,$B.
  |  | 
 |         If the buffer has a digit in it,the subtraction causes the
  |  | 
 |         register to become negative.The C flag is set.Let's take the digit
  |  | 
 |         5 as an example.
  |  | 
 |         The ASCII value of 5 is $35.After subtracting $41,you end up with
  |  | 
 |         -12 and the C flag is set.In this case,you won't branch with the
  |  | 
 |         BCC command.Instead you'll add 7 to get -5.Then 10 is added,and
  |  | 
 |         you end up with 5.Done!
  |  | 
 |         The routine as a disadvantage.If an illegal character is given,one
  |  | 
 |         that doesn't represent a hex digit,you'll get some nonsense result
  |  | 
 |         Let's ignore error checking for the moment though.
  |  | 
 |         Let's go on to multi-digit hex numbers.The first digit that you
  |  | 
 |         convert has the highest value and thus represents the highest
  |  | 
 |         nibble.To allow for this and to allow for an arbitrarily long
  |  | 
 |         number(actually not arbitrarily long,the number should fit in a
  |  | 
 |         long word-so it can only be eight digits long),you'll use a trick.
  |  | 
 |         Take a look at the whole program.It handles the calculations and
  |  | 
 |         puts the result in D1.It assumes that A0 is a pointer to a string
  |  | 
 |         and that this string is ended by null byte.
  |  | 
 | 
  |  | 
 |         hexin:                       ;converting a hex number
  |  | 
 |                clr.l   d1            ;first erase D1
  |  | 
 |                move.l  #string,a0    ;address of the string in A0
  |  | 
 |                jsr     hexinloop     ;test subroutine
  |  | 
 |                nop                   ;set breakpoint here
  |  | 
 | 
  |  | 
 |         hexinloop:
  |  | 
 |                tst.b   (a0)          ;test digit
  |  | 
 |                beq     hexinok       ;zero,then done
  |  | 
 |                bsr     nibblein      ;convert digit
  |  | 
 |                lsl.l   #4,d1         ;shift result
  |  | 
 |                or.b    d0,d1         ;insert nibble
  |  | 
 |                bra     hexinloop     ;and continue
  |  | 
 | 
  |  | 
 |         hexinok:
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         nibblein:
  |  | 
 |                clr.l   d0            ;convert the nibble from (A0)
  |  | 
 |                move.b  (a0)+,d0      ;get digit,increment A0
  |  | 
 |                sub     #'A',d0       ;subtract $41
  |  | 
 |                bcc     ischar        ;no problem:in range A-F
  |  | 
 |                add     #7,d0         ;else correct value
  |  | 
 |           
  |  | 
 |         ischar:
  |  | 
 |                add     #10,d0        ;correct value
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         string:DC.B "56789ABC',00    ;eight digit string,null byte
  |  | 
 |                                      ;to be converted
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         To test this subroutine,use AssemPro to assemble the routine,save
  |  | 
 |         the program and load it into the debugger.Next set a breakpoint at
  |  | 
 |         the NOP,to set the breakpoint in AssemPro select the correct
  |  | 
 |         address with the mouse and press the right-Amiga-B keys.Start the
  |  | 
 |         program and watch the contents of D1,the hex value is placed in
  |  | 
 |         this register.
  |  | 
 |         The trick is to shift left four times,to shift one nibble.In this
  |  | 
 |         way,the place of the last digit is incremented by one and there is
  |  | 
 |         room for the nibble that comes back from the "nibblein"routine.The
  |  | 
 |         program uses the TST.B instruction to check for the null byte at
  |  | 
 |         the end of the string,when it encounters the null byte the program
  |  | 
 |         ends.The result is in the D1 long word already!
  |  | 
 |         To do some error checking,you need to make some changes in the
  |  | 
 |         program.You'll do this right after you come back from the"nibblin"
  |  | 
 |         routine with the value of the current character.
  |  | 
 |         If the value in D0 is bigger than $F,there is an error.You can
  |  | 
 |         detect this in several ways.You chose the simplest one-you'll use
  |  | 
 |         CMP #$10,D0 to compare D0 with $10.If it smaller,then the C flag
  |  | 
 |         is set(since CMP uses subtraction)and everything is fine.If C is
  |  | 
 |         zero,there is an error.
  |  | 
 |         You can use this trick to skip the test for a null byte,since its
  |  | 
 |         an invalid character as well.The program looks like this:
  |  | 
 | 
  |  | 
 |         ;(4_3_3C) hex-conv2         optional disk name
  |  | 
 |         hexin:                      ;converting a hex number
  |  | 
 |                clr.l   d1           ;first erase D1
  |  | 
 |                move.l  #string,a0   ;address of string in A0
  |  | 
 |                jsr     hexinloop    ;test subroutine
  |  | 
 |                nop                  ;set breakpoint here
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         hexinloop:
  |  | 
 |                bsr     nibblein     ;convert digit
  |  | 
 |                cmp     $10,d0       ;test if good
  |  | 
 |                bcc     hexinok      ;no,then done
  |  | 
 |                lsl.l   #4,d1        ;shift result
  |  | 
 |                or.b    d0,d1        ;insert nibble
  |  | 
 |                bra     hexinloop    ;and continue
  |  | 
 | 
  |  | 
 |         hexinok:
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         nibblein:                   ;convert the nibble from (A0)
  |  | 
 |                clr.l   d0           ;erase D0
  |  | 
 |                move.b  (a0)+,d0     ;get digit,increment A0
  |  | 
 |                sub     #'A',d0      ;subtract $41
  |  | 
 |                bcc     ischar       ;no problem:in the range A-F
  |  | 
 |                add     #7,d0        ;else correct value
  |  | 
 | 
  |  | 
 |         ischar:
  |  | 
 |                add     #10,d0       ;correct value
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         string:DC.B "56789ABC',00   ;8 digit string ending with a
  |  | 
 |                                     ;null byte to be converted
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         To test this subroutine,use AssemPro to assemble the routine,save
  |  | 
 |         the program and load it into the debugger.Next set a breakpoint at
  |  | 
 |         the NOP,to set the breakpoint in AssemPro select the correct
  |  | 
 |         address with the mouse and press the right-Amiga-B keys.Start the
  |  | 
 |         program and watch the contents of D1,the hex value is placed in
  |  | 
 |         this register.
  |  | 
 |         This is the method for converting hex to binary.If you convert
  |  | 
 |         decimal to binary,the conversion is not much harder.
  |  | 
 | 
  |  | 
 |       4.3.4.Converting ASCII To Decimal.
  |  | 
 |       ---------------------------------
  |  | 
 |         You can use a very similar method to the one used above.Since you
  |  | 
 |         are not sure how many digits there are,you'll use a similar method
  |  | 
 |         for putting digits of a number in the next place up.You can't do
  |  | 
 |         this with shifting,but you can multiply by 10 and add the value of
  |  | 
 |         the digit.
  |  | 
 |         Heres the program for converting decimal numbers.
  |  | 
 | 
  |  | 
 |         decin:                      ;converting a decimal number
  |  | 
 |                clr.l   d1           ;first erase D1
  |  | 
 |                move.l  #string,a0   ;the string to convert
  |  | 
 |                jsr     decinloop    ;test subroutine
  |  | 
 |                nop                  ;breakpoint here
  |  | 
 | 
  |  | 
 |         decinloop:
  |  | 
 |                bsr     digitin      ;convert digit
  |  | 
 |                cmp     #10,d0       ;test,if valid
  |  | 
 |                bcc     decinok      ;no,then done
  |  | 
 |                mulu    #10,d1       ;shift result
  |  | 
 |                add     d0,d1        ;insert nibble
  |  | 
 |                bra     decinloop    ;and continue
  |  | 
 | 
  |  | 
 |         decinok:
  |  | 
 |                rts                  ;end of conversion
  |  | 
 | 
  |  | 
 |         digitin:                    ;converting the nibble from (A0)
  |  | 
 | 
  |  | 
 |                clr.l   d0           ;erase D0
  |  | 
 |                move.b  (a0)+,d0     ;get digit,increment A0
  |  | 
 |                sub     #'0',d0      ;subtract $30
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         string:dc.b '123456'        ;ASCII decimal string to convert
  |  | 
 | 
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         To test this subroutine,use AssemPro to assemble the routine,save
  |  | 
 |         the program and load it into the debugger.Next set a breakpoint at
  |  | 
 |         the NOP,to set the breakpoint in AssemPro select the correct
  |  | 
 |         address with the mouse and press thr right-Amiga-B keys.Select
  |  | 
 |         "Parameter-Output-numbers-Decimal"so the registers are displayed
  |  | 
 |         as decimal numbers.Then start the program and watch the contents
  |  | 
 |         of D1,the decimal value is placed in this register.
  |  | 
 |         This program can ONLY convert numbers upto 655350,although the hex
  |  | 
 |         conversion routine can go higher.Thats because the MULU command
  |  | 
 |         can only multiply 16-bit words.The last multiplication that can be
  |  | 
 |         done correctly is $FFFF*10--65535*10,which gives us the value
  |  | 
 |         655350.Normally this is a large enough range,so you won't
  |  | 
 |         complicate the program further. 
  |  | 
 | 
  |  | 
 |       CHAPTER 5.
  |  | 
 |       ---------
  |  | 
 |       5.Hardware Registers.
  |  | 
 |       --------------------
  |  | 
 |         You can get information about hardware functions without using
  |  | 
 |         library functions.You can use the hardware registers instead.These
  |  | 
 |         are memory locations at particular addresses that are neither in
  |  | 
 |         RAM nor in ROM.They are direct interfaces between the processor
  |  | 
 |         and its peripheral devices.
  |  | 
 |         Each device has a number of hardware registers that the processor
  |  | 
 |         accesses to control graphics,sound and input/output.There are lots
  |  | 
 |         of possibilities for assembly language programmers.We'll only be
  |  | 
 |         able to go into a few examples.
  |  | 
 |         The registers are generally used in byte-wise fashion.You'll find
  |  | 
 |         an example in the next chapter.
  |  | 
 | 
  |  | 
 |       5.1.Checking For Special Keys.
  |  | 
 |       -----------------------------
  |  | 
 |         Load AssemPro and enter the debugger,select "Parameter-Display-
  |  | 
 |         From-Address"and enter $BFEC00.Next select "Parameter-Display-Hex
  |  | 
 |         -Dump"to display the memory.(To use the SEKA assembler or a similar
  |  | 
 |         monitor program,enter "q $bfec00".)
  |  | 
 |         Yoy'll see a byte-wise listing of the addresses starting at
  |  | 
 |         $BFEC00 in which two bytes always repeat.These two bytes represent
  |  | 
 |         the status of the two hardware registers.
  |  | 
 |         The mirroring occurs because not all the address bits are used in
  |  | 
 |         decoding the address.In addressing this register,only the upper
  |  | 
 |         two bytes of the address and the low bit,bit 0,are used.The
  |  | 
 |         address of the two registers goes like this:$BFECxx,where the
  |  | 
 |         lower address byte xx doesn't contain any information in bits 1-7.
  |  | 
 |         Only bit 0 contains information about the desired register.You'll
  |  | 
 |         find this odd form of addressing with most hardware registers.
  |  | 
 |         Let's look at the information in these registers.Let's look at the
  |  | 
 |         second register,$BFEC01.Hold down the<ALT>key and select"Parameter
  |  | 
 |         -Display-HEX-Dump"to redisplay the screen.(SEKA owners must enter
  |  | 
 |         "q $bfec00"and press the<ALT>key right after pressing the<Return>
  |  | 
 |         key.)You'll see that contents of every two bytes($BFEC01,$BFEC03,
  |  | 
 |         etc...)have been changed to $37.This is the status of the special
  |  | 
 |         keys.This is also true for the other special keys.The following
  |  | 
 |         keys produce the bytes:
  |  | 
 | 
  |  | 
 |             Shift left      $3F
  |  | 
 |             Shift right     $3D
  |  | 
 |             Control         $39
  |  | 
 |             Alternate       $37
  |  | 
 |             Amiga left      $33
  |  | 
 |             Amiga right     $31
  |  | 
 | 
  |  | 
 |         You can use this register to have a machine language program check
  |  | 
 |         if one of these keys was pressed and then respond by calling or
  |  | 
 |         ending a function.A program section might look like this:
  |  | 
 | 
  |  | 
 |         skeys=$bfec01
  |  | 
 |               ...
  |  | 
 |               cmp.b   #$37,skeys   ;Alternate pressed?
  |  | 
 |               beq     function1    ;Yes!
  |  | 
 |               cmp.b   #$31,skeys   ;or right Amiga?
  |  | 
 |               beq     function2    ;Yes!
  |  | 
 |               ...                  ;and so on...
  |  | 
 | 
  |  | 
 |       5.2.Timing.
  |  | 
 |       ----------
  |  | 
 |         If you want to find out how much time elapsed between two events,
  |  | 
 |         you can use a hardware register to keep track of time quickly and
  |  | 
 |         precisely.The Amiga contains just such a timekeeper:the I/O port
  |  | 
 |         componant.The chip has a 24 bit wide counter that has a 60 Hertz
  |  | 
 |         clock.
  |  | 
 |         These 24 bits can't be read at once,for instance with a MOVE.L
  |  | 
 |         command,because the register is divided into three bytes.The low 
  |  | 
 |         byte is at address $BFE801,the middle at $BFE901,and the high byte
  |  | 
 |         with bits 16-23 at $BFEA01.
  |  | 
 |         Here's an example of a way to use this register:finding out how
  |  | 
 |         long a subroutine takes to run.
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |                bsr     gettime     ;put current time in D7
  |  | 
 |                move.l  d7,d6       ;save it in D6
  |  | 
 |                bsr     routine     ;routine to be timed
  |  | 
 |                bsr     gettime     ;get the time again
  |  | 
 |                sub.l   d6,d7       ;elapsed time in
  |  | 
 |                ...                 ;1/50 seconds in D7!
  |  | 
 |                nop                 ;set break point here to stop
  |  | 
 | 
  |  | 
 |         routine:                   ;test routine
  |  | 
 |                move    #500,d0     ;delay counter
  |  | 
 |           
  |  | 
 |         loop:
  |  | 
 |                dbra    d0,loop     ;count down
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         gettime:
  |  | 
 |                move.b  $bfea01,d7  ;hi-byte in D0
  |  | 
 |                lsl.l   #4,d7       ;shift twice by 4 bits
  |  | 
 |                lsl.l   #4,d7       ;(8 bits shifted)
  |  | 
 |                move.b  $bfe901,d7  ;get mid-byte
  |  | 
 |                lsl.l   #4,d7       
  |  | 
 |                lsl.l   #4,d7       ;shift again
  |  | 
 |                move.b  $bfe801,d7  ;get the lo-byte
  |  | 
 |                rts                 ;done
  |  | 
 |          
  |  | 
 |       5.3.Reading The Mouse-Joystick.
  |  | 
 |       -------------------------------
  |  | 
 |         There are two hardware registers for the mouse and the joystick.
  |  | 
 |         They contain the state(or the position)of these input devices.Its
  |  | 
 |         interesting that the same port is used with both the mouse and the
  |  | 
 |         joystick even through they work completely different.
  |  | 
 |         The joystick as four switches that are closed during movement and
  |  | 
 |         give off a potential(-)that is related to the movement of the
  |  | 
 |         joystick/mouse.The mouses movements give off lots of quick signals
  |  | 
 |         -two for horizontal and two for vertical movements.
  |  | 
 |         The computor must keep an eye on the ports so that it can evaluate
  |  | 
 |         the signals and calculate the new mouse position.This isn't the
  |  | 
 |         work of the processor though;it already has too much to do.
  |  | 
 |         You find the status of the mouse/joystick port at address $DFF00A
  |  | 
 |         for port 1 and $DFF00C for port 2.The information in these words
  |  | 
 |         is for vertical mouse movement in the lower byte and for
  |  | 
 |         horizontal movement in the upper byte.
  |  | 
 |         AssemPro owners be careful!Don't read these addresses,because for
  |  | 
 |         some reason that causes the computor to crash.This looks
  |  | 
 |         interesting(the screen begins to dance)but you can only recover by
  |  | 
 |         pressing <RESET>and losing all your data.
  |  | 
 |         To read this register,lets write a short program:
  |  | 
 | 
  |  | 
 |         ;(5.3A) mouse
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |               jsr     run       ;test subroutine
  |  | 
 |               jmp     test      ;continue until broken
  |  | 
 |               nop               ;breakpoint here
  |  | 
 | 
  |  | 
 |         joy= $dff00a
  |  | 
 |          
  |  | 
 |         run:
  |  | 
 |               move    joy,d6    ;data item 1 in D6
  |  | 
 |               move    joy+2,d7  ;data item 2 in D7
  |  | 
 |               jmp     run       ;rts for SEKA and other
  |  | 
 | 
  |  | 
 |               end
  |  | 
 | 
  |  | 
 |         If you assemble the program and start breakable in the debugger
  |  | 
 |         (SEKA-"j run"),D6 and D7 contain the contents of the two registers
  |  | 
 |         Move the mouse a bit and watch the register contents.
  |  | 
 |         As you see,the value in D6 is different.If you just move the mouse
  |  | 
 |         horizontaly,only the upper bytes value is different,if just moved
  |  | 
 |         vertically only the upper byte is different.
  |  | 
 |         You are not getting the absolute position of the mouse pointer on
  |  | 
 |         the screen.You can see that easily by moving the mouse in the
  |  | 
 |         upper left corner,then reading the value by restarting the program
  |  | 
 |         and moving the mouse left again.As you can see,the registers
  |  | 
 |         contents are always relative.
  |  | 
 |         Change the program as follows:
  |  | 
 | 
  |  | 
 |         ;(5.3B)                   mouse difference
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |               jsr      run        ;test subroutine
  |  | 
 |               jmp      test       ;continue until broken
  |  | 
 |               nop                 ;breakpoint here
  |  | 
 | 
  |  | 
 |         joy= $dff00a
  |  | 
 | 
  |  | 
 |         run:
  |  | 
 |               move     d7,d6      ;old position in D6
  |  | 
 |               move     joy,d7     ;new position in D7
  |  | 
 |               sub      d7,d6      ;difference in D6
  |  | 
 |               jmp      run        ;rts for SEKA and other
  |  | 
 | 
  |  | 
 |               end
  |  | 
 | 
  |  | 
 |         Start Breakable(right-Amiga-A)in the AssemPro debugger and watch
  |  | 
 |         D6,the result is zero or D7.(SEKA owners have to start the program
  |  | 
 |         two times.The result in D6 is zero.)If you move the mouse,D6
  |  | 
 |         contains the difference between the old and new positions since
  |  | 
 |         the start.You'll find the vertical and horizontal positions of the
  |  | 
 |         mouse relative to the last time you looked.In this way,you can use
  |  | 
 |         this register to find the relative mouse movement between two
  |  | 
 |         checks.
  |  | 
 |         Now to check the joysticks.Put a joystick in port 2 and change the
  |  | 
 |         address $DFF00A to $DFF00C in the program.Start Breakable in the
  |  | 
 |         AssemPro debugger and watch D6,the result is zero or D7.(SEKA
  |  | 
 |         owners have to start the program two times.The result in D6 is
  |  | 
 |         zero.)
  |  | 
 |         Move the joystick up.You'll get the value $FF00.One was subtracted
  |  | 
 |         from the upper byte.Let the joystick loose.This time you get the
  |  | 
 |         value $100-one is added.You'll get the same effect if you move the
  |  | 
 |         joystick left-after you let go,one is subtracted.
  |  | 
 |         The individual movements and their effects on the joystick program
  |  | 
 |         are:
  |  | 
 | 
  |  | 
 |                        UP      $FF00       HI-BYTE -1
  |  | 
 |                        DOWN    $FFFF       LO-BYTE -1
  |  | 
 |                        LEFT    $0100       HI-BYTE +1
  |  | 
 |                        RIGHT   $0001       LO-BYTE +1
  |  | 
 | 
  |  | 
 |         These values aren't terribly reliable.If you move the joystick a
  |  | 
 |         lot and then look at the value,you'll find a crazy value in D6.
  |  | 
 |         This is because the input driver thinks that a mouse is attached.
  |  | 
 |         Nevertheless,this is the quickest way to read a joystick.In this
  |  | 
 |         way,an external device that gives off evaluatable TTL signals can
  |  | 
 |         be connected to the port and watched by a machine language
  |  | 
 |         program.
  |  | 
 |         Now you just need to find out whether the fire button has been
  |  | 
 |         pressed,and you'll know how to get all the information you need
  |  | 
 |         from the joystick.The buttons state is in bit 7 of the byte that
  |  | 
 |         is in memory location $BFE001.If the bit is set,the button was'nt
  |  | 
 |         pressed.That's true for the joystick connected to port 2.Bit 6 of
  |  | 
 |         this byte contains the buttons state when the joystick is in port
  |  | 
 |         1 or the state of the left mouse button.
  |  | 
 |         Let's stay on port 2.You can test bit 7 to execute a function when
  |  | 
 |         the joystick button is pressed without any problems.Bit 7 is the
  |  | 
 |         sign bit.You can use this program segment:
  |  | 
 | 
  |  | 
 |              tst.b   $bfe001     ;was fire button 2 hit?
  |  | 
 |              bpl     fire        ;yes!branch
  |  | 
 | 
  |  | 
 |         The TST.B instruction tests the addressed byte and sets the Z and
  |  | 
 |         the N flag.If the N flag is set,you know that bit 7 of the tested
  |  | 
 |         byte is set.Since the fire button turns on LO potential,the bit is
  |  | 
 |         erased when the button is pressed.The N flag works that way with
  |  | 
 |         the TST command as well.The BPL command in the program above
  |  | 
 |         branches if the button was pressed.The PL stands for plus and is
  |  | 
 |         set when the sign bit is cleared.
  |  | 
 |         Here is the complete program to check the fire button and joystick
  |  | 
 |         difference:
  |  | 
 | 
  |  | 
 |         ;(5.3C) fire button and joy difference
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |                jsr     run        ;test subroutine
  |  | 
 |                tst.b   $bfe001    ;was fire button 2 hit?
  |  | 
 |                bpl     fire       ;yes! branch
  |  | 
 |                jmp     test       ;continue until broken
  |  | 
 | 
  |  | 
 |         joy = $dff00a
  |  | 
 |         run:
  |  | 
 |                move    d7,d6      ;old position in D6
  |  | 
 |                move    joy,d7     ;new position in D7
  |  | 
 |                sub     d7,d6      ;difference in D6
  |  | 
 |                jmp     run        ;rts for SEKA and other
  |  | 
 | 
  |  | 
 |         fire:
  |  | 
 |                nop                ;breakpoint here
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |       5.4.Tone Production.
  |  | 
 |       -------------------
  |  | 
 |         It's fun to make noises and sounds.The Amiga lets you use Audio
  |  | 
 |         Devices and various I\O structures to play tones,noises and/or
  |  | 
 |         music pieces in the background.You'll leave this method to C or
  |  | 
 |         Basic programmers,since you can use short machine language
  |  | 
 |         programs to directly program the audio hardware.
  |  | 
 |         The Paula chip has all the capabilities needed for tone production
  |  | 
 |         This chip can be accessed using the hardware registers of the
  |  | 
 |         processor.No library of any high level language can do more than
  |  | 
 |         you can-program the chip.
  |  | 
 |         How does it work?Since the disk uses Direct Memory Access(DMA)to
  |  | 
 |         get information,you just need to tell it where to look for the
  |  | 
 |         tone or tone sequences that you would like played.You also need to
  |  | 
 |         tell it how to interpret the data.
  |  | 
 |         Lets start with the easiest case-producing a constant tone.A tone
  |  | 
 |         like this consists of a single oscillation that is repeated over
  |  | 
 |         and over.If you make a diagram of the oscillation,you see the wave
  |  | 
 |         form of the oscillation.There are several standard waves: sine,
  |  | 
 |         square,triangle and saw tooth.The simplest is the square wave.
  |  | 
 |         To produce a square wave,you just need to turn the loud speaker on
  |  | 
 |         and off.The frequency that occurs here is the frequency of the
  |  | 
 |         tone. 
  |  | 
 |         You want to produce such a tone using the Amiga.First you need to
  |  | 
 |         make a table that contains the amplitude of the tone you wish to
  |  | 
 |         produce.For a square wave,you only need two entries in the table,a
  |  | 
 |         large and a small value.Since the sound chip in the Amiga has
  |  | 
 |         amplitude values between -128 and +127,our table looks like this:
  |  | 
 | 
  |  | 
 |         soundtab:
  |  | 
 |                dc.b -100,100
  |  | 
 | 
  |  | 
 |         You need to give the address of the table to the sound chip.You
  |  | 
 |         have four choices,since the Amiga as four sound channels.The
  |  | 
 |         address of the hardware register in which the table address for
  |  | 
 |         channel 0 must be written is $DFF0A0;for channel 1 it is $DFF0B0;
  |  | 
 |         for channel 2 its $DFF0C0;for channel 3 its $DFF0D0.For stereo
  |  | 
 |         output,channels 0 and 3 control the left loud speaker.Channels 1
  |  | 
 |         and 2 control the right loud speaker.For example,choose channel 0
  |  | 
 |         and write the following:
  |  | 
 | 
  |  | 
 |                move.l  #soundtab,$DFF0A0   ;address of the table
  |  | 
 | 
  |  | 
 |         Next you need to tell the sound chip how many items there are in
  |  | 
 |         the table.The data is read from beginning to end and sent to the
  |  | 
 |         loud speaker.Once it reaches the end,it starts over at the
  |  | 
 |         beginning.Since the sound chip gets this one word at a time,even
  |  | 
 |         though the data is in bytes,the table must always have an even
  |  | 
 |         number of bytes.The length that you give it is the number of words
  |  | 
 |         the number of bytes/2.
  |  | 
 |         You put the length for channel 0 in the register at address
  |  | 
 |         $DFF0A4(for channel x just add x*$10!):
  |  | 
 | 
  |  | 
 |                move  #1,$dff0a4   ;length of table in words
  |  | 
 | 
  |  | 
 |         Now you have to tell it how quickly to read the data and output it
  |  | 
 |         to the loud speaker.This word determines the frequency.However,it
  |  | 
 |         does this "backwards".The larger the value,the lower the frequency
  |  | 
 |         Choose the value 600 for this example:
  |  | 
 | 
  |  | 
 |                move  #600,$dff0a6   ;read in rate
  |  | 
 | 
  |  | 
 |         Now you need to decide the loudness level for the tone or noise.
  |  | 
 |         You have 65 different levels to choose from.Lets choose the middle
  |  | 
 |         value 40 for our example:
  |  | 
 | 
  |  | 
 |                move  #40,$dff0a8    ;loudness level
  |  | 
 | 
  |  | 
 |         Thats the data that the sound chip needs to produce the tone.
  |  | 
 |         However nothing happens yet.What next?The chip can't tell if the
  |  | 
 |         data thats in the registers is valid,so it doesn't know if it
  |  | 
 |         should use the data.
  |  | 
 |         You need to work with the DMA control register at address $DFF096
  |  | 
 |         to let it know.You only need six bits of this word for your
  |  | 
 |         purposes:
  |  | 
 | 
  |  | 
 |         Bit 15 ($8000)  If this bit is set,every bit that is written to
  |  | 
 |                         this internal register is set.Otherwise the bits
  |  | 
 |                         are erased.Zero bits aren't affected.This is very
  |  | 
 |                         useful because this word also contains DMA
  |  | 
 |                         information for disk operations that should'nt be
  |  | 
 |                         changed.
  |  | 
 | 
  |  | 
 |         Bit 9 ($200)    This bit makes it posible for the chip to access
  |  | 
 |                         DMA memory.If you want to start playing the tone,
  |  | 
 |                         you need to set this bit.
  |  | 
 | 
  |  | 
 |         Bit 0-3         Turn channel 0-3 on when bits are set.
  |  | 
 | 
  |  | 
 |         You'll start your tone by setting bits 15,9 and 0:
  |  | 
 | 
  |  | 
 |                move   #$8000+$200+1,$dff096   ;start DMA
  |  | 
 | 
  |  | 
 |         Heres an example of tone production-this time with tone using a
  |  | 
 |         sine wave:
  |  | 
 | 
  |  | 
 |         ;**Sound Generation using hardware registers** (5.5A)
  |  | 
 | 
  |  | 
 |         ctlw = $dff096              ;DMA control
  |  | 
 |         cothi = $dff0a0             ;table address HI
  |  | 
 |         c0tlo = $c0thi+2            ;table address LO
  |  | 
 |         c0tl = $c0thi+4             ;table length
  |  | 
 |         c0per = $c0thi+6            ;read in rate
  |  | 
 |         c0vol = $c0thi+8            ;loudness level
  |  | 
 |         
  |  | 
 |         run:                        ;*Produce a simple tone
  |  | 
 |              move.l  #table,c0thi   ;table beginning
  |  | 
 |              move    #8,c0tl        ;table length--8 words
  |  | 
 |              move    #400,c0per     ;read in rate
  |  | 
 |              move    #40,c0vol      ;loudness level (volume)
  |  | 
 |              move    #$8201,ctlw    ;DMA/Start sound
  |  | 
 |              rts
  |  | 
 | 
  |  | 
 |         data                        ;>500K place in CHIP memory
  |  | 
 |         table:                      ;sound table:sine
  |  | 
 |          dc.b -40,-70,-40,0,40,70,40,0
  |  | 
 | 
  |  | 
 |              end
  |  | 
 | 
  |  | 
 |         To test this subroutine,use AssemPro to assemble the routine,save
  |  | 
 |         the program and load it into the debugger.Next set a breakpoint at
  |  | 
 |         the RTS,to set the breakpoint in AssemPro select the correct
  |  | 
 |         address with the mouse and press the right-Amiga-B keys.Start the
  |  | 
 |         program and listen to the tone.You need another routine to turn
  |  | 
 |         the tone off,turn your sound down for now.
  |  | 
 |         To turn the tone off,you just need to erase bit 0 of the DMA
  |  | 
 |         control register.To do this,you just need to write a 0 in bit 15
  |  | 
 |         and all the set bits in this register are erased.To erase bit 0,
  |  | 
 |         just write a one to the memory location:bit 15=0=> bit 0 is erased
  |  | 
 |         Heres a small routine to stop the tone coming from channel 0:
  |  | 
 | 
  |  | 
 |         still:                   ;*turn off tone
  |  | 
 |                move    #1,ctlw   ;turn off channel 1
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         Now lets use the routine in a program to produce a short peep tone
  |  | 
 |         that you culd,for instance,use as a key click:
  |  | 
 | 
  |  | 
 |         ;** Producing a Peep Tone **
  |  | 
 |         ctlw = $dff096                ;DMA control
  |  | 
 |         c0thi = $dff0a0               ;HI table address
  |  | 
 |         c0tlo = $c0thi+2              ;LO table address
  |  | 
 |         c0tl = $c0thi+4               ;table length
  |  | 
 |         c0per = $c0thi+6              ;read in rate
  |  | 
 |         c0vol = $c0thi+8              ;volume
  |  | 
 | 
  |  | 
 |         beep:                         ;*Produce a short peep tone
  |  | 
 |                move.l  #table,c0thi   ;table beginning
  |  | 
 |                move    #8,c0tl        ;table length
  |  | 
 |                move    #400,c0per     ;read in rate
  |  | 
 |                move    #65,c0vol      ;volume
  |  | 
 |                move    #$8201,ctlw    ;Start DMA (sound)
  |  | 
 |                move.l  #20000,d0      ;delay counter
  |  | 
 | 
  |  | 
 |         loop:
  |  | 
 |                dbra    d0,loop        ;count down
  |  | 
 |         
  |  | 
 |         still:
  |  | 
 |                move    #1,ctlw        ;turn off tone
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         table:
  |  | 
 |                dc.b 40,70,90,100,90,70,40,0,-4,0
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         You can play upto four tones at the same time in such a way that
  |  | 
 |         they are independant of each other.The Amiga also offers another
  |  | 
 |         method of making the sound more interesting:you can modulate the
  |  | 
 |         tone.
  |  | 
 |         Lets produce a siren tone.You could do this by figuring out the
  |  | 
 |         entire sequence and programming it.However,as you can well imagine
  |  | 
 |         thats a lot of work.
  |  | 
 |         Its much easier to use two tone channels.Lets use channel 1 for
  |  | 
 |         the bass tone and channel 0 for its modulation.Channel 0 needs to
  |  | 
 |         hold the envelope of the siren tone.It needs to give the expanding
  |  | 
 |         and contracting of the tone at the right speed.
  |  | 
 |         You then have two ways that you can have channel zero work with
  |  | 
 |         channel one.You can control the volume via channel 0,the read in
  |  | 
 |         rate(frequency),or both.For our example,you'll use frequency
  |  | 
 |         modulation.
  |  | 
 | 
  |  | 
 |         Change the program as follows:
  |  | 
 | 
  |  | 
 |         ;** Modulated sound generation via hardware registers **
  |  | 
 |         ctlw = $dff096                   ;DMA control
  |  | 
 |         adcon = $dff09e                  ;Audio/Disk control
  |  | 
 |         c0thi = $dff0a0                  ;HI table address
  |  | 
 |         c0tlo = c0thi+2                  ;LO table address
  |  | 
 |         c0tl = c0thi+4                   ;table length
  |  | 
 |         c0per = c0thi+6                  ;read in rate
  |  | 
 |         c0vol = c0thi+8                  ;volume
  |  | 
 | 
  |  | 
 |         run:
  |  | 
 |                 move.l  #table,c0thi+16  ;table start for channel 1
  |  | 
 |                 move    #8,c0tl+16       ;table length--8 words
  |  | 
 |                 move    #300,c0per+16    ;read in rate
  |  | 
 |                 move    #40,c0vol+16     ;volume
  |  | 
 | 
  |  | 
 |                 move.l  #table2,c0thi    ;table start for channel 0
  |  | 
 |                 move    #8,c0tl          ;table length
  |  | 
 |                 move    #60000,c0per     ;read in rate
  |  | 
 |                 move    #30,c0vol        ;volume
  |  | 
 | 
  |  | 
 |                 move    #$8010,adcon     ;modulation mode:FM
  |  | 
 |                 move    #$8203,ctlw      ;start DMA
  |  | 
 |                 rts
  |  | 
 | 
  |  | 
 |         still:                           ;*Turn Off Tone
  |  | 
 |                 move    #$10,adcon       ;no more modulations
  |  | 
 |                 move    #3,ctlw          ;turn off channels
  |  | 
 |                 rts
  |  | 
 | 
  |  | 
 |         table:                           ;data for basic tone
  |  | 
 |          dc.b -40,-70,-90,-100,-90,-70,-40,0
  |  | 
 |          dc.b 40,70,90,100,90,70,40,0
  |  | 
 | 
  |  | 
 |         table2:                          ;data for modulation
  |  | 
 |          dc.w 400,430,470,500,530,500,470,430
  |  | 
 | 
  |  | 
 |                 end
  |  | 
 | 
  |  | 
 |         When you start the program,you'll here a siren.You can change this
  |  | 
 |         tone to your hearts content.
  |  | 
 |         Did you notice the added "adcon"register.This register controls
  |  | 
 |         the modulation of the audio channel as well as handling disk
  |  | 
 |         functions.The same technique is used here as for the DMA control
  |  | 
 |         register,bits can only be set if bit 15 is.As a result,you don't
  |  | 
 |         have to worry about the disk bits.I'd recommend against
  |  | 
 |         experimentation.
  |  | 
 |         Control bit 15 isn't the only one of interest to you.You can also 
  |  | 
 |         use bits 0-7,because they determine which audio channel modulates
  |  | 
 |         another channel.There is a restriction,though.A channel can only
  |  | 
 |         modulate the next higher numbered channel.For this reason you use
  |  | 
 |         channel 1 for the basic tone and channel 0 for the modulation in
  |  | 
 |         the example.You can't for example,modulate channel three with
  |  | 
 |         channel zero.Channel 3 can't be used to modulate any other
  |  | 
 |         channel.
  |  | 
 | 
  |  | 
 |         Here is an overview of bits 0-7 of the "adcon"register.
  |  | 
 | 
  |  | 
 |         Bit       Function
  |  | 
 |         -----------------------------------------------------------------
  |  | 
 |          0        Channel 0 modulates the volume of channel 1
  |  | 
 |          1        Channel 1 modulates the volume of channel 2
  |  | 
 |          2        Channel 2 modulates the volume of channel 3
  |  | 
 |          3        Turn of channel 3
  |  | 
 |          4        Channel 0 modulates the frequency of channel 1
  |  | 
 |          5        Channel 1 modulates the frequency of channel 2
  |  | 
 |          6        Channel 2 modulates the frequency of channel 3
  |  | 
 |          7        Turn off channel 3
  |  | 
 | 
  |  | 
 |         In the example,you set bit 4,which put channel 0 in charge of
  |  | 
 |         channel one's frequency modulations.
  |  | 
 |         When you've chosen a channel for use in modulating another channel
  |  | 
 |         some of the parameters of the channel change.You don't need to
  |  | 
 |         give volume for this channel,so you can omit it.Now the tables
  |  | 
 |         data is looked at as words instead of as bytes.These words are
  |  | 
 |         read into the register of the modulated register at a
  |  | 
 |         predetermined rate.The Read in Rate Register determines the rate.
  |  | 
 |         If you want to modulate the frequency and the volume of another
  |  | 
 |         channel,(In the example,set bits 0 and 4 of "adcon"),the data is
  |  | 
 |         interpreted a little differently.The first word in the table is
  |  | 
 |         the volume,the second is the read in rate,and so on.It alternates
  |  | 
 |         back and forth.In this way,you can for instance,produce the siren
  |  | 
 |         tone.
  |  | 
 | 
  |  | 
 |       5.5.Hardware Registers Overview.
  |  | 
 |       -------------------------------
  |  | 
 |         The following tables should give you an overview of the most
  |  | 
 |         important hardware registers.Theres not enough room to describe
  |  | 
 |         each register,so I'd recommend getting a hold of the appropriate
  |  | 
 |         literature.If you experiment with these registers,you should keep
  |  | 
 |         in mind that this can cause the computor to crash.Save your data
  |  | 
 |         to disk and then take the disk out of the drive,because you might
  |  | 
 |         cause the disk drive to execute some wierd functions.
  |  | 
 |         Lets start with the PIA's.This covers the PIA type 8520.You should
  |  | 
 |         keep in mind that some functions and connection of the 8520 are
  |  | 
 |         integrated into the Amiga and so there are limitations on what you
  |  | 
 |         can do with the PIA's.
  |  | 
 | 
  |  | 
 |         PIA A       PIA B       Registers Meaning
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |         BFE001      BFE000      Data register A
  |  | 
 |         BFE101      BFE100      Data register B
  |  | 
 |         BFE201      BFE200      Data direction register A
  |  | 
 |         BFE301      BFE300      Data direction register B
  |  | 
 |         BFE401      BFE400      Timer A LO
  |  | 
 |         BFE501      BFE500      Timer A HI
  |  | 
 |         BFE601      BFE600      Timer B LO
  |  | 
 |         BFE701      BFE700      Timer B HI
  |  | 
 |         BFE801      BFE800      Event register Bits 0-7
  |  | 
 |         BFE901      BFE900      Event register Bits 8-15
  |  | 
 |         BFEA01      BFEA00      Event register Bits 16-23
  |  | 
 |         BFEB01      BFEB00      Unused
  |  | 
 |         BFEC01      BFEC00      Serial data register
  |  | 
 |         BFED01      BFED00      Interrupt control register
  |  | 
 |         BFEE01      BFEE00      Control register A
  |  | 
 |         BFEF01      BFEF00      Control register B
  |  | 
 | 
  |  | 
 |         Some internal meanings:
  |  | 
 | 
  |  | 
 |         $BFE101    Data register for parallel interface
  |  | 
 |         $BFE301    Data direction register for the parallel interface
  |  | 
 |         $BFEC01    State of the keyboard,contains the last special key
  |  | 
 |                    pressed(Shift,Alternate,Control,Amiga)
  |  | 
 | 
  |  | 
 |         Now come the registers that are used for tone production.The first
  |  | 
 |         two registers should be treated especially carefully-if they are
  |  | 
 |         used wrong,very nasty effects can occur.
  |  | 
 |         These registers can be either read or written only.This
  |  | 
 |         information is included under R/W in the table.
  |  | 
 | 
  |  | 
 |         Address       R/W    Meaning
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |         DFF096         W     Write DMA Control
  |  | 
 |         DFF002         R     Read DMA Control and Blitter Status
  |  | 
 |         --Audio Channel 0--
  |  | 
 |         DFF0AA         W     Data register
  |  | 
 |         DFF0A0         W     Pointer to table beginning Bits 16-18
  |  | 
 |         DFF0A2         W     Pointer to table beginning Bits 0-15
  |  | 
 |         DFF0A4         W     Table length
  |  | 
 |         DFF0A6         W     Read in Rate
  |  | 
 |         DFF0A8         W     Volume
  |  | 
 |         --Audio Channel 1--
  |  | 
 |         DFF0BA         W     Data register
  |  | 
 |         DFF0B0         W     Pointer to table beginning Bits 16-18
  |  | 
 |         DFF0B2         W     Pointer to table beginning Bits 0-15
  |  | 
 |         DFF0B4         W     Table length
  |  | 
 |         DFF0B6         W     Read in Rate
  |  | 
 |         DFF0B8         W     Volume
  |  | 
 |         --Audio Channel 3--
  |  | 
 |         DFF0CA         W     Data register
  |  | 
 |         DFF0C0         W     Pointer to table beginning Bits 16-18
  |  | 
 |         DFF0C2         W     Pointer to table beginning Bits 0-15
  |  | 
 |         DFF0C4         W     Table length
  |  | 
 |         DFF0C6         W     Read in Rate
  |  | 
 |         DFF0C8         W     Volume
  |  | 
 |         --Audio Channel 4--
  |  | 
 |         DFF0DA         W     Data register
  |  | 
 |         DFF0D0         W     Pointer to table beginning Bits 16-18
  |  | 
 |         DFF0D2         W     Pointer to table beginning Bits 0-15
  |  | 
 |         DFF0D4         W     Table length
  |  | 
 |         DFF0D6         W     Read in Rate
  |  | 
 |         DFF0D8         W     Volume
  |  | 
 | 
  |  | 
 |         Now for the registers that contain information about the joystick,
  |  | 
 |         mouse or potentiometer.These addresses have been gone over in part
  |  | 
 |         previously.
  |  | 
 | 
  |  | 
 |         Address       R/W    Meaning
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |         DFF00A         R     Joystick/Mouse Port 1
  |  | 
 |         DFF00C         R     Joystick/Mouse Port 2
  |  | 
 |         DFF012         R     Potentiometer pair 1 Counter
  |  | 
 |         DFF014         R     Potentiometer pair 2 Counter
  |  | 
 |         DFF018         R     Potentiometer connection
  |  | 
 |         DFF034         W     Potentiometer port direction
  |  | 
 |          
  |  | 
 | 
  |  | 
 | 
  |  | 
 | 
  |  | 
 |       Chapter 6
  |  | 
 |       ---------
  |  | 
 |       6.The Operating System.
  |  | 
 |       -----------------------
  |  | 
 |         Now lets take a step forward in your ability to write assembly
  |  | 
 |         language programs.Its not enough to put a piece of text in memory 
  |  | 
 |         someplace.You want to be able to put it on the screen.Do you know
  |  | 
 |         how to write a character on the screen?Do you know how to draw a
  |  | 
 |         window on the screen that can be modified by the mouse?Actually
  |  | 
 |         you don't have to have terribly precise knowledge about such
  |  | 
 |         topics.
  |  | 
 |         Fortunately,the Amigas operating system supplies routines that
  |  | 
 |         take care of common tasks like this.It can seem quite complicated
  |  | 
 |         due to the number of routines necessary.These routines are in
  |  | 
 |         libraries.We'll look at the libraries in some depth now.
  |  | 
 | 
  |  | 
 |       6.1.Load Libraries.
  |  | 
 |       -------------------
  |  | 
 |         Before you can use a library,it must be available.It has to be
  |  | 
 |         loaded into memory.Unfortunately,the whole library must be loaded,
  |  | 
 |         even if you only need one of the functions.
  |  | 
 |         First you need to decide what the program must be able to do,so
  |  | 
 |         you can see which libraries you'll need.For simple I/O text,you
  |  | 
 |         don't need a library that contains routines for moving graphics!
  |  | 
 |         There are a number of libraries onj a normal Workbench disk.Heres
  |  | 
 |         an overview of the names and the sort of functions they do:
  |  | 
 |    
  |  | 
 |       Exec.Library;
  |  | 
 |         This library is needed to load the other libraries.It is already
  |  | 
 |         in memory and doesn't need to be loaded.Its in charge of basic
  |  | 
 |         functions like reserving memory and working with I/O channels.
  |  | 
 |   
  |  | 
 |       Dos.Library;
  |  | 
 |         Contains all the functions for normal I/O operations,for instance
  |  | 
 |         screen or disk access.
  |  | 
 |   
  |  | 
 |    
  |  | 
 |       Intuition.Library;
  |  | 
 |         Used for working with screens,windows,menus,etc...
  |  | 
 |    
  |  | 
 |       Clist.Library;
  |  | 
 |         This contains routines for working with the Copper lists that are
  |  | 
 |         used for controlling the screen.
  |  | 
 |      
  |  | 
 |       Console.Library;
  |  | 
 |         Contains graphics routines for text output in console windows.
  |  | 
 |    
  |  | 
 |       Diskfont.Library;
  |  | 
 |         Used for working with the character fonts that are stored on the
  |  | 
 |         disk.
  |  | 
 |      
  |  | 
 |       Graphics.Library;
  |  | 
 |         This library contains functions to control the Blitter(or graphics
  |  | 
 |         )chip.Its used for basic graphics functions.
  |  | 
 |  
  |  | 
 |       Icon.Library;
  |  | 
 |         Used in the development and use of workbench symbols(icons).
  |  | 
 | 
  |  | 
 |       Layers.Library;
  |  | 
 |         Used for working with screen memory (layers).
  |  | 
 | 
  |  | 
 |       Mathffp.Library;
  |  | 
 |         Contains basic math floating point operations.
  |  | 
 | 
  |  | 
 |       Mathieeedoubbas.Library;
  |  | 
 |         Contains basic math functions for integers.
  |  | 
 | 
  |  | 
 |       Mathtrans.Library;
  |  | 
 |         Contains higher level mathmatical functions.
  |  | 
 | 
  |  | 
 |       Potgo.Library;
  |  | 
 |         Used for evaluating analog input to the Amiga.
  |  | 
 | 
  |  | 
 |       Timer.Library;
  |  | 
 |         Contains routines for time critical programs.They can be used to
  |  | 
 |         program exact time intervals.
  |  | 
 | 
  |  | 
 |       Translator.Library;
  |  | 
 |         Contains the single function "Translate",that translates normal
  |  | 
 |         text written phonetically for the narrator,the speech synthesisor.
  |  | 
 | 
  |  | 
 |         You can open(load)all these libraries of course.You should
  |  | 
 |         remember that this takes time and memory.For this reason,you
  |  | 
 |         should always think about which functions you need and which
  |  | 
 |         libraries they are in.
  |  | 
 |         For example,lets say you want to write a program that does text
  |  | 
 |         input/output.You need the "Dos.Library",so it can be loaded.
  |  | 
 |         The "exec.library"is in charge of loading.This library contains
  |  | 
 |         the OpenLib function that can be called once you've passed the
  |  | 
 |         needed parameters.AssemPro Amiga includes all the libraries
  |  | 
 |         necessary for the Amiga,it also includes files that contain the 
  |  | 
 |         offsets for the operating system calls.The macros contained in
  |  | 
 |         AssemPro ease assembly language programming considerably.To make
  |  | 
 |         the programs in this book useful to the largest audience the
  |  | 
 |         following examples are written for generic assemblers and do not
  |  | 
 |         include AssemPro's macros.We have used the AssemPro ILABEL and the
  |  | 
 |         macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can start the
  |  | 
 |         programs from the desktop.(If you are using a different assembler
  |  | 
 |         check your documentation for instructions on linking programs).
  |  | 
 | 
  |  | 
 |       6.2.Calling Functions.
  |  | 
 |       ----------------------
  |  | 
 |         Since this chapter is rather complex we'll first describe the
  |  | 
 |         fundamental routines necessary to use the Amiga's operating system
  |  | 
 |         after a description a complete program is listed.Every library
  |  | 
 |         begins in memory with a number of JMP commands.These JMPs branch
  |  | 
 |         to the routines that are in the library.To call a function,you
  |  | 
 |         need to find the beginning of this JMP table and call function x
  |  | 
 |         by going to the xth JMP command.Usually you use an offset to get
  |  | 
 |         to the right JMP command.Normally,you don't start at the beginning
  |  | 
 |         but at the end of the JMP table,so use negative offsets.
  |  | 
 |         It works out very easily.Now lets open the "dos.library"by using
  |  | 
 |         "exec.library's"base address.This address is $000004.To call a
  |  | 
 |         fuction from another library,you need to use another base address.
  |  | 
 |         Now you need the offset for the function that you want.You want
  |  | 
 |         the OpenLib function that has -408 as an offset.You'll find a list
  |  | 
 |         of function offsets in the appendix.
  |  | 
 |         You need a pointer to the name of the library you are loading for
  |  | 
 |         the OpenLib function(in this case "dos.library")and a long word in
  |  | 
 |         memory that you can use to store the base address of the DOS
  |  | 
 |         library.You get this back from the OpenLib function.You need to be
  |  | 
 |         sure to write the library name in lower case letters(dos.library),
  |  | 
 |         otherwise you can't open it.I entered a name in capitol letters
  |  | 
 |         once and spent a lot of time finding this error.
  |  | 
 | 
  |  | 
 |         The routine looks like this:
  |  | 
 | 
  |  | 
 |         ;** Load the DOS library 'dos.library' (6.2A) **
  |  | 
 |         Execbase = 4                    ;base address of the EXEC library
  |  | 
 |         OpenLib  = -408                 ;offset for the OpenLib function
  |  | 
 | 
  |  | 
 |         IoErr    = -132                 ;offset for IoErr information
  |  | 
 | 
  |  | 
 |         init:
  |  | 
 |                move.l  Execbase,a6      ;base address in A6
  |  | 
 |                lea     dosname,a1       ;address of library name
  |  | 
 |                moveq   #0,d0            ;version number
  |  | 
 |                jsr     OpenLib(a6)      ;open DOS library
  |  | 
 |                move.l  d0,dosbase       ;save DOS base address
  |  | 
 |                beq     error            ;if zero,then error!
  |  | 
 |                ...                      ;your program goes here
  |  | 
 |                ...                      ;more program...
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         error:                          ;error
  |  | 
 |                move.l  dosbase,a6       ;address of library name
  |  | 
 |                jsr     IoErr(a6)        ;call IoErr for error info
  |  | 
 |                move.l  d0,d5            
  |  | 
 |                ...                      ;your error routine goes here
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         dosname:                        ;name of library to open
  |  | 
 |                dc.b    'dos.library',0,0
  |  | 
 |                align                    ;SEKA uses-even
  |  | 
 | 
  |  | 
 |         dosbase:                        ;storage for DOS base address
  |  | 
 |                blk.l   1
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         This is the way to load the DOS library so that you can use it.All
  |  | 
 |         library functions are called this way.Parameters are put in
  |  | 
 |         registers and passed to the function.When there is an error,when
  |  | 
 |         the function doesn't run correctly,a zero is usually put in data
  |  | 
 |         register D0.
  |  | 
 |         Once your program is done with its work,you need to close the
  |  | 
 |         libraries that are still open before you return to the CLI or 
  |  | 
 |         Workbench.The CloseLib function (offset -414)takes care of this
  |  | 
 |         job.This function is in the EXEC library just like the OpenLib.The
  |  | 
 |         only parameter it needs is the base address of the library that is
  |  | 
 |         closed.To close "dos.library",do the following:
  |  | 
 | 
  |  | 
 |         CloseLib = -414               ; (6.2B)
  |  | 
 |                ...
  |  | 
 |                move.l  Execbase,a6    ;EXEC base address
  |  | 
 |                move.l  dosbase,a1     ;DOS base address
  |  | 
 |                jsr     CloseLib(a6)   ;close library
  |  | 
 | 
  |  | 
 |       6.3.Program Initialization.
  |  | 
 |       ---------------------------
  |  | 
 |         Before you can start a program,you need to initialize many things
  |  | 
 |         so that the program can run.
  |  | 
 |         Lets take an example program that does some text editing.A program
  |  | 
 |         like this must be able to store text,so it needs to be able to
  |  | 
 |         access memory.It also needs to be able to accept keyboard input
  |  | 
 |         and do screen output,so it needs an output window.
  |  | 
 |         To do this,you need to open one or more of the libraries that we
  |  | 
 |         talked about earlier.Lets assume that you've loaded the DOS
  |  | 
 |         library,so that you can do the next steps.
  |  | 
 | 
  |  | 
 |       6.3.1.Reserve Memory.
  |  | 
 |       ---------------------
  |  | 
 |         There are several ways to get the operating system to assign you a
  |  | 
 |         chunk of memory.You need to use one of them,so that during multi-
  |  | 
 |         tasking,you don't have one program overwriting another programs
  |  | 
 |         memory area.
  |  | 
 |         Lets look at the function that is normally used.This function is
  |  | 
 |         in the resident EXEC library and has the name AllocMem (offset
  |  | 
 |         -$c6).It reserves a memory area,using the value in D0 as the
  |  | 
 |         length.The address that the memory area begins at is returned in
  |  | 
 |         the D0 data register.If it returns zero,the program could'nt give
  |  | 
 |         you that much memory.
  |  | 
 |         You can also use a mode word in D1 to determine whether the memory
  |  | 
 |         area that is reserved should be erased or not.
  |  | 
 |         The routine looks like this:
  |  | 
 | 
  |  | 
 |         ExecBase = 4                  ; (6.3.1A)
  |  | 
 |         AllocMem = -$c6
  |  | 
 |                ...
  |  | 
 |                move.l  #number,d0     ;number of bytes to reserve
  |  | 
 |                move    #mode,a6       ;mode word
  |  | 
 |                move.l  ExecBase,a6    ;DOS base address in A6
  |  | 
 |                jsr     AllocMem(a6)   ;call function
  |  | 
 |                move.l  d0,address     ;save memory's start address
  |  | 
 |                beq     error          ;memory not reserved
  |  | 
 |                ...
  |  | 
 | 
  |  | 
 |         The second way to reserve memory is to use the AllocAbs function
  |  | 
 |         (offset -$CC).This function in contrast to the AllocMem function
  |  | 
 |         reserves a particular memory area.The D0 register contains the
  |  | 
 |         number of bytes that should be reserved.Address register A1
  |  | 
 |         contains the desired start address.This function returns a zero in
  |  | 
 |         D0 if the memory area can't be reserved.
  |  | 
 | 
  |  | 
 |         ExecBase = 4                  ; (6.3.1B)
  |  | 
 |         AllocAbs = -$cc
  |  | 
 |                ...
  |  | 
 |                move.l  #number,d0     ;number of bytes to reserve
  |  | 
 |                lea     address,a1     ;desired start address
  |  | 
 |                move.l  execbase,a6    ;EXEC base address
  |  | 
 |                jsr     AllocAbs(a6)   ;reserve memory
  |  | 
 |                tst.l   d0             ;everything ok?
  |  | 
 |                beq     error          ;no!
  |  | 
 |                ...
  |  | 
 | 
  |  | 
 |         When the program has done its work and must return to the CLI or
  |  | 
 |         the Workbench,it needs to return the memory it as reserved to the
  |  | 
 |         system.The FreeMem function (offset -$D2) handles this.
  |  | 
 |         The function works like AllocAbs in that the number of bytes is
  |  | 
 |         put in D0 and the start address of the memory area is put in A1.
  |  | 
 |         If you try to free up a memory area that was'nt reserved,you'll
  |  | 
 |         usually crash the computor.
  |  | 
 |         The routine to free up a memory area looks like this:
  |  | 
 | 
  |  | 
 |         ExexBase = 4                  ; (6.3.1C)
  |  | 
 |         FreeMem = -$d2
  |  | 
 |                ...
  |  | 
 |                move.l  #number,d0     ;number of bytes released
  |  | 
 |                lea     address,a1     ;start address from AllocAbs
  |  | 
 |                move.l  ExecBase,a6    ;ExecBase address
  |  | 
 |                jsr     FreeMem(a6)    ;free up memory
  |  | 
 |                tst.l   d0             ;everything ok?
  |  | 
 |                beq     error          ;no!
  |  | 
 |                ...
  |  | 
 | 
  |  | 
 |       6.3.2.Opening a Simple Window.
  |  | 
 |       ------------------------------
  |  | 
 |         The title of this chapter may sound a bit strange.However,the
  |  | 
 |         differences between the two different methods of opening a window
  |  | 
 |         are so great that they should be handled in seperate chapters.
  |  | 
 |         The method of opening a window presented here is very simple,but
  |  | 
 |         it doesn't allow you to work with all the gadgets.These gadgets
  |  | 
 |         include the close symbol in the upper left corner of a window and
  |  | 
 |         the size symbol in the lower left corner.
  |  | 
 |         If you open the window in the simple manner,almost all the gadgets
  |  | 
 |         are present.However,the close symbol is not.As a result,this
  |  | 
 |         method isn't appropriate for every application.Now lets look at
  |  | 
 |         the method.
  |  | 
 |         To open a window,use a function from the DOS library,so you need
  |  | 
 |         to open the library first (see the section "Load Library").This
  |  | 
 |         open function is an all purpose function that can be used for many
  |  | 
 |         things.For this reason,it makes good sense to put a "open"
  |  | 
 |         subroutine in your program.You can use it a lot.Lets do the basic
  |  | 
 |         steps:
  |  | 
 | 
  |  | 
 |         ;** Load the DOS Library 'dos.library'  (6.3.2A) **
  |  | 
 |         ExecBase = 4                   ;base addres of the EXEC library
  |  | 
 |         OpenLib = -408                 ;offset of OpenLib function
  |  | 
 |         Open = -30                     ;Offset of the DOS function OPEN
  |  | 
 | 
  |  | 
 |         init:
  |  | 
 |                move.l  ExecBase,a6     ;base address in A6
  |  | 
 |                lea     dosname(pc),a1  ;address of library name
  |  | 
 |                move.q  #0,d0           ;version number:unimportant
  |  | 
 |                jsr     OpenLib(a6)     ;call the function
  |  | 
 |                move.l  d0,dosbase      ;save DOS base address
  |  | 
 |                beq     error           ;if zero,then error!
  |  | 
 |                ...                     ;more of your program
  |  | 
 |                ...                     ;now open window,etc...
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         error:
  |  | 
 |                ...                     ;error occured
  |  | 
 |                ...                     ;your error routine
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         openfile:                      ;general open function
  |  | 
 |                move.l  dosbase,a6      ;DOS base address in A6
  |  | 
 |                jsr     Open(a6)        ;call OPEN function
  |  | 
 |                tst.l   d0              ;test if ok
  |  | 
 |                rts                     ;done,evaluate test later
  |  | 
 | 
  |  | 
 |         dosname:                       ;name of library to be opened
  |  | 
 |                dc.b    'dos.library',0,0
  |  | 
 |                align                   ;even
  |  | 
 | 
  |  | 
 |         dosbase:                       ;spot for DOS base address
  |  | 
 |                blk.l   1
  |  | 
 | 
  |  | 
 |         You call the Openfile routine,because the label "Open"is already
  |  | 
 |         being used for the offset.This routine calls the Open function
  |  | 
 |         that is in the DOS library.
  |  | 
 |         This isn't everything.The function must be given some parameters
  |  | 
 |         so that it knows what to open.The parameters are sent in registers
  |  | 
 |         D1 and D2.D1 points to a definition block what specifies what
  |  | 
 |         should be opened.You need to have a filename ended with a null
  |  | 
 |         byte there.D1 must be passed as a long word like all addresses.D2
  |  | 
 |         contains the mode that the function should run in.There is an old
  |  | 
 |         (1005) and a new (1006) mode.This number must be passed in D2's
  |  | 
 |         long word.
  |  | 
 |         Heres an overview of how windows are opened.Fortunately,AmigaDos
  |  | 
 |         allows you to use input and output channels in the same way.The
  |  | 
 |         standard channels are disk files,the console (keyboard and screen)
  |  | 
 |         the printer interface and the serial RS232 interface.
  |  | 
 |         The console input/output is what you'll work with now.When you
  |  | 
 |         specify the console as the filename of the channel to be opened,a
  |  | 
 |         window is opened automatically.
  |  | 
 |         The name must begin with CON:to do this.Its similar to DF0:for
  |  | 
 |         disk operations.A little more infotmation about the window is
  |  | 
 |         still needed.
  |  | 
 |         You need to specify the X and Y coordinates of the upper left and
  |  | 
 |         lower right corners of the window as well as the name that should
  |  | 
 |         appear in the title line of the window.A complete definition block
  |  | 
 |         for a window like this would appear like the following line:
  |  | 
 | 
  |  | 
 |               consolname: dc.b 'CON:0/100/640/100/**Window**',0
  |  | 
 | 
  |  | 
 |         To open this window,the line above needs to be inserted in the
  |  | 
 |         following program:
  |  | 
 | 
  |  | 
 |         mode_old = 1005
  |  | 
 | 
  |  | 
 |         lea     consolname(pc),a1    ;consol definition
  |  | 
 |         move.l  #mode_old,d0         ;mode
  |  | 
 |         bsr     openfile             ;console open
  |  | 
 |         beq     error                ;didn't work
  |  | 
 |         move.l  d0,conhandle
  |  | 
 | 
  |  | 
 |         rts
  |  | 
 |                 ...
  |  | 
 |         conhandle:   dc.l 1          ;space for handle
  |  | 
 | 
  |  | 
 |         There are two points to clear up yet.
  |  | 
 |         You should use mode_old as the the mode when you open a window.
  |  | 
 |         Logically the window doesn't exist before opening so this seems
  |  | 
 |         wierd but it doesn't hurt anything.
  |  | 
 |         The parameter that returns from "openfile"in D0 is zero in the
  |  | 
 |         case of an error,in the case that opening didn't work.Otherwise
  |  | 
 |         the value is the identification number (handle number) of the
  |  | 
 |         opened channel.You need to store it away,because every function
  |  | 
 |         that wants to use this channel must give the handle number.In the
  |  | 
 |         example,you stored this number in the "conhandle"long word.
  |  | 
 |         As mentioned,the window you've opened doesn't have a close symbol
  |  | 
 |         but it can be made bigger and smaller and moved forward and back.
  |  | 
 |         The manipulations that are carried out using the mouse are
  |  | 
 |         completely taken care of by the Amiga (in contrast to the ATARI ST
  |  | 
 |         where the programmer has to take care of these things).
  |  | 
 |         An important function that uses the handle number is the one that
  |  | 
 |         closes the channel (in your case the window).This function is also
  |  | 
 |         in the DOS library and is called "Close".Its offset is -36 and it
  |  | 
 |         only needs one parameter;the handle number of the channel that is
  |  | 
 |         closed must be in the D1 register.
  |  | 
 |         After your work is done,you need to put the following lines in
  |  | 
 |         your program to close the window:
  |  | 
 | 
  |  | 
 |         Close = -36                    ; (6.3.2C)
  |  | 
 |                 ...
  |  | 
 |                 move.l  conhandle,d1   ;handle number in D1
  |  | 
 |                 move.l  dosbase,a6     ;DOS base address in A6
  |  | 
 |                 jsr     Close(a6)      ;close channel!
  |  | 
 | 
  |  | 
 |         The window disappears!
  |  | 
 | 
  |  | 
 |         Now for a few remarks about opening and closing the window in this
  |  | 
 |         way.If you open several windows in the same way,you'll get several
  |  | 
 |         windows and thus several handle numbers.In this way,you can put as
  |  | 
 |         many windows on the screen as you like.You can do your work with
  |  | 
 |         them and close them individually.
  |  | 
 |         Here is the complete program to open and close a simple window in
  |  | 
 |         AssemPro format (We have used the AssemPro ILABEL and the macros
  |  | 
 |         INIT_AMIGA and EXIT_AMIGA so AssemPro owners can start the program
  |  | 
 |         from desktop.If you are using a different assembler check your
  |  | 
 |         documentation for instructions on starting and exiting programs):
  |  | 
 | 
  |  | 
 |         ;***** 6.3.2 S.D *****
  |  | 
 | 
  |  | 
 |         OpenLib        =-30-378
  |  | 
 |         closelib       =-414
  |  | 
 |         ;execbase      =4                 ;defined in AssemPro macros
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         *calls to Amiga DOS:
  |  | 
 | 
  |  | 
 |         open           =-30
  |  | 
 |         close          =-30-6
  |  | 
 |         IoErr          =-132
  |  | 
 |         mode_old       = 1005
  |  | 
 |         alloc_abs      =-$cc
  |  | 
 | 
  |  | 
 |         ILABEL AssemPro:includes/Amiga.l  ;AssemPro only
  |  | 
 | 
  |  | 
 |         INIT_AMIGA                        ;AssemPro only
  |  | 
 | 
  |  | 
 |         run:
  |  | 
 |                bsr     init               ;initialization
  |  | 
 |                bra     test               ;system-test
  |  | 
 | 
  |  | 
 |         init:                             ;system initialization and open
  |  | 
 |                move.l  execbase,a6        ;number of execute-library
  |  | 
 |                lea     dosname(pc),a1     
  |  | 
 |                moveq   #0,d0
  |  | 
 |                jsr     openlib(a6)        ;open DOS-Library
  |  | 
 |                move.l  d0,dosbase
  |  | 
 |                beq     error
  |  | 
 | 
  |  | 
 |                lea     consolname(pc),a1  ;consol definition
  |  | 
 |                move.l  #mode_old,d0
  |  | 
 |                bsr     openfile           ;consol open
  |  | 
 |                beq     error
  |  | 
 |                move.l  d0,conhandle
  |  | 
 | 
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 | 
  |  | 
 |               bra qu                      ;quit and exit
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         error:
  |  | 
 |               move.l  dosbase,a6
  |  | 
 |               jsr     IoErr(a6)
  |  | 
 |               move.l  d0,d5
  |  | 
 | 
  |  | 
 |               move.l  #-1,d7              ;flag
  |  | 
 | 
  |  | 
 |         qu:
  |  | 
 |               move.l  conhandle,d1        ;window close
  |  | 
 |               move.l  dosbase,a6
  |  | 
 |               jsr     close(a6)
  |  | 
 |               move.l  dosbase,a1          ;DOS.Lib close
  |  | 
 |               move.l  execbase,a6
  |  | 
 |               jsr     closelib(a6)
  |  | 
 | 
  |  | 
 |               EXIT_AMIGA                  ;AssemPro only
  |  | 
 | 
  |  | 
 |         openfile:                         ;open file
  |  | 
 |               move.l  a1,d1               ;pointer to I/O-Definition-Text
  |  | 
 |               move.l  d0,d2
  |  | 
 |               move.l  dosbase,a6
  |  | 
 |               jsr     open(a6)
  |  | 
 |               tst.l   d0
  |  | 
 |               rts
  |  | 
 | 
  |  | 
 |         dosname: dc.b 'dos.library',0,0
  |  | 
 |               Align.w
  |  | 
 |         
  |  | 
 |         dosbase: dc.l 0
  |  | 
 | 
  |  | 
 |         consolname: dc.b 'CON:0/100/640/100/**CLI-Test**',0
  |  | 
 |               Align.w
  |  | 
 | 
  |  | 
 |         conhandle: dc.l 0
  |  | 
 | 
  |  | 
 | 
  |  | 
 |               end
  |  | 
 | 
  |  | 
 |         There is another way to open a window easily.Just use RAW:instead
  |  | 
 |         of CON:as the channel designator.All the other parameters and
  |  | 
 |         operations remain the same.
  |  | 
 |         If you try them both out,you won't see any differences between the
  |  | 
 |         two windows.They both look the same and can be worked with in the 
  |  | 
 |         same way with the mouse.The difference comes when you input to the
  |  | 
 |         window.In the RAW:window,the cursor keys are ignored.In the CON:
  |  | 
 |         window and in CLI,they do work.
  |  | 
 | 
  |  | 
 |       6.4.Input/Output.
  |  | 
 |       -----------------
  |  | 
 |         Besides managing and making calculations with data,the most
  |  | 
 |         important work of a program is to input and output the data.There
  |  | 
 |         are many methods of data transfer in and out of the computor,for
  |  | 
 |         instance screen or printer output,keyboard input,using the serial
  |  | 
 |         or the parallel interface,tone or speech output and finally disk
  |  | 
 |         operations.
  |  | 
 |         You want to learn about all these methods of data input and output
  |  | 
 |         for programming and applications.We've written some programs as
  |  | 
 |         subroutines that should be useful for later programs.It makes good
  |  | 
 |         sense to make a library of these subroutines that can either be
  |  | 
 |         directly integrated in a new program or linked to a program.At the
  |  | 
 |         end of the sections there is a list of a complete program so you
  |  | 
 |         can see how the subroutines are used.
  |  | 
 |         To prepare for input/output,you need to have data to output and
  |  | 
 |         space to input data.To get this ready,you need a correct program
  |  | 
 |         beginning in which the EXEC and DOS libraries are opened and
  |  | 
 |         memory is reserved.After this,you begin most programs by outputing
  |  | 
 |         some text.The text can be a program title or the instruction to
  |  | 
 |         input data over the keyboard.Lets start looking at screen output.
  |  | 
 | 
  |  | 
 |       6.4.1.Screen Output.
  |  | 
 |       --------------------
  |  | 
 |         For a computor like the Amiga the first question is where should
  |  | 
 |         the screen output be sent?The answer is simple for many computors;
  |  | 
 |         they only have one screen,and output goes there.You need to
  |  | 
 |         specify which window to write to when you use the Amiga,however.
  |  | 
 | 
  |  | 
 |         There are two possibilites:
  |  | 
 | 
  |  | 
 |         1.Output to CLI
  |  | 
 | 
  |  | 
 |         2.Output to another window
  |  | 
 | 
  |  | 
 |         The first posibillity only exists if the program that makes the
  |  | 
 |         output was started from CLI.If not,you need to open your own
  |  | 
 |         custom window for your program.If so,you can use the window that
  |  | 
 |         was opened by the CLI for output.
  |  | 
 |         If you use the second method,you need to open a window.As you've
  |  | 
 |         already seen,there are three methods.For simple text and character
  |  | 
 |         output,the difference between the three sorts of windows isn't
  |  | 
 |         very great.Here you have a free hand in determining which sort of
  |  | 
 |         window to use.Lets open a CON:window and put its handle number in
  |  | 
 |         "conhandle".
  |  | 
 |         You've opened your window and want to output a title.You choose
  |  | 
 |         text to output and then put it in memory using a code segment like
  |  | 
 |         this:
  |  | 
 | 
  |  | 
 |               title: dc.b "** Welcome to this Program! **"
  |  | 
 |               titleend:
  |  | 
 |               align              ;even
  |  | 
 | 
  |  | 
 |         The "align"(even) is a pseudo-op that should follow text when it
  |  | 
 |         is followed by either word data or program lines.It causes the
  |  | 
 |         assembler to insert a null byte if necessary to make the address
  |  | 
 |         even.
  |  | 
 |         To output this text you need another DOS function:Write.This has
  |  | 
 |         an offset of -48 and needs three parameters:
  |  | 
 | 
  |  | 
 |         In D1   the handle of an opened output channel that should be
  |  | 
 |                 written to (in your case,this is the handle number that
  |  | 
 |                 you go back from the Open command when you opened your
  |  | 
 |                 window.).
  |  | 
 |         In D2   the address of the text to be output (in the example,the
  |  | 
 |                 address "title").
  |  | 
 |         In D3   the number of characters to be output in bytes.
  |  | 
 | 
  |  | 
 |         To find the number of bytes to output,you need to count the number
  |  | 
 |         of characters in your text.Use "titleend"to calculate this.Using
  |  | 
 |         this label,the assembler can calculate the length of your text for
  |  | 
 |         itself (after all,why should you count when you have a computor?) 
  |  | 
 |         if you write:
  |  | 
 | 
  |  | 
 |              move.l  #titleend-title,d3
  |  | 
 | 
  |  | 
 |         The advantage of specifying the length is that you can put control
  |  | 
 |         characters between the beginning and end of the text.In this way,
  |  | 
 |         you can execute certain functions using text output.You'll learn
  |  | 
 |         about the control characters in a bit.
  |  | 
 | 
  |  | 
 |         Heres the routine:
  |  | 
 | 
  |  | 
 |         Write = -48                          ; (6.4.1A)
  |  | 
 |                 ...                          ;open window
  |  | 
 |                 ...
  |  | 
 |                 move.l  dosbase,a6           ;DOS base address
  |  | 
 |                 move.l  conhandle,d1         ;pass handle
  |  | 
 |                 move.l  #title,d2            ;text address
  |  | 
 |                 move.l  #titleend-title,d3   ;and length
  |  | 
 |                 jsr     Write(a6)            ;call function
  |  | 
 |                 ...
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         title: dc.b "** Welcome to this Program! **"
  |  | 
 |          
  |  | 
 |         titleend:
  |  | 
 |         
  |  | 
 |         align                                ;event
  |  | 
 | 
  |  | 
 |                 end
  |  | 
 | 
  |  | 
 |         You'll certainly use this function a lot.You'll often want to
  |  | 
 |         output just one character though.To allow you to do this and
  |  | 
 |         similar text related tasks,there are four subroutines,each of
  |  | 
 |         which do a different sort of output:
  |  | 
 | 
  |  | 
 |       Pmsg;
  |  | 
 |         Outputs the text from (D2) to the first null byte.
  |  | 
 | 
  |  | 
 |       Pline;
  |  | 
 |         Is the same as the routine above except that the text is
  |  | 
 |         automatically followed by a CR,the cursor is positioned at the
  |  | 
 |         beginning of the next line.
  |  | 
 | 
  |  | 
 |       Pchar;
  |  | 
 |         Outputs the character in D0
  |  | 
 | 
  |  | 
 |       Pcrlf;
  |  | 
 |         Puts the cursor at the beginning of the next line.
  |  | 
 | 
  |  | 
 |         Heres the subroutine package:
  |  | 
 | 
  |  | 
 |         Write = -48                  ; (6.4.1B)
  |  | 
 |                 ...
  |  | 
 | 
  |  | 
 |         pline:                       ;*output line and then a CR
  |  | 
 |                 bsr     pmsg         ;output line
  |  | 
 | 
  |  | 
 |         pcrlf:
  |  | 
 |                 move    #10,d0       ;line feed
  |  | 
 |                 bsr     pchar        ;output
  |  | 
 |                 move    #13,d0       ;and CR
  |  | 
 | 
  |  | 
 |         pchar:
  |  | 
 |                 move.b  d0,outline   ;character in output buffer
  |  | 
 |                 move.l  #outline,d2  ;address of the character
  |  | 
 |                  
  |  | 
 |         pmsg:                        ;*output line (D2) upto null
  |  | 
 |                 move.l  d2,a0        ;address in A0
  |  | 
 |                 clr     d3           ;length = 0
  |  | 
 | 
  |  | 
 |         ploop:
  |  | 
 |                 tst.b   (a0)+        ;null byte ?
  |  | 
 |                 beq     pmsg2        ;yes:length found
  |  | 
 |                 addq.l  #1,d3        ;else length + 1
  |  | 
 |                 bra     ploop        ;and continue looking
  |  | 
 | 
  |  | 
 |         pmsg2:
  |  | 
 |                 move.l  dosbase,a6   ;DOS base address in A6
  |  | 
 |                 move.l  conhandle,d1 ;our window handle
  |  | 
 |                 jsr     Write(a6)    ;call write function
  |  | 
 |                 rts                  ;done!
  |  | 
 | 
  |  | 
 |         outline:        dc.w 0       ;output buffer for 'pchar'
  |  | 
 | 
  |  | 
 |         conhandle:      dc.l 0       ;windows handle
  |  | 
 | 
  |  | 
 |         Here is an example program to open and close a simple window and
  |  | 
 |         output a text message in AssemPro format (We have used the
  |  | 
 |         AssemPro macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can
  |  | 
 |         start the program from desktop.If you are using a different
  |  | 
 |         assembler check your documentation for instructions on starting
  |  | 
 |         and exiting programs.):
  |  | 
 | 
  |  | 
 |         Here is the complete program in AssemPro format:
  |  | 
 | 
  |  | 
 |         ;***** 6.4.1C.asm S.D. *****
  |  | 
 | 
  |  | 
 |         Openlib     =-30-378
  |  | 
 |         closelib    =-414
  |  | 
 |         ;execbase   = 4                    ;Defined in AssemPro
  |  | 
 |                                            ;Macros
  |  | 
 | 
  |  | 
 |         * calls to Amiga Dos:
  |  | 
 | 
  |  | 
 |         open        =-30
  |  | 
 |         close       =-30-6
  |  | 
 |         write       =-48
  |  | 
 |         IoErr       =-132
  |  | 
 |         mode_old    = 1005
  |  | 
 |         alloc_abs   =-$cc
  |  | 
 | 
  |  | 
 |                ILABEL AssemPro:include/Amiga.l ;AssemPro only
  |  | 
 | 
  |  | 
 |                INIT_AMIGA                  ;AssemPro only
  |  | 
 | 
  |  | 
 |         run:
  |  | 
 |                bsr     init                ;initialization
  |  | 
 |                bsr     test                ;system test
  |  | 
 |                nop 
  |  | 
 |                bra qu                      ;quit and exit
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |                move.l  #title,d0
  |  | 
 |                bsr     pmsg
  |  | 
 |                bsr     pcrlf
  |  | 
 |                bsr     pcrlf
  |  | 
 | 
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         init:                              ;system initialization and
  |  | 
 |                                            ;open
  |  | 
 |                move.l  execbase,a6         ;number of execute-library
  |  | 
 |                lea     dosname(pc),a1
  |  | 
 |                moveq   #0,d0
  |  | 
 |                jsr     openlib(a6)         ;open DOS-library
  |  | 
 |                move.l  d0,dosname
  |  | 
 |                beq     error
  |  | 
 | 
  |  | 
 |                lea     consolname(pc),a1   ;console definition
  |  | 
 |                move.l  #mode_old,d0
  |  | 
 |                bsr     openfile            ;console open
  |  | 
 |                beq     error
  |  | 
 |                move.l  d0,conhandle
  |  | 
 | 
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         pmsg:                              ;print message (D0)
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)
  |  | 
 |                move.l  d0,a0
  |  | 
 |                move.l  a0,d2
  |  | 
 |                clr.l   d3
  |  | 
 | 
  |  | 
 |         ploop:
  |  | 
 |                tst.b   (a0)+
  |  | 
 |                beq     pmsg2
  |  | 
 |                addq.l  #1,d3
  |  | 
 |                bra     ploop               ;length calculate
  |  | 
 | 
  |  | 
 |         pmsg2:
  |  | 
 |                move.l  conhandle,d1
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     write(a6)
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         pcrlf:
  |  | 
 |                move    #10,d0
  |  | 
 |                bsr     pchar
  |  | 
 |                move    #13,d0
  |  | 
 | 
  |  | 
 |         pchar:                             ;output char in D0
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)   ;save all
  |  | 
 |                move.l  conhandle,d1
  |  | 
 | 
  |  | 
 |         pch1:
  |  | 
 |                lea     outline,a1
  |  | 
 |                move.b  d0,(a1)
  |  | 
 |                move.l  a1,d2
  |  | 
 |                move.l  #1,d3               ;1 letter
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     write(a6)
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6   ;restore all
  |  | 
 | 
  |  | 
 |         error:
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     IoErr(a6)
  |  | 
 |                move.l  d0,d5
  |  | 
 | 
  |  | 
 |                move.l  #-1,d7              ;flag
  |  | 
 | 
  |  | 
 |         qu:
  |  | 
 |                move.l  conhandle,d1        ;window close
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     close(a6)
  |  | 
 | 
  |  | 
 |                move.l  dosbase,a1          ;DOS.Lib close
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                jsr     closelib(a6)
  |  | 
 | 
  |  | 
 |                EXIT_AMIGA                  ;AssemPro only
  |  | 
 | 
  |  | 
 |         openfile:                          ;open file
  |  | 
 |                move.l  a1,d1               ;pointer to I/O-definition-
  |  | 
 |                                            ;text
  |  | 
 |                move.l  d0,d2
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     open(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         dosname: dc.b 'dos.library',0,0
  |  | 
 |                align.w
  |  | 
 | 
  |  | 
 |         dosbase: dc.l 0
  |  | 
 | 
  |  | 
 |         consolname: dc.b 'CON:0/100/640/100/** CLI-Test **',0
  |  | 
 |                align.w
  |  | 
 | 
  |  | 
 |         conhandle: dc.l 0
  |  | 
 | 
  |  | 
 |         title: dc.b '** Welcome to this Program! **'
  |  | 
 | 
  |  | 
 |         titleend:
  |  | 
 |                align
  |  | 
 | 
  |  | 
 |         outline: dc.w 0                    ;output buffer for char
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         Using this program,you can very easily put whatever you want in
  |  | 
 |         the CON:window.These functions also work in RAW:window.You should
  |  | 
 |         rename "conhandle"as "rawhandle",so that you don't get things
  |  | 
 |         mixed up later.
  |  | 
 |         Lets stay with the CON:window.As mentioned earlier,you can output
  |  | 
 |         special characters that execute functions or change parameters for
  |  | 
 |         output.These characters are called control characters.
  |  | 
 |         You've already learned about one of these control characters,Line
  |  | 
 |         Feed ($A).This character isn't just output;instead,it calls a
  |  | 
 |         function that moves the cursor into the next line and moves the
  |  | 
 |         screen up.This is very useful,but there are much more interesting
  |  | 
 |         control characters.
  |  | 
 |         Here's a list of control characters that execute functions.These
  |  | 
 |         characters are given in hex.
  |  | 
 | 
  |  | 
 |       Control Sequence;
  |  | 
 | 
  |  | 
 |         Sequence     Function
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |          08          Backspace
  |  | 
 |          0A          Line Feed,Cursor down
  |  | 
 |          0B          Move Cursor up a line
  |  | 
 |          0C          Clear screen
  |  | 
 |          0D          Carrige return,cursor in the first column
  |  | 
 |          0E          Turn on normal characters (Cancel Of Effects)
  |  | 
 |          0F          Turn on special characters
  |  | 
 |          1B          Escape
  |  | 
 | 
  |  | 
 |         The following sequences begin with $9B,the CSI (Control Sequence
  |  | 
 |         Introducer).The characters that follow execute a function.The
  |  | 
 |         values in square brackets can be left off.The n's you see
  |  | 
 |         represent one or more digit decimal numbers given using ASCII
  |  | 
 |         characters.The value that is used when n is left off,is given in
  |  | 
 |         the parenthesis that follow n in the description of the function
  |  | 
 |         in the table.
  |  | 
 | 
  |  | 
 |       Control Sequence Introducer;
  |  | 
 | 
  |  | 
 |         Sequence       Function
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |         9B[n]40        Insert n blanks
  |  | 
 |         9B[n]41        Move cursor n (1) lines up
  |  | 
 |         9B[n]42        Move cursor n (1) lines down
  |  | 
 |         9B[n]43        Move cursor n (1) characters to the right
  |  | 
 |         9B[n]44        Move cursor n (1) characters to the left
  |  | 
 |         9B[n]45        Move cursor down n (1) lines into column 1
  |  | 
 |         9B[n]46        Move cursor up n (1) lines and into column 1
  |  | 
 |         9B[n][3B n]48  Cursor in line;Set column
  |  | 
 |         9B 4A          Erase screen from cursor
  |  | 
 |         9B 4B          Erase line from the cursor
  |  | 
 |         9B 4C          Insert line
  |  | 
 |         9B 4D          Delete line
  |  | 
 |         9B[n]50        Delete n characters starting at cursor
  |  | 
 |         9B[n]53        Move up n lines
  |  | 
 |         9B[n]54        Move down n lines
  |  | 
 |         9B 32 30 68    Line feed => Line feed + return
  |  | 
 |         9B 32 30 6C    Line feed => just Line feed
  |  | 
 |         9B 6E          Sends the cursor position!A string of the following
  |  | 
 |                        form is returned:
  |  | 
 |                        9B (line) 3B (column) 52
  |  | 
 |         9B(style);(foreground colour);(Background Colour)6D
  |  | 
 |                        The three parameters are decimal numbers in ASCII
  |  | 
 |                        format.They mean:
  |  | 
 |                        Style:  0 = normal
  |  | 
 |                                1 = bold
  |  | 
 |                                3 = italic
  |  | 
 |                                4 = underline
  |  | 
 |                                7 = inverse
  |  | 
 |                        Foreground colour: 30-37
  |  | 
 |                        Colour 0-7 for Text
  |  | 
 |                        Background colour: 40-47
  |  | 
 |                        Colour 0-7 for background
  |  | 
 |         9B(length)74   sets the maximum number of lines to be displayed
  |  | 
 |         9B(width)75    sets the maximum line length
  |  | 
 |         9B(distance)78 defines the distance in pixels from the left border
  |  | 
 |                        of the window to the place where output should
  |  | 
 |                        begin
  |  | 
 |         9B(distance)79 defines the distance in pixels from the upper
  |  | 
 |                        border of the window to the place where output
  |  | 
 |                        should begin
  |  | 
 |                        The last four functions yield the normal values if
  |  | 
 |                        you leave off the parameters.
  |  | 
 | 
  |  | 
 |         9B 30 20 70    Make cursor invisible
  |  | 
 |         9B 20 70       Make cursor visible
  |  | 
 |         9B 71          Sends window construction.A string of the following
  |  | 
 |                        form is returned:
  |  | 
 |                        9B 31 3B 31 3B (lines) 3B (columns) 73
  |  | 
 | 
  |  | 
 |         To see how the control characters work,have "pmsg"output this text
  |  | 
 |         to your window:
  |  | 
 | 
  |  | 
 |         mytext: dc.b $9b,"4;31;40m"                ; (6.3.2D)
  |  | 
 |                 dc.b "underline"
  |  | 
 |                 dc.b $9b,"3;33;40m",$9b,"5;20H"
  |  | 
 |                 dc.b "** Hello World! **",0
  |  | 
 | 
  |  | 
 |         The parameters for the control sequence are put in quotation marks
  |  | 
 |         so they are treated as an ASCII string.Now you see,just how easy
  |  | 
 |         it is to do text output!
  |  | 
 |         Here is the complete program to open and output the text and
  |  | 
 |         control codes to your window in AssemPro format (We have used the
  |  | 
 |         AssemPro macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can
  |  | 
 |         start the programs from desktop.If you are using a different
  |  | 
 |         assembler check your documentation for instructions on starting
  |  | 
 |         and exiting programs):
  |  | 
 | 
  |  | 
 |         ; ***** 6.4.1D.ASM S.D. *****
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         openlib    =-30-378
  |  | 
 |         closelib   =-414
  |  | 
 |         ;execbase  = 4                     ;defined in AssemPro macros
  |  | 
 | 
  |  | 
 |         * calls to Amiga Dos:
  |  | 
 | 
  |  | 
 |         open       =-30
  |  | 
 |         close      =-30-6
  |  | 
 |         write      =-48
  |  | 
 |         IoErr      =-132
  |  | 
 |         mode_old   = 1005
  |  | 
 |         alloc_abs  =-$cc
  |  | 
 | 
  |  | 
 |                ILABEL AssemPro:includes/Amiga.l   ;AssemPro only
  |  | 
 | 
  |  | 
 |                INIT_AMIGA                  ;AssemPro only
  |  | 
 | 
  |  | 
 |         run:
  |  | 
 |                bsr     init                ;initialization
  |  | 
 |                bsr     test                ;system test
  |  | 
 |                nop
  |  | 
 |                bra qu                      ;quit and exit
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |                move.l  #mytext,d0
  |  | 
 |                bsr     pmsg
  |  | 
 |                bsr     pcrlf
  |  | 
 |                bsr     pcrlf
  |  | 
 | 
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         init:                              ;system initialization and open
  |  | 
 |                move.l  execbase,a6         ;number of execute-library
  |  | 
 |                lea     dosname(pc),a1
  |  | 
 |                moveq   #0,d0
  |  | 
 |                jsr     openlib(a6)         ;open DOS-Library
  |  | 
 |                move.l  d0,dosbase
  |  | 
 |                beq     error
  |  | 
 | 
  |  | 
 |                lea     consolname(pc),a1   ;console definition
  |  | 
 |                move.l  #mode_old,d0
  |  | 
 |                bsr     openfile            ;console open
  |  | 
 |                beq     error
  |  | 
 |                move.l  d0,conhandle
  |  | 
 | 
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         pmsg:                              ;print message (D0)
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)
  |  | 
 |                move.l  d0,a0
  |  | 
 |                move.l  a0,d2
  |  | 
 |                clr.l   d3
  |  | 
 | 
  |  | 
 |         ploop: 
  |  | 
 |                tst.b   (a0)+
  |  | 
 |                beq     pmsg2
  |  | 
 |                addq.l  #1,d3
  |  | 
 |                bra     ploop
  |  | 
 | 
  |  | 
 |         pmsg2:
  |  | 
 |                move.l  conhandle,d1
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     write(a6)
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         pcrlf:
  |  | 
 |                move    #10,d0
  |  | 
 |                bsr     pchar
  |  | 
 |                move    #13,d0
  |  | 
 | 
  |  | 
 |         pchar:                             ;output char in D0
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)   ;save all
  |  | 
 |                move.l  conhandle,d1
  |  | 
 | 
  |  | 
 |         pch1:
  |  | 
 |                lea     outline,a1
  |  | 
 |                move.b  d0,(a1)
  |  | 
 |                move.l  a1,d2
  |  | 
 |                move.l  #1,d3               ;one letter
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     write(a6)
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6   ;restore all
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         error:
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     IoErr(a6)
  |  | 
 |                move.l  d0,d5
  |  | 
 | 
  |  | 
 |                move.l  #-1,d7              ;flag
  |  | 
 | 
  |  | 
 |         qu:
  |  | 
 |                move.l  conhandle,d1        ;window close
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     close(a6)
  |  | 
 | 
  |  | 
 |                move.l  dosbase,a1          ;DOS.Lib close
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                jsr     closelib(a6)
  |  | 
 | 
  |  | 
 |                EXIT_AMIGA                  ;AssemPro only
  |  | 
 | 
  |  | 
 |         openfile:                          ;open file
  |  | 
 |                move.l  a1,d1               ;pointer to I/O-definition-
  |  | 
 |                                            ;text
  |  | 
 |                move.l  d0,d2
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     open(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         dosname: dc.b 'dos.library',0,0
  |  | 
 |                align.w
  |  | 
 | 
  |  | 
 |         dosbase: dc.l 0
  |  | 
 | 
  |  | 
 |         consolname: dc.b 'CON:0/100/640/100/ ** CLI-Test **',0
  |  | 
 |                align.w
  |  | 
 | 
  |  | 
 |         conhandle: dc.l 0
  |  | 
 | 
  |  | 
 |         mytext:
  |  | 
 |                dc.b $9b,'4;31;40m'
  |  | 
 |                dc.b 'underline'
  |  | 
 |                dc.b $9b,'3;33;40m',$9b,'5;20H'
  |  | 
 |                dc.b '** Hello World !! **',0
  |  | 
 | 
  |  | 
 |                align
  |  | 
 | 
  |  | 
 |         outline: dc.w 0                    ;output buffer for pchar
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         Now that you've done text and character output,its time to move on
  |  | 
 |         to text input.
  |  | 
 | 
  |  | 
 |       6.4.2.Keyboard Input.
  |  | 
 |       ---------------------
  |  | 
 |         You can read keyboard input very easily.You just need to open the
  |  | 
 |         I/O channel of the CON:window and read from it.You need the read 
  |  | 
 |         function from the DOS library to do this.Its offset is -42.
  |  | 
 |         The function has three parameters just like the WRITE function.
  |  | 
 | 
  |  | 
 |         In D1   the handle number that you get from the WRITE function.
  |  | 
 |         In D2   the address that the data read in is to start.
  |  | 
 |         In D3   the number of bytes to read.
  |  | 
 | 
  |  | 
 |         Here is a subroutine that reads the number of characters from the
  |  | 
 |         keyboard that it finds in D3.It puts them in a buffer.
  |  | 
 | 
  |  | 
 |         read    = -42                 ; (6.4.2A)
  |  | 
 |                ...
  |  | 
 | 
  |  | 
 |         getchr:                       ;* Get (D3) characters from the
  |  | 
 |                                       ;keyboard
  |  | 
 |                move.l  #inbuff,d2     ;address of buffer in D2
  |  | 
 |                move.l  dosbase,a6     ;DOS base address in A6
  |  | 
 |                move.l  conhandle,d1   ;our window handle
  |  | 
 |                jsr     read(a6)       ;call read function
  |  | 
 |                rts                    ;done!
  |  | 
 | 
  |  | 
 |         inbuff:        blk.b 80,0     ;buffer for keyboard input
  |  | 
 | 
  |  | 
 |         This routine returns to the main program when <Return> is entered.
  |  | 
 |         If more than D3 characters are entered,"inbuff"only gets the first
  |  | 
 |         characters.The routine gets the remaining characters when called a
  |  | 
 |         second time.
  |  | 
 |         This sort of input is fairly easy.You can backspace,because only
  |  | 
 |         the characters that should be there are put in the memory block
  |  | 
 |         starting at "inbuff".The number of characters moved into "inbuff"
  |  | 
 |         is put in D0.
  |  | 
 |          
  |  | 
 |         Try the program out as follows:
  |  | 
 | 
  |  | 
 |         After opening the CON:window,put the following lines in the main
  |  | 
 |         program:
  |  | 
 | 
  |  | 
 |                move   #80,d3          ;read 80 characters (6.4.2B)
  |  | 
 |                bsr    readchr         ;get line from keyboard
  |  | 
 |                lea    inline,a0       ;address of line in A0
  |  | 
 |                clr.b  0(a0,d0)        ;null byte on the end
  |  | 
 |                bsr    pmsg            ;output line again
  |  | 
 |         
  |  | 
 |         bp:
  |  | 
 | 
  |  | 
 |         After this comes the code segment that closes the window again.
  |  | 
 |         After loading the program into the AssemPro debugger,make "bp"a
  |  | 
 |         breakpoint and start the program.(SEKA users start the program
  |  | 
 |         with "g run"and enter "bp"as the breakpoint).The program quits at
  |  | 
 |         the breakpoint and you can take a look at the results on the
  |  | 
 |         screen.Then you can continue the program (SEKA with "j bp") and
  |  | 
 |         let the window close.
  |  | 
 |         After starting the program and opening the window,the cursor
  |  | 
 |         appears in the upper left corner of the window.Enter some text and
  |  | 
 |         press <Return>.The string that you just entered is output again on
  |  | 
 |         the screen.
  |  | 
 |         You use the "pmsg"routine from the previous chapter to do this
  |  | 
 |         output.This routine needs a null byte at the end of the text to be
  |  | 
 |         output.You put a null byte there by putting the address of the
  |  | 
 |         input buffer in A0 and then erasing the byte at A0+D0 using the
  |  | 
 |         CLR.B command.Since D0 contains the number of characters that were
  |  | 
 |         entered,this byte is the first unused byte.
  |  | 
 |         Since you're in the debugger you can redisplay the disassembled
  |  | 
 |         output when the program ends to see what "getchr"put in "inbuff"
  |  | 
 |         (SEKA owners can use "q inbuff"when the program ends to see what
  |  | 
 |         "getchr"put there.)You'll find the characters that you typed plus
  |  | 
 |         a closing $A.The $A stands for the <Return> key and its counted
  |  | 
 |         too,so if you entered a 12 and then hit <Return>,for example,D0
  |  | 
 |         will contain a 3.
  |  | 
 |         Try this again with a RAW:window.Change the window definition from
  |  | 
 |         CON: to RAW:and reassemble the program.You'll notice the diference
  |  | 
 |         right away.After you've entered one character,a return is executed
  |  | 
 |         D0 always as one bit in it.
  |  | 
 |         The advantage of this form of input is that cursor and function
  |  | 
 |         keys can be recognized.Using your own routine,you can repeatedly
  |  | 
 |         accept input of characters using "getchr"and then work with the
  |  | 
 |         special characters.
  |  | 
 |         Theres another form of keyboard input:checking for a single key.
  |  | 
 |         This is important when a program is about to execute an important
  |  | 
 |         function and the user must say he wants it executed by entering
  |  | 
 |         "Y"for yes.This can be treated as normal input,but in some cases,
  |  | 
 |         there is a better method.
  |  | 
 |         There is a function in the DOS library that waits a certain
  |  | 
 |         specified length of time for a key to be pressed,and returns a
  |  | 
 |         zero (FALSE) if no key was hit in this time period.It returns a -1
  |  | 
 |         ($FFFFFFFF = TRUE) if one was.To find out which key it takes
  |  | 
 |         another function.The WaitForChar function,is only good for tasks
  |  | 
 |         like waiting for the user to let the program know that it can
  |  | 
 |         continue scrolling text.
  |  | 
 | 
  |  | 
 |         The function needs two parameters:
  |  | 
 | 
  |  | 
 |         In D1    the handle number of the window or file from which the
  |  | 
 |                  character should be read.It can also wait for a character
  |  | 
 |                  from an interface.
  |  | 
 |         In D2    you pass the length of time in microseconds that you
  |  | 
 |                  should wait for a key stroke.
  |  | 
 | 
  |  | 
 |         To wait one second for one key to be hit,you can use the following
  |  | 
 |         routine:
  |  | 
 | 
  |  | 
 |         WaitForCh=-30-174                 ; (6.4.2C)
  |  | 
 |                ...
  |  | 
 | 
  |  | 
 |         scankey:                          ;* Wait for a key stroke
  |  | 
 |                move.l  conhandle,d1       ;in our window
  |  | 
 |                move.l  #1000000,d2        ;waiting time 1 second
  |  | 
 |                move.l  dosbase,a6         ;DOS base address
  |  | 
 |                jsr     waitforch(a6)      ;wait...
  |  | 
 |                tst.l   d0                 ;test result
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         The TST command at the end of the program allows the calling
  |  | 
 |         routine to use a BEQ or BNE command to evaluate the results of the
  |  | 
 |         routine-BEQ branches if no key was hit.BNE doesn't.
  |  | 
 |         Heres an example program in AssemPro format covering what you have
  |  | 
 |         learned so far.Opening and closing a window,displaying text in the
  |  | 
 |         window and inputting text:
  |  | 
 | 
  |  | 
 |         ;***** 6.4.2A.ASM S.D *****
  |  | 
 | 
  |  | 
 |         openlib    =-30-378
  |  | 
 |         closelib   =-414
  |  | 
 |         ;execbase  =4                      ;defined in AssemPro
  |  | 
 |                                            ;Macros
  |  | 
 | 
  |  | 
 |         * call to Amiga.Dos:
  |  | 
 | 
  |  | 
 |         open       =-30
  |  | 
 |         close      =-30-6
  |  | 
 |         read       =-42
  |  | 
 |         write      =-48
  |  | 
 |         IoErr      =-132
  |  | 
 |         mode_old   =1005
  |  | 
 |         alloc_abs  =-$cc
  |  | 
 | 
  |  | 
 |                ILABEL AssemPro:include/Amiga.l  ;AssemPro only
  |  | 
 | 
  |  | 
 |                INIT_AMIGA                  ;AssemPro only
  |  | 
 | 
  |  | 
 |         run:
  |  | 
 |                bsr     init                ;initialization
  |  | 
 |                bsr     test                ;system test
  |  | 
 |                nop                         
  |  | 
 |                bra     qu                  ;quit and exit
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |                move.l  #mytext,d0
  |  | 
 |                bsr     pmsg
  |  | 
 |                bsr     pcrlf
  |  | 
 |                bsr     pcrlf
  |  | 
 |                move.l  #80,d3              ;80 characters to read in (D3)
  |  | 
 |                bsr     getchr              ;get character
  |  | 
 |                bsr     pmsg                ;output line
  |  | 
 | 
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         init:                              ;system initialization and open
  |  | 
 |                move.l  execbase,a6         ;number of execute-library
  |  | 
 |                lea     dosname(pc),a1
  |  | 
 |                moveq   #0,d0
  |  | 
 |                jsr     openlib             ;open DOS-Library
  |  | 
 |                move.l  d0,dosbase
  |  | 
 |                beq     error
  |  | 
 |   
  |  | 
 |                lea     consolname(pc),a1   ;console definition
  |  | 
 |                move.l  #mode_old,d0
  |  | 
 |                bsr     openfile            ;console open
  |  | 
 |                beq     error
  |  | 
 |                move.l  d0,conhandle
  |  | 
 | 
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         pmsg:                              ;print message (D0)
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)
  |  | 
 |                move.l  d0,a0
  |  | 
 |                move.l  a0,d2
  |  | 
 |                clr.l   d3
  |  | 
 | 
  |  | 
 |         ploop:
  |  | 
 |                tst.b   (a0)+
  |  | 
 |                beq     pmsg2
  |  | 
 |                addq.l  #1,d3
  |  | 
 |                bra     ploop               ;check length
  |  | 
 | 
  |  | 
 |         pmsg2:
  |  | 
 |                move.l  conhandle,d1
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     write(a6)
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         pcrlf:
  |  | 
 |                move    #10,d0
  |  | 
 |                bsr     pchar
  |  | 
 |                move    #13,d0
  |  | 
 | 
  |  | 
 |         pchar:                             ;character in D0 output
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)   ;save all
  |  | 
 |                move.l  conhandle,d1
  |  | 
 | 
  |  | 
 |         pch1:
  |  | 
 |                lea     outline,a1
  |  | 
 |                move.b  d0,(a1)
  |  | 
 |                move.l  a1,d2
  |  | 
 |                move.l  #1,d3               ;1 letter
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     write(a6)
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6   ;restore all
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         getchr:                            ;get character for keyboard
  |  | 
 |                move.l  #1,d3               ;1 character
  |  | 
 |                move.l  conhandle,d1
  |  | 
 |                lea     inbuff,a1           ;buffer address
  |  | 
 |                move.l  a1,d2
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     read(a6)
  |  | 
 |                clr.l   d0
  |  | 
 |                move.b  inbuff,d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         error:
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     IoErr(a6)
  |  | 
 |                move.l  d0,d5
  |  | 
 | 
  |  | 
 |                move.l  #-1,d7              ;flag
  |  | 
 | 
  |  | 
 |         qu:
  |  | 
 |                move.l  conhandle,d1        ;window close
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     close(a6)
  |  | 
 | 
  |  | 
 |                move.l  dosbase,a1          ;DOS.Lib close
  |  | 
 |                move.l  execbase,a6 jsr     ;close lib (A6)
  |  | 
 | 
  |  | 
 |                EXIT_AMIGA                  ;AssemPro only
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         openfile:                          ;open file
  |  | 
 |                move.l  a1,d1               ;pointer to I/O-Definition-
  |  | 
 |                                            ;Text
  |  | 
 |                move.l  d0,d2               
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     open(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         dosname: dc.b 'dos.library',0,0
  |  | 
 |                align.w
  |  | 
 | 
  |  | 
 |         dosbase: dc.l 0
  |  | 
 | 
  |  | 
 |         consolname: dc.b 'CON:0/100/640/100/** CLI-TEST **',0
  |  | 
 |                align.w
  |  | 
 | 
  |  | 
 |         conhandle: dc.l 0
  |  | 
 | 
  |  | 
 |         mytext: dc.b '** Hello World !! **',0
  |  | 
 | 
  |  | 
 |                align
  |  | 
 | 
  |  | 
 |         outline: dc.w 0                     ;output buffer for pchar 
  |  | 
 |     
  |  | 
 |         inbuff: blk.b 8                     ;input buffer
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 | 
  |  | 
 |       6.4.3.Printer Control.
  |  | 
 |       ----------------------
  |  | 
 |         Now that you've looked at console I/O,lets look at outputting data
  |  | 
 |         from the computor.The first device that we'll discuss is the
  |  | 
 |         printer.
  |  | 
 |         Its very easy to use the printer.You just need to open another
  |  | 
 |         channel.It goes just the way you learned it with CON: and RAW:
  |  | 
 |         windows;the only difference is you enter PRT:instead.
  |  | 
 |         You open this channel using the same lines that you used above for
  |  | 
 |         the window except that the pointer is to the channel name PRT:in
  |  | 
 |         D1.You pass the mode "new"(1006) in D2 in the "do_open"routine as
  |  | 
 |         well.Save the handle number that comes back at a label called
  |  | 
 |         "prthandle".
  |  | 
 |         Now you can use the same output routines that you used with the
  |  | 
 |         windows to send text to the printer.You need to put "prthandle"
  |  | 
 |         instead of "conhandle"in the line with the "move.l conhandle,d1"
  |  | 
 |         command.
  |  | 
 |         Actually it would be better to eliminate this line from the
  |  | 
 |         routine totally.Then you can use the same routine for window and
  |  | 
 |         printer output.The calling procedure would then need to put
  |  | 
 |         "conhandle"in D1 for window output.It would put "prthandle" in D1
  |  | 
 |         for printer output.This is a very flexible output routine that can
  |  | 
 |         be used for window and printer output now.You can't accept input
  |  | 
 |         from the printer,because the printer doesn't send data.It just
  |  | 
 |         accepts it and prints it.
  |  | 
 | 
  |  | 
 |       6.4.4.Serial I/O.
  |  | 
 |       -----------------
  |  | 
 |         Its just as easy to use the serial interface as the printer.Just
  |  | 
 |         enter SER:as the filename.Now you can use the DOS functions READ
  |  | 
 |         and WRITE just as before to do I/O channels you've just opened.
  |  | 
 |         You can set the parameters for the interface (like Hand shake and
  |  | 
 |         Transfer rate) with the Preferences program. 
  |  | 
 | 
  |  | 
 |       6.4.5.Speech Output.
  |  | 
 |       --------------------
  |  | 
 |         The Amiga has a speech synthesizer built in.This isn't quite as
  |  | 
 |         easy to program as the I/O devices discussed earlier,however.You
  |  | 
 |         use the "narrator.device"to do this.
  |  | 
 |         This device requires several program steps to install it and then
  |  | 
 |         causes it to speak.You need to open the device,start the I/O,etc..
  |  | 
 |         Lets look at how to translate the text into the proper form and
  |  | 
 |         then output the text.
  |  | 
 |         First we need to do some initialization.Lets define the constants
  |  | 
 |         now.Some of them are new.
  |  | 
 | 
  |  | 
 |         ;***** Narrator Basic Functions 3/87 S.D ***** (6.4.5A)
  |  | 
 | 
  |  | 
 |         openlib     =-408                   
  |  | 
 |         closelib    =-414
  |  | 
 |         execbase    = 4
  |  | 
 | 
  |  | 
 |         open        =-30                    ;open file
  |  | 
 |         close       =-36                    ;close file
  |  | 
 |         mode_old    = 1005                  ;old mode
  |  | 
 |         
  |  | 
 |         opendevice  =-444                   ;open device
  |  | 
 |         closedev    =-450                   ;close device
  |  | 
 | 
  |  | 
 |         sendIo      =-462                   ;start I/O
  |  | 
 |         abortIO     =-480                   ;abort I/O
  |  | 
 | 
  |  | 
 |         translate   =-30                    ;translate text
  |  | 
 | 
  |  | 
 |         ;The initialization routine follows:
  |  | 
 |                
  |  | 
 |         init:                               ;initialize and open system
  |  | 
 | 
  |  | 
 |         ;* open DOS library * 
  |  | 
 | 
  |  | 
 |                move.l  execbase,a6          ;pointer to execbase
  |  | 
 |                lea     dosname,a1           ;pointer to DOS name
  |  | 
 |                moveq   #0,d0                ;version unimportant
  |  | 
 |                jsr     openlib(a6)          ;open DOS library
  |  | 
 |                move.l  d0,dosbase           ;save handle
  |  | 
 |                beq     error                ;error handle
  |  | 
 | 
  |  | 
 |         ;* Open translator.library *
  |  | 
 | 
  |  | 
 |                lea     transname,a1         ;pointer to translator name
  |  | 
 |                clr.l   d0 
  |  | 
 |                jsr     openlib(a6)          ;open translator
  |  | 
 |                move.l  d0,transbase         ;save handle
  |  | 
 |                beq     error                ;error handling
  |  | 
 | 
  |  | 
 |         ;* Set up I/O area for Narrator *
  |  | 
 | 
  |  | 
 |                lea     talkio,a1            ;pointer to I/O area in A1
  |  | 
 |                move.l  #nwrrep,14(a1)       ;enter port address
  |  | 
 |                move.l  #amaps,48+8(a1)      ;pointer to audio mask
  |  | 
 |                move    #4,48+12(a1)         ;number of the mask
  |  | 
 |                move.l  #512,36(a1)          ;length of the output area
  |  | 
 |                move    #3,28(a1)            ;command:write
  |  | 
 |                move.l  #outtext,40(a1)      ;address of output area
  |  | 
 | 
  |  | 
 |         ;* Open Narrator device *
  |  | 
 | 
  |  | 
 |                clr.l   d0                   ;number 0
  |  | 
 |                clr.l   d1                   ;no flags
  |  | 
 |                lea     nardevice,a0         ;pointer to device name
  |  | 
 |                jsr     opendevice(a6)       ;open narrator.device
  |  | 
 |                tst.l   d0                   :error?
  |  | 
 |                bne     error                ;Yes!
  |  | 
 | 
  |  | 
 |         ;* Open Window *
  |  | 
 | 
  |  | 
 |                move.l  #consolname,d1       ;console definition
  |  | 
 |                move.l  #mode_old,d2         ;old mode
  |  | 
 |                move.l  dosbase,a6           ;DOS base address
  |  | 
 |                jsr     open(a6)             ;open window
  |  | 
 |                tst.l   d0                   ;error?
  |  | 
 |                beq     error                ;Yes!
  |  | 
 |                move.l  d0,conhandle         ;else save handle
  |  | 
 | 
  |  | 
 |         After you've done this initialization,you can have the computor
  |  | 
 |         save the text you have prepared for it.To see what the Amiga is
  |  | 
 |         saying,use the "pmsg"function to have the text written to the
  |  | 
 |         window:
  |  | 
 | 
  |  | 
 | 
  |  | 
 |                move.l  #intext,d2           ;text for the Amiga to say
  |  | 
 |                bsr     pmsg                 ;output in window also
  |  | 
 | 
  |  | 
 |         sayit:                              ;have the text said
  |  | 
 | 
  |  | 
 |         ;*Translate the text into a form that the computor can use *
  |  | 
 | 
  |  | 
 |                lea     intext,a0            ;address of the text
  |  | 
 |                move.l  #outtext-intext,d0   ;length of the text
  |  | 
 |                lea     outtext,a1           ;address of output area
  |  | 
 |                move.l  #512,d1              ;length of output area
  |  | 
 |                move.l  tranbase,a6          ;translator base address
  |  | 
 |                jsr     translate(a6)        ;translate text
  |  | 
 | 
  |  | 
 |         ;* Speech output *
  |  | 
 | 
  |  | 
 |                lea     talkio,a1            ;address of I/O structure
  |  | 
 |                move.l  #512,36(a1)          ;length of output area
  |  | 
 |                move.l  execbase,a6          ;EXEC base address
  |  | 
 |                jsr     sendIO(a6)           ;start I/O (speech output)
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         Once the program ends,the I/O stops as well,so you need to put in
  |  | 
 |         something that keeps the program going longer.You'll use the
  |  | 
 |         "getchr"function that you programmed earlier to take care of this:
  |  | 
 | 
  |  | 
 | 
  |  | 
 |                bsr     getchr               ;wait for keyboard input
  |  | 
 | 
  |  | 
 |         The computor waits until the <Return> key is pressed.Now you can
  |  | 
 |         listen to what the Amiga as to say.Once the <Return> key is
  |  | 
 |         pressed,the program stops.
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         qu:                                 ; (6.4.5C)
  |  | 
 |                move.l  execbase,a6          ;EXEC base address
  |  | 
 |                lea     talkio,a1            ;pointer to I/O area
  |  | 
 |                jsr     abortio(a6)          ;stop the I/O
  |  | 
 | 
  |  | 
 |                move.l  conhandle,d1         
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     close(a6)            ;close window
  |  | 
 |                
  |  | 
 |                move.l  dosbase,d1
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                jsr     closelib(a6)         ;close DOS library
  |  | 
 | 
  |  | 
 |                lea     talkio,a1
  |  | 
 |                jsr     closedev(a6)         ;close narrator.device
  |  | 
 | 
  |  | 
 |                move.l  tranbase,a1              
  |  | 
 |                jsr     closelib(a6)         ;close translator library
  |  | 
 | 
  |  | 
 |                rts                          ;* end of program
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         Now comes the data that you need for the program above:
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         mytext:      dc.b  'This is a test text !',10,13,10,13,0,0
  |  | 
 |         dosmame:     dc.b  'dos.library',0,0
  |  | 
 |         transname:   dc.b  "translator.library",0
  |  | 
 |         consolname:  dc.b  'RAW:0/100/640/100/** Test window',0
  |  | 
 |         nardevice    dc.b  'narrator.device',0
  |  | 
 |            align
  |  | 
 |         dosbase:     dc.l  0
  |  | 
 |         tranbase     dc.l  0
  |  | 
 |         amaps:       dc.b  3,5,10,12
  |  | 
 |            align
  |  | 
 |         conhandle:   dc.l  0
  |  | 
 |         talkio:      blk.l 20,0
  |  | 
 |         nwrrep:      blk.l 8,0
  |  | 
 |         intext:      dc.b  'hello,i am the amiga talking to you',0
  |  | 
 |            align
  |  | 
 |         outtext:     blk.b 512,0
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         This is quite a bit of work,but its worth it because it opens so
  |  | 
 |         many possibilities for you.There are a lot of variations possible
  |  | 
 |         if you modify parameters.These parameters are entries in the I/O
  |  | 
 |         area starting at the "talkio"label.The area is built as follows:
  |  | 
 | 
  |  | 
 |         Offset        Length       Meaning
  |  | 
 |         ----------------------------------------------------------------
  |  | 
 |         ** Port Data **
  |  | 
 |           0             L          Pointer to next block 
  |  | 
 |           4             L          Pointer to last block
  |  | 
 |           8             B          I/O type
  |  | 
 |           9             B          Priority
  |  | 
 |           10            L          Pointer to I/O name
  |  | 
 |           14            L          Pointer to port
  |  | 
 |           18            W          Length
  |  | 
 |         ** I/O Data **
  |  | 
 |           20            L          Pointer to device
  |  | 
 |           24            L          Pointer to device unit
  |  | 
 |           28            W          Command word
  |  | 
 |           30            B          I/O flags
  |  | 
 |           31            B          I/O status
  |  | 
 |           32            L          I/O pointer
  |  | 
 |           36            L          I/O length
  |  | 
 |           40            L          Pointer to Data
  |  | 
 |           44            L          I/O offset
  |  | 
 |         ** Narrator data items **
  |  | 
 |           48            W          Speech speed
  |  | 
 |           50            W          Highness of voice
  |  | 
 |           52            W          Speech mode
  |  | 
 |           54            W          Sex (male/female voice)
  |  | 
 |           56            L          Pointer to audio mask
  |  | 
 |           60            W          Number of mask
  |  | 
 |           62            W          Volume
  |  | 
 |           64            W          Read in rate
  |  | 
 |           66            B          Flag for producing graphics (0=off)
  |  | 
 |           67            B          Actual mask (internal use)
  |  | 
 |           68            B          Channel used (internal use)
  |  | 
 | 
  |  | 
 |         We would'nt recommend experimenting with the data in the first two
  |  | 
 |         blocks.If you do,you can easily cause a system crash.You can use
  |  | 
 |         the last entries of the structure to produce some interesting
  |  | 
 |         effects though.
  |  | 
 |         Heres an overview of the parameters you can use to vary the speech
  |  | 
 |         output.The value in parenthesis is the standard value,the value
  |  | 
 |         set when narrator.device is opened.
  |  | 
 | 
  |  | 
 |       Speech speed (150);
  |  | 
 |         You can use this to set the speed of speech.The pitch of the voice
  |  | 
 |         is not affected by this value.
  |  | 
 | 
  |  | 
 |       Pitch of voice (110);
  |  | 
 |         You can choose a value between 65 and 320 for the pitch (from
  |  | 
 |         Goofy to Mickey Mouse).  
  |  | 
 | 
  |  | 
 |       Speech mode (0);
  |  | 
 |         The zero gives half-way naturel speech.A one lets the Amiga speak
  |  | 
 |         in monotone like a robot.
  |  | 
 | 
  |  | 
 |       Sex (0);
  |  | 
 |         A zero means masculine and a one means feminine (more or less..)
  |  | 
 | 
  |  | 
 |       Volume (64);
  |  | 
 |         The volume can range from 0 to 64.The standard value is the
  |  | 
 |         loudest possible.
  |  | 
 | 
  |  | 
 |       Read in rate (22200);
  |  | 
 |         By lowering this value,the voice is lowered.If you change this
  |  | 
 |         very much,you'll get some wierd voices!
  |  | 
 | 
  |  | 
 |         You can experiment a bit until you find a interesting voice.Have
  |  | 
 |         fun! 
  |  | 
 |         Here is a complete talking program in AssemPro format:
  |  | 
 | 
  |  | 
 |         ;***** Speech output S.D. *****
  |  | 
 | 
  |  | 
 |         openlib      =-30-378
  |  | 
 |         closelib     =-414
  |  | 
 |         ;execbase    =4                     ;defined by AssemPro
  |  | 
 | 
  |  | 
 |         * calls to Amiga Dos:         
  |  | 
 | 
  |  | 
 |         open         =-30
  |  | 
 |         close        =-30-6
  |  | 
 |         opendevice   =-444
  |  | 
 |         closedev     =-450
  |  | 
 |         addport      =-354
  |  | 
 |         remport      =-360
  |  | 
 |         ;DoIo        =-456
  |  | 
 |         sendIo       =-462
  |  | 
 |         abortIo      =-480
  |  | 
 |         read         =-30-12
  |  | 
 |         write        =-30-18
  |  | 
 |         ;myinput     =-30-24
  |  | 
 |         ;output      =-30-30
  |  | 
 |         ;currdir     =-30-96
  |  | 
 |         ;exit        =-30-114
  |  | 
 |         waitforch    =-30-174
  |  | 
 |         findtask     =-294
  |  | 
 |         translate    =-30
  |  | 
 |         mode_old     = 1005
  |  | 
 |         ;mode_new    = 1006
  |  | 
 |         ;alloc_abs   =-$cc
  |  | 
 |         ;free_mem    =-$d2
  |  | 
 | 
  |  | 
 |         ;!!!when>500KB !!! or place in chip memory
  |  | 
 |         ;org $40000
  |  | 
 |         ;load $40000
  |  | 
 |         ;!!!!!!!!!!!!!!!!!!!!!!!
  |  | 
 | 
  |  | 
 |                
  |  | 
 |                ILABEL AssemPro:includes/Amiga.l  ;AssemPro only
  |  | 
 | 
  |  | 
 |                INIT_AMIGA                   ;AssemPro only
  |  | 
 | 
  |  | 
 |         run:
  |  | 
 |                bsr     init                 ;initialization
  |  | 
 |                bra     test                 ;system-test
  |  | 
 | 
  |  | 
 |         init:                               ;system initialization and
  |  | 
 |                                             ;open
  |  | 
 |                move.l  execbase,a6          ;pointer to exec library
  |  | 
 |                lea     dosname(pc),a1       ;pointer to dos name
  |  | 
 |                moveq   #0,d0                ;version:not important
  |  | 
 |                jsr     openlib(a6)          ;open DOS-Library
  |  | 
 |                move.l  d0,dosbase           ;save handle
  |  | 
 |                beq     error                ;error routine
  |  | 
 | 
  |  | 
 |         ;*                                  ;open translator library
  |  | 
 |                move.l  execbase,a6          ;pointer to exec library
  |  | 
 |                lea     transname,a1         ;pointer to translator library
  |  | 
 |                clr.l   d0
  |  | 
 |                jsr     openlib(a6)          ;open translator
  |  | 
 |                move.l  d0,tranbase          ;save handle
  |  | 
 |                beq     error                ;error routine
  |  | 
 | 
  |  | 
 |         ;*                                  ;set up
  |  | 
 |                sub.l   a1,a1
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                jsr     findtask(a6)         ;find task
  |  | 
 |                move.l  d0,nwrrep+2
  |  | 
 | 
  |  | 
 |                lea     nwrrep,a1
  |  | 
 |                jsr     addport(a6)          ;add port
  |  | 
 | 
  |  | 
 |         ;*                                  ;open narrator device
  |  | 
 |                lea     talkio,a1            ;pointer to I/O area in A1
  |  | 
 |                move.l  #nwrrep,14(a1)       ;enter port address
  |  | 
 |                clr.l   d0                   ;number 0
  |  | 
 |                clr.l   d1                   ;no flags
  |  | 
 |                lea     nardevice,a0         ;pointer to device name
  |  | 
 |                jsr     opendevice(a6)       ;open narrator.device
  |  | 
 |                tst.l   d0                   ;error?
  |  | 
 |                bne     error                ;Yes!
  |  | 
 | 
  |  | 
 |         ;*                                  ;set up I/O for narrator
  |  | 
 |                                             ;device
  |  | 
 | 
  |  | 
 |         bp:
  |  | 
 |                lea     talkio,a1            ;pointer to I/O in A1
  |  | 
 |                move.l  #nwrrep,14(a1)       ;enter port address
  |  | 
 |                move.l  #amaps,48+8(a1)      ;pointer to audio mask
  |  | 
 |                move    #4,48+12(a1)         ;size of mask
  |  | 
 | 
  |  | 
 |                lea     consolname(pc),a1    ;console-definition
  |  | 
 |                move.l  #mode_old,d0
  |  | 
 |                bsr     openfile             ;console open
  |  | 
 |                beq     error        
  |  | 
 |                move.l  d0,conhandle
  |  | 
 | 
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |                move.l  #mytext,d0           
  |  | 
 |                bsr     pmsg                 ;test-text output 
  |  | 
 |  
  |  | 
 |                bsr     sayit                ;say text
  |  | 
 | 
  |  | 
 |                bsr     readin               ;input
  |  | 
 |                move    #10,d0
  |  | 
 |                bsr     pchar                ;LF output
  |  | 
 |                move.l  #inline+2,d0
  |  | 
 |                bsr     pmsg                 ;and again
  |  | 
 |                bsr     pcrlf
  |  | 
 |                bra     qu
  |  | 
 | 
  |  | 
 |         error:
  |  | 
 |                move.l  #-1,d7               ;flag
  |  | 
 | 
  |  | 
 |         qu:
  |  | 
 |                move.l  execbase,a6 
  |  | 
 |                lea     talkio,a1
  |  | 
 |                jsr     abortio(a6)
  |  | 
 |         
  |  | 
 |                move.l  conhandle,d1         ;window close
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     close(a6)
  |  | 
 | 
  |  | 
 |                move.l  dosbase,a1           ;DOS.Lib close
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                jsr     closelib(a6)
  |  | 
 | 
  |  | 
 |                lea     nwrrep,a1
  |  | 
 |                jsr     remport(a6)          ;remove port
  |  | 
 |                lea     talkio,a1
  |  | 
 |                jsr     closedev(a6)         ;close narrator device
  |  | 
 |                move.l  tranbase,a1
  |  | 
 |                jsr     closelib(a6)         ;close translator library
  |  | 
 | 
  |  | 
 |                EXIT_AMIGA                   ;AssemPro only
  |  | 
 | 
  |  | 
 |         openfile:                           ;open file
  |  | 
 |                move.l  a1,d1                ;pointer to I/O definition-
  |  | 
 |                                             ;text
  |  | 
 |                move.l  d0,d2
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     open(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         pmsg:                               ;print message (D0)
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)    
  |  | 
 |                move.l  d0,a0
  |  | 
 |                move.l  a0,d2
  |  | 
 |                clr.l   d3
  |  | 
 | 
  |  | 
 |         mess1:
  |  | 
 |                tst.b   (a0)+
  |  | 
 |                beq     mess2
  |  | 
 |                addq.l  #1,d3
  |  | 
 |                bra     mess1                ;length calculate
  |  | 
 | 
  |  | 
 |         mess2:
  |  | 
 |                move.l  conhandle,d1
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     write(a6)
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         pcrlf:
  |  | 
 |                move    #10,d0
  |  | 
 |                bsr     pchar
  |  | 
 |                move    #13,d0
  |  | 
 | 
  |  | 
 |         pchar:                              ;output characters in D0
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)    ;save all
  |  | 
 |                move.l  conhandle,d1
  |  | 
 | 
  |  | 
 |         pch1:
  |  | 
 |                lea     chbuff,a1
  |  | 
 |                move.b  d0,(a1)
  |  | 
 |                move.l  a1,d2
  |  | 
 |                move.l  #1,d3                ;1 letter
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     write(a6)
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6    ;restore all
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         scankey:                            ;test key
  |  | 
 |                move.l  conhandle,d1
  |  | 
 |                move.l  #500,d2              ;wait value
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     waitforch(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         readin:                             ;input from keyboard
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)    ;save registers
  |  | 
 |                lea     inline+2,a2          ;pointer to input buffer
  |  | 
 |                clr.l   (a2)
  |  | 
 | 
  |  | 
 |         inplop:
  |  | 
 |                bsr     getchr
  |  | 
 |                cmp.b   #8,d0
  |  | 
 |                beq     backspace
  |  | 
 |                cmp.b   #127,d0              ;delete?
  |  | 
 |                beq     backspace
  |  | 
 |                bsr     pchar                ;character output
  |  | 
 |                cmp.b   #13,d0
  |  | 
 |                beq     inputx
  |  | 
 |                move.b  d0,(a2)+
  |  | 
 |                bra     inplop
  |  | 
 | 
  |  | 
 |         inputx:
  |  | 
 |                clr.b   (a2)+
  |  | 
 |                sub.l   #inline,a2
  |  | 
 |                move    a2,inline            ;length in lines+1
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6    ;registers
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         backspace:
  |  | 
 |                cmp.l   #inline,a2           ;at the beginning?
  |  | 
 |                beq     inplop               ;yes
  |  | 
 |                move.b  #8,d0
  |  | 
 |                bsr     pchar                ;backspace
  |  | 
 |                move    #32,d0
  |  | 
 |                bsr     pchar                ;blank
  |  | 
 |                move    #8,d0
  |  | 
 |                bsr     pchar                ;backspace
  |  | 
 |                clr.b   (a2)
  |  | 
 |                subq.l  #1,a2
  |  | 
 |                bra     inplop
  |  | 
 | 
  |  | 
 |         getchr:                             ;get one character from
  |  | 
 |                                             ;keyboard
  |  | 
 |                move.l  #1,d3                ;one character
  |  | 
 |                move.l  conhandle,d1      
  |  | 
 |                lea     inbuff,a1            ;buffer address
  |  | 
 |                move.l  a1,d2
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     read(a6)
  |  | 
 |                clr.l   d0
  |  | 
 |                move.b  inbuff,d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         sayit:
  |  | 
 |                lea     intext,a0
  |  | 
 |                move.l  #outtext-intext,d0
  |  | 
 |                lea     outtext,a1
  |  | 
 |                move.l  #512,d1
  |  | 
 |                move.l  tranbase,a6
  |  | 
 |                jsr     translate(a6)
  |  | 
 | 
  |  | 
 |         p:
  |  | 
 |                lea     talkio,a1
  |  | 
 |                move    #3,28(a1)            ;??
  |  | 
 |                move.l  #512,36(a1)
  |  | 
 |                move.l  #outtext,40(a1)
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                jsr     sendio(a6)
  |  | 
 |                
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         mytext:        dc.b 'This is our Test-Text !',10,13,10,13,0,0
  |  | 
 | 
  |  | 
 |         dosname:       dc.b 'dos.library',0,0
  |  | 
 |  
  |  | 
 |         transname:     dc.b "translator.library",0
  |  | 
 |                align.w
  |  | 
 | 
  |  | 
 |         dosbase:       dc.l 0
  |  | 
 |   
  |  | 
 |         tranbase:      dc.l 0
  |  | 
 | 
  |  | 
 |         consolname:    dc.b 'CON:0/100/640/100/* Speech-Test S.D.* ',0
  |  | 
 | 
  |  | 
 |         nardevice:     dc.b 'narrator.device',0
  |  | 
 | 
  |  | 
 |         amaps:         dc.b 3,5,10,12,0,0
  |  | 
 |                align.w
  |  | 
 | 
  |  | 
 |         conhandle:     dc.l 0
  |  | 
 | 
  |  | 
 |         inbuff:        blk.b 8
  |  | 
 | 
  |  | 
 |         inline:        blk.b 180,0
  |  | 
 |      
  |  | 
 |         chbuff:        blk.b 82,0
  |  | 
 | 
  |  | 
 |         narread:       blk.l 20,0
  |  | 
 |    
  |  | 
 |         talkio:        blk.l 20,0
  |  | 
 | 
  |  | 
 |         nwrrep:        blk.l 8,0
  |  | 
 | 
  |  | 
 |         intext:        dc.b 'hello,i am the amiga computor',0
  |  | 
 |                align.w
  |  | 
 | 
  |  | 
 |         outtext:       blk.l 128,0
  |  | 
 | 
  |  | 
 |         
  |  | 
 |         end
  |  | 
 | 
  |  | 
 |       6.5.Disk Operations.
  |  | 
 |       --------------------
  |  | 
 |         The most important peripheral device for a computor like the Amiga
  |  | 
 |         is the disk drive.You use it to save data,so that you don't lose
  |  | 
 |         it when you turn off the computor.We'll look at saving and
  |  | 
 |         retrieving data in this chapter.                                  
  |  | 
 |         Lets first look at the simple disk operations that are used for
  |  | 
 |         data management.To gain access to a file,you must open it first.  
  |  | 
 |         This is done using the OPEN function from the DOS library,a
  |  | 
 |         function that you're already familiar with.I'll assume in the
  |  | 
 |         following examples,that you've already opened the DOS library.
  |  | 
 | 
  |  | 
 |       6.5.1.Open Files.
  |  | 
 |       -----------------
  |  | 
 |         The open function needs a parameter for the mode.The mode has a
  |  | 
 |         particular meaning.If the file is opened for reading,it must
  |  | 
 |         already exist.The mode for the OPEN function must be "old"(1005)
  |  | 
 |         in this case.
  |  | 
 |         If you want to produce a file,you must open it first.Since it does
  |  | 
 |         not exist,you use the "new"(1006) mode.If a file is opened for
  |  | 
 |         writing using this mode even though a file with this name already
  |  | 
 |         exists,the old file with this name is erased and replaced.To avoid
  |  | 
 |         loss of data,you should check if a file by that name already
  |  | 
 |         exists and then output an error message if it does.
  |  | 
 |         You're going to start with a subroutine that opens a file.Lets
  |  | 
 |         assume that the filename starts at the label "filename",and that
  |  | 
 |         it is closed with a null byte.You just need to pass the mode in
  |  | 
 |         register D2.
  |  | 
 |         The routine puts the file handle number in "filehd"and returns to
  |  | 
 |         the main program.Since the operation with the handle is the last
  |  | 
 |         one performed by the subroutine,the status of the operation can be
  |  | 
 |         evaluated once the return has been executed.If the operation went
  |  | 
 |         smoothly and the file is opened,the handle number has a non-zero
  |  | 
 |         value.If it is zero and "bsr openfile"is followed by "beq error", 
  |  | 
 |         you can branch to an error handling routine when problems occur.
  |  | 
 | 
  |  | 
 |         Here is a subroutine for opening and closing a file:
  |  | 
 | 
  |  | 
 |         open       =-30                   ; (6.5.1A)                    
  |  | 
 |         close      =-36
  |  | 
 |         mode_old   = 1005
  |  | 
 |         mode_new   = 1006
  |  | 
 |              ...
  |  | 
 |         openfile:                       ;*open file,mode in D0
  |  | 
 |                move.l  dosbase,a6       ;DOS base address in A6
  |  | 
 |                move.l  #filename,d1     ;pointer to filename
  |  | 
 |                jsr     open(a6)         ;open file
  |  | 
 |                move.l  d0,filehd        ;save handle
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         closefile:                      ;*close file
  |  | 
 |                move.l  dosbase,a6       ;DOS base address in A6
  |  | 
 |                move.l  filehd,d1        ;file handle in D1
  |  | 
 |                jsr     close(a6)        ;close file
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         filehd:     dc.l   0            ;storage for file handle
  |  | 
 |         filename:   dc.b  "filename",0  ;file to be opened
  |  | 
 |                align                    ;even
  |  | 
 | 
  |  | 
 |         To use these subroutines,you must look at how you can load and
  |  | 
 |         save data.                                                        
  |  | 
 |                                                                           
  |  | 
 |       6.5.2.Reading and Writing Data.                                     
  |  | 
 |       -------------------------------                                     
  |  | 
 |         Lets write a new file.To start,write the following lines:      
  |  | 
 | 
  |  | 
 |                 move.l  #mode_new,d2    ;open new file (6.5.2A)
  |  | 
 |                 bsr     openfile        ;open file
  |  | 
 |                 beq     error           ;did'nt work!
  |  | 
 | 
  |  | 
 |         For the filename,write a name like "Testfile"in the line labelled 
  |  | 
 |         "filename".After calling the "openfile"routine,a file with this
  |  | 
 |         name is created on the disk.If one existed already,it is erased.
  |  | 
 | 
  |  | 
 |         Lets assume you want to write a short text file.For the example
  |  | 
 |         lets use:
  |  | 
 | 
  |  | 
 |         text:  dc.b   "This is a test text for the Testfile",0
  |  | 
 |         textend:
  |  | 
 | 
  |  | 
 |         The "textend"label is used so that you can calculate the number of
  |  | 
 |         data bytes by subtracting "text".
  |  | 
 |         You want to write this text in the file.Use the WRITE function
  |  | 
 |         which needs three parameters:
  |  | 
 | 
  |  | 
 |         In D1   the file handle that you got back from the OPEN function.
  |  | 
 |         In D2   a pointer to the data that should be written.
  |  | 
 |         In D3   the number of bytes to be written.
  |  | 
 | 
  |  | 
 |         For the example,you'll need another segment of code to put the
  |  | 
 |         pointer to the data in D2 and the number of bytes in D3:
  |  | 
 | 
  |  | 
 |         write  =-48                      ; (6.5.2B)
  |  | 
 |               ...
  |  | 
 |         writedata:                       ;*write data in the file
  |  | 
 |               move.l  dosbase,a6         ;DOS base address
  |  | 
 |               move.l  filehd,d1          ;file handle in D1
  |  | 
 |               jsr     write(a6)          ;write data
  |  | 
 |               rts
  |  | 
 | 
  |  | 
 |         After opening the file,you can call the subroutine from the main
  |  | 
 |         program with the following lines: 
  |  | 
 | 
  |  | 
 |               move.l  #text,d2           ;pointer to data
  |  | 
 |               move.l  #textend-text,d3   ;number of bytes
  |  | 
 |               bsr     writedata          ;write data in the file
  |  | 
 | 
  |  | 
 |         Then close the file with:
  |  | 
 | 
  |  | 
 |               bsr     closefile          ;close file
  |  | 
 |               bra     end                ;end program
  |  | 
 | 
  |  | 
 |         After running the program,look at the directory of the diskette,  
  |  | 
 |         you should find the file "testfile".It is just as long as your
  |  | 
 |         text.You want to read this file in,to make sure it contains the
  |  | 
 |         right data.
  |  | 
 |         You need the DOS function READ,which needs the same parameters as
  |  | 
 |         the WRITE function.You can use parameters for the number of bytes
  |  | 
 |         to read just part of the file.If you give a larger number than the
  |  | 
 |         file contains,the whole file is loaded.You'll find the number of
  |  | 
 |         bytes read in D0.
  |  | 
 |         Lets set up a field that as enough space for the data you want to
  |  | 
 |         read.You can do this with the following line:
  |  | 
 | 
  |  | 
 |         field: blk.b  100     ;reserve 100 bytes
  |  | 
 | 
  |  | 
 |         For the example data,this is plenty.If you want to load another
  |  | 
 |         file,you may need to reserve more space.
  |  | 
 |         Now lets write a subroutine to read the data.You always want to
  |  | 
 |         load whole files.You just need to pass the address of the buffer
  |  | 
 |         so the data is loaded into the subroutine.In the example,its the
  |  | 
 |         address "field".
  |  | 
 |         Heres the subroutine that reads the entire opened file into the
  |  | 
 |         memory area pointed to by D2:
  |  | 
 | 
  |  | 
 |         read   = -42                  ; (6.5.2C)
  |  | 
 |                ...
  |  | 
 |         readdata:                     ;*read file
  |  | 
 |                move.l  dosbase,a6     ;DOS base address in A6
  |  | 
 |                move.l  filehd,d1      ;file handle in D1
  |  | 
 |                move.l  #$ffffff,d3    ;read an arbitrary number of bytes
  |  | 
 |                jsr     read(a6)       ;read data
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         To use this routine to load the file into the buffer "field",use
  |  | 
 |         the following main program:
  |  | 
 | 
  |  | 
 |                move,l  #mode_old,d2   ;old file
  |  | 
 |                bsr     openfile       ;open file
  |  | 
 |                beq     error          ;did'nt work!
  |  | 
 |                move.l  #field,d2      ;pointer to data buffer
  |  | 
 |                bsr     readdata       ;read file
  |  | 
 |                move.l  d0,d6          ;save number of bytes in D6
  |  | 
 |                bsr     closefile      ;close file
  |  | 
 |                bra     end            ;program end
  |  | 
 | 
  |  | 
 |         After assembling and starting this program,you can use the
  |  | 
 |         debugger to look at the data buffer that you filled with data from
  |  | 
 |         the file.In D6,you'll find the number of bytes that were read from
  |  | 
 |         the file. 
  |  | 
 | 
  |  | 
 |       6.5.3.Erase Files.
  |  | 
 |       ------------------
  |  | 
 |         Once you've experimented enough with the program above,you'll
  |  | 
 |         certainly want to erase the "Testfile"file.The DELETEFILE function
  |  | 
 |         in the DOS library has an offset of -72.It only needs 1 parameter.
  |  | 
 |         The parameter is passed in D1.The parameter is a pointer to the
  |  | 
 |         filename.The name must be closed with a null byte.
  |  | 
 | 
  |  | 
 |         To erase "Testfile",use the following lines:
  |  | 
 | 
  |  | 
 |         deletefile  =-72                ; (6.5.3)
  |  | 
 |                ...
  |  | 
 |                move.l  dosbase,a6       ;DOS base address in A6
  |  | 
 |                move.l  #filename,d1     ;pointer to filename in D1
  |  | 
 |                jsr     deletefile(a6)   ;erase file
  |  | 
 | 
  |  | 
 |         The file is deleted.You can't save the file with normal methods if
  |  | 
 |         you accidently erase it!You can use a trick that saves the data.  
  |  | 
 |         We'll take a look at this trick later.Its used in lots of programs
  |  | 
 | 
  |  | 
 |       6.5.4.Rename Files.
  |  | 
 |       -------------------
  |  | 
 |         When a text editing program writes a text that as be altered back
  |  | 
 |         to the disk,the old file usually isn't erased.Often the old file
  |  | 
 |         is renamed.For example,it might get the name "Backup".The new file
  |  | 
 |         is written to disk with the old name.
  |  | 
 |         The function in the DOS library that allows you to change the
  |  | 
 |         names of programs is called RENAME and has -78 as an offset.You
  |  | 
 |         need to pass two parameters-D1 as a pointer to the old name and D2
  |  | 
 |         as a pointer to the new name of the file.
  |  | 
 | 
  |  | 
 |         To rename "Testfile"as "Backup"(before you erase it),use the
  |  | 
 |         following lines: 
  |  | 
 | 
  |  | 
 |         rename  =-78
  |  | 
 |                ...
  |  | 
 |                move.l  dosbase,a6    ;DOS base address in A6
  |  | 
 |                move.l  #oldname,d1   ;pointer to old name in D1
  |  | 
 |                move.l  #newname,d2   ;pointer to new name in D2
  |  | 
 |                jsr     rename(a6)    ;rename file
  |  | 
 |                ...
  |  | 
 |         oldname: dc.b "testfile",0
  |  | 
 |         newname: dc.b "backup",0
  |  | 
 | 
  |  | 
 |       6.5.5.CLI Directory.
  |  | 
 |       --------------------
  |  | 
 |         Lets pretend you've programmed a text editor and started it.Now
  |  | 
 |         you want to load a text from disk and edit it-but whats the name
  |  | 
 |         of that file?
  |  | 
 |         You need a function to read and display the directory of the disk.
  |  | 
 |         There are several ways to do this.First lets use the easiest
  |  | 
 |         method.It doesn't require much programming and can be quite
  |  | 
 |         useful.
  |  | 
 |         The trick is to call the Dir or List programs that are in the C   
  |  | 
 |         directory.You'll use the CLI commands.The DOS library contains a
  |  | 
 |         command called "Execute"with offset -222 that allows you to
  |  | 
 |         execute CLI commands. 
  |  | 
 |         The function needs three parameters:
  |  | 
 | 
  |  | 
 |         In D1   a pointer to a string closed with a zero that contains the
  |  | 
 |                 name of the command to be executed.This string must
  |  | 
 |                 contain the same command that you would give in the CLI.It
  |  | 
 |                 can be a null pointer as well.
  |  | 
 |         In D2   the input file is determined.Normally theres a zero here. 
  |  | 
 |                 If however,you give the file handle of a text file,though,
  |  | 
 |                 this file is read and interpreted as a command sequence.If
  |  | 
 |                 you define a window as the input medium,you've programmed
  |  | 
 |                 a new CLI window!
  |  | 
 |         In D3   the output file is determined.If there a zero here,the
  |  | 
 |                 output of the commands (for example,DIR output) is sent to
  |  | 
 |                 the standard CLI window.
  |  | 
 | 
  |  | 
 |         To try this out,insert this subroutine in a program that has
  |  | 
 |         already opened the DOS library and a window.
  |  | 
 | 
  |  | 
 |         execute  = -222              ; (6.5.5)
  |  | 
 |               ...
  |  | 
 |         dir: 
  |  | 
 |               move.l  dosbase,a6     ;DOS base address in A6
  |  | 
 |               move.l  #command,d1    ;pointer to command line
  |  | 
 |               clr.l   d2             ;no input (CLI window)
  |  | 
 |               move.l  conhandle,d3   ;output in our window
  |  | 
 |               jsr     execute(a6)    ;execute command
  |  | 
 |               rts
  |  | 
 | 
  |  | 
 |         command:
  |  | 
 |               dc.b    "dir",0
  |  | 
 | 
  |  | 
 |         This program works with the List command as well.The disadvantage 
  |  | 
 |         of this method is that the disk that the Workbench is loaded from 
  |  | 
 |         must be in the drive or the system requests you to put it in.The  
  |  | 
 |         Dir command is just a program,and the Amiga must load it before it
  |  | 
 |         can run.
  |  | 
 |         The disadvantage isn't too great.The program is short,and it
  |  | 
 |         allows you to use any CLI command in a program.
  |  | 
 |         Here is the complete program in AssemPro format that calls the dir
  |  | 
 |         program:
  |  | 
 | 
  |  | 
 |         ;***** 6.5.5A DIR.ASM S.D.*****   
  |  | 
 |         
  |  | 
 |         openlib      =-408
  |  | 
 |         closelib     =-414
  |  | 
 |         ;execbase    = 4                    ;defined in AssemPro
  |  | 
 |                                             ;macros
  |  | 
 |                        
  |  | 
 |                                        
  |  | 
 |         *calls to Amiga Dos:
  |  | 
 | 
  |  | 
 |         open         =-30
  |  | 
 |         close        =-36
  |  | 
 |         execute      =-222
  |  | 
 |         IoErr        =-132
  |  | 
 |         mode_old     = 1005
  |  | 
 |         alloc_abs    =-$cc
  |  | 
 | 
  |  | 
 |                ILABEL AssemPro:includes/Amiga.l   ;AssemPro only
  |  | 
 | 
  |  | 
 |                INIT_AMIGA                   ;AssemPro only                
  |  | 
 |                                                                           
  |  | 
 |         run:
  |  | 
 |                bsr     init                 ;initialization
  |  | 
 |                bra     test                 ;system test
  |  | 
 | 
  |  | 
 |         init:                               ;system initialization and
  |  | 
 |                                             ;open
  |  | 
 |                move.l  execbase,a6          ;number of execute-library
  |  | 
 |                lea     dosname(pc),a1
  |  | 
 |                moveq   #0,d0
  |  | 
 |                jsr     openlib(a6)          ;open DOS-library
  |  | 
 |                move.l  d0,dosbase
  |  | 
 |                beq     error
  |  | 
 | 
  |  | 
 |                lea     consolname(pc),a1    ;console definition
  |  | 
 |                move.l  #mode_old,d0
  |  | 
 |                bsr     openfile             ;console open
  |  | 
 |                beq     error
  |  | 
 |                move.l  d0,conhandle
  |  | 
 | 
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |                bsr     dir                  ;do directory
  |  | 
 |                bra     qu                   ;quit and exit
  |  | 
 | 
  |  | 
 |         dir:
  |  | 
 |                move.l  dosbase,a6           ;DOS base address in A6
  |  | 
 |                move.l  #command,d1          ;pointer to command line
  |  | 
 |                clr.l   d2                   ;no input (CLI window)
  |  | 
 |                move.l  conhandle,d3         ;output in our window
  |  | 
 |                jsr     execute(a6)          ;execute command
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         error:
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     IoErr(a6)
  |  | 
 |                move.l  d0,d5
  |  | 
 | 
  |  | 
 |                move.l  #-1,d7               ;flag
  |  | 
 | 
  |  | 
 |         qu:
  |  | 
 |                move.l  conhandle,d1         ;window close
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     close(a6)
  |  | 
 | 
  |  | 
 |                move.l  dosbase,a1           ;DOS.Lib close
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                jsr     closelib(a6)
  |  | 
 | 
  |  | 
 |                EXIT_AMIGA                   ;AssemPro only
  |  | 
 | 
  |  | 
 |         openfile:                           ;open file
  |  | 
 |                move.l  a1,d1                ;pointer to I/O-Definition-
  |  | 
 |                                             ;text
  |  | 
 |                move.l  d0,d2
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     open(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         dosname: dc.b 'dos.library',0,0
  |  | 
 |                align.w
  |  | 
 |         dosbase: dc.l 0
  |  | 
 |         consolname: dc.b 'CON:0/100/640/100/** CLI-Test **',0
  |  | 
 |                align.w
  |  | 
 |         conhandle: dc.l 0
  |  | 
 |         command:
  |  | 
 |                dc.b    "dir",0
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |       6.5.6.Read Directory.
  |  | 
 |       ---------------------
  |  | 
 |         Now,lets look at another method that doesn't need the CLI.In this
  |  | 
 |         way,you can read the directory of any disk without having to play
  |  | 
 |         Disk Jockey.                                                      
  |  | 
 |         You need to writ a program that does what CLI's Dir program does. 
  |  | 
 |         There are several steps.
  |  | 
 |         First you must give the system a key to the desired directory.That
  |  | 
 |         means you must call DOS'Lock function.It needs two parameters:
  |  | 
 | 
  |  | 
 |         In D1    pass a pointer to a text that contains the name of the
  |  | 
 |                  directory you wish to read.If,for example,you want to
  |  | 
 |                  read the contents of the RAM disk,the text would be 
  |  | 
 |                  'RAM:',0.
  |  | 
 |         In D2    put the mode that determines whether to read or write.Let
  |  | 
 |                  us use the "Read"(-2) mode.
  |  | 
 | 
  |  | 
 |         You call the Lock function (offset -84) and get either a point to
  |  | 
 |         the key or a zero returned to you in the D0 register.If you get a
  |  | 
 |         zero,the call did'nt work,the file was'nt found.This function can
  |  | 
 |         be used to find if a file is on the disk.You use this function
  |  | 
 |         with the name and see if D0 comes back zero.If not,the file
  |  | 
 |         exists.
  |  | 
 |         Lets assume the file or path exists.You need to save the value
  |  | 
 |         that came back in D0.You'll need it for both functions that you'll
  |  | 
 |         call.
  |  | 
 |         The next function you need is called Examine.You use it to search 
  |  | 
 |         the disk for an acceptable entry.It returns parameters like name, 
  |  | 
 |         length and date that correspond to the entry.You need to reserve a
  |  | 
 |         memory block for this information and put the beginning of the
  |  | 
 |         block in D2 before calling the Examine function.Put the key you
  |  | 
 |         got from the Lock function in the D1 register.
  |  | 
 |         The memory area that is filled with information is called a
  |  | 
 |         FileInfoBlock.Its 260 bytes long and contains information about
  |  | 
 |         the file.The name starts in the 9th byte and ends with a null byte
  |  | 
 |         so you can easily print it with our "pmsg"routine.The information
  |  | 
 |         that Examine gives isn't about a particular file,but about the
  |  | 
 |         disk.The name in FileInfoBlock is the disk name.
  |  | 
 |         The Examine function sends the status back in the D0 register.
  |  | 
 |         Since the Lock function already tested if the file existed,evalua-
  |  | 
 |         ting the status really isn't necessary.
  |  | 
 |         Now to the function that you can use to read individual files from
  |  | 
 |         the directory.The function is called ExNext (Examine Next).This   
  |  | 
 |         function searches for the next entry that fits the key every time
  |  | 
 |         it is called.ExNext gets the same parameters as Examine gets.     
  |  | 
 |         However,the return parameter in D0 is more important here.
  |  | 
 |         The ExNext function is always called in the same way.It always
  |  | 
 |         gets the next entry of the directory.If no more entries exist in
  |  | 
 |         the directory,ExNext puts a zero in the D0 register.
  |  | 
 |         You need to continue performing this operation until there aren't 
  |  | 
 |         any more entries.You can find this using the IoErr function from
  |  | 
 |         the DOS library.
  |  | 
 |         This function doesn't need any parameters.It returns the status of
  |  | 
 |         the last I/O operation that was performed in the D0 register.After
  |  | 
 |         the last ExNext,this value is 232,which means no_more_Entries.
  |  | 
 | 
  |  | 
 |         Heres a complete routine for reading the directory of the disk in 
  |  | 
 |         DFO:and displaying the contents in the window.
  |  | 
 | 
  |  | 
 |         ; 6.5.5B.ASM
  |  | 
 |         ;***** DOS-Sample function  3/87 S.D. *****
  |  | 
 | 
  |  | 
 |         openlib      =-30-378
  |  | 
 |         closelib     =-414
  |  | 
 |         exbase       =4
  |  | 
 | 
  |  | 
 |         * calls to amiga dos:
  |  | 
 | 
  |  | 
 |         open         =-30
  |  | 
 |         close        =-30-6
  |  | 
 |         read         =-30-12
  |  | 
 |         write        =-30-18
  |  | 
 |         myinput      =-30-24
  |  | 
 |         output       =-30-30
  |  | 
 |         currdir      =-30-96
  |  | 
 |         lock         =-30-54
  |  | 
 |         examine      =-30-72
  |  | 
 |         exnext       =-30-78
  |  | 
 |         exit         =-30-114
  |  | 
 |         IoErr        =-30-102
  |  | 
 |         waitforch    =-30-174
  |  | 
 |         mode         = 0
  |  | 
 |         mode_old     = 1005
  |  | 
 |         mode_new     = 1006
  |  | 
 |         alloc_abs    =-$cc
  |  | 
 |         free_mem     =-$d2
  |  | 
 | 
  |  | 
 |                ILABEL AssemPro:includes/Amiga.l   ;AssemPro only
  |  | 
 | 
  |  | 
 |                INIT_AMIGA                   ;AssemPro only
  |  | 
 | 
  |  | 
 |         run:                                                              
  |  | 
 |                bsr     init                 ;initialization
  |  | 
 |                bra     test                 ;system-test
  |  | 
 | 
  |  | 
 |         init:                               ;system initialization and
  |  | 
 |                                             ;open
  |  | 
 |                move.l  exbase,a6            ;pointer to exec.library
  |  | 
 |                lea     dosname(pc),a1
  |  | 
 |                moveq   #0,d0
  |  | 
 |                jsr     openlib(a6)          ;open dos-library
  |  | 
 |                move.l  do,dosbase
  |  | 
 |                beq     error
  |  | 
 | 
  |  | 
 |                lea     consolname(pc),a1    ;console definition
  |  | 
 |                move.l  #mode_old,d0
  |  | 
 |                bsr     openfile             ;console open
  |  | 
 |                beq     error
  |  | 
 |                moveq   d0,conhandle
  |  | 
 | 
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |                move.l  #mytext,d0
  |  | 
 |                bsr     pmsg                 ;test-text output
  |  | 
 | 
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                move.l  #name,d1
  |  | 
 |                move.l  #-2,d2
  |  | 
 |                jsr     lock(a6)
  |  | 
 |                move.l  d0,d5
  |  | 
 |                tst.l   d0
  |  | 
 |                beq     error
  |  | 
 |                move.l  d0,locksav
  |  | 
 | 
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                move.l  locksav,d1
  |  | 
 |                move.l  #fileinfo,d2
  |  | 
 |                jsr     examine(a6)
  |  | 
 |                move.l  d0,d6
  |  | 
 |                tst.l   d0
  |  | 
 |                beq     error
  |  | 
 | 
  |  | 
 |         loop:
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                move.l  locksav,d1
  |  | 
 |                move.l  #fileinfo,d2
  |  | 
 |                jsr     exnext(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                beq     error
  |  | 
 | 
  |  | 
 |                move.l  #fileinfo+8,d0
  |  | 
 |                bsr     pmsg
  |  | 
 |                bsr     pcrlf
  |  | 
 |                bra     loop
  |  | 
 | 
  |  | 
 |         error:
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     ioerr(a6)
  |  | 
 |                move.l  d0,d6
  |  | 
 | 
  |  | 
 |                move.l  #presskey,d0
  |  | 
 |                bsr     pmsg
  |  | 
 |                bsr     getch
  |  | 
 |                move.l  #-1,d7               ;flag
  |  | 
 | 
  |  | 
 |         qu:
  |  | 
 |                move.l  conhandle,d1         ;window close
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     close(a6)
  |  | 
 | 
  |  | 
 |                move.l  dosbase,a1           ;dos.lib close
  |  | 
 |                move.l  exbase,a6
  |  | 
 |                jsr     closelib(a6)
  |  | 
 |               
  |  | 
 |                EXIT_AMIGA                   ;AssemPro only
  |  | 
 | 
  |  | 
 |         openfile:                           ;open file
  |  | 
 |                move.l  a1,d1                ;pointer to I/O-Definition-
  |  | 
 |                                             ;Text
  |  | 
 |                move.l  d0,d2
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     open(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         pmsg:                               ;print message (D0)
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)
  |  | 
 |                move.l  d0,a0
  |  | 
 |                move.l  a0,d2
  |  | 
 |                clr.l   d3
  |  | 
 | 
  |  | 
 |         mess1:
  |  | 
 |                tst.b   (a0)+
  |  | 
 |                beq     mess2
  |  | 
 |                addq.l  #1,d3
  |  | 
 |                bra     mess1
  |  | 
 | 
  |  | 
 |         mess2:
  |  | 
 |                move.l  conhandle,d1
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     write(a6)
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         pcrlf:
  |  | 
 |                move    #10,d0
  |  | 
 |                bsr     pchar
  |  | 
 |                move    #13,d0
  |  | 
 | 
  |  | 
 |         pchar:                              ;character in D0 output
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)    ;save all
  |  | 
 |                move.l  conhandle,d1
  |  | 
 | 
  |  | 
 |         pch1:
  |  | 
 |                lea     chbuff,a1
  |  | 
 |                move.b  d0,(a1)
  |  | 
 |                move.l  a1,d2
  |  | 
 |                move.l  #1,d3
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     write(a6)
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6    ;restore all
  |  | 
 |                rts
  |  | 
 |        
  |  | 
 |         scankey:                            ;test key
  |  | 
 |                move.l  conhandle,d1
  |  | 
 |                move.l  #500,d2              ;wait value
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     waitforch(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         readin:                             ;input from keyboard
  |  | 
 |                movem.l d0-d7/a0-a6,-(sp)    ;registers
  |  | 
 |                lea     inline+2,a2          ;pointer to input buffer
  |  | 
 |                clr.l   (a2)
  |  | 
 | 
  |  | 
 |         inplop:
  |  | 
 |                bsr     getchr
  |  | 
 |                cmp.b   #8,d0
  |  | 
 |                beq     backspace
  |  | 
 |                cmp.b   #127,d0              ;delete?
  |  | 
 |                beq     backspace
  |  | 
 |                bsr     pchar                ;character output
  |  | 
 |                cmp.b   #13,d0
  |  | 
 |                beq     inputx
  |  | 
 |                move.b  d0,(a2)+
  |  | 
 |                bra     inplop
  |  | 
 | 
  |  | 
 |         input:
  |  | 
 |                clr.b   (a2)+
  |  | 
 |                sub.l   #inline,a2
  |  | 
 |                move    a2,inline            ;length in inline+1
  |  | 
 |                movem.l (sp)+,d0-d7/a0-a6    ;registers
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         backspace:
  |  | 
 |                cmp.l   #inline,a2           ;at beginning?
  |  | 
 |                beq     inplop               ;yes
  |  | 
 |                move.b  #8,d0
  |  | 
 |                bsr     pchar                ;backspace
  |  | 
 |                move    #32,d0
  |  | 
 |                bsr     pchar                ;blank
  |  | 
 |                move    #8,d0
  |  | 
 |                bsr     pchar                ;backspace
  |  | 
 |                clr.b   (a2)
  |  | 
 |                subq.l  #1,a2
  |  | 
 |                bra     inplop
  |  | 
 | 
  |  | 
 |         getchr:                             ;get 1 character from keyboard
  |  | 
 |                move.l  #1,d3                ;1 character
  |  | 
 |                move.l  conhandle,d1
  |  | 
 |                lea     inbuff,a1            ;buffer-address
  |  | 
 |                move.l  a1,d2
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     read(a6)
  |  | 
 |                clr.l   d0
  |  | 
 |                move.b  inbuff,d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         mytext:     dc.b 'Directory of Diskette: DFO:',10,13,10,13,0,0
  |  | 
 |         dosname:    dc.b 'dos.library',0,0
  |  | 
 |         presskey:   dc.b 'Press thr Return key!!',0
  |  | 
 |                align.w
  |  | 
 |         dosbase:    dc.l 0
  |  | 
 |         consolname: dc.b 'CON:0/100/640/100/** Directory-Test **',0
  |  | 
 |         name:       dc.b 'DFO:',0
  |  | 
 |                align.w
  |  | 
 |         locksav:    dc.l 0
  |  | 
 |         fileinfo:   ds.l 20
  |  | 
 |         conhandle:  dc.l 0
  |  | 
 |         inbuff:     DS.B 8
  |  | 
 |         inline:     DS.B 180
  |  | 
 |         chbuff      DS.B 82
  |  | 
 | 
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         The FileInfoBlock contains the following entries:
  |  | 
 | 
  |  | 
 |         Offset   Name             Meaning
  |  | 
 |         ----------------------------------------------------------------
  |  | 
 |           0      DiskKey.L        Disk Number
  |  | 
 |           4      DieEntryType.L   Entry Type (+=Directory,-=File)
  |  | 
 |           8      FileName         108 bytes with the filename
  |  | 
 |          116     Protection.L     File Protected?
  |  | 
 |          120     EntryType.L      Entry type
  |  | 
 |          124     Size.L           Length of file in bytes
  |  | 
 |          128     NumBlocks.L      Number of blocks
  |  | 
 |          132     Days.L           Creation day
  |  | 
 |          136     Minute.L         Creation time
  |  | 
 |          140     Tick.L           Creation time
  |  | 
 |          144     Comment          116 bytes with comments
  |  | 
 | 
  |  | 
 |         If you want to have the program output the file length as well,you
  |  | 
 |         can read the length with "move.l fileinfo+124,d0"and then use a
  |  | 
 |         conversion routine to produce a decimal number.You can output this
  |  | 
 |         result with the name.
  |  | 
 | 
  |  | 
 |       6.5.7.Direct Access To Disk.
  |  | 
 |       ----------------------------                                        
  |  | 
 |         There isn't a simple function in the library for accessing single 
  |  | 
 |         disk sectors.Here,you must work with a device just like you did
  |  | 
 |         with speech output.This time you'll be working with the trackdisk.
  |  | 
 |         device.
  |  | 
 |         You want to work with this device to directly program the disk
  |  | 
 |         drives.Once you've built up the necessary program machinery,you
  |  | 
 |         can experiment with various commands for disk access.Remember that
  |  | 
 |         an error can cause the disk to be modified and thus unusable.Make
  |  | 
 |         sure you're using a non-essential disk.Don't use one which
  |  | 
 |         contains your only copy of something.                             
  |  | 
 |         The initialization here is similar to that for speech output.Here
  |  | 
 |         is the initialization routine for your program:
  |  | 
 | 
  |  | 
 |         ;** Direct disk access via trackdisk.device ** (6.5.7)
  |  | 
 | 
  |  | 
 |         openlib    =-408
  |  | 
 |         closelib   =-414
  |  | 
 |         execbase   = 4
  |  | 
 |         open       =-30
  |  | 
 |         close      =-36
  |  | 
 |         opendevice =-444
  |  | 
 |         closedev   =-450
  |  | 
 |         sendIo     =-462
  |  | 
 |         read       =-30-12
  |  | 
 |         write      =-30-18
  |  | 
 |         waitforch  =-30-174
  |  | 
 |         mode_old   = 1005
  |  | 
 | 
  |  | 
 |         run:                             
  |  | 
 |                bsr     init                 ;initialization                     
  |  | 
 |                bra     test                 ;system-test
  |  | 
 | 
  |  | 
 |         init:                               ;initialize and open system
  |  | 
 |                move.l  execbase,a6          ;pointer to exec.library
  |  | 
 |                lea     dosname,a1
  |  | 
 |                moveq   #0,d0
  |  | 
 |                jsr     openlib(a6)          ;open dos.library
  |  | 
 |                move.l  d0,dosbase
  |  | 
 |                beq     error
  |  | 
 |                lea     diskio,a1            ;pointer to disk I/O area
  |  | 
 |                move.l  #diskrep,14(a1)      ;pointer to port
  |  | 
 |                clr.l   d0                   ;drive 0 (built in)
  |  | 
 |                clr.l   d1                   ;no flags
  |  | 
 |                lea     trddevice,a0         ;pointer to device name
  |  | 
 |                jsr     opendevice(a6)       ;open trackdisk.device
  |  | 
 |                tst.l   d0                   ;error?
  |  | 
 |                bne     error                ;yes!
  |  | 
 |                move.l  #consolname(pc),d1   ;console definition
  |  | 
 |                move.l  #mode_old,d2         ;old mode
  |  | 
 |                move.l  dosbase,a6           ;dos base address
  |  | 
 |                jsr     open(a6)             ;open window
  |  | 
 |                tst.l   d0                   ;error?
  |  | 
 |                beq     error                ;yes!
  |  | 
 |                move.l  d0,conhandle         ;else save handle
  |  | 
 |                rts                          ;done
  |  | 
 | 
  |  | 
 |         test:                               ;place for test routine
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         And now for the functions that take care of the various messages
  |  | 
 |         at the end of the program.
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         error:
  |  | 
 |                move.l  #-1,d7               ;flag for error (for SEKA)
  |  | 
 | 
  |  | 
 |         qu:
  |  | 
 |                move.l  execbase,a6          ;exec base address
  |  | 
 |                lea     diskio,a1            ;pointer to disk I/O
  |  | 
 |                move.l  32(a1),d7            ;IO_ACTUAL in D7 (for testing)
  |  | 
 |                move    #9,28(a1)            ;command motor on/off
  |  | 
 |                move.l  #0,36(a1)            ;0=off,1=on,so turn motor
  |  | 
 |                jsr     sendio(a6)           ;off
  |  | 
 |                move.l  conhandle,d1         ;close window
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     close(a6)
  |  | 
 |                move.l  dosbase,d1           ;close dos.lib
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                jsr     closelib(a6)
  |  | 
 |                lea     diskio,a1
  |  | 
 |                jsr     closedev(a6)         ;close trackdisk.device
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         Lets not forget the routine that waits for the user to press
  |  | 
 |         <Return>,so that you can watch the effects of the test function in
  |  | 
 |         peace:
  |  | 
 | 
  |  | 
 |         getchr:                             ;get a character from keyboard
  |  | 
 |                move.l  #1,d3                ;1 character
  |  | 
 |                move.l  conhandle,d1         ;window handle
  |  | 
 |                move.l  #inbuff,d2           ;buffer address
  |  | 
 |                move.l  dosbase,a6           ;dos base address
  |  | 
 |                jsr     read(a6)             ;read character
  |  | 
 |                rts                          ;thats it
  |  | 
 | 
  |  | 
 | 
  |  | 
 |         The last thing you need is the section of code that declares the
  |  | 
 |         text and data fields that your program needs:                     
  |  | 
 |                                                                           
  |  | 
 |         dosname:       dc.b  'dos.library',0
  |  | 
 |                align
  |  | 
 |         consolname:    dc.b  'RAW:0/100/640/50/** Wait window',0
  |  | 
 |                align
  |  | 
 |         trddevice:     dc.b  'trackdisk.device',0
  |  | 
 |                align
  |  | 
 |         dosbase:       dc.l 0               ;dos base address
  |  | 
 |         conhandle:     dc.l 0               ;window handle
  |  | 
 |         inbuff:        blk.b 80,0           ;keyboard buffer
  |  | 
 |         diskio:        blk.l 20,0           ;I/O structure
  |  | 
 |         diskrep:       blk.l 8,0            ;I/O port
  |  | 
 |         diskbuff:      blk.b 512*2,0        ;place for 2 sectors
  |  | 
 | 
  |  | 
 |         There,now you've done with the set up work.Lets look at how you
  |  | 
 |         can give commands to the disk drives.The first and easiest command
  |  | 
 |         is the one for turning the drive motor on and off.You've already
  |  | 
 |         seen this command in the program.This is command number nine.This
  |  | 
 |         number goes in the command word of the I/O structure (bytes 28 and
  |  | 
 |         29 of the structure).
  |  | 
 |         You need to pass a parameter that lets the computor know whether
  |  | 
 |         to turn the motor off or on.This information goes in the I/O long
  |  | 
 |         word that starts at byte 36:its zero for off,and one for on.
  |  | 
 |         You already chose the motor that should be turned on or off when
  |  | 
 |         you opened the device.You put the number of the chosen disk drive
  |  | 
 |         in D0-in your case you put a zero there because you are using the
  |  | 
 |         DFO:disk drive.
  |  | 
 |         Heres an overview of the commands you can use to access
  |  | 
 |         information on the disk:
  |  | 
 | 
  |  | 
 |         No    Name          Function
  |  | 
 |         -----------------------------------------------------------------
  |  | 
 |         2     READ          Read one or more sectors
  |  | 
 |         3     WRITE         Write sectors
  |  | 
 |         4     UPDATE        Update the track buffer
  |  | 
 |         5     CLEAR         Erase track buffer
  |  | 
 |         9     MOTOR         Turn motor on/off
  |  | 
 |         10    SEEK          Search for a track
  |  | 
 |         11    FORMAT        Format tracks
  |  | 
 |         12    REMOVE        Initialize routine that is called when you
  |  | 
 |                             remove the disk
  |  | 
 |         13    CHANGENUM     Find out number of disk changes
  |  | 
 |         14    CHANGESTATE   Test if disk is in drive
  |  | 
 |         15    PROTSTATUS    Test if disk is write protected
  |  | 
 | 
  |  | 
 |         You've already learned about command number nine.Lets look at the
  |  | 
 |         three commands you can use to make tests.These are the last three
  |  | 
 |         commands.They put a return value in the long word that begins in
  |  | 
 |         the 32nd byte in the I/O structure.This value was written in D7 in
  |  | 
 |         the program above for testing purposes.You can read its contents  
  |  | 
 |         directly if you ran the program with AssemPro.
  |  | 
 |         Here is a simple routine that you can use to run one of these
  |  | 
 |         commands with:
  |  | 
 | 
  |  | 
 |         test:                               ; (6.5.7B)
  |  | 
 |                lea     diskio,a1            ;pointer to I/O structure
  |  | 
 |                move    #13,28(a1)           ;pass command (for example 13)
  |  | 
 |                move.l  execbase,a6          ;execbase address in A6
  |  | 
 |                jsr     sendio(a6)           ;call function
  |  | 
 | 
  |  | 
 |         If CHANGENUM (command 13) is executed,in D7 you'll get the number
  |  | 
 |         of times a disk was taken out and put in the drive.If you call the
  |  | 
 |         program,you'll get a value back.If you take the disk out and put
  |  | 
 |         it back in,the number is two higher the next time you call the
  |  | 
 |         program.
  |  | 
 |         The CHANGESTATE command (command 14) tells whether a disk is in
  |  | 
 |         the drive or not.If one is,a zero comes back.Otherwise,a $FF is
  |  | 
 |         returned.
  |  | 
 |         You get the same values back from the PROTSTATUS function (command
  |  | 
 |         15).Here a zero means that the disk isn't write protected,while
  |  | 
 |         $FF means that it is.
  |  | 
 |         Now lets look at the READ and WRITE functions.These operations
  |  | 
 |         need a few more parameters than the status functions.You need to
  |  | 
 |         pass the following parameters: 
  |  | 
 | 
  |  | 
 |         The address of the I/O buffer in the data pointer,the number of
  |  | 
 |         bytes to be transfered in I/O length,and the data address on the
  |  | 
 |         disk in I/O offset. 
  |  | 
 | 
  |  | 
 |         The number of data bytes must be a multiple of 512,since every
  |  | 
 |         sector is 512 bytes,and only whole sectors can be read.
  |  | 
 | 
  |  | 
 |         The data address is the number of the first byte in the sector.If 
  |  | 
 |         you want to use the first sector,the offset is zero.For the second
  |  | 
 |         sector,its 512,etc...The formula is:
  |  | 
 | 
  |  | 
 |             offset = (sector_number -1) *512
  |  | 
 | 
  |  | 
 |         Here is a routine that loads the first two sectors of the disk
  |  | 
 |         into the buffer:
  |  | 
 | 
  |  | 
 |         test:  (6.5.7C)
  |  | 
 |                lea     diskio,a1           
  |  | 
 |                move    #2,28(a1)           ;command:READ
  |  | 
 |                move.l  #diskbuff,40(a1)    ;buffer
  |  | 
 |                move.l  #2*512,36(a1)       ;length:2 sectors
  |  | 
 |                move.l  #0*512,44(a1)       ;offset:0 sectors
  |  | 
 |                move.l  execbase,a6         ;exec base address
  |  | 
 |                jsr     sendio(a6)          ;start function
  |  | 
 | 
  |  | 
 |         Start the program from the debugger and then look at the buffers  
  |  | 
 |         contents after the program ends.You can find out the format of the
  |  | 
 |         disk here.If you want to read a sector thats being used,change the
  |  | 
 |         0 in the offset definition to 700 and start again.Its highly
  |  | 
 |         probable that theres some data there.
  |  | 
 |         To modify and write back the data that you've read from the disk, 
  |  | 
 |         you need command number three,the WRITE command.The parameters are
  |  | 
 |         the same.
  |  | 
 |         If you've executed the WRITE commandyou're probably wondering why
  |  | 
 |         the disk light did'nt go on.Thats because the Amiga writes a track
  |  | 
 |         that as been read into a buffer on its own.It WRITE's data there
  |  | 
 |         as well.It won't write the data to disk until another track is
  |  | 
 |         accessed.
  |  | 
 |         You can have the data updated directly as well using command four,
  |  | 
 |         the UPDATE command.
  |  | 
 |         Command 11,the FORMAT command,is also quite interesting.This
  |  | 
 |         command needs a data field that is 11*512=5632 bytes long-the
  |  | 
 |         length of a track.The offset must be a multiple of this number so 
  |  | 
 |         that you start at the beginning of a track.
  |  | 
 |         The length must be a multiple of 5632 as a result.If several
  |  | 
 |         tracks are formatted,each track is filled with the same data.
  |  | 
 |         You can use this function to easy write a disk copy program.You
  |  | 
 |         READ the source disk and then FORMAT the corresponding track on
  |  | 
 |         the destination disk.Thats how the DiskCopy program works-it
  |  | 
 |         reformats the destination disk.
  |  | 
 |         Command ten,the SEEK command,just needs the offset.It moves the
  |  | 
 |         Read/Write head of the drive to the position specified without
  |  | 
 |         making a disk access or testing if its at the right position.
  |  | 
 |         Command 12,the REMOVE command,is used to install an interrupt
  |  | 
 |         routine that is called when the disk is removed from the disk
  |  | 
 |         drive.The address of the interrupt structure is passed in the data
  |  | 
 |         pointer of the I/O structure.If theres a zero here,the interrupt  
  |  | 
 |         routine is turned off.
  |  | 
 | 
  |  | 
 |         Heres a complete example program in AssemPro format:
  |  | 
 | 
  |  | 
 |         ;***** Track disk-Basic function  10/86 S.D. *****
  |  | 
 | 
  |  | 
 |                ILABEL ASSEMPRO:includes/Amiga.l   :AssemPro only
  |  | 
 | 
  |  | 
 |         openlib      =-30-378
  |  | 
 |         closelib     =-414
  |  | 
 |         ;execbase    = 4                    ;defined in INIT_AMIGA
  |  | 
 | 
  |  | 
 |         * calls to amiga dos:
  |  | 
 | 
  |  | 
 |         open         =-30
  |  | 
 |         close        =-30-6
  |  | 
 |         opendevice   =-444
  |  | 
 |         closedev     =-450
  |  | 
 |         sendIo       =-462
  |  | 
 |         read         =-30-12
  |  | 
 |         write        =-30-18
  |  | 
 |         waitforch    =-30-174
  |  | 
 |         mode_old     = 1005
  |  | 
 | 
  |  | 
 |                INIT_AMIGA                   ;AssemPro only
  |  | 
 | 
  |  | 
 |         run:
  |  | 
 |                bsr     init                 ;initialization
  |  | 
 |                bra     test                 ;system test
  |  | 
 | 
  |  | 
 |         init:                               ;system initialization and
  |  | 
 |                                             ;open 
  |  | 
 |                move.l  execbase,a6          ;pointer to exec-library
  |  | 
 |                lea     dosname,a1
  |  | 
 |                moveq   #0,d0
  |  | 
 |                jsr     openlib(a6)          ;open dos-library
  |  | 
 |                move.l  d0,dosbase
  |  | 
 |                beq     error
  |  | 
 | 
  |  | 
 |                lea     diskio,a1
  |  | 
 |                move.l  #diskrep,14(a1)
  |  | 
 |                clr.l   d0
  |  | 
 |                clr.l   d1
  |  | 
 |                lea     trddevice,a0
  |  | 
 |                jsr     opendevice(a6)       ;open trackdisk.device
  |  | 
 |                tst.l   d0
  |  | 
 |                bne     error
  |  | 
 | 
  |  | 
 |         bp:
  |  | 
 |                lea     consolname(pc),a1    ;console-definition
  |  | 
 |                move.l  #mode_old,d0
  |  | 
 |                bsr     openfile             ;console open
  |  | 
 |                beq     error
  |  | 
 |                move.l  d0,conhandle
  |  | 
 | 
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |                bsr     accdisk
  |  | 
 | 
  |  | 
 |                bsr     getchr               ;wait for character
  |  | 
 |                bra     qu
  |  | 
 | 
  |  | 
 |         error:
  |  | 
 |                move.l  #-1,d7               ;flag
  |  | 
 | 
  |  | 
 |         qu:
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                lea     diskio,a1
  |  | 
 |                move    #9,28(a1)
  |  | 
 |                move.l  #0,36(a1)
  |  | 
 |                jsr     sendio(a6)
  |  | 
 | 
  |  | 
 |                move.l  conhandle,d1         ;window close
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     close(a6)
  |  | 
 | 
  |  | 
 |                move.l  dosbase,a1           ;dos.lib close
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                jsr     closelib(a6)
  |  | 
 | 
  |  | 
 |                lea     diskio,a1
  |  | 
 |                move.l  32(a1),d7
  |  | 
 |                jsr     closedev(a6)
  |  | 
 | 
  |  | 
 |                EXIT_AMIGA                   ;AssemPro only
  |  | 
 | 
  |  | 
 |         openfile:                           ;open file
  |  | 
 |                move.l  a1,d1                ;pointer to the I/O-definition
  |  | 
 |                                             ;text
  |  | 
 |                move.l  d0,d2
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     open(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         scankey:                            ;test for key
  |  | 
 |                move.l  conhandle,d1                      
  |  | 
 |                move.l  #500,d2              ;wait value
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     waitforch(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         getchr:                             ;get one character from
  |  | 
 |                                             ;keyboard
  |  | 
 |                move.l  #1,d3                ;1 character
  |  | 
 |                move.l  conhandle,d1
  |  | 
 |                lea     inbuff,a1            ;buffer-address
  |  | 
 |                move.l  a1,d2
  |  | 
 |                move.l  dosbase,a6
  |  | 
 |                jsr     read(a6)
  |  | 
 |                clr.l   d0
  |  | 
 |                move.b  inbuff,d0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         accdisk:
  |  | 
 |                lea     diskio,a1
  |  | 
 |                move    #2,28(a1)            ;command:READ                 
  |  | 
 |                move.l  #diskbuff,40(a1)     ;buffer
  |  | 
 |                move.l  #2*512,36(a1)        ;length:2 sectors
  |  | 
 |                move.l  #20*512,44(a1)       ;offset: n sectors
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                jsr     sendio(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         dosname:       dc.b 'dos.library',0,0
  |  | 
 |                align.w
  |  | 
 |         dosbase:       dc.l 0
  |  | 
 |         consolname:    dc.b 'RAW:0/100/640/100/** Test-Window S.D.V0.1',0
  |  | 
 |         trddevice:     dc.b 'trackdisk.device',0
  |  | 
 |                align.w
  |  | 
 |         conhandle      dc.l 0
  |  | 
 |         inbuff:        ds.b 8                                             
  |  | 
 |         diskio:        ds.l 20,0                                          
  |  | 
 |         diskrep:       ds.l 8,0                                           
  |  | 
 |         diskbuff:      ds.b 512*2,0                                       
  |  | 
 |                                                                           
  |  | 
 |                end
  |  | 
 |            
  |  | 
 |       Chapter 7.
  |  | 
 |       ----------
  |  | 
 |       7.Working With Intuition.
  |  | 
 |       -------------------------
  |  | 
 |         Now that you've learned so much about machine language,lets look
  |  | 
 |         at the special features of the Amiga.Lets look at the operating
  |  | 
 |         system Intuition that is in charge of windows,screens,the mouse
  |  | 
 |         and lots of other things.Beforetaking a look at these beautiful   
  |  | 
 |         features,theres some bad news.
  |  | 
 |         First,though,lets here the good news.Since Intuition has so many
  |  | 
 |         functions,it allows you to be very creative in programming your
  |  | 
 |         ideas.The disadvantage is that the flexibility means that you have
  |  | 
 |         to use a lot of parameters,and that makes for a lot of tedious
  |  | 
 |         work.
  |  | 
 |         However,this is no grounds for panic.Once you've built up the
  |  | 
 |         necessary routines,the programming and experimentation becomes
  |  | 
 |         increasingly interesting.Before you try out new program variations
  |  | 
 |         you should save your source code to disk,because Intuition gets
  |  | 
 |         fairly upset about bad parameters and often responds by crashing
  |  | 
 |         the system.
  |  | 
 |         Now lets get to work.To start working with Intuition,you need the 
  |  | 
 |         Intuition library.You can load it with the OpenLibrary function
  |  | 
 |         from the EXEC library.Heres the subroutine that takes care of
  |  | 
 |         initialization.
  |  | 
 | 
  |  | 
 |         openlib   =-408
  |  | 
 |         execbase  = 4
  |  | 
 | 
  |  | 
 |         run:
  |  | 
 |                bsr     openint         ;load intuition library
  |  | 
 |                ...
  |  | 
 | 
  |  | 
 |         openint:                       ;*initialize and open system
  |  | 
 |                move.l  execbase,a6     ;exec base address 
  |  | 
 |                lea     intname,a1      ;name of intuition library
  |  | 
 |                jsr     openlib(a6)     ;open intuition
  |  | 
 |                move.l  d0,intbase      ;save intuition base address
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         intname: dc.b "intuition.library",0
  |  | 
 |                align
  |  | 
 |         intbase: dc.l 0                ;base address of intuition
  |  | 
 | 
  |  | 
 |         When your program is finished,you need to close the screens,the
  |  | 
 |         window and the library.To do this,use the CloseLibrary function
  |  | 
 |         from the EXEC library.It has an offset of -414.
  |  | 
 |         Heres the subroutine:
  |  | 
 | 
  |  | 
 |         closelibrary  =-414
  |  | 
 |                ...
  |  | 
 |         closeint:                        ;*close intuition
  |  | 
 |                move.l  execbase,a6       ;exec base address in A6
  |  | 
 |                move.l  intbase,a1        ;intuition base address in A1
  |  | 
 |                jsr     closelibrary(a6)  ;close intuition
  |  | 
 |                rts                       ;done
  |  | 
 | 
  |  | 
 |         Now that you've got that taken care of,you can finally start
  |  | 
 |         working with Intuition.
  |  | 
 | 
  |  | 
 |       7.1.Open Screen.
  |  | 
 |       ----------------
  |  | 
 |         Intuition is a graphics operating system.For this reason,you'll be
  |  | 
 |         working with the screen.Its even more interesting to work with
  |  | 
 |         several screens at the same time.However,you only have one monitor
  |  | 
 |         on the Amiga.
  |  | 
 |         You can open as many screens as you like (at least,as long as
  |  | 
 |         theres some memory available).You can open a window,display menus
  |  | 
 |         and do I/O's there.The individual screens are fully independant.
  |  | 
 |         You can work with all of them simultaneously on the monitor.
  |  | 
 |         You can move individual screens forward and back to your hearts
  |  | 
 |         content.You can also press the left <Amiga> key and then an "m"to
  |  | 
 |         return to the workbench screen after getting into the different
  |  | 
 |         screens.
  |  | 
 |         You want to begin programming Intuition by setting up a screen.You
  |  | 
 |         have already loaded the Intuition library,so you can use the Open-
  |  | 
 |         Screen function.
  |  | 
 |         Wait a minute!What should the screen look like,where should it go,
  |  | 
 |         and what form should it have?You need to look at the options for
  |  | 
 |         the form of the screen you have available.
  |  | 
 |         The input to the screen is in the form of a table that has 13
  |  | 
 |         entries.Lets take a look at the parameters that you need for our
  |  | 
 |         screen.
  |  | 
 |         You'll start the table with the label "screen_defs"which must be
  |  | 
 |         at an even address:
  |  | 
 | 
  |  | 
 |                align
  |  | 
 |         screen_defs:                 ;The screen table begins here
  |  | 
 | 
  |  | 
 |         The first bit of information that the screen needs is the position
  |  | 
 |         and size.Lets have it start in the upper left corner and fill the
  |  | 
 |         entire screen.You'll use the positions X=0 and Y=0,the width 320
  |  | 
 |         and the height 200.This means that your screen is the maximum
  |  | 
 |         size.
  |  | 
 | 
  |  | 
 |         x_pos:     dc.w   0        ;X-Position
  |  | 
 |         y_pos:     dc.w   0        ;Y-Position
  |  | 
 |         width:     dc.w   320      ;width
  |  | 
 |         height:    dc.w   200      ;height
  |  | 
 | 
  |  | 
 |         Next you need to decide which colors should be displayed.That
  |  | 
 |         depends on the number of bitplanes,on the depth.Lets choose two.  
  |  | 
 |         That means you have 2^2 (4) colours available.Lets choose two,
  |  | 
 |         since four colours is usually plenty.
  |  | 
 | 
  |  | 
 |         depth:     dc.w   2        ;number of bitplanes
  |  | 
 | 
  |  | 
 |         Next you need to choose the colour of the title line and the
  |  | 
 |         function symbols.Give the number of the colour register:
  |  | 
 | 
  |  | 
 |         detail_pen:  dc.b   0      ;colour of text,etc...
  |  | 
 | 
  |  | 
 |         Now for the colour of the text background:
  |  | 
 | 
  |  | 
 |         block_pen    dc.b   1      ;background colour
  |  | 
 | 
  |  | 
 |         Make sure that these two inputs fit in a byte.The colours are
  |  | 
 |         normally the following (if the standard values have'nt been
  |  | 
 |         changed).You'll notice that the number of colours depends on the
  |  | 
 |         number of bit maps.
  |  | 
 | 
  |  | 
 |             Pen        Colour
  |  | 
 |          ---------------------------------------------------------
  |  | 
 |              0         Background (blue)
  |  | 
 |              1         White
  |  | 
 |           for two bit planes
  |  | 
 |              2         Black
  |  | 
 |              3         Red
  |  | 
 |           for three bit planes
  |  | 
 |              4         Blue
  |  | 
 |              5         Violet
  |  | 
 |              6         Turquoise
  |  | 
 |              7         White
  |  | 
 |           for four bit planes
  |  | 
 |              8         Black
  |  | 
 |              9         Red
  |  | 
 |             10         Green
  |  | 
 |             11         Brown
  |  | 
 |             12         Blue
  |  | 
 |             13         Blue
  |  | 
 |             14         Green
  |  | 
 |             15         Green
  |  | 
 | 
  |  | 
 |         The next word contains the bits that describe the appearance of
  |  | 
 |         the screen.The bits are:
  |  | 
 | 
  |  | 
 |         Bit    Value    Name             Meaning
  |  | 
 |         ---------------------------------------------------------------  
  |  | 
 |          1       2      GENLOCK_VIDEO    
  |  | 
 |          2       4      INTERLACE        Puts the screen in Interlace
  |  | 
 |                                          mode.The resolution and thus the 
  |  | 
 |                                          maximum screen size are doubled.
  |  | 
 |          6     $40      PFBA
  |  | 
 |          7     $80      EXTRA_HALFBRITE
  |  | 
 |          8     $100     GENLOCL_AUDIO
  |  | 
 |         10     $400     DBLPF            Divides the screen into a border
  |  | 
 |         and                              character area.
  |  | 
 |         11     $800     HOLDNMODIFY      Turns on Hold-and-Modify mode.
  |  | 
 |         13     $2000    VP_HIDE
  |  | 
 |         14     $4000    SPRITES          Allows sprites to be used.
  |  | 
 |         15     $8000    MODE_640         Turns on the highest resolution  
  |  | 
 |                                          graphics for the screen(640x400).
  |  | 
 | 
  |  | 
 |         Choose the value two (normal) for your example screen:
  |  | 
 | 
  |  | 
 |         view_modes:  dc.w   2         ;representation mode
  |  | 
 | 
  |  | 
 |         The following word is constructed in such away that each bit as
  |  | 
 |         its own meaning.Use this to set what sort of screen it is.Choose
  |  | 
 |         15 so the screen is a "Custom screen",which allows you all of the 
  |  | 
 |         options.
  |  | 
 | 
  |  | 
 |         screen_type:  dc.w  15      ;screen type:custom screen
  |  | 
 | 
  |  | 
 |         Next theres a pointer to the character set to be used for all
  |  | 
 |         output to the screen.If you don't want to install your own
  |  | 
 |         character set,just put a zero here,and the standard character set 
  |  | 
 |         is used.
  |  | 
 | 
  |  | 
 |         font:   dc.l  0         ;character set:standard
  |  | 
 | 
  |  | 
 |         Next theres a pointer to the text thats used as the name of the
  |  | 
 |         screen.The text ends with a zero,just like window names must. 
  |  | 
 | 
  |  | 
 |         title:  dc.l  name      ;pointer to title text
  |  | 
 | 
  |  | 
 |         Next comes a long word that defines the gadgets.These gadgets
  |  | 
 |         represent the functions,like "Bring forward",that can be accessed 
  |  | 
 |         via a mouse click in the screen.The long word in this table is a
  |  | 
 |         pointer to a list which specifies the gadgets.These aren't the
  |  | 
 |         system gadgets.However,you're only using system gadgets here,so
  |  | 
 |         put a zero here.
  |  | 
 | 
  |  | 
 |         gadgets:  dc.l  0        ;no gadgets
  |  | 
 | 
  |  | 
 |         Finally theres a long word that you only need if you want to use
  |  | 
 |         the special bitmap just for your screen.Since this isn't the case,
  |  | 
 |         just put a zero here.
  |  | 
 | 
  |  | 
 |         bitmap:  dc.l  0         ;no bitmap
  |  | 
 | 
  |  | 
 |         Thats it for the list entries that you need to define the screen. 
  |  | 
 |         You still need the text for the name of the screen.Enter the
  |  | 
 |         following:
  |  | 
 | 
  |  | 
 |         sname:   dc.b  'Our Screen',0    ;screen title
  |  | 
 | 
  |  | 
 |         Heres a quick overview of the list:
  |  | 
 | 
  |  | 
 |                align
  |  | 
 |         screen_defs:                  ;*The screen ta
  |  | 
 |         x_pos:        dc.w  0         ;X-position
  |  | 
 |         y_pos:        dc.w  0         ;Y-position
  |  | 
 |         width:        dc.w  320       ;width
  |  | 
 |         height:       dc.w  200       ;height
  |  | 
 |         depth:        dc.w  2         ;number of bitplanes
  |  | 
 |         detail_pen:   dc.b  0         ;colour of the text,etc...
  |  | 
 |         block_pen:    dc.b  1         ;background colour
  |  | 
 |         view_modes:   dc.w  2         ;representation mode
  |  | 
 |         screen_type:  dc.w  15        ;screen type:custom screen
  |  | 
 |         font:         dc.l  0         ;character set:standard
  |  | 
 |         title:        dc.l  sname     ;pointer to title text
  |  | 
 |         gadgets:      dc.l  0         ;no gadgets
  |  | 
 |         bitmap:       dc.l  0         ;no bit map
  |  | 
 |         sname:        dc.b  'Our Screen',0  ;screen title
  |  | 
 | 
  |  | 
 |         Once you've decided on the parameters,its very easy to open the
  |  | 
 |         screen.You need Intuitions OpenScreen function.Its offset is -198 
  |  | 
 |         and it only needs one parameter,the address of the parameter
  |  | 
 |         table.The program fragment looks like this:
  |  | 
 | 
  |  | 
 |         openscreen =-198
  |  | 
 |                bsr     openint            ;open intuition
  |  | 
 |                bsr     scropen            ;open screen
  |  | 
 |                ...
  |  | 
 |         scropen:                          ;*open screen
  |  | 
 |                move.l  intbase,a6         ;intuition base address in A6
  |  | 
 |                lea     screen_defs,a0     ;pointer to table
  |  | 
 |                jsr     openscreen(a6)     ;and open
  |  | 
 |                move.l  d0,screenhd        ;save screen handle
  |  | 
 |                rts                        ;return to main program
  |  | 
 |                ...
  |  | 
 |         screen_defs:                      ;table info follows
  |  | 
 | 
  |  | 
 |         Now the Amigas Workbench screen is covered by your screen.Now you 
  |  | 
 |         can do what you want with it until the program is done.Afterwards,
  |  | 
 |         the screen must be closed again,so that you can see the Workbench 
  |  | 
 |         screen again.
  |  | 
 |         Use the CloseScreen function (offset -66) to do this.The only
  |  | 
 |         parameter it needs is the pointer to the screen structure you got 
  |  | 
 |         back from the OpenScreen function.
  |  | 
 | 
  |  | 
 |         closescreen =-66
  |  | 
 |                ...
  |  | 
 |         scrclose:                         ;* close screen
  |  | 
 |                move.l  intbase,a6         ;intuition base address in A6
  |  | 
 |                move.l  screenhd,a0        ;screen handle in A0
  |  | 
 |                jsr     closescreen(a6)    ;clos screen
  |  | 
 |                rts                        ;done
  |  | 
 | 
  |  | 
 |         The long word that OpenScreen returned to you is a pointer to a
  |  | 
 |         screen structure that contains all the needed data about the
  |  | 
 |         screen.Besides the data which was given,there is a pointer in the 
  |  | 
 |         screen area for individual bit planes,etc...
  |  | 
 |         The form of this structure is fairly complicated and contains some
  |  | 
 |         data that you can't use.Several of the parameters are interesting,
  |  | 
 |         however.Heres a selection of usable parameters:
  |  | 
 | 
  |  | 
 |         No    Name              Function
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |         0     (NextScreen.L)    Pointer to next screen.
  |  | 
 |         4     (FirstWindow)     Pointer to first window structure
  |  | 
 |         8     (LeftEdge.W)      
  |  | 
 |         $A    (TopEdge.W)       Position of screen
  |  | 
 |         $C    (Width.W)         Width
  |  | 
 |         $E    (Height.W)        Height
  |  | 
 |         $10   (MouseY.W)
  |  | 
 |         $12   (MouseX.W)        Mouse position in the screen
  |  | 
 |         $14   (Flags.W)         Screen flags
  |  | 
 |         $16   (Title.L)         Pointer to title text
  |  | 
 |         $1A   (DefaultTitle)    Pointer to normal title
  |  | 
 |         $28   (Font.L)          Pointer to character set
  |  | 
 |         $C0   (Plane0.L)        Pointer to bitplane 0
  |  | 
 |         $C4   (Plane1.L)        Pointer to bitplane 1
  |  | 
 |         $C8   (Plane2.L)        Pointer to bitplane 2
  |  | 
 |         $CC   (Plane3.L)        Pointer to bitplane 3
  |  | 
 | 
  |  | 
 |         An example of an application for the plane pointer is writing and 
  |  | 
 |         using your own character routine.Next you want to move the address
  |  | 
 |         of the plane into an address register as follows:
  |  | 
 | 
  |  | 
 |                move.l  screenhd,a5        ;screen pointer in A5
  |  | 
 |                move.l  $c0(a5),a5         ;bitplane 0-pointer in A5
  |  | 
 | 
  |  | 
 |         If you want to try this,do the following:
  |  | 
 | 
  |  | 
 |                move.l  screenhd,a5        ;screen pointer in A5
  |  | 
 |                move.l  $c0(a5),a5         ;bitplane 0-pointer in A5
  |  | 
 |                move    #$20,d0            ;Counter D0=$20
  |  | 
 | 
  |  | 
 |         lop1:
  |  | 
 |                move    d0,(a5)            ;write counter bits in picture
  |  | 
 |                add.l   #80,a5             ;address+80,next line
  |  | 
 |                dbra    d0,lop1            ;continue until D0 < 0
  |  | 
 | 
  |  | 
 |         This program draws a white,square pattern that corresponds to the 
  |  | 
 |         bit pattern for the numbers $20 to 0.This isn't a particularly
  |  | 
 |         useful program,but it shows how easy it is to write from a machine
  |  | 
 |         language program directly to the screen.If you change the offset
  |  | 
 |         in the second line to $C4,the pattern is read.
  |  | 
 |         You can move the entire screen with the normal technique of moving
  |  | 
 |         the mouse pointer into the upper border and moving it up and down 
  |  | 
 |         with the left mouse key depressed.You can do the same with a
  |  | 
 |         program.
  |  | 
 |         Lets move the screen without the mouse.Use the joystick for
  |  | 
 |         demonstration purposes.Put the joystick in port two.As you saw in
  |  | 
 |         the chapter on the hardware register,you can read memory location 
  |  | 
 |         $DFF00C to find information about the joystick.You can find the
  |  | 
 |         direction the screen should be moved here.
  |  | 
 |         Moving the screen requires another Intuition function.You use the 
  |  | 
 |         MoveScreen function which as an offset of -162 and needs three
  |  | 
 |         parameters to do this.The parameters are:
  |  | 
 | 
  |  | 
 |         In A0   the pointer to the screen structure that you got back in
  |  | 
 |                 D0 when you opened the screen.(You saved it in "screenhd")
  |  | 
 |         In D1   the desired movement in the Y-direction,the vertical
  |  | 
 |                 direction.
  |  | 
 |         In D0   the horizontal movement in the X-direction.The varient
  |  | 
 |                 doesn't work so you can only move the screen vertically.
  |  | 
 | 
  |  | 
 |         Insert the following lines in your program:
  |  | 
 | 
  |  | 
 |         MoveScreen =-162
  |  | 
 |                ...
  |  | 
 |         scrmove:                          ;*move screen D0 to the right
  |  | 
 |                                           ;and D1 down
  |  | 
 |                move.l  intbase,a6         ;intuition base address in A6
  |  | 
 |                move.l  screenhd,a0        ;screen handle in A0
  |  | 
 |                clr.l   d0                 ;no horizontal movement
  |  | 
 |                jsr     movescreen(a6)     ;move screen
  |  | 
 |                rts                        ;done
  |  | 
 | 
  |  | 
 |         Now your looking at a complete program that goes through the
  |  | 
 |         following steps:
  |  | 
 | 
  |  | 
 |         1.  Opens the Intuition library
  |  | 
 |         2.  Opens the screen
  |  | 
 |         3.  Moves the screen in the direction specified by the joystick in
  |  | 
 |             port two
  |  | 
 |         4.  Closes the screen when the fire button is hit
  |  | 
 |         5.  Closes the Intuition library
  |  | 
 |         6.  Ends
  |  | 
 | 
  |  | 
 |         Here is the complete program including the subroutines,so you'll
  |  | 
 |         have it all in one spot:
  |  | 
 | 
  |  | 
 |         ;** Demo program to open and move a screen **
  |  | 
 | 
  |  | 
 |         movescreen   =-162
  |  | 
 |         openscreen   =-198
  |  | 
 |         closescreen  =-66
  |  | 
 |         closelibrary =-414
  |  | 
 |         openlib      =-408                ;open library
  |  | 
 |         execbase     = 4                  ;exec base address
  |  | 
 |         joy2         =$dff00c             ;joystick 2 data
  |  | 
 |         fire         =$bfe001             ;firebutton 2:bit 7
  |  | 
 | 
  |  | 
 |         run:
  |  | 
 |                bsr     openint            ;open intuition
  |  | 
 |                bsr     scropen            ;open screen
  |  | 
 |                move    joy2,d6            ;save joystick info
  |  | 
 | 
  |  | 
 |         loop:
  |  | 
 |                tst.b   fire               ;test fire button
  |  | 
 |                bpl     ende               ;pressed down:done
  |  | 
 |                move    joy2,d0            ;basic info in D0
  |  | 
 |                sub     d6,d0              ;subtract new data
  |  | 
 |                cmp     #$0100,d0          ;up?
  |  | 
 |                bne     noup               ;no
  |  | 
 |                move.l  #-1,d1             ;dy=-1 direction y
  |  | 
 |                bsr     scrmove            ;move up
  |  | 
 |                bra     loop
  |  | 
 | 
  |  | 
 |         noup:
  |  | 
 |                cmp     #$0001,d0          ;down?
  |  | 
 |                bne     loop               ;no
  |  | 
 |                move.l  #1,d1              ;dy=1
  |  | 
 |                bsr     scrmove            ;move down
  |  | 
 |                bra     loop
  |  | 
 | 
  |  | 
 |         ende:
  |  | 
 |                bsr     scrclose           ;close screen
  |  | 
 |                bsr     closeint           ;close intuition
  |  | 
 |                rts                        ;done!
  |  | 
 | 
  |  | 
 |         openint:                          ;*initialize and open system
  |  | 
 |                move.l  execbase,a6        ;exec base address
  |  | 
 |                lea     intname,a1         ;name of intuition library
  |  | 
 |                jsr     openlib(a6)        ;open intuition
  |  | 
 |                move.l  d0,intbase         ;save intuition base address
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         closeint:                         ;*close intuition
  |  | 
 |                move.l  execbase,a6        ;exec base address in A6
  |  | 
 |                move.l  intbase,a1         ;intuition base address in A1
  |  | 
 |                jsr     closelibrary(a6)   ;close intuition
  |  | 
 |                rts                        ;done
  |  | 
 | 
  |  | 
 |         scropen:                          ;*open screen
  |  | 
 |                move.l  intbase,a6         ;intuition base address in A6
  |  | 
 |                lea     screen_defs,a0     ;pointer to table
  |  | 
 |                jsr     openscreen(a6)     ;open
  |  | 
 |                move.l  d0,screenhd        ;save screen handle
  |  | 
 |                rts                        ;return to main program
  |  | 
 | 
  |  | 
 |         scrclose:                         ;*close screen
  |  | 
 |                move.l  intbase,a6         ;intuition base address in A6
  |  | 
 |                move.l  screenhd,a0        ;screen handle in A0
  |  | 
 |                jsr     closescreen(a6)    ;close screen
  |  | 
 |                rts                        ;done
  |  | 
 | 
  |  | 
 |         scrmove:                          ;move screen D0 right/D1 down
  |  | 
 |                move.l  intbase,a6         ;intuition base address in A6
  |  | 
 |                move.l  screenhd,a0        ;screen handle in A0
  |  | 
 |                clr.l   d0                 ;no horizontal movement
  |  | 
 |                jsr     movescreen(a6)     ;and move
  |  | 
 |                rts                        ;done
  |  | 
 |                align
  |  | 
 | 
  |  | 
 |         screen_defs:                      ;*screen table begins here
  |  | 
 |         x_pos:         dc.w  0            ;X-position
  |  | 
 |         y_pos:         dc.w  0            ;Y-position
  |  | 
 |         width:         dc.w  320          ;width
  |  | 
 |         height:        dc.w  200          ;height
  |  | 
 |         depth:         dc.w  2            ;number of bitplanes
  |  | 
 |         detail_pen:    dc.b  1            ;Text colour=white
  |  | 
 |         block_pen:     dc.b  3            ;background colour=red
  |  | 
 |         view_modes:    dc.w  2            ;representation mode
  |  | 
 |         screen_type    dc.w  15           ;screen type:custom screen
  |  | 
 |         font:          dc.l  0            ;standard character set
  |  | 
 |         title:         dc.l  sname        ;pointer to title text
  |  | 
 |         gadgets:       dc.l  0            ;no gadgets
  |  | 
 |         bitmap:        dc.l  0            ;no bit map
  |  | 
 |         intbase:       dc.l  0            ;base address of intuition
  |  | 
 |         screenhd:      dc.l  0            ;screen handle
  |  | 
 |         intname:       dc.b  'intuition.library',0
  |  | 
 |                align
  |  | 
 |         sname:         dc.b  'Our Screen',0   ;Screen title
  |  | 
 |                align
  |  | 
 |                end
  |  | 
 | 
  |  | 
 |         From this example,you can see how easy scrolling actually is.     
  |  | 
 |         Another easy thing to do is to use the DisplayBeep function.It as 
  |  | 
 |         an offset -96;the only parameter it needs is the screen pointer
  |  | 
 |         that you stored in the "screenhd"memory block.This function covers
  |  | 
 |         the screen with an orange colour for a short while.The screen is  
  |  | 
 |         not changed.The beep function can be used as follows:
  |  | 
 | 
  |  | 
 |         DisplayBeep: =-96
  |  | 
 |                ...
  |  | 
 |                move.l  intbase,a6         ;intuition base address in A6
  |  | 
 |                move.l  screenhd,a0        ;screen pointer in A0
  |  | 
 |                jsr     displaybeep(a6)    ;light up screen
  |  | 
 | 
  |  | 
 |         If you put a zero instead of a screen pointer in A0,the whole
  |  | 
 |         screen blinks.
  |  | 
 |         Good,now you have your own screen that you can move up and down.  
  |  | 
 |         What good is it if you can't put anything on it?Lets open a window
  |  | 
 |         on the screen!
  |  | 
 | 
  |  | 
 |       7.2.Open Window.
  |  | 
 |       ----------------
  |  | 
 |         As you saw in the chapter on program initialization,its easy to
  |  | 
 |         open a window with the DOS library.You can't use this method on
  |  | 
 |         your own screen however.You need to use another method that can
  |  | 
 |         open any window on any screen.
  |  | 
 |         Intuition has a function called OpenWindow which handles this sort
  |  | 
 |         of work.It has an offset of -204 and needs only one parameter,a
  |  | 
 |         pointer to a window definition table.This pointer goes in register
  |  | 
 |         A0.
  |  | 
 |         This table is very similar to the one used to define the screen.  
  |  | 
 |         The first four values specify the X-and Y-positions,the width,and
  |  | 
 |         the height of the window to be opened.Heres an example:
  |  | 
 | 
  |  | 
 |                align
  |  | 
 |         window_defs:
  |  | 
 |                        dc.w  10           ;x-position
  |  | 
 |                        dc.w  20           ;y-position
  |  | 
 |                        dc.w  300          ;width
  |  | 
 |                        dc.w  150          ;height
  |  | 
 | 
  |  | 
 |         Next come two bytes that define the colour of the letters on the  
  |  | 
 |         background:
  |  | 
 | 
  |  | 
 |                        dc.b  1            ;white letter colour
  |  | 
 |                        dc.b  3            ;on a red background
  |  | 
 | 
  |  | 
 |         The next long word contains the IDCMP flags in its bits.The bits  
  |  | 
 |         determine the circumstances under which Intuition sends a message 
  |  | 
 |         to the program.The bits have the following meanings:
  |  | 
 | 
  |  | 
 |         Bit  Value     Name             Meaning
  |  | 
 |         -----------------------------------------------------------------
  |  | 
 |          0   $000001   SIZEVERIFY
  |  | 
 |          1   $000002   NEWSIZE          Window size changed
  |  | 
 |          2   $000004   REFRESHWINDOW
  |  | 
 |          3   $000008   MOUSEBUTTONS     Mouse key hit
  |  | 
 |          4   $000010   MOUSEMOVE        Mouse moved
  |  | 
 |          5   $000020   GADGETDOWN       A special gadget chosen
  |  | 
 |          6   $000040   GADGETUP         Same as above
  |  | 
 |          7   $000080   REQSET
  |  | 
 |          8   $000100   MENUPICK         A menu item chosen
  |  | 
 |          9   $000200   CLOSEWINDOW      A window closed
  |  | 
 |         10   $000400   RAWKEY           A key pressed
  |  | 
 |         11   $000800   REQVERIFY
  |  | 
 |         12   $001000   REQCLEAR
  |  | 
 |         13   $002000   MENUVERIFY
  |  | 
 |         14   $004000   NEWPREFS         Preferences modified
  |  | 
 |         15   $008000   DISKINSERTED     A disk put in
  |  | 
 |         16   $010000   DISKREMOVED      A disk taken out
  |  | 
 |         17   $020000   WBENCHMESSAGE
  |  | 
 |         18   $040000   ACTIVEWINDOW     A window activated
  |  | 
 |         19   $080000   INACTIVEWINDOW   A window deactivated
  |  | 
 |         20   $100000   DELTAMOVE        Report relative mouse movement
  |  | 
 | 
  |  | 
 |         If you want your first window to respond only by clicking on the
  |  | 
 |         close symbol,write the following:
  |  | 
 | 
  |  | 
 |             dc.l  $200   ;IDCMP flags:CLOSEWINDOW
  |  | 
 | 
  |  | 
 |         Next comes a long word whose bits determine the windows type.You  
  |  | 
 |         can use this to construct a window to your exact specifications.  
  |  | 
 |         This is quite different from windows opened with the DOS function.
  |  | 
 |         The bits mean:
  |  | 
 | 
  |  | 
 |         Bit  Value     Name             Meaning
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |          0   $0000001  WINDOWSIZING     Window size is changeable
  |  | 
 |          1   $0000002  WINDOWDRAG       Window is moveable
  |  | 
 |          2   $0000004  WINDOWDEPTH      Window covering is posible
  |  | 
 |          3   $0000008  WINDOWCLOSE      Window close symbol
  |  | 
 |          4   $0000010  SIZEBRIGHT
  |  | 
 |          5   $0000020  SIZEBOTTOM
  |  | 
 |          6   $0000040  SIMPLE_REFRESH   New drawing manuel
  |  | 
 |          7   $0000080  SUPER_BITMAP     Save the windows contents
  |  | 
 |          8   $0000100  BACKDROP         Move window back
  |  | 
 |          9   $0000200  REPORTMOUSE      Report mouse co-ordinates
  |  | 
 |         10   $0000400  GIMMEZEROZERO
  |  | 
 |         11   $0000800  BORDERLESS       Window without border
  |  | 
 |         12   $0001000  ACTIVATE         Window active
  |  | 
 |         13   $0002000  WINDOWACTIVATE
  |  | 
 |         14   $0004000  INREQUEST
  |  | 
 |         15   $0008000  MENUSTATE
  |  | 
 |         16   $0010000  RMBTRAP          Right mouse key:no menu
  |  | 
 |         17   $0020000  NOCAREREFRESH    No refresh message
  |  | 
 |         24   $1000000  WINDOWREFRESH
  |  | 
 |         25   $2000000  WBENCHWINDOW
  |  | 
 | 
  |  | 
 |         To refresh is to rebuild the window contents when necessary,for
  |  | 
 |         instance when the windows size is changed.If none of the refresh
  |  | 
 |         bits are set,you're in Smart-Refresh-Mode.In this case,Intuition
  |  | 
 |         takes care of refreshing the window.This is the easiest method.
  |  | 
 |         If you choose the value $100F as the type for your example window,
  |  | 
 |         the window is active once its opened,and it has all the system
  |  | 
 |         gadgets:
  |  | 
 | 
  |  | 
 |              dc.l   $100F       ;ACTIVATE and all gadgets
  |  | 
 | 
  |  | 
 |         The next long word in the list allows you to use your own gadgets
  |  | 
 |         in the window.This long word is a pointer to the structure of a
  |  | 
 |         your gadget.Since you don't want this,just put a zero here.
  |  | 
 | 
  |  | 
 |              dc.l   0           ;first gadget:no gadgets of our own
  |  | 
 | 
  |  | 
 |         The next long word is a pointer to a graphics structure so you can
  |  | 
 |         design your own symbol for checking menu points.Put a zero here.
  |  | 
 |         You'll use the standard sign:
  |  | 
 | 
  |  | 
 |              dc.l   windowname  ;pointer to window name
  |  | 
 | 
  |  | 
 |         The next long word is a pointer to the screen structure that you
  |  | 
 |         got back after calling the OpenScreen function.The easiest way to
  |  | 
 |         do this is to save the pointer to this location in the buffer:
  |  | 
 | 
  |  | 
 |         screenhd:   dc.l 0   ;screen pointer
  |  | 
 | 
  |  | 
 |         The next long word is a pointer to a bit map if you want one of
  |  | 
 |         your own for the window.Since you don't want one,put a zero here.
  |  | 
 | 
  |  | 
 |                 dc.l  0        ;no bit map of our own
  |  | 
 | 
  |  | 
 |         Next come four values that set the maximum and minimum width and  
  |  | 
 |         height of the window:
  |  | 
 | 
  |  | 
 |                 dc.w  150      ;smallest width
  |  | 
 |                 dc.w  50       ;smallest height
  |  | 
 |                 dc.w  320      ;maximum width
  |  | 
 |                 dc.w  200      ;maximum height
  |  | 
 | 
  |  | 
 |         The last value in the list is the screen type of the screen the
  |  | 
 |         window is located in.Put a 15 here.You're using our screen as a   
  |  | 
 |         custom screen:
  |  | 
 | 
  |  | 
 |                 dc.w  15       ;screen type:custom screen
  |  | 
 | 
  |  | 
 |         Heres a quick overview of the whole list:
  |  | 
 | 
  |  | 
 |             align
  |  | 
 |         window_prefs:
  |  | 
 |                       dc.w   10           ;X-position
  |  | 
 |                       dc.w   20           ;Y-position
  |  | 
 |                       dc.w   300          ;width
  |  | 
 |                       dc.w   150          ;height
  |  | 
 |                       dc.b   1            ;white print colour
  |  | 
 |                       dc.b   3            ;on red background
  |  | 
 |                       dc.l   $200         ;IDCMP flags:CLOSEWINDOW
  |  | 
 |                       dc.l   $100f        ;ACTIVATE and all gadgets
  |  | 
 |                       dc.l   0            ;first gadget:no gadgets of
  |  | 
 |                                           ;our own
  |  | 
 |                       dc.l   0            ;checkmark:standard
  |  | 
 |                       dc.l   windowname   ;pointer to window name
  |  | 
 |         screenhd:     dc.l   0            ;screen pointer
  |  | 
 |                       dc.l   0            ;no bitmap of our own
  |  | 
 |                       dc.w   150          ;smallest width
  |  | 
 |                       dc.w   50           ;smallest height
  |  | 
 |                       dc.w   320          ;maximum width
  |  | 
 |                       dc.w   200          ;maximum height
  |  | 
 |                       dc.w   15           ;screen type:custom screen
  |  | 
 |  
  |  | 
 |         ;and here comes the window name:
  |  | 
 |         windowname:   dc.b   'Our Window',0
  |  | 
 |             align
  |  | 
 | 
  |  | 
 |         Insert these lines in the program you listed above.Here are two   
  |  | 
 |         subroutines for opening and closing the window:
  |  | 
 | 
  |  | 
 |         openwindow  =-204
  |  | 
 |         closewindow =-72
  |  | 
 |                ...
  |  | 
 |         windopen:
  |  | 
 |                move.l  intbase,a6        ;intuition base address in A6
  |  | 
 |                lea     windowdef,a0      ;pointer to window definition
  |  | 
 |                jsr     openwindow(a6)    ;open window
  |  | 
 |                move.l  d0,windowhd       ;save window handle
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         windclose:
  |  | 
 |                move.l  intbase,a6        ;intuition base address in A6
  |  | 
 |                move.l  windowhd,a0       ;window handle
  |  | 
 |                jsr     closewindow(a6)   ;close window
  |  | 
 |                rts
  |  | 
 |                ...
  |  | 
 |         windowhd:      dc.l   0          ;window handle
  |  | 
 | 
  |  | 
 |         Now you can insert a "bsr windowopen"after the "bsr scropen"and a 
  |  | 
 |         "bsr windclose"before the "bsr scrclose"command.Once you've
  |  | 
 |         started the program,move the window around in the screen.You'll
  |  | 
 |         find that you can't move the window out of the screen with the
  |  | 
 |         mouse. 
  |  | 
 |         The window in the example has the close gadget in the upper left
  |  | 
 |         corner.Normally if you click it,the window is closed.Try clicking
  |  | 
 |         it.You'll find that nothing happens.
  |  | 
 |         The display of this and all other gadgets,as well as other events
  |  | 
 |         must be programmed in,since Intuition doesn't know which action
  |  | 
 |         causes which event.We'll take a look at how to handle this in the 
  |  | 
 |         next chapter.
  |  | 
 | 
  |  | 
 |       7.3.Requesters.
  |  | 
 |       ---------------
  |  | 
 |         If you only have one disk drive,you've certainly seen the Amiga   
  |  | 
 |         message,"Please insert xxx in unit 0",a lot.This window is another
  |  | 
 |         that has two fields for clicking.This sort of message with a
  |  | 
 |         choice of options is called a requester.                          
  |  | 
 |         You want to take a look at how to program a requester.First,you
  |  | 
 |         need a window for the requester to appear in.You opened a window
  |  | 
 |         of this sort in the example program.
  |  | 
 |         To display a requester,use the Intuition function AutoRequest
  |  | 
 |         (offset -348).It takes care of drawing and managing the requester.
  |  | 
 |         This function needs the following parameters:
  |  | 
 | 
  |  | 
 |         In A0   The pointer to the window structure that you put in
  |  | 
 |                 "windowhd".
  |  | 
 |         In A1   A pointer to the text structure that should stand over the 
  |  | 
 |                 choice buttons.
  |  | 
 |         In A2   Same as above for the text of the left button.
  |  | 
 |         In A3   Same as above for the right button.
  |  | 
 |         In D0   The IDCMP flag which lets you know what event should go
  |  | 
 |                 with the clicking of the left button.
  |  | 
 |         In D1   Same as above for the right button.
  |  | 
 |         In D2   The width of the whole requester.
  |  | 
 |         In D3   The height of the requester.
  |  | 
 | 
  |  | 
 |         Insert the following lines in your program:
  |  | 
 | 
  |  | 
 |         autorequest =-348
  |  | 
 |                ...
  |  | 
 |         request:
  |  | 
 |                move.l  windowhd,a0       ;pointer to window structure
  |  | 
 |                lea     btext,a1          
  |  | 
 |                lea     ltext,a2          ;pointer to text structure
  |  | 
 |                lea     rtext,a3        
  |  | 
 |                move.l  #0,d0             ;left activates by clicking
  |  | 
 |                move.l  #0,d1             ;right activates by clicking
  |  | 
 |                move.l  #180,d2           ;width and
  |  | 
 |                move.l  #80,d3            ;height of requester
  |  | 
 |                move.l  intbase,a6        ;intuition base address
  |  | 
 |                jsr     autorequest(a6)   ;display requester
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         The flags passed in D0 and D1 offer some interesting posibilites. 
  |  | 
 |         The system messages that tells you to enter a particular disk are 
  |  | 
 |         overlooked when the DISKINSERTED flag is similar.Putting a disk in
  |  | 
 |         brings about the same responce as clicking the "Retry"button.
  |  | 
 |         Whats new is the use of a text structure.Use three of them.Text   
  |  | 
 |         structures are lists that contain entries for the text that you
  |  | 
 |         need. 
  |  | 
 |         These lists begin with two bytes that are used to define the
  |  | 
 |         colour.The first byte is the colour of the text.The second is for
  |  | 
 |         the background colour.Here this doesn't have any meaning.
  |  | 
 | 
  |  | 
 |         btext:
  |  | 
 |                dc.b    2                 ;black text colour
  |  | 
 |                dc.b    0                 ;background colour
  |  | 
 | 
  |  | 
 |         The next byte specifies the character mode.A zero means that the
  |  | 
 |         text is output normally.A four means the text is output inverted.
  |  | 
 | 
  |  | 
 |                dc.b    0                 ;normal text representation
  |  | 
 | 
  |  | 
 |         The next entries are words.For this reason the addresses must be
  |  | 
 |         even,so you need to either insert another byte or use the "align" 
  |  | 
 |         pseudo-op.The following words are the X-and Y-position of the text
  |  | 
 |         relative to the upper left corner of the requester.
  |  | 
 | 
  |  | 
 |                dc.w    10                ;X-position
  |  | 
 |                dc.w    5                 ;Y-position relative to upper
  |  | 
 |                                          ;left corner
  |  | 
 | 
  |  | 
 |         Next,theres a pointer to the character set that is used.Put a zero
  |  | 
 |         here to use the standard set.
  |  | 
 | 
  |  | 
 |                dc.l    0                 ;standard character set
  |  | 
 | 
  |  | 
 |         Next you need to give the address of the text that should be
  |  | 
 |         output.This text must be closed with a null byte.
  |  | 
 | 
  |  | 
 |                dc.l    text              ;pointer to text
  |  | 
 | 
  |  | 
 |         You need a long word at the end of the list that is either a
  |  | 
 |         pointer to another text or a zero if no more text is needed.
  |  | 
 | 
  |  | 
 |                dc.l    0                 ;no more text
  |  | 
 | 
  |  | 
 |         Here are the three text structures that you need for the example:
  |  | 
 | 
  |  | 
 |         btext:                           ;text structure for the title
  |  | 
 |                dc.b    0,1               ;colour
  |  | 
 |                dc.b    0                 ;mode
  |  | 
 |                align
  |  | 
 |                dc.w    10,10             ;text position
  |  | 
 |                dc.l    0                 ;standard font
  |  | 
 |                dc.l    bodytxt           ;pointer to text
  |  | 
 |                dc.l    0                 ;no more text
  |  | 
 | 
  |  | 
 |         bodytxt:
  |  | 
 |                dc.b    "Requester Text",0
  |  | 
 |                align
  |  | 
 |         ltext:                           ;text structure of left button
  |  | 
 |                dc.b    0,1               ;colour
  |  | 
 |                dc.b    0                 ;mode
  |  | 
 |                align 
  |  | 
 |                dc.w    5,3               ;text position
  |  | 
 |                dc.l    0                 ;standard font
  |  | 
 |                dc.l    lefttext          ;pointer to text
  |  | 
 |                dc.l    0                 ;no more text
  |  | 
 | 
  |  | 
 |         lefttext:
  |  | 
 |                dc.b    "left",0
  |  | 
 |                align
  |  | 
 | 
  |  | 
 |         rtext:
  |  | 
 |                dc.b    0,1               ;colour
  |  | 
 |                dc.b    0                 ;mode
  |  | 
 |                align
  |  | 
 |                dc.w    5,3               ;text position
  |  | 
 |                dc.l    0                 ;standard font
  |  | 
 |                dc.l    righttext         ;pointer to text
  |  | 
 |                dc.l    0                 ;no more text
  |  | 
 | 
  |  | 
 |         righttext:
  |  | 
 |                dc.b    "right",0
  |  | 
 |                align
  |  | 
 | 
  |  | 
 |         After calling the requester,D0 contains the information about
  |  | 
 |         which of the buttons were pressed,and in which button the event
  |  | 
 |         took place.If D0 is zero,it was the right button.If it is one,it
  |  | 
 |         was the left button.
  |  | 
 | 
  |  | 
 |       7.4.Event Handling.
  |  | 
 |       -------------------
  |  | 
 |         Pretend you've opened a window that as a close symbol,and you want
  |  | 
 |         the program to react to this symbol being clicked.You need a
  |  | 
 |         signal from Intuition that lets you know that an event as taken
  |  | 
 |         place.The signal is called a message.
  |  | 
 |         The IDCMP flag of the window specifies which events should cause
  |  | 
 |         Intuition to send a message.By setting the bits for WINDOWCLOSE,  
  |  | 
 |         you can allow a message to be sent when the close symbol is
  |  | 
 |         clicked.
  |  | 
 |         To get the message,you can use the EXEC function GetMsg (offset
  |  | 
 |         -372).It needs the source address of the event as a parameter.Here
  |  | 
 |         the source is the User port (which doesn't have anything to do
  |  | 
 |         with the User port on old Commodore computors).
  |  | 
 |         The User port contains a table which has entrieswhich specify the
  |  | 
 |         events that have taken place and related things like mouse
  |  | 
 |         position and time.
  |  | 
 |         How do you find the User port?Use the pointer to the window
  |  | 
 |         structure that you got back from the OpenWindow function and
  |  | 
 |         stored in the "windowhd"memory block.
  |  | 
 |         This pointer points to the window structure of this window.This
  |  | 
 |         structure consists of a number of entries.Some are copies of the
  |  | 
 |         parameters from our window definition table.We won't cover all the
  |  | 
 |         entries,because most won't be interesting to you.You're more
  |  | 
 |         interested in the pointer to the User port.Its in the window
  |  | 
 |         structure.
  |  | 
 |         You can find this in the long word that begins in the 86th byte of
  |  | 
 |         the structure.You can get this long word with the following lines
  |  | 
 |         of code:
  |  | 
 | 
  |  | 
 |                move.l  windowhd,a0       ;pointer to structure in A0
  |  | 
 |                move.l  86(a0),a0         ;user port pointer in A0
  |  | 
 | 
  |  | 
 |         You can call the GetMsg function with this pointer in A0 by using 
  |  | 
 |         the following lines of code in your program:
  |  | 
 | 
  |  | 
 |         GetMsg  = -372
  |  | 
 |                ...
  |  | 
 |                move.l  windowhd,a0       ;pointer to structure in A0
  |  | 
 |                move.l  86(a0),a0         ;user port pointer in A0
  |  | 
 |                move.l  execbase,a6       ;exec base address in A6
  |  | 
 |                jsr     getmsg(a6)        ;get message
  |  | 
 | 
  |  | 
 |         This function returns a value in the D0 register.This value is a  
  |  | 
 |         pointer to another structure,the Intuition Message Structure.If
  |  | 
 |         theres a zero in D0,no event as taken place.
  |  | 
 |         The long word that starts at the 20th byte in this structure
  |  | 
 |         contains the information about which event took place.Evaluating
  |  | 
 |         the information is easy,since the bits of this long word have the 
  |  | 
 |         same meaning as the IDCMP flag that you described when you looked 
  |  | 
 |         at opening windows.
  |  | 
 |         Put the lines above after "loop"and then insert the following:
  |  | 
 | 
  |  | 
 |                move.l  d0,a0             ;message pointer in A0
  |  | 
 |                move.l  20(a0),d6         ;save event in D6
  |  | 
 |                tst.l   d0                ;did the event take place?
  |  | 
 |                bne     end               ;yes!
  |  | 
 | 
  |  | 
 |         Now you can end this program by clicking the close symbol.This way
  |  | 
 |         you can find out if an event as taken place.You can use D6 to
  |  | 
 |         determine what event took place.In the example,D6 contains the
  |  | 
 |         number $00000200,which means that the close symbol was clicked.
  |  | 
 |         To see if this works with other events,change the $200 IDCMP flag
  |  | 
 |         to $10200 in the window definition table.When you've assembled and
  |  | 
 |         started this version,take the disk out of the drive-the program
  |  | 
 |         terminates.
  |  | 
 |         The IDCMP flags that you've got now cause the clicking of the
  |  | 
 |         close symbol and the taking out of the disk (DISKREMOVED) to be
  |  | 
 |         reported.If you want to find out which of the events took place,  
  |  | 
 |         you can look in D6.It has a $200 in it if the window is closed,a  
  |  | 
 |         $10000 if the disk was removed.
  |  | 
 | 
  |  | 
 |       7.5.Menu Programming.
  |  | 
 |       ---------------------
  |  | 
 |         Now lets look at one of Intuitions more interesting capabillities:
  |  | 
 |         menu programming.By using menus,you can make your programs very
  |  | 
 |         user friendly.
  |  | 
 |         There are a lot of ways for you to use menus.You can make menu
  |  | 
 |         points unusable,output sub-menus,choose the type of menu entries  
  |  | 
 |         (allow text or pictures to be output),etc..To have lots of options
  |  | 
 |         you need some parameters.
  |  | 
 |         Lets produce a menu with the SetMenuStrip function (offset -264)
  |  | 
 |         of Intuition.The function only needs two parameters,a pointer to
  |  | 
 |         the menu structure of the window to be drawn and a pointer to the 
  |  | 
 |         window structure of the window in which the menu is to function.  
  |  | 
 |         Each window can have its own menu that is active when the window
  |  | 
 |         is activated.
  |  | 
 |         Heres the subroutine to set up the menu:
  |  | 
 | 
  |  | 
 |         SetMenuStrip =-264
  |  | 
 |                ...
  |  | 
 |         setmenu:                         ;* Initialize a menu
  |  | 
 |                move.l  intbase,a6        ;intuition base address in A6
  |  | 
 |                move.l  windowhd,a0       ;pointer to window structure
  |  | 
 |                lea     menu,a1           ;pointer to menu structure
  |  | 
 |                jsr     setmenustrip(a6)  ;call function
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         Heres a routine to erase the menu:
  |  | 
 | 
  |  | 
 |         ClearMenuStrip =-54
  |  | 
 |                ...
  |  | 
 |         clearmenu:
  |  | 
 |                move.l  intbase,a6        ;intuition base address in A6
  |  | 
 |                move.l  windowhd,a0       ;pointer to window structure
  |  | 
 |                jsr     clearmenustrip(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         You've already got the pointer to the window structure.Lets look
  |  | 
 |         at the menu structure you need for the menu.You need to build a
  |  | 
 |         structure like this for each menu--for each menu title that
  |  | 
 |         appears when you press the right mouse key.
  |  | 
 |         This structure is a table with the following form:
  |  | 
 | 
  |  | 
 |         First there is a long word that points to the menu structure of
  |  | 
 |         the next menu.If the current menu is the last one,a zero goes
  |  | 
 |         here.
  |  | 
 | 
  |  | 
 |                align
  |  | 
 |         menu:
  |  | 
 |                dc.l    menu1             ;pointer to the next menu
  |  | 
 | 
  |  | 
 |         Next come two words which contain tha X- and Y-position of the
  |  | 
 |         menu title:
  |  | 
 | 
  |  | 
 |                dc.w    20                ;X-position
  |  | 
 |                dc.w    0                 ;Y-position
  |  | 
 | 
  |  | 
 |         Next,use two words to store the menu titles width and height in
  |  | 
 |         pixels:
  |  | 
 | 
  |  | 
 |                dc.w    50                ;width
  |  | 
 |                dc.w    10                ;height of menu title
  |  | 
 | 
  |  | 
 |         The next word contains the flag bit that determines whether the
  |  | 
 |         menu is available or not.An unavailable menu either as grey
  |  | 
 |         entries or they are drawn weakly.If the flag bit,bit 0,is set the 
  |  | 
 |         menu is available.Otherwise,it is not.
  |  | 
 | 
  |  | 
 |                dc.w    1                 ;menu available
  |  | 
 | 
  |  | 
 |         Now comes a long word which functions as a pointer to the text
  |  | 
 |         which is used as the menu title.Make sure the length isn't larger 
  |  | 
 |         than the width entry allows!Otherwise unpleasent things will
  |  | 
 |         happen.
  |  | 
 | 
  |  | 
 |                dc.l    menutext          ;pointer to title text
  |  | 
 | 
  |  | 
 |         Next comes a long word which functions as a pointer to the
  |  | 
 |         structure of the first menu entry of this menu.Each menu entry
  |  | 
 |         needs its own structure. 
  |  | 
 | 
  |  | 
 |                dc.l    menuitem01        ;pointer to the first menu item
  |  | 
 | 
  |  | 
 |         The last entries in the table are four words that are reserved for
  |  | 
 |         internal functions.They must be here.
  |  | 
 | 
  |  | 
 |                dc.w    0,0,0,0           ;reserved words
  |  | 
 | 
  |  | 
 |         Thats the structure of the first menu.This structures first long
  |  | 
 |         word points to the next structure which has the same form.The
  |  | 
 |         pointer is set to zero in the last menu.
  |  | 
 |         You still need the structure of the menu entries.These structure
  |  | 
 |         tables have the following form:
  |  | 
 | 
  |  | 
 |         They start with a pointer to the next menu item.This pointer is
  |  | 
 |         set to zero for the last entry.
  |  | 
 | 
  |  | 
 |                align
  |  | 
 |         menuitem01:
  |  | 
 |                dc.l    menuitem02        ;pointer to next menu item
  |  | 
 | 
  |  | 
 |         Next comes the four words:the X- and Y-position,the width and the 
  |  | 
 |         height of the box the menu entry goes in.The size becomes obvious 
  |  | 
 |         when the item is chosen by having the right mouse key clicked on
  |  | 
 |         it.Then the box becomes visible.As you can see,the next word is   
  |  | 
 |         determined in the flags.First lets set the position and size of
  |  | 
 |         the menu point,though:
  |  | 
 | 
  |  | 
 |                dc.w    0                 ;X-position of entry
  |  | 
 |                dc.w    0                 ;Y-position
  |  | 
 |                dc.w    90                ;width in pixels
  |  | 
 |                dc.w    10                ;height in pixels
  |  | 
 | 
  |  | 
 |         The position entries are relative to the upper left corner of the 
  |  | 
 |         menu that is pulled down.
  |  | 
 |         The following word was described above:it contains flags for
  |  | 
 |         entries to this menu item.There are several interesting variations
  |  | 
 |         possible.The following flag bits are contained in this word:
  |  | 
 | 
  |  | 
 |         Bit   Value   Name          Meaning When Set
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |          0    $0001   CHECKIT       Point is checked when chosen
  |  | 
 |          1    $0002   ITEMTEXT      Text menu item
  |  | 
 |          2    $0004   COMMSEQ       Choice can be made with keys as well
  |  | 
 |          3    $0008   MENUTOGGLE    Check turned on and off
  |  | 
 |          4    $0010   ITEMENABLED   Menu item available
  |  | 
 |          6    $0040   HIGHCOMP      Item inverted when chosen
  |  | 
 |          7    $0080   HIGHBOX       Iten framed when chosen
  |  | 
 |          8    $0100   CHECKED       Item is checked
  |  | 
 | 
  |  | 
 |         Heres a description of the bits:
  |  | 
 | 
  |  | 
 |         Name           Description
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |         CHECKIT        If this bit is set,a check or a user-defined
  |  | 
 |                        drawing is put in front of the text when the item  
  |  | 
 |                        is chosen.The text should begin with two blanks.
  |  | 
 |         
  |  | 
 |         ITEMTEXT       The menu item is a normal text if this bit is set. 
  |  | 
 |                        Otherwise a drawing is output.
  |  | 
 | 
  |  | 
 |         COMMSEQ        By setting this bit and entering a character,this  
  |  | 
 |                        menu point can be chosen by pressing the right
  |  | 
 |                        <Amiga> key and the key that was input.The input   
  |  | 
 |                        character is then displayed in the menu with the
  |  | 
 |                        Amiga symbol.There needs to be space available for 
  |  | 
 |                        this.
  |  | 
 | 
  |  | 
 |         MENUTOGGLE     If this bit is set and checking is allowed (bit 0),
  |  | 
 |                        the second time this point is chosen the check is
  |  | 
 |                        erased,the next time it is displayed again,etc...
  |  | 
 | 
  |  | 
 |         ITEMENABLED    Erasing this bit makes the menu item available.
  |  | 
 | 
  |  | 
 |         HIGHCOMP       If this bit is set,the box you've defined is
  |  | 
 |                        inverted when this menu item is chosen by the mouse
  |  | 
 |                        pointer.
  |  | 
 | 
  |  | 
 |         HIGHBOX        In this mode,the box is framed whin its chosen.
  |  | 
 | 
  |  | 
 |         The two previous bits determine the mode of the chosen menu item. 
  |  | 
 |         The following combinations are possible:
  |  | 
 | 
  |  | 
 |         HIGHIMAGE      If both bits are cleared,choosing the bit causes a 
  |  | 
 |                        self-defined drawing to be output.
  |  | 
 | 
  |  | 
 |         HIGHNONE       When both bits are set,there isn't any reaction to 
  |  | 
 |                        choosing this item.
  |  | 
 | 
  |  | 
 |         CHECKED        This bit can be set by either the program or
  |  | 
 |                        Intuition.It lets you know if the menu text has a
  |  | 
 |                        check next to it or not.You can use this to find
  |  | 
 |                        out if the item was checked by testing but eight.If
  |  | 
 |                        its set,the item was checked.You can also use it to
  |  | 
 |                        cause the item to be checked.
  |  | 
 | 
  |  | 
 |         You're choosing the mode CHECKIT,ITEMTEXT,COMMSEQ,MENUTOGGLE,ITEM-
  |  | 
 |         ENABLED and HIGHBOX for the example:
  |  | 
 | 
  |  | 
 |               dc.w    $10011111         ;mode flag
  |  | 
 | 
  |  | 
 |         Lets get back to the structure of the menu items.After the flag
  |  | 
 |         word,there is a long word whose flag bits determine whether this  
  |  | 
 |         menu point can be turn off another one.Set this to zero:
  |  | 
 | 
  |  | 
 |               dc.l    0                 ;no connection
  |  | 
 | 
  |  | 
 |         Now comes the pointer to the structure of the text that should be 
  |  | 
 |         displayed.If the ITEMTEXT bit isn't set,this pointer must point to
  |  | 
 |         the structure of the drawing.If nothing should be shown,you can
  |  | 
 |         set this to zero.Use a text in the example and write the
  |  | 
 |         following:
  |  | 
 | 
  |  | 
 |               dc.l    menu01text        ;pointer to menu text structure
  |  | 
 | 
  |  | 
 |         The following long word only has a meaning if the HIGHIMAGE flag
  |  | 
 |         is set.Then this long word points to the text or the drawing that 
  |  | 
 |         should be displayed when the menu items box is clicked.Otherwise  
  |  | 
 |         the long word is ignored,so insert a zero:
  |  | 
 | 
  |  | 
 |               dc.l    0                 ;no drawing when clicked
  |  | 
 | 
  |  | 
 |         The next entry is a byte that is used for input of keyboard
  |  | 
 |         characters,which together with the right <Amiga> key can be used
  |  | 
 |         to choose the menu item.This only works if the COMMSEQ bit is set.
  |  | 
 |         Place a character here:
  |  | 
 | 
  |  | 
 |               dc.b    'A'               ;choose item using <Amiga>/'A'
  |  | 
 | 
  |  | 
 |         Since the next item is a long word,you need an "align"peudo-op
  |  | 
 |         here.Next comes the long word that points to the menu item
  |  | 
 |         structure or a submenu.The submenu is automatically shown when
  |  | 
 |         this menu item is clicked.You can't nest them any deeper,however, 
  |  | 
 |         so this long word is ignored for submenus.
  |  | 
 |         If you don't want a submenu to this item,put a zero here:
  |  | 
 | 
  |  | 
 |           align
  |  | 
 |               dc.l    0                 ;no submenu
  |  | 
 | 
  |  | 
 |         The next and final long word is written to by Intuition if you
  |  | 
 |         choose several menu itens.In this case,the menu number of the next
  |  | 
 |         menu item chosen goes here:
  |  | 
 | 
  |  | 
 |               dc.l    0                 ;preparation
  |  | 
 | 
  |  | 
 |         Thats the structure for a menu item.You still need the text
  |  | 
 |         structure for the text of the item.This isn't complicated,but it
  |  | 
 |         makes you get into fine details about the form of the menu.You've 
  |  | 
 |         already learned about this text structure when you looked at
  |  | 
 |         requesters,so we'll skip an explanation.
  |  | 
 |         Heres the complete structure of an example menu.You can use two
  |  | 
 |         menus,each with two subpoints.The second menu point of the left
  |  | 
 |         menu has a submenu with two entries.You ought to type this program
  |  | 
 |         in,so that you can experiment with it.You can also use this
  |  | 
 |         example to evaluate the clicked menu item.
  |  | 
 | 
  |  | 
 |         ;**Complete menu structure foe example menu **
  |  | 
 |         menu:
  |  | 
 |                dc.l menu1         ;no next menu
  |  | 
 |                dc.w 10,30         ;X/Y
  |  | 
 |                dc.w 50,10         ;width/height
  |  | 
 |                dc.w 1             ;menu enabled
  |  | 
 |                dc.l menuname      ;menu title
  |  | 
 |                dc.l menuitem01    ;menu entry
  |  | 
 |         menuname:
  |  | 
 |                dc.b "Menu 1",0    ;first menu name
  |  | 
 |            align
  |  | 
 |         menu1:
  |  | 
 |                dc.l 0             ;no further menu
  |  | 
 |                dc.w 80,0          ;see above
  |  | 
 |                dc.w 50,10
  |  | 
 |                dc.w 1
  |  | 
 |                dc.l menuname1
  |  | 
 |                dc.l menuitem11
  |  | 
 |                dc.w 0,0,0,0
  |  | 
 |         menuname1:
  |  | 
 |                dc.b "Menu 2",0    ;second menu name
  |  | 
 |            align
  |  | 
 |         menuitem01:               ;first menu item
  |  | 
 |                dc.l menuitem02    ;pointer to next entry
  |  | 
 |                dc.w 0,0           ;X/Y
  |  | 
 |                dc.w 130,12        ;width/height
  |  | 
 |                dc.w $9f           ;flags
  |  | 
 |                dc.l 0             ;exclude
  |  | 
 |                dc.l text01        ;pointer to text structure
  |  | 
 |                dc.l 0             ;select fill
  |  | 
 |                dc.b "1"           ;command
  |  | 
 |            align
  |  | 
 |                dc.l 0             ;subitem:none
  |  | 
 |                dc.w 0             ;next select:no
  |  | 
 |         text01:
  |  | 
 |                dc.b 0,1           ;colours
  |  | 
 |                dc.b 0             ;mode:overwrite
  |  | 
 |            align
  |  | 
 |                dc.w 5,3           ;X/Y position
  |  | 
 |                dc.l 0             ;standard character set
  |  | 
 |                dc.l text01txt     ;pointer to text
  |  | 
 |                dc.l 0             ;no more text
  |  | 
 |         text01txt:
  |  | 
 |                dc.b "Point 0.1",0
  |  | 
 |            align
  |  | 
 |         menuitem02:               ;second menu item
  |  | 
 |                dc.l 0
  |  | 
 |                dc.w 0,10
  |  | 
 |                dc.w 130,12
  |  | 
 |                dc.w $57
  |  | 
 |                dc.l 0
  |  | 
 |                dc.l text02
  |  | 
 |                dc.l 0
  |  | 
 |                dc.b "2"           ;activate with <Amiga>/'2'
  |  | 
 |            align
  |  | 
 |                dc.l 0
  |  | 
 |                dc.w 0
  |  | 
 |         text02:
  |  | 
 |                dc.b 0,1
  |  | 
 |                dc.b 0
  |  | 
 |            align
  |  | 
 |                dc.w 5,3
  |  | 
 |                dc.l 0
  |  | 
 |                dc.l text02txt
  |  | 
 |                dc.l 0
  |  | 
 |         text02txt:
  |  | 
 |                dc.b "Point 0.2",0
  |  | 
 |            align
  |  | 
 |         menuitem11:               ;first menu point of the second menu
  |  | 
 |                dc.l menuitem12    ;pointer to second menu point
  |  | 
 |                dc.w 0,0
  |  | 
 |                dc.w 90,12
  |  | 
 |                dc.w $52
  |  | 
 |                dc.l 0 
  |  | 
 |                dc.l text11
  |  | 
 |                dc.l 0
  |  | 
 |                dc.b 0
  |  | 
 |            align
  |  | 
 |                dc.l 0
  |  | 
 |                dc.w 0
  |  | 
 |         text11:
  |  | 
 |                dc.b 0,1
  |  | 
 |                dc.b 0
  |  | 
 |            align
  |  | 
 |                dc.w 5,3
  |  | 
 |                dc.l 0
  |  | 
 |                dc.l text11txt
  |  | 
 |                dc.l 0
  |  | 
 |         text11txt:
  |  | 
 |                dc.b "Point 1.1",0
  |  | 
 |            align
  |  | 
 |         menuitem12:               ;second menu item of second menu
  |  | 
 |                dc.l 0             ;no more items
  |  | 
 |                dc.w 0,10
  |  | 
 |                dc.w 90,12
  |  | 
 |                dc.w $92
  |  | 
 |                dc.l 0
  |  | 
 |                dc.l text12
  |  | 
 |                dc.l 0
  |  | 
 |                dc.b 0
  |  | 
 |            align
  |  | 
 |                dc.l submenu0      ;pointer to submenu
  |  | 
 |                dc.w 0
  |  | 
 |         text12:
  |  | 
 |                dc.b 0,1
  |  | 
 |                dc.b 0
  |  | 
 |            align
  |  | 
 |                dc.w 5,3
  |  | 
 |                dc.l 0
  |  | 
 |                dc.l text12txt
  |  | 
 |                dc.l 0
  |  | 
 |         text12txt:
  |  | 
 |                dc.b "Point 1.2",0
  |  | 
 |            align
  |  | 
 |         submenu0:                 ;first point of submenu
  |  | 
 |                dc.l submenu1      ;pointer to next point
  |  | 
 |                dc.w 80,5
  |  | 
 |                dc.w 90,12
  |  | 
 |                dc.w $52
  |  | 
 |                dc.l 0
  |  | 
 |                dc.l texts0
  |  | 
 |                dc.l 0
  |  | 
 |                dc.b 0
  |  | 
 |            align
  |  | 
 |                dc.l 0
  |  | 
 |                dc.w 0
  |  | 
 |         texts0:
  |  | 
 |                dc.b 0,1
  |  | 
 |                dc.b 0
  |  | 
 |            align
  |  | 
 |                dc.w 5,3
  |  | 
 |                dc.l 0,texts0txt,0
  |  | 
 |         texts0txt:
  |  | 
 |                dc.b "S Point 1",0
  |  | 
 |            align
  |  | 
 |         submenu1:                 ;submenu,second item
  |  | 
 |                dc.l 0
  |  | 
 |                dc.w 80,15
  |  | 
 |                dc.w 90,12
  |  | 
 |                dc.w $52
  |  | 
 |                dc.l 0
  |  | 
 |                dc.l texts1
  |  | 
 |                dc.l 0
  |  | 
 |                dc.b 0
  |  | 
 |            align
  |  | 
 |                dc.l 0
  |  | 
 |                dc.w 0
  |  | 
 |         texts1:
  |  | 
 |                dc.b 0,1
  |  | 
 |                dc.b 0
  |  | 
 |            align
  |  | 
 |                dc.w 5,3
  |  | 
 |                dc.l 0
  |  | 
 |                dc.l texts1txt
  |  | 
 |                dc.l 0
  |  | 
 |         texts1txt:
  |  | 
 |                dc.b "S Point 2",0
  |  | 
 |            align
  |  | 
 | 
  |  | 
 |         The menu items in this example have the following properties as a 
  |  | 
 |         result of their flags:
  |  | 
 | 
  |  | 
 |       Menu 1;
  |  | 
 |         The first item,"Point 0.1",can be chosen using the right <Amiga>
  |  | 
 |         key and the "1" key.This point alternates between checked and not 
  |  | 
 |         checked,which can easily be used to check out the key function.If
  |  | 
 |         the item is checked and you hit both keys,the check disappears and
  |  | 
 |         vice versa.The box at this point is framed when the mouse pointer 
  |  | 
 |         clicks on it.
  |  | 
 |         The second item,"Point 0.2",can be chosen using the right <Amiga> 
  |  | 
 |         key and the "2"key.This item is checked the first time it is
  |  | 
 |         chosen.However,in contrast to the item above,it can't be erased.  
  |  | 
 |         The box of this item is inverted when clicked.
  |  | 
 | 
  |  | 
 |       Menu 2;
  |  | 
 |         These two points can't be chosen using keys.The box of the upper  
  |  | 
 |         item is inverted when clicked on:the lower one is framed.When you 
  |  | 
 |         click the second item,"Point 1.2",a submenu with two entries is
  |  | 
 |         displayed.
  |  | 
 | 
  |  | 
 |         Experiment with this structure a little bit.Change some values and
  |  | 
 |         see what happens.As you can see,menu programming isn't as bad as
  |  | 
 |         you thought,and it offers a lot of options (but you'll have to do
  |  | 
 |         lots of typing!).
  |  | 
 |         When you've done experimenting,you'll want to produce your own
  |  | 
 |         program with menus.How does the program find whether a menu item
  |  | 
 |         in a menu has been clicked on?
  |  | 
 |         You already looked at one way to find out the menus state.You can
  |  | 
 |         test the CHECKED bit in the flag word of a menu item.If this is
  |  | 
 |         set,the user clicked on this item with the mouse.
  |  | 
 |         This only works if checking is allowed for the item being tested. 
  |  | 
 |         You could allow all the menu items to be checked,but this still
  |  | 
 |         isn't a good solution--it requires testing all the flag bits of
  |  | 
 |         all the menus one after the other.That makes very boring
  |  | 
 |         programming.
  |  | 
 |         You've already learned about finding about events from Intuition. 
  |  | 
 |         You've moved the message about which event took place into D6,and 
  |  | 
 |         you can look at it to find out what happend.
  |  | 
 |         If you set the eight bit,the MENUPICK bit,of the IDCMP flag long
  |  | 
 |         word in the window definition,the choice of the menu point is
  |  | 
 |         reported.Put the following lines in your loop in the main program.
  |  | 
 | 
  |  | 
 |         loop:
  |  | 
 |                move.l  execbase,a6      ;exec base address in A6
  |  | 
 |                move.l  windowhd,a0      ;window structure pointer
  |  | 
 |                move.l  86(a0),a0        ;user point pointer in A0
  |  | 
 |                jsr     getmsg(a6)       ;get message
  |  | 
 |                tst,l   d0               ;whay happend?
  |  | 
 |                beq     loop             ;nothing happend
  |  | 
 |                move.l  d0,a0            ;message pointer in A0
  |  | 
 |                move.l  $14(a0),d6       ;event in D6
  |  | 
 | 
  |  | 
 |         If the program makes it out of the loop,an event as taken place.  
  |  | 
 |         You have the events flag in the D6 register.You can evaluate the  
  |  | 
 |         event using CMP or BTST to find out which flag bits are set.You
  |  | 
 |         can then execute the function corresponding to the set bit.You can
  |  | 
 |         use lines like the following ones:
  |  | 
 | 
  |  | 
 |                cmp     #$200,d6         ;WINDOWCLOSE?
  |  | 
 |                beq     ende             ;yes:program end
  |  | 
 | 
  |  | 
 |         These lines terminate the program when the window is closed.
  |  | 
 | 
  |  | 
 |         If the user chose a menu item,there is a $100 in the D6 register.
  |  | 
 |         You now need to determine which item it was.
  |  | 
 |         You can find this information in a word that comes right after the
  |  | 
 |         long word with the event flags in the message structure.Write:
  |  | 
 | 
  |  | 
 |                move    $18(a0),d7
  |  | 
 | 
  |  | 
 |         You now have the code for the clicked menu item in the D7
  |  | 
 |         register.If the user just pressed the right key and let it go
  |  | 
 |         without choosing a menu item,you'll find a $FFFF here.This word
  |  | 
 |         doesn't contain just one,but three pieces of information:
  |  | 
 | 
  |  | 
 |           Which menu was the item chosen from?
  |  | 
 |           Which menu item?
  |  | 
 |           Which submenu?
  |  | 
 | 
  |  | 
 |         The information is divided in three bit groups.The division is as 
  |  | 
 |         follows:
  |  | 
 | 
  |  | 
 |         Bits  0-4   Menu title number
  |  | 
 |         Bits  5-10  Menu item number
  |  | 
 |         Bits 11-15  Submenu item number
  |  | 
 | 
  |  | 
 |         The numbering begins with zero-ie the first menu point of the
  |  | 
 |         first menu has the numbers 0 and 0.
  |  | 
 |         
  |  | 
 |         To try this out insert the following lines:
  |  | 
 | 
  |  | 
 |                move    d7,d6            ;move code into D6
  |  | 
 |                lsr     #8,d7            ;shift right 11 times
  |  | 
 |                lsr     #3,d7            ;submenu item now in D7
  |  | 
 |                clr.l   d5
  |  | 
 |                roxr    #1,d6            ;bit 0 in X-flag
  |  | 
 |                roxl    #1,d5            ;menu number now in D5
  |  | 
 |                and.l   #$7f,d6          ;issolate lower bits
  |  | 
 |                cmp     #$7f,d6          ;no menu item?
  |  | 
 |                beq     loop             ;no:continue
  |  | 
 |                lsr     #4,d6            ;else menu item in D6
  |  | 
 |                ende
  |  | 
 | 
  |  | 
 |         By making a test run with AssemPro,you can easily see if this
  |  | 
 |         works right-just look at the registers after the program is over.
  |  | 
 |  
  |  | 
 |         If you,for example,want to write a program with four menus with 10
  |  | 
 |         menu items each,this sort of method is too much work-there are 44 
  |  | 
 |         tables.For this reason,lets look at a short program that takes
  |  | 
 |         care of the necessary structure table itself.
  |  | 
 |         The menu structure is built very simply-it doesn't offer submenus 
  |  | 
 |         or the option of choosing items via the keyboard.If you want these
  |  | 
 |         extras,you can still use this program,but you'll have to use MOVE 
  |  | 
 |         commands to insert the desired flags and pointers.
  |  | 
 |         The input that this program needs is a list of the menu names and 
  |  | 
 |         the items in each menu.The addresses of the menu texts go in a
  |  | 
 |         table with the following simple form:
  |  | 
 | 
  |  | 
 |               dc.l   Menu title 1
  |  | 
 |               dc.l   Point1,Point2,Point3,...,0
  |  | 
 |               dc.l   Menu title 2
  |  | 
 |               dc.l   Point1,Point2,Point3,...,0
  |  | 
 |               dc.l   Menu title 3 oder 0
  |  | 
 | 
  |  | 
 |         This program is set up in such a way that up to four menus can lie
  |  | 
 |         next to each other (in normal screen resolution),which is often
  |  | 
 |         plenty.The table above ends by putting a zero instead of a pointer
  |  | 
 |         to the nxt menu title.As you can see,its pretty simple.
  |  | 
 |         This program is inserted in your big program right behind the
  |  | 
 |         "setmenu"label.After the "bsr setmenu"command is executed,the menu
  |  | 
 |         structure is built and initialized at the same time.You don't need
  |  | 
 |         to change the rest of the program,it'll be shorter that way.
  |  | 
 | 
  |  | 
 |         Heres the program fragment for the complete "setmenu"routine:
  |  | 
 | 
  |  | 
 |         setmenu:                        ;*initialize menu structure
  |  | 
 |                lea     mentab,a0        ;pointer to text pointer in A0
  |  | 
 |                lea     menu,a1          ;pointer to menu field in A1
  |  | 
 |                move    #10,d1           ;horizontal menu position=10
  |  | 
 |  
  |  | 
 |         menuloop:
  |  | 
 |                clr.l   d2               ;vertical menu position=0
  |  | 
 |                move.l  a1,a2            ;save address of pointer
  |  | 
 |                tst.l   (a0)             ;another menu there?
  |  | 
 |                beq     setmenu1         ;no:quit
  |  | 
 |                clr.l   (a1)+            ;"no more menus"preperations
  |  | 
 |                move    d1,(a1)+         ;set X-position
  |  | 
 |                add.l   #70,d1           ;and increment
  |  | 
 |                move.l  #50,(a1)+        ;Y-position and width
  |  | 
 |                move.l  #$a0001,(a1)+    ;height and flag
  |  | 
 |                move.l  (a0)+,(a1)+      ;menu title
  |  | 
 |                lea     12(a1),a3
  |  | 
 |                move.l  a3,(a1)+         ;pointer to menu item
  |  | 
 |                clr.l   (a1)+            ;reserved words
  |  | 
 |                clr.l   (a1)+
  |  | 
 | 
  |  | 
 |         itemloop:
  |  | 
 |                tst.l   (a0)             ;last entry?
  |  | 
 |                beq     menuend          ;yes:menu done
  |  | 
 |                lea     54(a1),a3
  |  | 
 |                move.l  a3,(a1)+         ;pointer to next item
  |  | 
 |                move.l  d2,(a1)+         ;X- and Y-positions
  |  | 
 |                add     #10,d2           ;Y-position+10
  |  | 
 |                move.l  #$5a000a,(A1)+   ;WIDTH/HEIGHT
  |  | 
 |                move    #$52,(a1)+       ;flag:normal
  |  | 
 |                clr.l   (a1)+            ;no connection
  |  | 
 |                lea     16(a1),a3
  |  | 
 |                move.l  a3,(a1)+         ;text structure pointer
  |  | 
 |                clr.l   (a1)+            ;no fill structure
  |  | 
 |                clr.l   (a1)+            ;no command,no submenu
  |  | 
 |                clr.l   (a1)+            ;and no continuation
  |  | 
 |                move    #$1,(a1)+        ;set text structure:colour
  |  | 
 |                clr.l   (a1)+            ;mode 0
  |  | 
 |                move.l  #$50003,(a1)+    ;X- and Y-position
  |  | 
 |                clr.l   (a1)+            ;standard character set
  |  | 
 |                move.l  (a0)+,(a1)+      ;text pointer
  |  | 
 |                clr.l   (a1)+            ;no continuation
  |  | 
 |                bra     itemloop         ;next item...
  |  | 
 | 
  |  | 
 |         menuend:                        ;eventual transfer to next menu
  |  | 
 |                clr.l   -54(a1)          ;erase pointer to next item
  |  | 
 |                tst.l   (a0)+            ;increment table pointer
  |  | 
 |                tst.l   (a0)             ;another menu there?
  |  | 
 |                beq     setmenu1         ;no:done
  |  | 
 |                move.l  a1,(a2)          ;pointer to next menu
  |  | 
 |                bra     menuloop         ;and continue
  |  | 
 |         setmenu1:                       ;*initialize menu (like before)
  |  | 
 |                move.l  intbase,a6       ;intuition base address in A6
  |  | 
 |                move,l  windowhd,a0      ;window structure in A0
  |  | 
 |                lea     menu,a1          ;pointer to menu structure
  |  | 
 |                jsr     setmenustrip(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         You need three things yet for this program:the memory to be used
  |  | 
 |         for the structure,the table of text pointers and the text.Heres an
  |  | 
 |         example:
  |  | 
 | 
  |  | 
 |         mentab:
  |  | 
 |                dc.l menu1               ;first menu title
  |  | 
 |                dc.l mp11,mp12,mp13      ;menu items
  |  | 
 |                dc.l 0                   ;end of menu 1
  |  | 
 |                dc.l menu2               ;second menu title
  |  | 
 |                dc.l mp21,mp22,mp23      ;menu items
  |  | 
 |                dc.l 0                   ;end of menu 2
  |  | 
 |                dc,l 0                   ;you're out of menus!
  |  | 
 | 
  |  | 
 |         ;** Menu Text **
  |  | 
 |         menu1: dc.b "Menu 1",0
  |  | 
 |         mp11:  dc.b "Point11",0
  |  | 
 |         mp12:  dc.b "Point12",0
  |  | 
 |         mp13:  dc.b "Point13",0
  |  | 
 |         menu2: dc.b "Menu 2",0
  |  | 
 |         mp21:  dc.b "Point21",0
  |  | 
 |         mp22:  dc.b "Point22",0
  |  | 
 |         mp23:  dc.b "Point23",0
  |  | 
 |             align
  |  | 
 |         ;** Storage space for menu structure **
  |  | 
 |         menu:  blk.w 500
  |  | 
 | 
  |  | 
 |         Make sure that the memory area reserved for the menu structure is 
  |  | 
 |         big enough and change the entry "blk.w 500"to the calculated
  |  | 
 |         value. 
  |  | 
 |         If you use this program,and want to build some special features
  |  | 
 |         into the menu (for instance key commands),you can make entries in
  |  | 
 |         the menu structure table while the program is running.You can find
  |  | 
 |         the word (or byte or long word) that interests you in the table as
  |  | 
 |         follows:
  |  | 
 | 
  |  | 
 |         For example,to find the keyboard command byte of the second entry
  |  | 
 |         in the first menu,calculate as follows:
  |  | 
 | 
  |  | 
 |         Address = Start_address+Menu*30+(entry-1)*54+26
  |  | 
 | 
  |  | 
 |         which in the example comes to:
  |  | 
 | 
  |  | 
 |         Address = menu+30+54+26
  |  | 
 |                 = menu+110
  |  | 
 | 
  |  | 
 |         The 26 is the distance from the beginning of the MenuItem
  |  | 
 |         structure to the desired byte,the command byte.In this way,you can
  |  | 
 |         calculate the addresses and use MOVE commands to modify the menu
  |  | 
 |         to fit your wishes.By the way,in the example above,the correspond-
  |  | 
 |         ing flag bit must be set as well,so that the keyboard command is  
  |  | 
 |         recognized.
  |  | 
 |         Now lets get back to the window.Its nice to have a window that you
  |  | 
 |         can change and close,but you really want to be able to output text
  |  | 
 |         in a window!
  |  | 
 | 
  |  | 
 |       7.6.Text Output.
  |  | 
 |       ----------------
  |  | 
 |         Its very easy to use Intuition's text output function.Use the
  |  | 
 |         PrintIText function (offset -216).It needs four parameters.
  |  | 
 | 
  |  | 
 |         In A0    A pointer to the RastPort of the window.You can find this
  |  | 
 |                  in the window structure.
  |  | 
 |         In A1    A pointer to the text structure of the text that should
  |  | 
 |                  be output.
  |  | 
 |         In D0    The X-position.
  |  | 
 |         In D1    The Y-position of the text in the window.
  |  | 
 | 
  |  | 
 |         Its very easy to enter the X- and Y-positions.You've already used 
  |  | 
 |         the text structure twice (for requesters and menus).
  |  | 
 |         Whats new is accessing the windows RastPort.The RastPort is a
  |  | 
 |         structure that describes the window.The address is needed by
  |  | 
 |         several Intuition functions.
  |  | 
 |         The pointer to the RastPort starts at the 50th byte in the window 
  |  | 
 |         structure.You can access it as follows:
  |  | 
 |  
  |  | 
 |             move.l  windowhd,a0           ;address of window structure
  |  | 
 |             move.l  50(a0),a0             ;RastPort address in A0
  |  | 
 | 
  |  | 
 |         Now you've got the address of the RastPort.Lets write a routine
  |  | 
 |         that prints a text.The X- and Y-positions are in D0 and D1
  |  | 
 |         respectively and the address of the text structure in A1 before
  |  | 
 |         the routine is called:
  |  | 
 | 
  |  | 
 |         PrintIText = -216
  |  | 
 |                ...
  |  | 
 |         print:
  |  | 
 |                move.l  intbase,a6       ;intuition base address in A6
  |  | 
 |                move.l  windowhd,a0      ;address of window structure
  |  | 
 |                move.l  50(a0),a0        ;rastport address in A0
  |  | 
 |                jsr     printitext(a6)   ;call function
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         You can try out this routine by using the requesters text that is 
  |  | 
 |         still in a structure of the program.Write the following lines
  |  | 
 |         before the "loop"label:
  |  | 
 | 
  |  | 
 |                lea     btext,a1         ;pointer to text structure in A1
  |  | 
 |                move.l  #10,d0           ;X-position
  |  | 
 |                move.l  #30,d1           ;Y-position of text
  |  | 
 |                bsr     print            ;output text
  |  | 
 | 
  |  | 
 |         Start the program and the text appears in the middle of the window
  |  | 
 |         If this doesn't happen,check the colour of the text in the text   
  |  | 
 |         structure.Its probably zero.Just change it to three,and the text  
  |  | 
 |         appears in red the next time you start the program.
  |  | 
 | 
  |  | 
 |       7.7.Images.
  |  | 
 |       -----------
  |  | 
 |         An image is a drawing that goes in a rectangular field and is
  |  | 
 |         defined bitwise.The disk symbol of the Intuition screen and the   
  |  | 
 |         system gadgets in the screen and window borders are examples of
  |  | 
 |         such Images.
  |  | 
 |         The rectangle that the drawing goes in can be arbitrarily large,  
  |  | 
 |         but each pixel in the rectangle needs its own bit,so programming  
  |  | 
 |         screen-sized Images isn't advisable.You'll stick to an Image that 
  |  | 
 |         requires about 32x16 bits-an Image thats about 3x1cm.
  |  | 
 |         You can make all sorts of images as you've seen looking at window 
  |  | 
 |         gadgets.There is an Intuition functionthat draws an Image:It is
  |  | 
 |         the DrawImage function (offset -114) and it needs 4 parameters:
  |  | 
 | 
  |  | 
 |         In A0   The address of the rastport image is drawn in.You've
  |  | 
 |                 already learned how to access this address in the section 
  |  | 
 |                 on the text function.
  |  | 
 |         In A1   The structure address of the image to be drawn.
  |  | 
 |         In D0   The relative X-position
  |  | 
 |         In D1   The relative Y-position of the drawing.
  |  | 
 | 
  |  | 
 |         Lets draw this picture in your window.It justs takes a simple
  |  | 
 |         routine.You just need to put the address of the image structure in
  |  | 
 |         A1 and the position of the image in D0 and D1 before you call it.
  |  | 
 | 
  |  | 
 |         DrawImage =-114
  |  | 
 |                ...
  |  | 
 |         draw:                           ;*draw image
  |  | 
 |                move.l  intbase,a6       ;intuition base address in A6
  |  | 
 |                move.l  windowhd,a0      ;pointer to window structure
  |  | 
 |                move.l  50(a0),a0        ;now,rastport address in A0
  |  | 
 |                jsr     drawimage(a6)    ;draw image
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         Now you need the structure of the image.The structure contains
  |  | 
 |         nine entries which have the following meanings:
  |  | 
 | 
  |  | 
 |         The first two entries are words which specify the distance in the 
  |  | 
 |         X- and Y-direction from the co-ordinates that were given to tell  
  |  | 
 |         where the image should be drawn.You'll just put two zeros here:
  |  | 
 | 
  |  | 
 |         image:
  |  | 
 |                dc.w  0,0                ;X- and Y-position
  |  | 
 | 
  |  | 
 |         Next come two words which specify the width and height of the
  |  | 
 |         image in pixels.Lets draw a 32x13 point image.Enter: 
  |  | 
 | 
  |  | 
 |                dc.w  32,13              ;width and height of image
  |  | 
 | 
  |  | 
 |         The next word in the list specifies the number of planes in the
  |  | 
 |         drawing.If its a simple image that only uses two colours,just
  |  | 
 |         enter a one.For more colours,you'll need a correspondingly bigger 
  |  | 
 |         number.When more colurs are worked with,the bit pattern of the
  |  | 
 |         image must have more data.Lets just have one bit plane:
  |  | 
 | 
  |  | 
 |                dc.w  1                  ;one bitplane:2^1=2 colours
  |  | 
 | 
  |  | 
 |         Next comes a long word that points to the data of the image:
  |  | 
 | 
  |  | 
 |                dc.l  imgdata            ;pointer to image data
  |  | 
 | 
  |  | 
 |         The next two bytes are very interesting.The first byte,the
  |  | 
 |         PlanePick byte,tells which plane of the window or screen the image
  |  | 
 |         data should be written in.Since you only have one plane,you need
  |  | 
 |         to enter the bit plane of the window.This information is found in
  |  | 
 |         the bits of the byte-bit0 stands for plane 0,bit 1 for plane 1,etc
  |  | 
 |         ..You also define the colour of the image with this input.If you
  |  | 
 |         enter a two,every set bit of your image represents a red point.
  |  | 
 | 
  |  | 
 |                dc.b  2                  ;drawing red:plane 1
  |  | 
 | 
  |  | 
 |         The second byte,the PlaneOnOff byte,is an interesting enhancement.
  |  | 
 |         Each bit of the window bit plane corresponds to a whole number
  |  | 
 |         here.The only bytes that are interesting though are the ones that
  |  | 
 |         are cleared in the PlanePick byte.If the bit is set in PlaneOnOff,
  |  | 
 |         evert bit of the image in the corresponding plane is set.Otherwise
  |  | 
 |         they are cleared.To make sure that each bit of the image that
  |  | 
 |         isn't set appears white,enter a one.All the bits of the image that
  |  | 
 |         aren't set,are set in Plane 1 and appear white.
  |  | 
 | 
  |  | 
 |                dc.b  1                  ;background:white
  |  | 
 | 
  |  | 
 |         The last entry of the structure is a lobg word that points to
  |  | 
 |         another image.You don't need this,so set the long word to zero:
  |  | 
 | 
  |  | 
 |                dc.l  0                  ;no more images
  |  | 
 | 
  |  | 
 |         Heres a quick overview of the image structure:
  |  | 
 |        
  |  | 
 |         image:
  |  | 
 |                dc.w  0,0                ;X- and Y-positions
  |  | 
 |                dc.w  32,13              ;width and height of image
  |  | 
 |                dc.w  1                  ;one bitplane:2^1=2 colours
  |  | 
 |                dc.l  imgdata            ;pointer to image data
  |  | 
 |                dc.b  2                  ;drawing red:plane 1
  |  | 
 |                dc.b  1                  ;background:white
  |  | 
 |                dc.l  0                  ;no more images
  |  | 
 | 
  |  | 
 |         Now lets produce the image data.Each image row uses a word,long
  |  | 
 |         word,or several of these represent the pattern.The set points of
  |  | 
 |         the image correspond to the set bits.This is repeated as often as 
  |  | 
 |         the height of the image requires.The data on each line must begin 
  |  | 
 |         on a word border,on a even address.
  |  | 
 |         For the example,its easy to decide on the data,since you're going 
  |  | 
 |         32 points across-that corresponds to exacty one long word.Its
  |  | 
 |         easiest to program the image using the binary representation of
  |  | 
 |         the data.
  |  | 
 |         Lets use,as an example,an image that represents a switch in "OFF" 
  |  | 
 |         mode.This form is chosen for a good reason,so you should type it
  |  | 
 |         in.In the chapter on gadgets thats coming up,we'll show you how to
  |  | 
 |         turn the switch on.Here is the example data for the switch image:
  |  | 
 | 
  |  | 
 |         imgdata:   ;Data for switch in "OFF" mode
  |  | 
 |            dc.l    %00000000000000000000000000000000
  |  | 
 |            dc.l    %00000000000000000000111000000000
  |  | 
 |            dc.l    %00011101110111000001111100000000
  |  | 
 |            dc.l    %00010101000100000001111100000000
  |  | 
 |            dc.l    %00010101100110000001111000000000
  |  | 
 |            dc.l    %00011101000100000011100000000000
  |  | 
 |            dc.l    %00000000000000000111000000000000
  |  | 
 |            dc.l    %00000000000000001110000000000000
  |  | 
 |            dc.l    %00000000000111111111100000000000
  |  | 
 |            dc.l    %00000000001111111111110000000000
  |  | 
 |            dc.l    %00000000001111111111110000000000
  |  | 
 |            dc.l    %00000000000110000001100000000000
  |  | 
 |            dc.l    %00000000000000000000000000000000
  |  | 
 | 
  |  | 
 |         Once you've typed in this data,you can experiment with displaying
  |  | 
 |         it on the screen.Enter the following lines before the "loop"label:
  |  | 
 | 
  |  | 
 |             move.l  image,a1           ;pointer to image structure
  |  | 
 |             move    #30,d0             ;X-postion in window
  |  | 
 |             move    #50,d1             ;Y-position
  |  | 
 |             bsr     draw               ;draw image
  |  | 
 | 
  |  | 
 |         How do you like the image on the screen?You'll run into this
  |  | 
 |         switch again when we talk about putting the switch in the "ON"    
  |  | 
 |         state when discussing gadgets.You need to look at other methods of
  |  | 
 |         drawing in the window first,though.
  |  | 
 | 
  |  | 
 |       7.8.Borders.
  |  | 
 |       ------------
  |  | 
 |         A border is a collection of lines that are connected.They can be
  |  | 
 |         of any length or at any angle.Intuition lets you draw borders to
  |  | 
 |         do things like put frames around windows and screens.They are used
  |  | 
 |         to put borders around pictures or text,especially for use with
  |  | 
 |         string gadgets.We'll talk about that later,though.
  |  | 
 |         Its easy to draw borders.Just use the Intuition function
  |  | 
 |         DrawBorder (offset -108) which needs four parameters:
  |  | 
 | 
  |  | 
 |         In A0   The rastport address of the output medium the lines should
  |  | 
 |                 be drawn in.Use your window.
  |  | 
 |         In A1   The address of the border structure.We'll look at the form
  |  | 
 |                 of this structure shortly.
  |  | 
 |         In D0   The relative X-co-ordinate which is used with the X- and Y
  |  | 
 |                 co-ordinate list to calulate the actual line co-ordinates.
  |  | 
 |         In D1   The relative Y-co-ordinates.Relative,here too,means that
  |  | 
 |                 this is relative to the upper left corner of the screen.
  |  | 
 | 
  |  | 
 |         Lets write a short routine that is called with three parameters.  
  |  | 
 |         The structure address in A1 and the X and Y co-ordinates are in D0
  |  | 
 |         and D1 respectively when the routine is called.The border is drawn
  |  | 
 |         in the window whose structure address is in "windowhd".
  |  | 
 | 
  |  | 
 |         DrawBorder =-108
  |  | 
 |                ...
  |  | 
 |         borderdraw:                     ;* draw several lines
  |  | 
 |                move.l  inbase,a6        ;intuition base address in A6
  |  | 
 |                move.l  windowhd,a0      ;pointer to window structure
  |  | 
 |                move.l  50(a0),a0        ;now rastport address in A0
  |  | 
 |                jsr     drawborder(a6)   ;draw lines
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         Now lets look at the border structure.The list needs the eight
  |  | 
 |         following parameters:
  |  | 
 | 
  |  | 
 |         First,you need two words for the vertical and horizontal distance 
  |  | 
 |         from the co-ordinates given in the function call.To avoid losing  
  |  | 
 |         sight of some of the many distance entries,put two zeros here:
  |  | 
 | 
  |  | 
 |         border:
  |  | 
 |                dc.w  0                  ;horizontal distance
  |  | 
 |                dc.w  0                  ;vertical distance
  |  | 
 | 
  |  | 
 |         Next come two bytes that determine the colour.Use a red frame:
  |  | 
 | 
  |  | 
 |                dc.b  3                  ;red frame
  |  | 
 |                dc.b  0                  ;background (unused)
  |  | 
 | 
  |  | 
 |         As you can see,the background colour isn't used.You have two modes
  |  | 
 |         to choose between for drawing the lines.The following mode
  |  | 
 |         determines the mode that is used.If it is zero,each line is drawn
  |  | 
 |         in the colour chosen,no matter what was done before.This is the
  |  | 
 |         JAM1 mode.The other mode is the XOR mode which ignores both colour
  |  | 
 |         entries.In this mode,all the points that lie under the line have
  |  | 
 |         their colour value inverted.As a result,a white point becomes
  |  | 
 |         black,and a blue one becomes red.That is mode two.Lets use the
  |  | 
 |         JAM1 mode for the example:
  |  | 
 | 
  |  | 
 |                dc.b  0                  ;mode:JAM1 (2=XOR)
  |  | 
 | 
  |  | 
 |         The next entry specifies how many co-ordinate pairs there are in
  |  | 
 |         the list.Since this word must be on an even address,you need to
  |  | 
 |         use the "align"peudo-op first.Then enter the number of pairs.     
  |  | 
 |         Remember that you need three points to draw two lines:beginning,  
  |  | 
 |         corner and end point.To draw a rectangular frame,you need five
  |  | 
 |         pairs:
  |  | 
 | 
  |  | 
 |                dc.b  5                  ;5 X,Y pairs used together
  |  | 
 | 
  |  | 
 |         The next item is a pointer to the co-ordinate table that contains
  |  | 
 |         a list of points to be connected:
  |  | 
 | 
  |  | 
 |                dc.l  coord              ;pointer to cordinate table
  |  | 
 | 
  |  | 
 |         The border structures final entry is a long word that can point to
  |  | 
 |         another border structure.If you don't have any more structures to
  |  | 
 |         be pointed to,just enter a zero here.The pointer is useful for
  |  | 
 |         connecting two independant border structures-for example,to
  |  | 
 |         produce a two coloured frame that really stands out.You don't need
  |  | 
 |         this pointer in the example,though:
  |  | 
 | 
  |  | 
 |                dc.l  0                  ;no more structures
  |  | 
 | 
  |  | 
 |         Thats the border structure.Now lets look at the co-ordinate list.
  |  | 
 |         For the example,it consists of five pairs of numbers which
  |  | 
 |         represent a rectangle.I recommend entering these values,because
  |  | 
 |         you'll use them in example programs further down the line.
  |  | 
 | 
  |  | 
 |         coord:                          ;coordinates for rectangle frame
  |  | 
 |                dc.w  -2,-2
  |  | 
 |                dc.w  80,-2
  |  | 
 |                dc.w  80,9
  |  | 
 |                dc.w  -2,9
  |  | 
 |                dc.w  -2,-2
  |  | 
 | 
  |  | 
 |         Heres a quick overview of the border structure:
  |  | 
 | 
  |  | 
 |         border:
  |  | 
 |                dc.w  0                  ;horizontal distance
  |  | 
 |                dc.w  0                  ;vertical distance
  |  | 
 |                dc.b  3                  ;red frame
  |  | 
 |                dc.b  0                  ;background (unused)
  |  | 
 |                dc.b  0                  ;mode:JAM1 (2=XOR)
  |  | 
 |                dc.b  5                  ;5 X,Y pairs used together
  |  | 
 |                dc.l  coord              ;pointer to cordinate table
  |  | 
 |                dc.l  0                  ;no more structures
  |  | 
 |         coord:                          ;coordinates for rectangle frame
  |  | 
 |                dc.w  -2,-2
  |  | 
 |                dc.w  80,-2
  |  | 
 |                dc.w  80,9
  |  | 
 |                dc.w  -2,9
  |  | 
 |                dc.w  -2,-2
  |  | 
 | 
  |  | 
 |         Once you've typed this in,you can try the whole thing out.Type the
  |  | 
 |         following lines before the "loop"label in the program:
  |  | 
 | 
  |  | 
 |                lea     border,a1        ;address of the border structure
  |  | 
 |                move    #20,d0           ;X base position
  |  | 
 |                move    #80,d1           ;Y base position
  |  | 
 |                bsr     drawborder       ;draw frame
  |  | 
 | 
  |  | 
 |         As you can see,using enough X and Y co-ordinates,you can draw the 
  |  | 
 |         Eiffel tower.Thats enough about simple drawings.You want to put
  |  | 
 |         some life into your drawings and text.Lets manipulate them with
  |  | 
 |         the mouse!
  |  | 
 | 
  |  | 
 |       7.9.Gadgets.
  |  | 
 |       ------------
  |  | 
 |         We already talked a bit about gadgets when you looked at screen
  |  | 
 |         construction.Looking at system gadgets like the window close
  |  | 
 |         symbol,you can activate by clicking and causes a program function 
  |  | 
 |         to be executed.
  |  | 
 |         You can make your own gadgets as well.Intuition allows you a lot
  |  | 
 |         of interesting possibilities.
  |  | 
 |         
  |  | 
 |         There are four types of gadgets:
  |  | 
 | 
  |  | 
 |         Boolean gadgets are used in Yes/No situations.You can click and
  |  | 
 |         activate it (Yes) or deactivate it (No).
  |  | 
 | 
  |  | 
 |         String gadgets are used to accept input of text of a specified
  |  | 
 |         length.
  |  | 
 |  
  |  | 
 |         Integer gadgets are a special sort of string gadgets which accept
  |  | 
 |         the input of a decimal number.Intuition converts the value into a 
  |  | 
 |         long word and sends it to the program.
  |  | 
 | 
  |  | 
 |         Proportional gadgets let you choose an analog value with the mouse
  |  | 
 |         You can move these around with the mouse.
  |  | 
 | 
  |  | 
 |       7.9.1.Boolean Gadgets.
  |  | 
 |       ----------------------
  |  | 
 |         Lets start with the simplest type,the boolean gadget.an example of
  |  | 
 |         this sort of gadget is the close symbol of the window.The only
  |  | 
 |         status it differenciates between are clicked and not clicked.Lets 
  |  | 
 |         develop a gadget of this type step by step.The flags and other    
  |  | 
 |         parameters are similar for the other gadgets.
  |  | 
 |         Each gadget needs a structure containing fifteen entries.There is
  |  | 
 |         a pointer to this structure in window,screen or requester that the
  |  | 
 |         gadget is to appear in.Theres always a long word available for
  |  | 
 |         this purpose.Up to this point,you've just put a zero there.If
  |  | 
 |         there is an address of a gadget structure there,the gadget or
  |  | 
 |         gadgets are displayed when the window is opened.
  |  | 
 | 
  |  | 
 |         A gadget structure as the following entries:
  |  | 
 | 
  |  | 
 |         The first long word is a pointer to the next gadget to be
  |  | 
 |         installed.The gadgets are displayed in a row,like pearls on a
  |  | 
 |         string.This pointer is the first gadget in this linked list of
  |  | 
 |         gadgets.If you just want one gadget in your window,put a zero
  |  | 
 |         here:
  |  | 
 |        
  |  | 
 |         gadget1:
  |  | 
 |                dc.l  0                  ;no more gadgets
  |  | 
 | 
  |  | 
 |         The next two words determine the position of the gadget in the
  |  | 
 |         window.There are several ways to determine the position.Use flags 
  |  | 
 |         to access the various possibilities.Lets start with a gadget that 
  |  | 
 |         stays in one spot:
  |  | 
 | 
  |  | 
 |                dc.w  40                 ;X and
  |  | 
 |                dc.w  50                 ;Y position of the gadget
  |  | 
 | 
  |  | 
 |         The next two words determine the size of the gadgets Hit box.This 
  |  | 
 |         box isn't the visible size of the gadget (that depends on the
  |  | 
 |         image data).It is the size of the rectangle that Intuition should 
  |  | 
 |         watch.If the mouse pointer is moved into this box and the left
  |  | 
 |         button pressed,the gadget is activated.Clicking on parts of the
  |  | 
 |         gadget that are outside this box have no effect!
  |  | 
 | 
  |  | 
 |                dc.w  32                 ;width and
  |  | 
 |                dc.w  13                 ;height of the hit box
  |  | 
 | 
  |  | 
 |         Next comes the word whose bits determine the properties of the
  |  | 
 |         gadget.Bits 0 and 1 determine what should happen when this objects
  |  | 
 |         hit box is clicked on.The meanings of the various values of these
  |  | 
 |         bits go as follows:
  |  | 
 | 
  |  | 
 |         Bit 0   1   Value   Name          Meaning
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |          0      0     0     GADGHCOMP     The gadget inverted
  |  | 
 |          0      1     1     GADGHBOX      The gadget framed
  |  | 
 |          1      0     2     GADGHIMAGE    Another image appears
  |  | 
 |          1      1     3     GADGHNONE     No reaction
  |  | 
 | 
  |  | 
 |         Bit 2 determines whether the gadget should consist of a drawing or
  |  | 
 |         a border.If it is set(Value+4),it is treated as an image;otherwise
  |  | 
 |         its treated like a border.
  |  | 
 |         The next bit determines if the gadget should appear in the upper
  |  | 
 |         or lower border of the frame.If it is set(Value+8).the position is
  |  | 
 |         relative to the lower border;otherwise it is relative to the upper
  |  | 
 |         border.The next bit as the same meaning for the horizontal
  |  | 
 |         position.If set(Value+$10),it is a relative positioning.Otherwise,
  |  | 
 |         it is an absolute positioning.
  |  | 
 |         Notice that when you define a gadget to be relative,you must have
  |  | 
 |         a negative value in the position input in the first word of the
  |  | 
 |         structure.Since the desired position isn't under,but its over this
  |  | 
 |         position!
  |  | 
 |         In this way,you can choose either absolute or relative positioning
  |  | 
 |         of the gadget.An example of a gadget that is positioned absolutely
  |  | 
 |         is the system gadget,close window.An example of a relative gadget 
  |  | 
 |         is the symbol for changing the size.
  |  | 
 |         The width and height of the gadgets hit box can also be relative
  |  | 
 |         to the window size.Specify this by using bit 5 for width (Value +
  |  | 
 |         $20)and bit 6 for the height (Value +$40).A set bit mens a
  |  | 
 |         relative size.
  |  | 
 |         Bit 7 (Value+$80)makes the object active as soon as the window is
  |  | 
 |         opened.
  |  | 
 |         Bit 8 (Value+$100)determines whether the gadget can be used or not
  |  | 
 |         If this bit is set,the gadget can't be activated.
  |  | 
 |         For the example,you'll use absolute positioning and size,the
  |  | 
 |         inverted appearance for the activated gadget,and the
  |  | 
 |         representation of the object as an image.That means you must use
  |  | 
 |         the value four:
  |  | 
 | 
  |  | 
 |               dc.w  4              ;flags:image,invert
  |  | 
 | 
  |  | 
 |         Next comes a word whose bits are used as flags.This flag is called
  |  | 
 |         the Activation Flag.It determines the functions of the gadget.The 
  |  | 
 |         bits,their values and meanings follow:
  |  | 
 | 
  |  | 
 |         Bit   Value   Name            Meaning
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |          0     1      RELVERIFY       Causes the gadget to be activated
  |  | 
 |                                       only when the left mouse key is let
  |  | 
 |                                       loose over the gadget.
  |  | 
 |          1     2      GADGIMMEDIATE   Lets the gadget be active as soon as
  |  | 
 |                                       there is a click.
  |  | 
 |          2     4      ENDGADGET       Lets you choose to end this choice
  |  | 
 |                                       and have it disappear if this is a  
  |  | 
 |                                       requester gadget.
  |  | 
 |          3     8      FOLLOWMOUSE     Lets the gadget know the mouse
  |  | 
 |                                       position at regular intervals from
  |  | 
 |                                       the time it is selected until the
  |  | 
 |                                       time it is deselected.You can use
  |  | 
 |                                       this to move the gadget with the
  |  | 
 |                                       mouse when you want to change the
  |  | 
 |                                       gadget position.
  |  | 
 |          4     $10    RIGHTBORDER     This makes sure thay when borders
  |  | 
 |                                       are used that the page is adjusted
  |  | 
 |                                       to the size of the gadget so that it
  |  | 
 |                                       fits in the border.
  |  | 
 |          5     $20    LEFTBORDER
  |  | 
 |          6     $40    TOPBORDER
  |  | 
 |          7     $80    BOTTOMBORDER
  |  | 
 |          8     $100   TOGGLESELECT    Allows the objects state to change  
  |  | 
 |                                       every time it is clicked.If
  |  | 
 |                                       activated,it becomes deactivated and
  |  | 
 |                                       vice versa.
  |  | 
 |          9     $200   STRINGCENTRE    For a string gadget,these two bits  
  |  | 
 |                                       determine whether the string should 
  |  | 
 |                                       appear centred or right justified.If
  |  | 
 |                                       neither is set,the string is output 
  |  | 
 |                                       left justified.
  |  | 
 |          10    $400   STRINGRIGHT
  |  | 
 |          11    $800   LONGINT         Turns a string gadget into a Integer
  |  | 
 |                                       gadget (explanation later).
  |  | 
 |          12    $1000  ALTKEYMAP       Causes another ketboard placement to
  |  | 
 |                                       be in effect for string gadget input
  |  | 
 | 
  |  | 
 |         Thats it for the activation flags.Lets choose the TOGGLESELECT and
  |  | 
 |         GADGETIMMEDIATED flags for example:
  |  | 
 | 
  |  | 
 |              dc.w  $102             ;activation
  |  | 
 | 
  |  | 
 |         The next word of the gadget structure determines the gadget type. 
  |  | 
 |         Heres the meaning of the individual bits:
  |  | 
 | 
  |  | 
 |         Bit   Value   Name            Meaning(report what circumstances)
  |  | 
 |         ----------------------------------------------------------------
  |  | 
 |          0     1      BOOLGADGET      This is a boolean gadget
  |  | 
 |          1     2      GADGET002       
  |  | 
 |          2     4      STRGADGET       String order Integer gadget
  |  | 
 |         0+1    3      PROPGADGET      Proportional gadget
  |  | 
 | 
  |  | 
 |         System gadgets:
  |  | 
 |          4     $10    SIZING          Size changing gadget
  |  | 
 |          5     $20    WDRAGGING       Moving gadget for window
  |  | 
 |         4+5    $30    SDRAGGING       Same for screen
  |  | 
 |          6     $40    WUPFRONT        Gadget to move window forward
  |  | 
 |         6+4    $50    SUPFRONT        Gadget to move screen forward
  |  | 
 |         6+5    $60    WDOWNBACK       Move window back
  |  | 
 |         6+5+4  $70    SDOWNBACK       Move screen back
  |  | 
 |          7     $80    CLOSE           Window close gadget
  |  | 
 | 
  |  | 
 |         Type definitions:
  |  | 
 |          12    $1000  REQGADGET       Requester gadget
  |  | 
 |          13    $2000  GZZGADGET       Border gadget in GIMMEZEROZERO
  |  | 
 |                                       window
  |  | 
 |          14    $4000  SCRGADGET       Screen gadget when set
  |  | 
 |          15    $8000  SYSGADGET       System gadget when set
  |  | 
 | 
  |  | 
 |         You want to use a simple boolean gadget for your example,so enter:
  |  | 
 | 
  |  | 
 |                dc.w  1                ;gadget type:boolean
  |  | 
 | 
  |  | 
 |         Next comes a pointer to the gadget structure.The first pointer
  |  | 
 |         contains the address of the image or border structure which should
  |  | 
 |         be used to represent the gadget.If no representation is needed,put
  |  | 
 |         a zero here.You want to represent the gadget as an image,so put a 
  |  | 
 |         pointer to the image structure that you produced in the chapter
  |  | 
 |         about images:
  |  | 
 | 
  |  | 
 |                dc.l  image            ;gadget image
  |  | 
 | 
  |  | 
 |         The next pointer is only used if the GADGHIMAGE flag in the flag
  |  | 
 |         word of the structure is set.This is a pointer to another
  |  | 
 |         structure that should be put on the screen when the object is
  |  | 
 |         activated.If a border structure is used for the gadget represent- 
  |  | 
 |         ation,this must be a border structure as well.You won't use a
  |  | 
 |         second image,so put a zero here:
  |  | 
 | 
  |  | 
 |                dc.l  0                ;no new gadget displayed
  |  | 
 | 
  |  | 
 |         The next pointer is to the text structure that should be output by
  |  | 
 |         the gadget.If no text is needed,just put a zero here.You want to
  |  | 
 |         use some text,however:
  |  | 
 | 
  |  | 
 |                dc.l  ggtext           ;gadget text
  |  | 
 | 
  |  | 
 |         Now comes a long word that determines which gadgets are
  |  | 
 |         deactivated when this is activated.This function still doesn't
  |  | 
 |         work right so put a zero here:
  |  | 
 | 
  |  | 
 |                dc.l  0                ;no exclude
  |  | 
 | 
  |  | 
 |         You'll set the next pointer to zero as well,because it is only
  |  | 
 |         used for String and Proportional gadgets.For these gadgets,this is
  |  | 
 |         a special structure to describe the characteristics of the gadget.
  |  | 
 |         Its called SpecialInfo.
  |  | 
 | 
  |  | 
 |                dc.l  0                ;no SpecialInfo
  |  | 
 |  
  |  | 
 |         The next word contains the Gadget Identification (ID) number:
  |  | 
 | 
  |  | 
 |                dc.w  1                ;gadget ID
  |  | 
 | 
  |  | 
 |         Finally there is a long word that doesn't have any function,so put
  |  | 
 |         a zero here:
  |  | 
 | 
  |  | 
 |                dc.l  0                ;user data (ignore)
  |  | 
 | 
  |  | 
 |         Thats it.Heres a quick overview of the gadget structure:
  |  | 
 | 
  |  | 
 |         gadget1:
  |  | 
 |                dc.l  0                ;no more gadgets
  |  | 
 |                dc.w  40               ;X and
  |  | 
 |                dc.w  50               ;Y position of gadget
  |  | 
 |                dc.w  32               ;width and
  |  | 
 |                dc.w  13               ;height of hit box
  |  | 
 |                dc.w  4                ;flags:image,invert
  |  | 
 |                dc.w  $102             ;activation flags
  |  | 
 |                dc.w  1                ;gadget type:boolean
  |  | 
 |                dc.l  image            ;gadget image
  |  | 
 |                dc.l  0                ;no new gadget displayed
  |  | 
 |                dc.l  ggtext           ;gadget text
  |  | 
 |                dc.l  0                ;no exclude
  |  | 
 |                dc.l  0                ;no SpecialInfo
  |  | 
 |                dc.w  1                ;gadget ID
  |  | 
 |                dc.l  0                ;user data (ignore)
  |  | 
 | 
  |  | 
 |         You've already prepared a structure that you can use for this
  |  | 
 |         image.Now you need the text that appears under the gadget.
  |  | 
 |         Since the gadget looks like a switch,label it "switch".The text
  |  | 
 |         structure looks like this:
  |  | 
 | 
  |  | 
 |         ggtext:
  |  | 
 |                dc.b  1,0              ;colours
  |  | 
 |                dc.b  1                ;mode
  |  | 
 |            align
  |  | 
 |                dc.w  -8,14            ;X and Y position
  |  | 
 |                dc.l  0                ;standard font
  |  | 
 |                dc.l  swtext           ;pointer to text
  |  | 
 |                dc.l  0                ;no more text
  |  | 
 |         swtext:
  |  | 
 |                dc.b  "switch",0
  |  | 
 |            align
  |  | 
 | 
  |  | 
 |         Once you've typed this in,save it,assemble it and start again.You 
  |  | 
 |         can click the switch and cause it to be inverted.Click it again,  
  |  | 
 |         and it appears normal.
  |  | 
 |         Now you can experriment with the structure.If you change the flag 
  |  | 
 |         from four to five,you can cause the gadget to be framed when it is
  |  | 
 |         activated.Set the RELVERIFY bit(bit0:+1)in the Activation Flag
  |  | 
 |         word.Then you can move the mouse pointer onto the object and press
  |  | 
 |         the button.It is activated.Keep the mouse button pressed down and 
  |  | 
 |         move the mouse.Once you leave the hit box,the activation disapears
  |  | 
 |         This way,you can avoid accidently activating a gadget.
  |  | 
 |         Now you want to display the switch in an on state.This is easy.All
  |  | 
 |         you need to do is produce another image structure,one for the on  
  |  | 
 |         state.You put this pointer in the long word right after the
  |  | 
 |         pointer to the normal image structure.You can change the flag word
  |  | 
 |         to six which causes a second image to be displayed when the gadget
  |  | 
 |         is activated.
  |  | 
 |         Here is the image structure for the switch in the one state.
  |  | 
 | 
  |  | 
 |         image2:
  |  | 
 |                dc.w  0,0              ;no offset
  |  | 
 |                dc.w  32,13            ;32x13 pixels
  |  | 
 |                dc.w  1                ;mode 1
  |  | 
 |                dc.l  imgdata2         ;pointer to the data
  |  | 
 |                dc.b  2,1              ;same colours as before
  |  | 
 |                dc.l  0                ;nothing else
  |  | 
 |        
  |  | 
 |         imgdata2:                     ;data for switch in the On state
  |  | 
 |                dc.l  %00000000000000000000000000000000
  |  | 
 |                dc.l  %00000000011100000000000000000000
  |  | 
 |                dc.l  %00000000111110000011101001000000
  |  | 
 |                dc.l  %00000000111110000010101101000000
  |  | 
 |                dc.l  %00000000011110000010101011000000
  |  | 
 |                dc.l  %00000000000111000011101001000000
  |  | 
 |                dc.l  %00000000000011100000000000000000
  |  | 
 |                dc.l  %00000000000001110000000000000000
  |  | 
 |                dc.l  %00000000000111111111100000000000
  |  | 
 |                dc.l  %00000000001111111111110000000000
  |  | 
 |                dc.l  %00000000001111111111110000000000
  |  | 
 |                dc.l  %00000000000110000001100000000000
  |  | 
 |                dc.l  %00000000000000000000000000000000
  |  | 
 | 
  |  | 
 |         Now the state of the object can be determined by looking at the
  |  | 
 |         picture.If the gadget is activated,the switch is on.If not,the
  |  | 
 |         switch is off.
  |  | 
 |         Thats it for boolean gadgets.You can learn about the things you
  |  | 
 |         did'nt touch with some experimentation.You want to get to the
  |  | 
 |         string gadgets that also do some interesting things.
  |  | 
 | 
  |  | 
 |       7.9.2.String Gadgets.
  |  | 
 |       ---------------------
  |  | 
 |         Lets pretend you want a program to load data from the disk.To get 
  |  | 
 |         the user to enter the filename,you need to output text telling the
  |  | 
 |         user to enter the name.Then you need to call an input routine to
  |  | 
 |         evaluate the keyboard input.
  |  | 
 |         Its easier and more elegant to use a String gadget.This function  
  |  | 
 |         allows for easy input and/or editingof short text.You have the
  |  | 
 |         option of having the text framed.The Undo function can be used by 
  |  | 
 |         pressing the right <Amiga> key and a "Q",and the old contents of
  |  | 
 |         the gadget,the old text are restored.
  |  | 
 |         You can also vary the size of the text and the input field.If the 
  |  | 
 |         text is longer than the input field is wide,the text is moved back
  |  | 
 |         and forth through the visible area when you move the cursor keys
  |  | 
 |         or the normal input to the border.
  |  | 
 |         You can also restrict input to just digits.This makes it posible
  |  | 
 |         to accept numeric input.Intuition even converts the digit string  
  |  | 
 |         into a binary number.This saves the machine language programmer
  |  | 
 |         some work.A specialized String gadget of this sort is called a    
  |  | 
 |         Integer gadget.
  |  | 
 |         The structure is similar to the Boolean gadgets structure.There
  |  | 
 |         are only two major differences:
  |  | 
 | 
  |  | 
 |         The type word of the structure must be a four to declare that this
  |  | 
 |         is a String gadget (STRGADGET).
  |  | 
 |   
  |  | 
 |         The pointer to the SpecialInfo structure is needed.Put a pointer
  |  | 
 |         to the StringInfo structure that you are going to design later
  |  | 
 |         here.
  |  | 
 | 
  |  | 
 |         The width and height entries in the gadget structure have a
  |  | 
 |         different meaning than they had previously.They do declare the
  |  | 
 |         area in which you can bring the mouse pointer to activate the
  |  | 
 |         String gadget.However,it is also used for representation of text. 
  |  | 
 |         These values determine the size of the box in which the text is
  |  | 
 |         output.You should surround the box with a border using the Border 
  |  | 
 |         function,so that the user can see where it is.
  |  | 
 |         If the text is longer than the box,only a portion of it is seen on
  |  | 
 |         the screen.You can move through the area by entering text or using
  |  | 
 |         the left/right cursor keys to move through the box.The characters 
  |  | 
 |         that are entered are inserted at the cursor position,so the rest
  |  | 
 |         of the text is shifted by one character when you are on the right 
  |  | 
 |         edge of the input area.The following functions can be used for
  |  | 
 |         editing this text:
  |  | 
 | 
  |  | 
 |         Cursor key left/right
  |  | 
 |               Moves the cursor over the text thats already on hand.Moves
  |  | 
 |               the text through the Container.
  |  | 
 | 
  |  | 
 |         Cursor keys with <Shift>
  |  | 
 |               Puts the cursor on the beginning or the end of the text.
  |  | 
 | 
  |  | 
 |         <Del> Deletes the character under the cursor.
  |  | 
 | 
  |  | 
 |         <Backspace>
  |  | 
 |               Deletes the character to the left of the cursor.
  |  | 
 | 
  |  | 
 |         <Return>
  |  | 
 |               Ends text input.
  |  | 
 | 
  |  | 
 |         <Amiga>right+"Q"
  |  | 
 |               This is the Undo function.It replaces the text with the
  |  | 
 |               original contents.
  |  | 
 | 
  |  | 
 |         The StringInfo structure only has a few entries:
  |  | 
 | 
  |  | 
 |         First theres a pointer to the memory area that is used to store
  |  | 
 |         the text that is input.The memory buffer must be big enough to
  |  | 
 |         handle all the text entered.
  |  | 
 | 
  |  | 
 |         strinfo:
  |  | 
 |                dc.l  strpuffer        ;pointer to text buffer
  |  | 
 | 
  |  | 
 |         Next comes the pointer to the Undo buffer.This pointer and this
  |  | 
 |         buffer are only needed if you want the Undo function.If you do,you
  |  | 
 |         must have a buffer that is at least as big as your text buffer.   
  |  | 
 |         Every time the string gadget function is called,the text buffers  
  |  | 
 |         contents are copied into this buffer.To get the old contents back,
  |  | 
 |         just press the right <Amiga>key and the "Q"key.The contents of the
  |  | 
 |         Undo buffer are copied back to the text buffer.If you use several 
  |  | 
 |         string gadgets in a program,you can use the same Undo buffer for
  |  | 
 |         all of them,since only one string gadget is used at one time.
  |  | 
 | 
  |  | 
 |                dc.l  undo             ;pointer to undo buffer
  |  | 
 | 
  |  | 
 |         The following word contains the cursor position in the text.You   
  |  | 
 |         should set this word to zero,so that the user can see the
  |  | 
 |         beginning of the text when the string gadget appears.
  |  | 
 | 
  |  | 
 |                dc.w  0                ;cursor position
  |  | 
 | 
  |  | 
 |         The next word contains the maximum number of characters that can
  |  | 
 |         be input.If you type one more than this number of characters,the  
  |  | 
 |         screen blinks,to show that you can't enter a longer input string. 
  |  | 
 |         The number of characters and the reserved space for the input
  |  | 
 |         field don't have to agree,since text can be scrolled by typing.
  |  | 
 | 
  |  | 
 |                dc.w  10               ;maximum # of characters
  |  | 
 | 
  |  | 
 |         The following word tells at which character of text in the buffer,
  |  | 
 |         the output to the box should begin.You should put a zero here,so
  |  | 
 |         that the user can see the beginning of the text.
  |  | 
 | 
  |  | 
 |                dc.w  0                ;output text from this character
  |  | 
 | 
  |  | 
 |         The next five words are used by Intuition,so you don't have to    
  |  | 
 |         initialize them.Just put zeros here.The words contain the
  |  | 
 |         following information:
  |  | 
 | 
  |  | 
 |                dc.w  0                ;character position in undo buffer
  |  | 
 |                dc.w  0                ;number of chars in text buffer
  |  | 
 |                dc.w  0                ;number of chars visible in box
  |  | 
 |                dc.w  0                ;horizontal box offset
  |  | 
 |                dc.w  0                ;vertical box offset
  |  | 
 | 
  |  | 
 |         The next two long words are initialized by Intuition as well:
  |  | 
 | 
  |  | 
 |                dc.l  0                ;pointer to rastport
  |  | 
 |                dc.l  0                ;long word with value of the input
  |  | 
 |         ;                             ;(for integer gadgets)
  |  | 
 | 
  |  | 
 |         The final entry is a pointer to the keyboard table that is used if
  |  | 
 |         the ALTKEYMAP flag of the gadget is set.
  |  | 
 | 
  |  | 
 |                dc.l  0                ;standard keyboard table
  |  | 
 | 
  |  | 
 |         Heres a quick overview of the StringInfo structure:
  |  | 
 | 
  |  | 
 |         strinfo:
  |  | 
 |                dc.l  strpuffer        ;pointer to text buffer
  |  | 
 |                dc.l  undo             ;pointer to undo buffer
  |  | 
 |                dc.w  0                ;cursor position
  |  | 
 |                dc.w  10               ;maximum # of characters
  |  | 
 |                dc.w  0                ;output text from this character
  |  | 
 |                dc.w  0                ;character position in undo buffer
  |  | 
 |                dc.w  0                ;number of chars in text buffer
  |  | 
 |                dc.w  0                ;number of chars visible in box
  |  | 
 |                dc.w  0                ;horizontal box offset
  |  | 
 |                dc.w  0                ;vertical box offset
  |  | 
 |                dc.l  0                ;pointer to rastport
  |  | 
 |                dc.l  0                ;long word with value of input
  |  | 
 |         ;                             ;(for integer gadgets)
  |  | 
 |                dc.l  0                ;standard keyboard table
  |  | 
 | 
  |  | 
 |         Here are the text and undo buffers:
  |  | 
 | 
  |  | 
 |         strpuffer:
  |  | 
 |                dc.b  "Hello!",0,0,0
  |  | 
 | 
  |  | 
 |         undo:
  |  | 
 |                dc.l  0,0,0,0
  |  | 
 |            align
  |  | 
 | 
  |  | 
 |         Once you've entered these lines,you can either alter the old
  |  | 
 |         gadget structure or build a new one.We'd recommend building
  |  | 
 |         another gadget structure so that you can have the switch and use
  |  | 
 |         it later.Change the first pointer in the old structure from zero
  |  | 
 |         to "gadget1"and insert this new structure.Here is an example
  |  | 
 |         strucure for the string gadget.It as the following entries:
  |  | 
 | 
  |  | 
 |         gadget1:                      ;*structure for string gadget
  |  | 
 |                dc.l  0                ;no more gadgets
  |  | 
 |                dc.w  20,80            ;position
  |  | 
 |                dc.w  80,10            ;width and height of box
  |  | 
 |                dc.w  0                ;flags:normal
  |  | 
 |                dc.w  2                ;activation($802 for long int)
  |  | 
 |                dc.w  4                ;type:string gadget
  |  | 
 |                dc.l  border           ;pointer to border
  |  | 
 |                dc.l  0                ;no drawing selected
  |  | 
 |                dc.l  0                ;no text
  |  | 
 |                dc.l  0                ;no exclude
  |  | 
 |                dc.l  strinfo          ;pointer to stringinfo structure
  |  | 
 |                dc.w  2                ;gadget ID
  |  | 
 |                dc.l  0                ;no user data
  |  | 
 | 
  |  | 
 |         border:                       ;*border for box frame
  |  | 
 |                dc.w  0,0              ;no offset
  |  | 
 |                dc.b  3,3              ;red colour
  |  | 
 |                dc.b  0                ;mode:JAM1
  |  | 
 |                dc.b  5                ;5 X,Y pairs
  |  | 
 |                dc.l  coord            ;pointer to coordinates table
  |  | 
 |                dc.l  0                ;no more structures
  |  | 
 | 
  |  | 
 |         coord:                        ;*coordinates for frame
  |  | 
 |                dc.w  -2,-2            ;start in upper left corner
  |  | 
 |                dc.w  80,-2            ;upper right
  |  | 
 |                dc.w  80,9             ;lower right
  |  | 
 |                dc.w  -2,9             ;lower left
  |  | 
 |                dc.w  -2,-2            ;back to beginning
  |  | 
 | 
  |  | 
 |         This data causes a red rectangle,the border,to appear around the  
  |  | 
 |         "Hello!"text.You can change the text by clicking in the field and 
  |  | 
 |         editing once the cursor appears.If you type something wrong,you
  |  | 
 |         can use the undo function(the right <Amiga> key and the Q key),to 
  |  | 
 |         get "Hello!"back.
  |  | 
 |         Once you've done some typing and deactivated the gadget by
  |  | 
 |         pressing <Return> or by clicking outside the field (cursors
  |  | 
 |         disapear),you can terminate the program.
  |  | 
 |         Change the activation flag to $802 and the "strbuffer"to "dc.l
  |  | 
 |         0,0,0,0",assemble,and then start the program.You can type in the
  |  | 
 |         string gadget once it has been activated,but you can only enter
  |  | 
 |         digits.The screen blinks if you enter letters.
  |  | 
 |         Enter a number,and then end the program after deactivating the
  |  | 
 |         gadget.If you look at the stringinfo structure you can look at the
  |  | 
 |         value of the number you input(in hex)in the eight long word.
  |  | 
 |         After looking at boolean,text and numeric input to gadgets,lets
  |  | 
 |         look at Proportional gadgets which allow the user to enter analog 
  |  | 
 |         values by moving a symbol.
  |  | 
 | 
  |  | 
 |       7.9.3.Proportional Gadgets.
  |  | 
 |       ---------------------------
  |  | 
 |         You've seen the advantages of slider devices over knobs that you
  |  | 
 |         turn,maybe on a hifi,maybe on a toaster,but certainly someplace.
  |  | 
 |         Its easier to tell the state the item is in with a slider,
  |  | 
 |         especially if several such devices are next to each other(for
  |  | 
 |         example graphic equalizers).You can represent sliders on the
  |  | 
 |         Amigas screen and work with them with the mouse.This offers a nice
  |  | 
 |         way to represent information graphically in your programs.
  |  | 
 |         You can do this with gadgets.Using Proportional gadgets,you can
  |  | 
 |         put a symbol in a frame and move horzontally and/or vertically.The
  |  | 
 |         size of the frame and the slider can be variable size,so that the
  |  | 
 |         frame size is relative to the screen size so when the window
  |  | 
 |         changes size,it will also.The slider can be set up so that its
  |  | 
 |         size in the grows or shrinks.
  |  | 
 |         These are best seen via example and experimentation.(The
  |  | 
 |         posibilities mentioned do not form a complete list by any stretch 
  |  | 
 |         of the imagination.)You want to set up a simple Proportional
  |  | 
 |         gadget that can be moved horizontally.
  |  | 
 |         You need a gadget structure that as the same form as others.To
  |  | 
 |         show the differences,heres a complete example structure for your  
  |  | 
 |         gadget.You can connect this gadget to the other one,by changing
  |  | 
 |         the first long word in the last structure to "dc.l gadget2".
  |  | 
 | 
  |  | 
 |         gadget2:                      ;*structure for Proportional gadget
  |  | 
 |                dc.l  0                ;no more gadgets
  |  | 
 |                dc.w  150,30           ;position
  |  | 
 |                dc.w  100,10           ;width and height of frame
  |  | 
 |                dc.w  4                ;flags:GADGIMAGE
  |  | 
 |                dc.w  2                ;activation:GADGIMMEDIATE
  |  | 
 |                dc.w  3                ;type:proportional gadget
  |  | 
 |                dc.l  mover            ;pointer to slider data
  |  | 
 |                dc.l  0                ;no select structure
  |  | 
 |                dc.l  0                ;no text
  |  | 
 |                dc.l  0                ;no exclude
  |  | 
 |                dc.l  propinfo         ;pointer to propinfo structure
  |  | 
 |                dc.w  3                ;gadget ID
  |  | 
 |                dc.l  0                ;no user data
  |  | 
 | 
  |  | 
 |         You see two special features.Use an image structure for the mover 
  |  | 
 |         and put a pointer to another structure in the spot for the Special
  |  | 
 |         Info pointer.
  |  | 
 |         First,lets look at the "mover"structure,the sliders image
  |  | 
 |         structure.Heres an example of this structure:
  |  | 
 | 
  |  | 
 |         mover:                        ;*structure for slider image
  |  | 
 |                dc.w  0,0              ;no offset
  |  | 
 |                dc.w  16,7             ;16x7 pixels big
  |  | 
 |                dc.w  1                ;one bit plane
  |  | 
 |                dc.l  moverdata        ;pointer to image data
  |  | 
 |                dc.b  1,0              ;colour:white
  |  | 
 |                dc.l  0                ;don't continue
  |  | 
 | 
  |  | 
 |         moverdata:                    ;*image data for mover
  |  | 
 |                dc.w %0111111111111110
  |  | 
 |                dc.w %0101111111111010
  |  | 
 |                dc.w %0101011111101010
  |  | 
 |                dc.w %0101010110101010
  |  | 
 |                dc.w %0101011111101010
  |  | 
 |                dc.w %0101111111111010
  |  | 
 |                dc.w %0111111111111110
  |  | 
 | 
  |  | 
 |         Up till now,there was'nt anything new.Now lets look at the
  |  | 
 |         PropInfo structure that describes the properties of the
  |  | 
 |         Proportional gadget.
  |  | 
 | 
  |  | 
 |         The structure starts with a flag word that contains the following 
  |  | 
 |         bits:
  |  | 
 | 
  |  | 
 |         Bits   Value   Name              Meaning
  |  | 
 |         -----------------------------------------------------------------
  |  | 
 |          0       1     AUTOKNOB          Mover is set up automatically
  |  | 
 |          1       2     FREEHORIZ         Allows horizontal movement
  |  | 
 |          2       4     FREEVERT          Allows vertical movement
  |  | 
 |          3       8     PROPBORDERLESS    Turns off automatic framing
  |  | 
 |          8      $100   KNOBHIT           Set when the mover is touched
  |  | 
 | 
  |  | 
 |         You can set the first four bits to get the representation that you
  |  | 
 |         want.Bit 8 is set by Intuition when the mover is clicked with the
  |  | 
 |         mouse pointer.
  |  | 
 |         Bit 0,AUTOKNOB,allos for the simplest sort of Proportional gadget.
  |  | 
 |         If this bit is set,no move data are used for the mover image.
  |  | 
 |         Instead,a white mover is generated that is adjusted to the size of
  |  | 
 |         the box and the values to be represented.When you use this slider
  |  | 
 |         to represent the displayed lines in a long text of a program,the
  |  | 
 |         displayed lines are a percentage of the total text.The
  |  | 
 |         relationship between the total number of lines and the lines shown
  |  | 
 |         is represented by an AUTOKNOB as the relationship between the
  |  | 
 |         frame and the slider.The bigger the percentage,the bigger the
  |  | 
 |         slider is.You don't want to work with this though,even though it
  |  | 
 |         is simple and interesting,because a simple white button isn't
  |  | 
 |         particularly attractive.If you experiment with it,make sure that
  |  | 
 |         the pointer to the image data points to a four word long buffer
  |  | 
 |         that Intuition can use to store values.The buffer is of the
  |  | 
 |         following form:
  |  | 
 | 
  |  | 
 |         buffer:
  |  | 
 |                dc.w  0                ;X position of the slider in the box
  |  | 
 |                dc.w  0                ;Y position in the box
  |  | 
 |                dc.w  0                ;width of slider
  |  | 
 |                dc.w  0                ;height of slider
  |  | 
 | 
  |  | 
 |         Leys look at the PropInfo structure.Since you're not using
  |  | 
 |         AUTOKNOB and wish to allow horizontal movement only,put two in as
  |  | 
 |         a flag:
  |  | 
 | 
  |  | 
 |         propinfo:
  |  | 
 |                dc.w  2                ;flags:FREEHORIZ
  |  | 
 | 
  |  | 
 |         In the next two words of the structure,the horizontal (HorizPot)
  |  | 
 |         and vertical (VertPot) position of sliders are stored.A value of  
  |  | 
 |         zero means left or upper,while the value $FFFF means right or
  |  | 
 |         lower.The value that results from movement is in this range.You
  |  | 
 |         set these values to zero at the start of the program.After moving 
  |  | 
 |         the mouse,there is different values here.
  |  | 
 | 
  |  | 
 |                dc.w  0,0              ;X and Y position of the slider
  |  | 
 |  
  |  | 
 |         Next come two words which determine the size of the AUTOKNOB or
  |  | 
 |         the step size of the slider(this determines how far the slider
  |  | 
 |         moves when you click in the box next to the slider).These words
  |  | 
 |         are called HorizBody (horizontal movement) and VertBody (vertical 
  |  | 
 |         movement).
  |  | 
 | 
  |  | 
 |                dc.w  $ffff/16         ;horizontal step size:1/16
  |  | 
 |                dc.w  0                ;no vertical movement
  |  | 
 |         ;The next six words are initialized by Intuition.
  |  | 
 |                dc.w  0                ;box width
  |  | 
 |                dc.w  0                ;box height
  |  | 
 |                dc.w  0                ;absolute step size horizontal
  |  | 
 |                dc.w  0                ;and vertical
  |  | 
 |                dc.w  0                ;left border of box 
  |  | 
 |                dc.w  0                ;upper border of box
  |  | 
 | 
  |  | 
 |         Thats it.Heres a quick overview of the PropInfo structure:
  |  | 
 |          
  |  | 
 |         prpoinfo:
  |  | 
 |                dc.w  2                ;flags:FREEHORIZ
  |  | 
 |                dc.w  0,0              ;X and Y position of slider
  |  | 
 |                dc.w  $ffff/16         ;horizontal step size:1/16
  |  | 
 |                dc.w  0                ;no vertical movement
  |  | 
 |                dc.w  0                ;box width
  |  | 
 |                dc.w  0                ;box height
  |  | 
 |                dc.w  0                ;absolute step size horizontal
  |  | 
 |                dc.w  0                ;and vertical
  |  | 
 |                dc.w  0                ;left border of box
  |  | 
 |                dc.w  0                ;upper border of box
  |  | 
 | 
  |  | 
 |         Once you've typed this in,you can start the program and try it
  |  | 
 |         out.
  |  | 
 |         You can also try vertical movement by setting the flag word equal
  |  | 
 |         to six,the vertical step size to $FFFF/10,and the height of the
  |  | 
 |         gadget to 80,for the example.To try out the AUTOKNOBs,change the  
  |  | 
 |         flag value to seven.
  |  | 
 | 
  |  | 
 |       7.10.Example Program.
  |  | 
 |       ---------------------
  |  | 
 |         Here is a complete example program using what you have learned in
  |  | 
 |         this chapter:
  |  | 
 | 
  |  | 
 |         ;7_Intuition.asm
  |  | 
 |         ;** Demo-Program for working with Intuition **
  |  | 
 | 
  |  | 
 |         movescreen    =-162
  |  | 
 |         openscreen    =-198
  |  | 
 |         closescreen   =-66
  |  | 
 |         openwindow    =-204
  |  | 
 |         closewindow   =-72
  |  | 
 |         autorequest   =-348
  |  | 
 |         setmenustrip  =-264
  |  | 
 |         clearmenustrip=-54
  |  | 
 |         printitext    =-216
  |  | 
 |         drawimage     =-144
  |  | 
 |         drawborder    =-108
  |  | 
 |         displaybeep   =-96
  |  | 
 |         closelibrary  =-414
  |  | 
 |         openlib       =-408
  |  | 
 |         execbase      = 4
  |  | 
 |         getmsg        =-372
  |  | 
 | 
  |  | 
 |         joy2          =$dff0c
  |  | 
 |         fire          =$bfe001
  |  | 
 | 
  |  | 
 |         ;!!!when > 500kb !!!
  |  | 
 |         ;org $40000
  |  | 
 |         ;load $40000
  |  | 
 |         ; or use AssemPro to place in CHIP RAM
  |  | 
 |         ;!!!!!!!!!!!!!!!!!!!!!!!
  |  | 
 | 
  |  | 
 |         run:   
  |  | 
 |                bsr     openint
  |  | 
 |                bsr     scropen
  |  | 
 |                bsr     windopen
  |  | 
 |                bsr     setmenu
  |  | 
 |                bsr     print
  |  | 
 | 
  |  | 
 |                lea     border,a1
  |  | 
 |                move    #22,d0
  |  | 
 |                move    #30,d1
  |  | 
 |                bsr     borderdraw
  |  | 
 |               
  |  | 
 |                bsr     draw
  |  | 
 |                
  |  | 
 |                bsr     request
  |  | 
 | 
  |  | 
 |         loop:
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                move.l  windowhd,a0
  |  | 
 |                move.l  86(a0),a0        ;user port
  |  | 
 |                jsr     getmsg(a6)
  |  | 
 |                tst.l   d0
  |  | 
 |                beq     loop             ;no event
  |  | 
 |                move.l  d0,a0
  |  | 
 |                move.l  $16(a0),msg      ;event:LO=item,HI=Event
  |  | 
 |                move.l  msg,d6           ;to test
  |  | 
 |                move.l  d6,d7
  |  | 
 |                lsr     #8,d7
  |  | 
 |                lsr     #3,d7            ;sub menu point in D7
  |  | 
 |                clr.l   d5
  |  | 
 |                roxr    #1,d6
  |  | 
 |                roxl    #1,d5            ;menu number in D5
  |  | 
 |                and.l   #$7f,d6
  |  | 
 |                cmp     #$7f,d6          ;no menu point?
  |  | 
 |                beq     loop             ;no:continue
  |  | 
 |                lsr     #4,d6            ;menu point in D6
  |  | 
 |                cmp     #1,d6            ;point 2?
  |  | 
 |                bne     no1
  |  | 
 |                move,l  intbase,a6
  |  | 
 |                move.l  screenhd,a0
  |  | 
 |                jsr     displaybeep(a6)
  |  | 
 | 
  |  | 
 |         no1:
  |  | 
 |                cmp     #0,d6
  |  | 
 |                bne     loop
  |  | 
 | 
  |  | 
 |         ende:
  |  | 
 |                bsr     clearmenu
  |  | 
 |                bsr     windclose
  |  | 
 |                bsr     scrclose
  |  | 
 |                bsr     closeint
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         openint:
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                lea     intname,a1
  |  | 
 |                jsr     openlib(a6)
  |  | 
 |                move.l  d0,intbase
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         closeint:
  |  | 
 |                move.l  execbase,a6
  |  | 
 |                move.l  intbase,a1
  |  | 
 |                jsr     closelibrary(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         scropen:
  |  | 
 |                move.l  inbase,a6
  |  | 
 |                lea     screen_defs,a0
  |  | 
 |                jsr     openscreen(a6)
  |  | 
 |                move.l  d0,screenhd
  |  | 
 | 
  |  | 
 |         scrclose:
  |  | 
 |                move.l  inbase,a6
  |  | 
 |                move.l  screenhd,a0
  |  | 
 |                jsr     closescreen(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         scrmove:
  |  | 
 |                move.l  intbase,a6
  |  | 
 |                move,l  screenhd,a0
  |  | 
 |                jsr     movescreen(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         windopen:
  |  | 
 |                move.l  intbase,a6
  |  | 
 |                lea     windowdef,a0
  |  | 
 |                jsr     openwindow(a6)
  |  | 
 |                move.l  d0,windowhd
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         windclose:
  |  | 
 |                move.l  intbase,a6
  |  | 
 |                move.l  windowhd,a0
  |  | 
 |                jsr     closewindow(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         request:
  |  | 
 |                move.l  windowhd,a0
  |  | 
 |                lea     btext,a1
  |  | 
 |                lea     ltext,a2
  |  | 
 |                lea     rtext,a3
  |  | 
 |                move.l  #0,d0
  |  | 
 |                move.l  #0,d1
  |  | 
 |                move.l  #180,d2
  |  | 
 |                move.l  #80,d3
  |  | 
 |                move.l  intbase,a6
  |  | 
 |                jsr     autorequest(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         setmenu:
  |  | 
 |                lea     mentab,a0        ;pointer to text pointer in A0
  |  | 
 |                lea     menu,a1          ;pointer to menu field in A1
  |  | 
 |                move    #10,d1           ;menu position = 10
  |  | 
 | 
  |  | 
 |         menuloop:
  |  | 
 |                clr.l   d2               ;menu point-Y=0
  |  | 
 |                move.l  a1,a2            ;save pointer
  |  | 
 |                tst.l   (a0)
  |  | 
 |                beq     setmenu1         ;end
  |  | 
 |                clr.l   (a1)+
  |  | 
 |                move    d1,(a1)+
  |  | 
 |                add.l   #70,d1
  |  | 
 |                move.l  #50,(a1)+
  |  | 
 |                move.l  #$a0001,(a1)+
  |  | 
 |                move.l  (a0)+,(a1)+      ;menu title
  |  | 
 |                lea     12(a1),a3
  |  | 
 |                move.l  a3,(a1)+         ;menu point
  |  | 
 |                clr.l   (a1)+
  |  | 
 |                clr.l   (a1)+
  |  | 
 | 
  |  | 
 |         itemloop:
  |  | 
 |                tst.l   (a0)             ;last one?
  |  | 
 |                beq     menuend          ;yes
  |  | 
 |                lea     54(a1),a3
  |  | 
 |                move.l  a3,(a1)+         ;pointer to next point
  |  | 
 |                move.l  d2,(a1)+         ;X/Y
  |  | 
 |                add     #10,d2
  |  | 
 |                move.l  #$5a000a,(a1)+   ;width/height
  |  | 
 |                move    #$52,(a1)+
  |  | 
 |                clr.l   (a1)+
  |  | 
 |                lea     16(a1),a3
  |  | 
 |                move.l  a3,(a1)+         ;text structor-pointer
  |  | 
 |                clr.l   (a1)+
  |  | 
 |                clr.l   (a1)+
  |  | 
 |                clr.l   (a1)+
  |  | 
 | 
  |  | 
 |                move    #$1,(a1)+        ;text-structor set
  |  | 
 |                clr     (a1)+
  |  | 
 |                move.l  #$50003,(a1)+
  |  | 
 |                clr.l   (a1)+
  |  | 
 |                move.l  (a0)+,(a1)+      ;text pointer
  |  | 
 |                clr.l   (a1)+
  |  | 
 | 
  |  | 
 |                bra     itemloop         ;next point...
  |  | 
 | 
  |  | 
 |         menuend:
  |  | 
 |                clr.l   -54(a1)
  |  | 
 |                tst.l   (a0)+
  |  | 
 |                tst.l   (a0)             ;still in menu?
  |  | 
 |                beq     setmenu1         ;no:ready
  |  | 
 |                move.l  a1,(a2)          ;pointer to next menu
  |  | 
 |                bra     menuloop         ;and continue
  |  | 
 | 
  |  | 
 |         setmenu1:
  |  | 
 |                move.l  intbase,a6
  |  | 
 |                move.l  windowhd,a0
  |  | 
 |                lea     menu,a1
  |  | 
 |                jsr     setmenustrip(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         clearmenu:
  |  | 
 |                move.l  intbase,a6
  |  | 
 |                move.l  windowhd,a0
  |  | 
 |                jsr     clearmenustrip(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         print:
  |  | 
 |                move.l  intbase,a6
  |  | 
 |                move.l  windowhd,a0
  |  | 
 |                move.l  50(a0),a0
  |  | 
 |                lea     ggtext,a1
  |  | 
 |                move.l  #30,d0           ;X
  |  | 
 |                move.l  #16,d1           ;Y
  |  | 
 |                jsr     printitext(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         draw:
  |  | 
 |                move.l  intbase,a6
  |  | 
 |                move.l  windowhd,a0
  |  | 
 |                move.l  50(a0),a0
  |  | 
 |                lea     image,a1
  |  | 
 |                move.l  #200,d0
  |  | 
 |                move.l  #100,d1
  |  | 
 |                jsr     drawimage(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         borderdraw:
  |  | 
 |                move.l  intbase,a6
  |  | 
 |                move.l  windowhd,a0
  |  | 
 |                move.l  50(a0),a0
  |  | 
 |                jsr     drawborder(a6)
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         screen_defs:
  |  | 
 |                dc.w  0,0
  |  | 
 |                dc.w  640,200
  |  | 
 |                dc.w  4
  |  | 
 |                dc.b  0
  |  | 
 |                dc.b  1
  |  | 
 |                dc.w  $800
  |  | 
 |                dc.w  15
  |  | 
 |                dc.l  0
  |  | 
 |                dc.l  tite1
  |  | 
 |                dc.l  0
  |  | 
 |                dc.l  0
  |  | 
 | 
  |  | 
 |         windowdef:
  |  | 
 |                dc.w  10,20
  |  | 
 |                dc.w  300,150
  |  | 
 |                dc.b  0,1
  |  | 
 |                dc.l  $300
  |  | 
 |                dc.l  $100f
  |  | 
 |                dc.l  gadget
  |  | 
 |                dc.l  0
  |  | 
 |                dc.l  windname
  |  | 
 | 
  |  | 
 |         screenhd:
  |  | 
 |                dc.l  0
  |  | 
 |                dc.l  0 
  |  | 
 |                dc.w  200,40,600,200
  |  | 
 |                dc.w  $f
  |  | 
 | 
  |  | 
 |         btext:
  |  | 
 |                dc.b  3,3
  |  | 
 |                dc.b  0
  |  | 
 |                align
  |  | 
 |                dc.w  10,10
  |  | 
 |                dc.l  0
  |  | 
 |                dc.l  bodytxt
  |  | 
 |                dc.l  0
  |  | 
 |       
  |  | 
 |         bodytxt:dc.b  "Requester-Text",0
  |  | 
 |                align
  |  | 
 | 
  |  | 
 |         ltext:
  |  | 
 |                dc.b  3,1
  |  | 
 |                dc.b  0
  |  | 
 |                align  dc.w 5,3
  |  | 
 |                dc.l  0
  |  | 
 |                dc.l  lefttext
  |  | 
 |                dc.l  0
  |  | 
 | 
  |  | 
 |         lefttext: dc.b "left",0
  |  | 
 |                align
  |  | 
 | 
  |  | 
 |         rtext:
  |  | 
 |                dc.b  0,1
  |  | 
 |                dc.b  0
  |  | 
 |                align  dc.w 5,3
  |  | 
 |                dc.l  0
  |  | 
 |                dc.l  righttext
  |  | 
 |                dc.l  0
  |  | 
 | 
  |  | 
 |         righttext: dc.b "right",0
  |  | 
 |                align
  |  | 
 |         tite1: dc.b  "User Screen",0
  |  | 
 |         windname: dc.b "Window-Title",0
  |  | 
 |                align  windowhd: dc.l 0
  |  | 
 | 
  |  | 
 |         intbase:dc.l  0
  |  | 
 |         intname:dc.b  "intuition.library",0
  |  | 
 |                align  msg:dc.l 0
  |  | 
 | 
  |  | 
 |         mentab:
  |  | 
 |                dc.l  menu1
  |  | 
 |                dc.l  mp11,np12,mp13,mp14,mp15,mp16,mp17,mp18,mp19,0
  |  | 
 |                dc.l  menu2
  |  | 
 |                dc.l  mp21,mp22,mp23,0
  |  | 
 |                dc.l  menu3
  |  | 
 |                dc.l  mp31,mp32,0
  |  | 
 |                dc.l  menu4,mp41,0
  |  | 
 |                dc.l  0
  |  | 
 | 
  |  | 
 |         menu1: dc.b  "Menu 1",0
  |  | 
 |         mp11:  dc.b  "Point 11",0
  |  | 
 |         mp12:  dc.b  "Point 12",0
  |  | 
 |         mp13:  dc.b  "Point 13",0
  |  | 
 |         mp14:  dc.b  "Point 14",0
  |  | 
 |         mp15:  dc.b  "Point 15",0
  |  | 
 |         mp16:  dc.b  "Point 16",0
  |  | 
 |         mp17:  dc.b  "Point 17",0
  |  | 
 |         mp18:  dc.b  "Point 18",0
  |  | 
 |         mp19:  dc.b  "Point 19",0
  |  | 
 | 
  |  | 
 |         menu2: dc.b  "Menu 2",0
  |  | 
 |         mp21:  dc.b  "End!",0
  |  | 
 |         mp22:  dc.b  "Beep",0
  |  | 
 |         mp23:  dc.b  "Point 23",0
  |  | 
 |   
  |  | 
 |         menu3: dc.b  "Menu 3",0
  |  | 
 |         mp31:  dc.b  "Point 31",0
  |  | 
 |         mp32:  dc.b  "Point 32",0
  |  | 
 | 
  |  | 
 |         menu4: dc.b  "Menu 4",0
  |  | 
 |         mp41:  dc.b  "Point 41",0
  |  | 
 |                align
  |  | 
 | 
  |  | 
 |         gadget:
  |  | 
 |                dc.l  gadget1
  |  | 
 |                dc.w  20,80,80,10
  |  | 
 |                dc.w  0
  |  | 
 |                dc.w  $2               ;activation,$802 for longint
  |  | 
 |                dc.w  4
  |  | 
 |                dc.l  border
  |  | 
 |                dc.l  0
  |  | 
 |                dc.l  0
  |  | 
 |                dc.l  0
  |  | 
 |                dc.l  strinfo
  |  | 
 |                dc.w  2
  |  | 
 |                dc.l  0
  |  | 
 | 
  |  | 
 |         border:
  |  | 
 |                dc.w  0,0
  |  | 
 |                dc.b  1,0,0
  |  | 
 |                dc.d  5               ;XY-pair
  |  | 
 |                dc.l  koord
  |  | 
 |                dc.l  0
  |  | 
 | 
  |  | 
 |         koord:
  |  | 
 |                dc.w  -2,-2,80,-2,80,9,-2,9,-2,-2
  |  | 
 | 
  |  | 
 |         strinfo:
  |  | 
 |                dc.l  strpuffer
  |  | 
 |                dc.l  undo
  |  | 
 |                dc.w  0               ;cursor position
  |  | 
 |                dc.w  10              ;max.char
  |  | 
 |                dc.w  0  
  |  | 
 |                dc.w  0,0,0,0,0
  |  | 
 |                dc.l  0,0,0
  |  | 
 | 
  |  | 
 |         strpuffer:
  |  | 
 |                dc.b  "Hello!",0,0,0
  |  | 
 |         
  |  | 
 |         undo:  dc.l  0,0,0
  |  | 
 |                align
  |  | 
 | 
  |  | 
 |         gadget1:
  |  | 
 |                dc.l  gadget2           ;more gadget
  |  | 
 |                dc.w  40,50,32,13
  |  | 
 |                dc.w  $6                ;flags:invert
  |  | 
 |                dc.w  $103              ;activate
  |  | 
 |                dc.w  1                 ;gadget type
  |  | 
 |                dc.l  image             ;gadget image
  |  | 
 |                dc.l  image2            ;select gadget
  |  | 
 |                dc.l  ggtext            ;gadget text
  |  | 
 |                dc.l  0                 ;no exclude
  |  | 
 |                dc.l  0                 ;special info
  |  | 
 |                dc.w  1                 ;ID
  |  | 
 |                dc.l  0                 ;user data
  |  | 
 | 
  |  | 
 |         ggtext:
  |  | 
 |                dc.b  1,0,1
  |  | 
 |                align
  |  | 
 |                dc.w  -8,14
  |  | 
 |                dc.l  0
  |  | 
 |                dc.l  swtext
  |  | 
 |                dc,l  0
  |  | 
 |        
  |  | 
 |         swtext:
  |  | 
 |                dc.b  "Switch",0
  |  | 
 |                align
  |  | 
 | 
  |  | 
 |         image:
  |  | 
 |                dc.w  0,0
  |  | 
 |                dc.w  32,13
  |  | 
 |                dc.w  1
  |  | 
 |                dc.l  imgdata
  |  | 
 |                dc.b  2,1
  |  | 
 |                dc.l  0
  |  | 
 | 
  |  | 
 |         image2:
  |  | 
 |                dc.w  0,0
  |  | 
 |                dc.w  32,13
  |  | 
 |                dc.w  1
  |  | 
 |                dc.l  imgdata2
  |  | 
 |                dc.b  2,1
  |  | 
 |                dc.l  0
  |  | 
 | 
  |  | 
 |         imgdata:
  |  | 
 |                dc.l 0
  |  | 
 |                dc.l %00000000011100000000000000000000
  |  | 
 |                dc.l %00000000111110000011101001000000
  |  | 
 |                dc.l %00000000111110000010101101000000
  |  | 
 |                dc.l %00000000011110000010101011000000
  |  | 
 |                dc.l %00000000000111000011101001000000
  |  | 
 |                dc.l %00000000000011100000000000000000
  |  | 
 |                dc.l %00000000000001110000000000000000
  |  | 
 |                dc.l %00000000000111111111100000000000
  |  | 
 |                dc.l %00000000001111111111110000000000
  |  | 
 |                dc.l %00000000001111111111110000000000
  |  | 
 |                dc.l %00000000000110000001100000000000
  |  | 
 |                dc.l 0
  |  | 
 | 
  |  | 
 |         imgdata2:
  |  | 
 |                dc.l 0
  |  | 
 |                dc.l %00000000000000000000111000000000
  |  | 
 |                dc.l %00011101110111000001111100000000
  |  | 
 |                dc.l %00010101000100000001111100000000
  |  | 
 |                dc.l %00010101100110000001111000000000
  |  | 
 |                dc.l %00011101000100000011100000000000
  |  | 
 |                dc.l %00000000000000000111000000000000
  |  | 
 |                dc.l %00000000000000001110000000000000
  |  | 
 |                dc.l %00000000000111111111100000000000
  |  | 
 |                dc.l %00000000001111111111110000000000
  |  | 
 |                dc.l %00000000001111111111110000000000
  |  | 
 |                dc.l %00000000000110000001100000000000
  |  | 
 |                dc.l 0
  |  | 
 | 
  |  | 
 |         gadget2:
  |  | 
 |                dc.l  0
  |  | 
 |                dc.w  150,30,100,50
  |  | 
 |                dc.w  5
  |  | 
 |                dc.w  2
  |  | 
 |                dc.w  3                   ;prop.gadet
  |  | 
 |                dc.l  mover               ;border
  |  | 
 |                dc.l  0,0,0
  |  | 
 |                dc.l  specinfo
  |  | 
 |                dc.w  3
  |  | 
 |                dc.l  0
  |  | 
 | 
  |  | 
 |         specinfo:
  |  | 
 |                dc.w  6                   ;flags:free horiz
  |  | 
 |                dc.w  0,0
  |  | 
 |                dc.w  $ffff/10,$ffff/5
  |  | 
 |                dc.w  0,0,0,0,0,0
  |  | 
 | 
  |  | 
 |         mover:
  |  | 
 |                dc.w  0,0,16,7
  |  | 
 |                dc.w  1
  |  | 
 |                dc.l  moverdata
  |  | 
 |                dc.b  1,0
  |  | 
 |                dc.l  0
  |  | 
 | 
  |  | 
 |         moverdata:
  |  | 
 |                dc.w %0111111111111110
  |  | 
 |                dc.w %0101111111111010
  |  | 
 |                dc.w %0101011111101010
  |  | 
 |                dc.w %0101010110101010
  |  | 
 |                dc.w %0101011111101010
  |  | 
 |                dc.w %0101111111111010
  |  | 
 |                dc.w %0111111111111110
  |  | 
 | 
  |  | 
 |         menu:blk.w  500
  |  | 
 | 
  |  | 
 |                end
  |  | 
 |                
  |  | 
 |                
  |  | 
 | 
  |  | 
 | 
  |  | 
 |       Chapter 8.
  |  | 
 |       ----------
  |  | 
 |       8.Advanced Programming.
  |  | 
 |       -----------------------
  |  | 
 |         You've learned a lot about machine language programming on the
  |  | 
 |         Amiga.What you need yet are a few routines that can be used as
  |  | 
 |         programming tools.We'll work on that right now.They'll be easy to 
  |  | 
 |         use in your own program.The sky's the limit now!
  |  | 
 | 
  |  | 
 |       8.1.Supervisor Mode.
  |  | 
 |       --------------------
  |  | 
 |         As mentioned in the chapter on the MC68000 processor,there are two
  |  | 
 |         operating modes:the User and the Supervisor mode.It is often
  |  | 
 |         necessary to move between the two modes.However,this isn't a
  |  | 
 |         simple process.
  |  | 
 |         The reason you want to do this,is that in User mode,you can't
  |  | 
 |         access the Status register.If you write to one of them,an
  |  | 
 |         Exception is executed which crashes the program.
  |  | 
 | 
  |  | 
 |         How can you get in Supervisor mode?
  |  | 
 | 
  |  | 
 |         No problem.The operating system of the Amiga contains a function
  |  | 
 |         in the EXEC library that lets you get into supervisor mode.Its
  |  | 
 |         called SuperState and it doesn't need any parameters.You can
  |  | 
 |         easily call this program by using the following lines:
  |  | 
 | 
  |  | 
 |         execbase    = 4                 ;exec base address
  |  | 
 |         superstate  =-150               ;turn on function
  |  | 
 |                ...
  |  | 
 |                move.l  execbase,a6      ;exec base address in A6
  |  | 
 |                jsr     superstate(a6)   ;turn on supervisor mode
  |  | 
 |                move.l  d0,savesp        ;save return value
  |  | 
 |                ...
  |  | 
 |         savesp:blk.l   1                ;space for sp value
  |  | 
 | 
  |  | 
 |         You get the value of the Stack Pointer(SP)back in the D0 register.
  |  | 
 |         You'll also find it in register A7,but this register is changed   
  |  | 
 |         regularly.The reason is that in Supervisor mode,the Amiga works
  |  | 
 |         with all the Interrupts and with the SP,and there are lots of     
  |  | 
 |         Interrupts for this computor.We'll talk about interrupts in a bit.
  |  | 
 | 
  |  | 
 |         After this call,you'll use the user stack instead of the
  |  | 
 |         supervisor stack.In this way,you can access the old user stack.You
  |  | 
 |         need to make sure that the user stack is large enough since the   
  |  | 
 |         interrupts must have enough room for their data on the stack.
  |  | 
 |         You need to save the value returned in D0,because you'll need this
  |  | 
 |         value later.You need to return to user mode sometime.Theres a
  |  | 
 |         function for this in the exec library as well.It is called the    
  |  | 
 |         UserState function.It needs one parameter,the SP value that comes 
  |  | 
 |         back from the SuperState function.
  |  | 
 |         Since you've saved this value in the long word starting at
  |  | 
 |         "savesp",you can write the following:
  |  | 
 | 
  |  | 
 |         userstate     =-156
  |  | 
 |                ...
  |  | 
 |                move.l  execbase,a6      ;exec base address in A6
  |  | 
 |                move.l  savesp,d0        ;put old sp in D0
  |  | 
 |                jsr     userstate(a6)    ;return to user mode
  |  | 
 | 
  |  | 
 |         Now you are back in the user mode.The user stack point(USP)is the 
  |  | 
 |         same as before.You can write functions that need to be run from
  |  | 
 |         the supervisor mode as subroutines.First you call superstate,save 
  |  | 
 |         the return value,execute the desired function,call userstate,and  
  |  | 
 |         end with a RTS command.If the USP was changed,the RTS command     
  |  | 
 |         would'nt work right,and the computor would jump who knows where
  |  | 
 |         and perhaps crash.Here it works though.
  |  | 
 |         Now comes the question:how does the operating system get the
  |  | 
 |         supervisor mode?Thats not too difficult;it goes like this:
  |  | 
 | 
  |  | 
 |         The superstate function attempts to access a Status Register.This 
  |  | 
 |         causes an Exception to occur and a routine is called whose address
  |  | 
 |         begins at the long word starting at $20.It is the Exception Vector
  |  | 
 |         for Privilege Violation.The routine that it branches to is called 
  |  | 
 |         in supervisor mode.Then it tests where this exception came from.If
  |  | 
 |         the routine finds that the exception comes from the superstate    
  |  | 
 |         routine whose address it knows,the matter is settled.It just
  |  | 
 |         branches to the routine without turning off the user mode.Thats
  |  | 
 |         all there is to it.
  |  | 
 | 
  |  | 
 |       8.2.Exception Programming.
  |  | 
 |       --------------------------
  |  | 
 |         The exceptions described in the processor chapter offer you a lot 
  |  | 
 |         of oppertunities to control the Amiga's functions.You can use them
  |  | 
 |         to specify how errors should be handled and even list a crash
  |  | 
 |         program.
  |  | 
 | 
  |  | 
 |         Here is a list of vectors that are used to jump to the exception  
  |  | 
 |         routines:
  |  | 
 | 
  |  | 
 |         Number      Address          Use with
  |  | 
 |         ------------------------------------------------------------------
  |  | 
 |           2         $008             Bus error
  |  | 
 |           3         $00C             Address eror
  |  | 
 |           4         $010             Illegal command
  |  | 
 |           5         $014             Division by zero
  |  | 
 |           6         $018             CHK command
  |  | 
 |           7         $01C             TRAPV command
  |  | 
 |           8         $020             Privilege Violation
  |  | 
 |           9         $024             Trace
  |  | 
 |          10         $028             Axxx command emulation
  |  | 
 |          11         $02C             Fxxx command emulation
  |  | 
 |                     $030-$038        Reserved
  |  | 
 |          15         $03C             Uninitialized interrupt
  |  | 
 |                     $040-$05F        Reserved
  |  | 
 |          24         $060             Unauthorised interrupt
  |  | 
 |         25-31       $064-$083        Level 1-7 interrupt
  |  | 
 |         32-47       $080-$0BF        TRAP commands
  |  | 
 |                     $0C0-$0FF        Reserved
  |  | 
 |         64-255      $100-$3FF        User interrupt vector
  |  | 
 | 
  |  | 
 |         Lets look at the TRAP commands as an example.They aren't used in
  |  | 
 |         the Amiga operating system.A TRAP command and a number between
  |  | 
 |         zero and fifteen are used to call one of the 16 posible TRAP
  |  | 
 |         routines.If the command TRAP #0 is executed,the processor (in
  |  | 
 |         supervisor mode)branches to the routine whose address lies at $80 
  |  | 
 |         in memory.This routine must end with a RTE(ReTurn from Exception) 
  |  | 
 |         command.
  |  | 
 |         Some operating systems,for example,the ATARI ST's TOS operating   
  |  | 
 |         systems,are completely callable via these TRAP's.Parameters are
  |  | 
 |         put on the stack,and then a TRAP command is executed.The advantage
  |  | 
 |         is that you don't have to know any of the operating systems
  |  | 
 |         addresses.In the Amiga you must know the addresses(Execbase=4).
  |  | 
 | 
  |  | 
 |         Lets write your own TRAP routine to demonstrate the use of the
  |  | 
 |         TRAP command.You'll need three program sections:
  |  | 
 | 
  |  | 
 |         1.The initialization of the TRAP vector.
  |  | 
 |         2.The TRAP routine itself(It must end with RTE).
  |  | 
 |         3.A test routine that calls the TRAP command.
  |  | 
 | 
  |  | 
 |         Initialization is very short:
  |  | 
 | 
  |  | 
 |         init:
  |  | 
 |                move.l  #trap0,$80        ;set vector for TRAP #0
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         Now you need to write the trap0 routine.Lets use the example from 
  |  | 
 |         the hardware chapter that produced a beep.
  |  | 
 |         Lets write this routine using as little effort as possible.Change 
  |  | 
 |         the RTS to a RTE at the end,erase the line in which the loop
  |  | 
 |         counter D0 was loaded for the tone production,and change the loop 
  |  | 
 |         so that it works with long words.Now you can load the register
  |  | 
 |         with an arbitrary value and have the TRAP #0 followed by a peep of
  |  | 
 |         arbitrary duration.
  |  | 
 | 
  |  | 
 |         ;** beep tone production after a TRAP #0 **
  |  | 
 | 
  |  | 
 |         ctlw   =$dff096                  ;DMA control
  |  | 
 |         c0thi  =$dff0a0                  ;HI table address
  |  | 
 |         c0tlo  =c0thi+2                  ;LO table address
  |  | 
 |         c0tl   =c0thi+4                  ;table length
  |  | 
 |         c0per  =c0thi+6                  ;read in rate
  |  | 
 |         c0vol  =c0thi+8                  ;volume
  |  | 
 | 
  |  | 
 |         trap0:                           ;* produce a short peep
  |  | 
 |                move.l  #table,c0thi      ;table beginning
  |  | 
 |                move    #4,c0tl           ;table length
  |  | 
 |                move    #300,c0per        ;read in rate
  |  | 
 |                move    #40,c0vol         ;volume
  |  | 
 |                move    #$8201,ctlw       ;start DMA (sound)
  |  | 
 | 
  |  | 
 |         loop:
  |  | 
 |                subq.l  #1,d0             ;counter -1
  |  | 
 |                bne     loop              ;count dwn to zero
  |  | 
 | 
  |  | 
 |         still:
  |  | 
 |                move    #1,ctlw           ;turn on tone
  |  | 
 |                rte                       ;exception end
  |  | 
 | 
  |  | 
 |         table:                           ;sound table
  |  | 
 |                dc.b    -40,-70,-40,0,40,70,40,0
  |  | 
 | 
  |  | 
 |         You need to make sure that "table"is in CHIP RAM($00000-$7FFFF),
  |  | 
 |         otherwise the sound chip can't access the data!
  |  | 
 | 
  |  | 
 |         After entering this,you can test it out using the following
  |  | 
 |         routine:
  |  | 
 | 
  |  | 
 |         test:
  |  | 
 |                move.l  #$2ffff,d0        ;pass tone length in D0
  |  | 
 |                trap    #0                ;carry out exception:peep
  |  | 
 |                rts
  |  | 
 | 
  |  | 
 |         Now assemble both routines and start the initialization routine,  
  |  | 
 |         init.Nothing happens.
  |  | 
 |         Start the second routine,test.A beep that lasts about one second
  |  | 
 |         is output.
  |  | 
 |         One thing you must keep in mind is that if you change the program 
  |  | 
 |         and reassemble it,the address of the trap0 routine can change.    
  |  | 
 |         Before you execute the TRAP command,you must repeat the initializ-
  |  | 
 |         ation,so that the computor doesn't jump to the wrong location!               
  |  | 
 |         
  |  | 
 | 
  |  | 
 | 
  |  | 
 | 
  |  | 
 |       Appendices.
  |  | 
 |       -----------
  |  | 
 |       Overview of Library Functions.
  |  | 
 |       ------------------------------
  |  | 
 |         The following table gives you an overview of the available
  |  | 
 |         libraries and their functions.Each sublist of functions is
  |  | 
 |         preceded by the name of the library it is found in.
  |  | 
 |         These functions are listed with their negative offset in hex and  
  |  | 
 |         decimal.Their name and their parameters are also specified.The    
  |  | 
 |         parameter names are in parenthesis behind the function name.The   
  |  | 
 |         second set of parenthesis includes a list of registers that
  |  | 
 |         correspond to the parameter names.If no parameters are needed,we  
  |  | 
 |         put () to let you know.
  |  | 
 | 
  |  | 
 |  CLIST.LIBRARY
  |  | 
 |   -$001E  -30             InitCLPool (cLPool,size) (A0,D0)
  |  | 
 |   -$0024  -36             AllocCList (cLPool) (A1)
  |  | 
 |   -$002A  -42             FreeCList (cList) (A0)
  |  | 
 |   -$0030  -48             FlushCList (cList) (A0)
  |  | 
 |   -$0036  -54             SizeCList (cList) (A0)
  |  | 
 |   -$003C  -60             PutCLChar (cList,byte) (A0,D0)
  |  | 
 |   -$0042  -66             GetCLChar (cList) (A0)
  |  | 
 |   -$0048  -72             UnGetCLChar (cList,byte) (A0,D0)
  |  | 
 |   -$004E  -78             UpPutCLChar (cList) (A0)
  |  | 
 |   -$0054  -84             PutCLWord (cList,word) (A0,D0)
  |  | 
 |   -$005A  -90             GetCLWord (cList) (A0)
  |  | 
 |   -$0060  -96             UnGetCLWord (cList,word) (A0,D0)
  |  | 
 |   -$0066  -102            UnPutCLWord (cList) (A0)
  |  | 
 |   -$006C  -108            PutCLBuf (cList,buffer,length) (A0,A1,D1)
  |  | 
 |   -$0072  -114            GetCLBuf (cList,buffer,maxLength) (A0,A1,D1)
  |  | 
 |   -$0078  -120            MarkCList (cList,offset) (A0,D0)
  |  | 
 |   -$007E  -126            IncrCLMark (cList) (A0)
  |  | 
 |   -$0084  -132            PeekCLMark (cList) (A0)
  |  | 
 |   -$008A  -138            SplitCList (cList) (A0)
  |  | 
 |   -$0090  -144            CopyCList (cList) (A0)
  |  | 
 |   -$0096  -150            SubCList (cList,index,length) (A0,D0.D1)
  |  | 
 |   -$009C  -156            ConcatCList (sourceCList,destCList) (A0,A1)
  |  | 
 | 
  |  | 
 |  CONSOLE.LIBRARY
  |  | 
 |   -$002A  -42             CDInputHandler (events,device) (A0,A1)
  |  | 
 |   -$0030  -48             RawKeyConvert (events,buffer,length,keyMap)
  |  | 
 |                                         (A0,A1,D1,A2)
  |  | 
 |  DISKFONT.LIBRARY
  |  | 
 |   -$001E  -30             OpenDiskFont (textAttr) (A0)
  |  | 
 |   -$0024  -36             AvailFonts (buffer,bufBytes,flags) (A0,D0,D1)
  |  | 
 | 
  |  | 
 |  DOS.LIBRARY
  |  | 
 |   -$001e   -30            Open (name,access mode)(d1,d2)
  |  | 
 |   -$0024   -36            Close (file)(d1)
  |  | 
 |   -$002a   -42            Read (file,buffer,length)(d1,d2,d3)
  |  | 
 |   -$0030   -48            Write (file,buffer,length)(d1,d2,d3)
  |  | 
 |   -$0036   -54            Input()
  |  | 
 |   -$003c   -60            Output()
  |  | 
 |   -$0042   -66            Seek(file,position,offset)(d1,d2,d3)
  |  | 
 |   -$0048   -72            DeleteFile (name)(d1)
  |  | 
 |   -$004e   -78            Rename(oldname,newname)(d1,d2)
  |  | 
 |   -$0054   -84            Lock(name,type)(d1,d2)
  |  | 
 |   -$005a   -90            UnLock(lock)(d1)
  |  | 
 |   -$0060   -96            DupLock(lock)(d1)
  |  | 
 |   -$0066   -102           Examine(lock,fileinfoblock)(d1,d2)
  |  | 
 |   -$006c   -108           ExNext(lock,fileinfoblock)(d1,d2)
  |  | 
 |   -$0072   -114           Info(lock,parameterblock)(d1,d2)
  |  | 
 |   -$0078   -120           CreateDir(name)(d1)
  |  | 
 |   -$007e   -126           CurrentDir(lock)(d1)
  |  | 
 |   -$0084   -132           IoErr()
  |  | 
 |   -$008a   -138           CreateProc(name,pri,seglist,stacksize)(d1,d2,d3,d4)
  |  | 
 |   -$0090   -144           Exit(returncode)(d1)
  |  | 
 |   -$0096   -150           LoadSeg(filename)(d1)
  |  | 
 |   -$009c   -156           UnLoadSeg(segment)(d1)
  |  | 
 |   -$00a2   -162           Getpacket(wait)(d1)
  |  | 
 |   -$00a8   -168           Queuepacket(packet)(d1)
  |  | 
 |   -$00ae   -174           DeviceProc(name)(d1)
  |  | 
 |   -$00be   -180           SetComment(name,comment)(d1,d2)
  |  | 
 |   -$ooba   -186           SetProtection(name,mask)(d1,d2)
  |  | 
 |   -$00c0   -192           DateStamp(date)(d1)
  |  | 
 |   -$00c6   -198           Delay(timeout)(d1)
  |  | 
 |   -$00cc   -204           WaitForChar(file,timeout)(d1,d2)
  |  | 
 |   -$00d2   -210           ParentDir(lock)(d1)
  |  | 
 |   -$00d8   -216           IsInteractive(file)(d1)
  |  | 
 |   -$00de   -222           Execute(string,file,file)(d1,d2,d3)
  |  | 
 | 
  |  | 
 |  EXEC.LIBRARY
  |  | 
 |   -$001e   -30            Supervisor()
  |  | 
 |   -$0024   -36            ExitIntr()
  |  | 
 |   -$002a   -42            Schedule()
  |  | 
 |   -$0030   -48            Reschedule()
  |  | 
 |   -$0036   -54            Switch()
  |  | 
 |   -$003c   -60            Dispatch()
  |  | 
 |   -$0042   -66            Exception()
  |  | 
 |   -$0048   -72            InitCode(startclass,version)(d0,d1)
  |  | 
 |   -$004e   -78            InitStruct(inittable,memory,size)(a1,a2,d0)
  |  | 
 |   -$0054   -84            MakeLibrary(funcinit,structinit,libinit,datasize,
  |  | 
 |                           codesize)(a0,a1,a2,d0,d1)
  |  | 
 |   -$005a   -90            MakeFunctions(target,functionarray,funcdispbase)
  |  | 
 |                           (a0,a1,a2)
  |  | 
 |   -$0060   -96            FindResident(name)(a1)
  |  | 
 |   -$0066   -102           InitResident(resident,seglist)(a1,d1)
  |  | 
 |   -$006c   -108           Alert(alertnum,parameters)(d7,a5)
  |  | 
 |   -$0072   -114           Debug()
  |  | 
 |   -$0078   -120           Disable()
  |  | 
 |   -$007e   -126           Enable()
  |  | 
 |   -$0084   -132           Forbid()
  |  | 
 |   -$008a   -138           Permit()
  |  | 
 |   -$0090   -144           SetSR(newsr,mask)(d0,d1)
  |  | 
 |   -$0096   -150           SuperState()
  |  | 
 |   -$009c   -156           UserState(sysstack)(d0)
  |  | 
 |   -$00a2   -162           setIntVector(intnumber,interrupt)(d0,d1)
  |  | 
 |   -$00a8   -168           AddIntServer(intnumber,interrupt)(d0,d1)
  |  | 
 |   -$00ae   -174           RemIntServer(intnumber,interrupt)(d0,d1)
  |  | 
 |   -$00b4   -180           Cause(interrup)(a1)
  |  | 
 |   -$00ba   -186           Allocate(freelist,bytesize)(a0,d0)
  |  | 
 |   -$00c0   -192           Deallocate(freelist,memoryblock,bytesize)(a0,a1,d0)
  |  | 
 |   -$00c6   -198           AllocMem(bytesize,requirements)(d0,d1)
  |  | 
 |   -$00cc   -204           AlloAbs(bytesize,location)(d0,a1)
  |  | 
 |   -$00d2   -210           FreeMem(memoryblock,bytesize)(a1,d0)
  |  | 
 |   -$00d8   -216           AvailMem(requirements)(d1)
  |  | 
 |   -$00de   -222           AllocEntry(entry)(a0)
  |  | 
 |   -$00e4   -228           FreeEntry(entry)(a0)
  |  | 
 |   -$00ea   -234           Insert(list,node,pred)(a0,a1,a2)
  |  | 
 |   -$00f0   -240           AddHead(list,node)(a0,a1)
  |  | 
 |   -$00f6   -246           AddTail(list,node)(a0,a1)
  |  | 
 |   -$00fc   -252           Remove(node)(a1)
  |  | 
 |   -$0102   -258           RemHead(list)(a0)
  |  | 
 |   -$0108   -264           RemTail(list)(a0)
  |  | 
 |   -$010e   -270           Enqueue(list,node)(a0,a1)
  |  | 
 |   -$0114   -276           FindName(list,name)(a0,a1)
  |  | 
 |   -$011a   -282           AddTask(task,initpc,finalpc)(a1,a2,a3)
  |  | 
 |   -$0120   -288           RemTask(task)(a1)
  |  | 
 |   -$0126   -294           FindTask(name)(a1)
  |  | 
 |   -$012c   -300           SetTaskPri(task,prority)(a1,d0)
  |  | 
 |   -$0132   -306           SetSignal(newsignals,signelset)(d0,d1)
  |  | 
 |   -$0138   -312           SetExcept(newsignals,signalset)(d0,d1)
  |  | 
 |   -$013e   -318           Wait(signalset)(d0)
  |  | 
 |   -$0144   -324           Signal(task,signalset)(a1,d0)
  |  | 
 |   -$014a   -330           AllocSignal(signalnum)(d0)
  |  | 
 |   -$0150   -336           FreeSignal(signalnum)(d0)
  |  | 
 |   -$0156   -342           AllocTrap(trapnum)(d0)
  |  | 
 |   -$015c   -348           FreeTrap(trapnum)(d0)
  |  | 
 |   -$0162   -354           AddPort(port)(a1)
  |  | 
 |   -$0168   -360           RemPort(port)(a1)
  |  | 
 |   -$016e   -366           PutMsg(port,message)(a0,a1)
  |  | 
 |   -$0174   -372           GetMsg(port)(a0)
  |  | 
 |   -$017a   -378           ReplyMsg(message)(a1)
  |  | 
 |   -$0180   -384           WaitPort(port)(a0)
  |  | 
 |   -$0186   -390           FindPort(name)(a1)
  |  | 
 |   -$018c   -396           AddLibrary(library)(a1)
  |  | 
 |   -$0192   -402           RemLibrary(library)(a1)
  |  | 
 |   -$0198   -408           OldOpenLibrary(libname)(a1)
  |  | 
 |   -$019e   -414           CloseLibrary(library)(a1)
  |  | 
 |   -$01a4   -420           Setfunction(library,funcoffset,funcentry)(a1,a0,d0)
  |  | 
 |   -$01aa   -426           SumLibrary(library)(a1)
  |  | 
 |   -$01b0   -432           AddDevice(device)(a1)
  |  | 
 |   -$01b6   -438           RemDevice(device)(a1)
  |  | 
 |   -$01bc   -444           OpenDevice(devname,unit,iorequest,flags)(a0,d0,a1
  |  | 
 |                           ,d1)
  |  | 
 |   -$01c2   -450           CloseDevice(iorequest)(a1)
  |  | 
 |   -$01c8   -456           DoIO(iorequest)(a1)
  |  | 
 |   -$01ce   -462           SendIO(iorequest)(a1)
  |  | 
 |   -$01d4   -468           CheckIO(iorequest)(a1)
  |  | 
 |   -$01da   -474           WaitIO(iorequest)(a1)
  |  | 
 |   -$01e0   -480           AbortIO(iorequest)(a1)
  |  | 
 |   -$01e6   -486           AddResource(resource)(a1)
  |  | 
 |   -$01ec   -492           RemResource(resource)(a1)
  |  | 
 |   -$01f2   -498           OpenResource(resname,version)(a1,d0)
  |  | 
 |   -$01f8   -504           RawIOInit()
  |  | 
 |   -$01fe   -510           RawMayGetChar()
  |  | 
 |   -$0204   -516           RawPutChar(char)(d0)
  |  | 
 |   -$020a   -522           RawDoFmt()(a0,a1,a2,a3)
  |  | 
 |   -$0210   -528           GetCC()
  |  | 
 |   -$0216   -534           TypeOfMem(address)(a1)
  |  | 
 |   -$021c   -540           Procedure(semaport,bidmsg)(a0,a1)
  |  | 
 |   -$0222   -546           Vacate(semaport)(a0)
  |  | 
 |   -$0228   -552           OpenLibrary(libname,version)(a1,d0)
  |  | 
 | 
  |  | 
 |  GRAPHICS.LIBRARY
  |  | 
 |   -$001e   -30            BltBitMap(scrbitmap,scrx,scry,destbitmap,destx,
  |  | 
 |                           desty,sizex,sizey,minterm,mask,tempa)
  |  | 
 |                           (a0,d0,d1,a1,d2,d3,d4,d5,d6,d7,a2)
  |  | 
 |   -$0024   -36            BltTemplate(source,scrx,scrmod,destrastport,destx,
  |  | 
 |                           desty,sixex,sizey)(a0,d0,d1,a1,d2,d3,d4,d5)
  |  | 
 |   -$002a   -42            ClearEOL(rastport)(a1)
  |  | 
 |   -$0030   -48            ClearScreen(rastport)(a1)
  |  | 
 |   -$0036   -54            TextLength(rastport,string,count)(a1,a0,d0)
  |  | 
 |   -$003c   -60            Text(rastport,string,count)(a1,a0,d0)
  |  | 
 |   -$0042   -66            SetFont(rastportid,textfont)(a1,a0)
  |  | 
 |   -$0048   -72            OpenFont(textattr)(a0)
  |  | 
 |   -$004e   -78            CloseFont(textfont)(a1)
  |  | 
 |   -$0054   -84            AskSoftStyle(rastport)(a1)
  |  | 
 |   -$005a   -90            SetSoftStyle(rastport,style,enable)(a1,d0,d1)
  |  | 
 |   -$0060   -96            AddBob(bob,rastport)(a0,a1)
  |  | 
 |   -$0066   -102           AddVSprite(vsprite,rastport)(a0,a1)
  |  | 
 |   -$006c   -108           DoCollision(rastport)(a1)
  |  | 
 |   -$0072   -114           DrawGList(rastport,viewport)(a1,a0)
  |  | 
 |   -$0078   -120           InitGels(dummyhead,dummytail,gelsinfo)(a0,a1,a2)
  |  | 
 |   -$007e   -126           InitMasks(vsprite)(a0)
  |  | 
 |   -$0084   -132           RemIBob(bob,rastport,viewport)(a0,a1,a2)
  |  | 
 |   -$008a   -138           RemVSprite(vsprite)(a0)
  |  | 
 |   -$0090   -144           SetCollision(type,routine,gelsinfo)(d0,a0,a1)
  |  | 
 |   -$0096   -150           SortGList(rastport)(a1)
  |  | 
 |   -$009c   -156           AddAnimObj(obj,animationkey,rastport)(a0,a1,a2)
  |  | 
 |   -$00a2   -162           Animate(animationkey,rastport)(a0,a1)
  |  | 
 |   -$00a8   -168           etGBuffers(animationobj,rastport,doublebuffer)(a0,
  |  | 
 |                           a1,d0)
  |  | 
 |   -$00ae   -174           InitGMasks(animationobj)(a0)
  |  | 
 |   -$00b4   -180           GelsFuncE()
  |  | 
 |   -$00ba   -186           GelsFuncF()
  |  | 
 |   -$00c0   -192           LoadRGB4(viewport,colurs,count)(a0,a1,d0)
  |  | 
 |   -$00c6   -198           InitRastPort(rastport)(a1)
  |  | 
 |   -$00cc   -204           InitVPort(viewport)(a0)
  |  | 
 |   -$00d2   -210           MrgCop(view)(a1)        
  |  | 
 |   -$00D8  -216            MakeVPort (view,viewPort) (A0,A1)
  |  | 
 |   -$00DE  -222            LoadView (view) (A1)
  |  | 
 |   -$00E4  -228            WaitBlit ()
  |  | 
 |   -$00EA  -234            SetRast (rastPort,color) (A1,D0)
  |  | 
 |   -$00F0  -240            Move (rastPort,x,y) (A1,D0,D1)
  |  | 
 |   -$00F6  -246            Draw (rastPort,x,y) (A1,D0,D1)
  |  | 
 |   -$00FC  -252            AreaMove (rastPort,x,y) (A1,D0,D1)
  |  | 
 |   -$0102  -258            AreaDraw (rastPort,x,y) (A1,D0,D1)
  |  | 
 |   -$0108  -264            AreaEnd (rastPort) (A1)
  |  | 
 |   -$010E  -270            WaitTOF ()
  |  | 
 |   -$0114  -276            QBlit (blit) (A1)
  |  | 
 |   -$011A  -282            InitArea (areaInfo,vectorTable,vectorTableSize)
  |  | 
 |                           (A0,A1,D0)
  |  | 
 |   -$0120  -288            SetRGB4 (viewPort,index,r,g,b) (A0,D0,D1,D2,D3)
  |  | 
 |   -$0126  -294            QBSBlit (blit) (A1)
  |  | 
 |   -$012C  -300            BltClear (memory,size,flags) (A1,D0,D1)
  |  | 
 |   -$0132  -306            RectFill (rastPort,xl,yl,xu,yu)
  |  | 
 |                           (A1,D0,D1,D2,D3)
  |  | 
 |   -$0138  -312            BltPattern (rastPort,ras,xl,yl,maxX,maxY,
  |  | 
 |                           fillBytes) (A1,A0,D0,D1,D2,D3,D4)
  |  | 
 |   -$013E  -318            ReadPixel (rastPort,x,y) (A1,D0,D1)
  |  | 
 |   -$0144  -324            WritePixel (rastPort,x,y) (A1,D0,D1)
  |  | 
 |   -$014A  -330            Flood (rastPort,mode,x,y) (A1,D2,D0,D1)
  |  | 
 |   -$0150  -336            PolyDraw (rastPort,count,polyTable) (A1,D0,A0)
  |  | 
 |   -$0156  -342            SetAPen (rastPort,pen) (A1,D0)
  |  | 
 |   -$015C  -348            SetBPen (rastPort,pen) (A1,D0)
  |  | 
 |   -$0162  -354            SetDrMd (rastPort,drawMode) (A1,D0)
  |  | 
 |   -$0168  -360            InitView (view) (A1)
  |  | 
 |   -$016E  -366            CBump (copperList) (A1)
  |  | 
 |   -$0174  -372            CMove (copperList,destination,data) (A1,D0,D1)
  |  | 
 |   -$017A  -378            CWait (copperList,x,y) (A1,D0,D10
  |  | 
 |   -$0180  -384            VBeamPos ()
  |  | 
 |   -$0186  -390            InitBitMap (bitMap,depth,width,height)
  |  | 
 |                           (A0,D0,D1,D2)
  |  | 
 |   -$018C  -396            ScrollRaster (rastPort,dX,dY,minx,miny,maxx,
  |  | 
 |                           maxy) (A1,D0,D1,D2,D3,D4,D5)
  |  | 
 |   -$0192  -402            WaitBOVP (viewPort) (A0)
  |  | 
 |   -$0198  -408            GetSprite (simpleSprite,num) (A0,D0)
  |  | 
 |   -$019E  -414            FreeSprite (num) (D0)
  |  | 
 |   -$01A4  -420            ChangeSprite (vp,simpleSprite,data) (A0,A1,A2)
  |  | 
 |   -$01AA  -426            MoveSprite (viewPort,simpleSprite,x,y)
  |  | 
 |                           (A0,A1,D0,D1)
  |  | 
 |   -$01B0  -432            LockLayerRom (layer) (A5)
  |  | 
 |   -$01B6  -438            UnlockLayerRom (layer) (A5)
  |  | 
 |   -$01BC  -444            SyncSBitMap (1) (A0)
  |  | 
 |   -$01C2  -450            CopySBitMap (11,12) (A0,A1)
  |  | 
 |   -$01C8  -456            OwnBlitter ()
  |  | 
 |   -$01CE  -462            DisownBlitter ()
  |  | 
 |   -$01D4  -468            InitTmpRas (tmpras,buff,size) (A0,A1,D0)
  |  | 
 |   -$01DA  -474            AskFont (rastPort,textAttr) (A1,A0)
  |  | 
 |   -$01E0  -480            AddFont (textFont) (A1)
  |  | 
 |   -$01E6  -486            RemFont (textFont) (A1)
  |  | 
 |   -$01EC  -492            AllocRaster (width,height) (D0,D1)
  |  | 
 |   -$01F2  -498            FreeRaster (planeptr,width,height) (A0,D0,D1)
  |  | 
 |   -$01F8  -504            AndRectRegion (rgn,rect) (A0,A1)
  |  | 
 |   -$01FE  -510            OrRectRegion (rgn,rect) (A0,A1)
  |  | 
 |   -$0204  -516            NewRegion ()
  |  | 
 |   -$020A  -522            ** reserved **
  |  | 
 |   -$0210  -528            ClearRegion (rgn) (A0)
  |  | 
 |   -$0216  -534            DisposeRegion (rgn) (A0)
  |  | 
 |   -$021C  -540            FreeVPortCopLists (viewPort) (A0)
  |  | 
 |   -$0222  -546            FreeCopList (coplist) (A0)
  |  | 
 |   -$0228  -552            ClipBlit (srcrp,srcX,srcY,destrp,destX,destY,
  |  | 
 |                           sizeX,sizeY,minterm) (A0,D0,D1,A1,D2,D3,D4,D5,D6)
  |  | 
 |   -$022E  -558            XorRectRegion (rgn,rect) (A0,A1)
  |  | 
 |   -$0234  -564            FreeCprList (cprlist) (A0)
  |  | 
 |   -$023A  -570            GetColorMap (entries) (D0)
  |  | 
 |   -$0240  -576            FreeColorMap (colormap) (A0)
  |  | 
 |   -$0246  -582            GetRGB4 (colormap,entry) (A0,D0)
  |  | 
 |   -$024C  -588            ScrollVPort (vp) (A0)
  |  | 
 |   -$0252  -594            UCopperListInit (copperlist,num) (A0,D0)
  |  | 
 |   -$0258  -600            FreeGBuffers (animationObj,rastPort,
  |  | 
 |                           doubleBuffer) (A0,A1,D0)
  |  | 
 |   -$025E  -606            BltBitMapRastPort (srcbm,srcx,srcy,destrp,
  |  | 
 |                           destX,destY,sizeX,sizeY,minter)
  |  | 
 |                           (A0,D0,D1,A1,D2,D3,D4,D5,D6)
  |  | 
 | 
  |  | 
 |  ICON.LIBRARY
  |  | 
 |   -$001E  -30             GetWBObject (name) (A0)
  |  | 
 |   -$0024  -36             PutWBObject (name,object) (A0,A1)
  |  | 
 |   -$002A  -42             GetIcon (name,icon,freelist) (A0,A1,A2)
  |  | 
 |   -$0030  -48             PutIcon (name,icon) (A0,A1)
  |  | 
 |   -$0036  -54             FreeFreeList (freelist) (A0)
  |  | 
 |   -$003C  -60             FreeWBOject (WBOject) (A0)
  |  | 
 |   -$0042  -66             AllocWBOject ()
  |  | 
 |   -$0048  -72             AddFreeList (freelist,mem,size) (A0,A1,A2)
  |  | 
 |   -$004E  -78             GetDiskObject (name) (A0)
  |  | 
 |   -$0054  -84             PutDiskObject (name,diskobj) (A0,A1)
  |  | 
 |   -$005A  -90             FreeDiskObj (diskobj) (A0)
  |  | 
 |   -$0060  -96             FindToolType (toolTypeArray,typeName) (A0.A1)
  |  | 
 |   -$0066  -102            MatchToolValue (typeString,value) (A0,A1)
  |  | 
 |   -$006C  -108            BumbRevision (newname,oldname) (A0,A1)
  |  | 
 | 
  |  | 
 |  INTUITION.LIBRARY
  |  | 
 |   -$001E  -30             OpenIntuition ()
  |  | 
 |   -$0024  -36             Intuition (ievent) (A0)
  |  | 
 |   -$002A  -42             AddGadget (AddPtr,Gadget,Position) (A0,A1,D0)
  |  | 
 |   -$0030  -48             ClearDMRequest (Window) (A0)
  |  | 
 |   -$0036  -54             ClearMenuStrip (Window) (A0)
  |  | 
 |   -$003C  -60             ClearPointer (Window) (A0)
  |  | 
 |   -$0042  -66             CloseScreen (Screen) (A0)
  |  | 
 |   -$0048  -72             CloseWindow (Window) (A0)
  |  | 
 |   -$004E  -78             CloseWorkbench ()
  |  | 
 |   -$0054  -84             CurrentTime (Seconds,Micros) (A0,A1)
  |  | 
 |   -$005A  -90             DisplayAlert (AlertNumber,String,Height)
  |  | 
 |                           (D0,A0,D1)
  |  | 
 |   -$0060  -96             DiplayBeep (Screen) (A0)
  |  | 
 |   -$0066  -102            DoubleClick (sseconds,smicros,cseconds,
  |  | 
 |                           cmicros) (D0,D1,D2,D3)
  |  | 
 |   -$006C  -108            DrawBorder (Rport,Border,LeftOffset,TopOffset)
  |  | 
 |                           (A0,A1,D0,D1)
  |  | 
 |   -$0072  -114            DrawImage (RPort,Image,LeftOffset,TopOffset)
  |  | 
 |                           (A0,A1,D0,D1)
  |  | 
 |   -$0078  -120            EndRequest (requester,window) (A0,A1)
  |  | 
 |   -$007E  -126            GetDefPref (preferences,size) (A0,D0)
  |  | 
 |   -$0084  -132            GetPrefs (preferences,size) (A0,D0)
  |  | 
 |   -$008A  -138            InitRequester (req) (A0)
  |  | 
 |   -$0090  -144            ItemAddress (MenuStrip,MenuNumber) (A0,D0)
  |  | 
 |   -$0096  -150            ModifyIDCMP (Window,Flags) (A0,D0)
  |  | 
 |   -$009C  -156            ModifyProp (Gadget,Ptr,Reg,Flags,HPos,VPos,
  |  | 
 |                           HBody,VBody) (A0,A1,A2,D0,D1,D2,D3,D4)
  |  | 
 |   -$00A2  -162            MoveScreen (Screen,dx,dy) (A0,D0,D1)
  |  | 
 |   -$00A8  -168            MoveWindow (Window,dx,dy) (A0,D0,D1)
  |  | 
 |   -$00AE  -174            OffGadget (Gadget,Ptr,Req) (A0,A1,A2)
  |  | 
 |   -$00B4  -180            OffMenu (Window,MenuNumber) (A0,D0)
  |  | 
 |   -$00BA  -186            OnGadget (Gadget,Ptr,Req) (A0,A1,A2)
  |  | 
 |   -$00C0  -192            OnMenu (Window,MenuNumber) (A0,D0)
  |  | 
 |   -$00C6  -198            OpenScreen (OSArgs) (A0)
  |  | 
 |   -$00CC  -204            OpenWindow (OWArgs) (A0)
  |  | 
 |   -$00D2  -210            OpenWorkBench ()
  |  | 
 |   -$00D8  -216            PrintIText (rp,itext,left,top) (A0,A1,D0,D1)
  |  | 
 |   -$00DE  -222            RefreshGadgets (Gadgets,Ptr,Req) (A0,A1,A2)
  |  | 
 |   -$00E4  -228            RemoveGadgets (RemPtr,Gadget) (A0,A1)
  |  | 
 |   -$00EA  -234            ReportMouse (Window,Boolean) (A0,D0)
  |  | 
 |   -$00F0  -240            Request (Requester,Window) (A0,A1)
  |  | 
 |   -$00F6  -246            ScreenToBack (Screen) (A0)
  |  | 
 |   -$00FC  -252            SCreenToFront (Screen) (A0)
  |  | 
 |   -$0102  -258            SetDMRequest (Window,req) (A0,A1)
  |  | 
 |   -$0108  -264            SetMenuStrip (Window,Menu) (A0,A1)
  |  | 
 |   -$010E  -270            SetPointer (Window,Pointer,Height,Width,
  |  | 
 |                           XOFFset, YOFFset) (A0,A1,D0,D1,D2,D3)
  |  | 
 |   -$0114  -276            SetWindowTitles (Window,windowTitle,
  |  | 
 |                           screenTitle) (A0,A1,A2)
  |  | 
 |   -$011A  -282            ShowTitle (Screen,ShowIt) (A0,D0)
  |  | 
 |   -$0120  -288            SizeWindow (Windowmdx,dy) (A0,D0,D1)
  |  | 
 |   -$0126  -294            ViewAddress ()
  |  | 
 |   -$012C  -300            ViewPortAddress (Window) (A0)
  |  | 
 |   -$0132  -306            WindowToBack (Window) (A0)
  |  | 
 |   -$0138  -312            WindowToFront (Window) (A0)
  |  | 
 |   -$013E  -318            WindowLimits (Window,minwidth,minheight,
  |  | 
 |                           maxwidth, maxheight) (A0,D0,D1,D2,D3)
  |  | 
 |   -$0144  -324            SetPrefs (preferences,size,flag) (A0,D0,D1)
  |  | 
 |   -$014A  -330            IntuiTextLength (itext) (A0)
  |  | 
 |   -$0150  -336            WBenchToBack ()
  |  | 
 |   -$0156  -342            WBenchToFront ()
  |  | 
 |   -$015C  -348            AutoRequest (Window,Body,PText,NText,PFlag,
  |  | 
 |                           NFlag,W,H) (A0,A1,A2,A3,D0,D1,D2,D3)
  |  | 
 |   -$0162  -354            BeginRefresh (Window) (A0)
  |  | 
 |   -$0168  -360            BuildSysRequest (Window,Body,PosText,NegText,
  |  | 
 |                           Flags,W,H) (A0,A1,A2,A3,D0,D1,D2)
  |  | 
 |   -$016E  -366            EndRefresh (Window,Complete) (A0,D0)
  |  | 
 |   -$0174  -372            FreeSysRequest (Window) (A0)
  |  | 
 |   -$017A  -378            MakeScreen (Screen) (A0)
  |  | 
 |   -$0180  -384            RemakeDisplay ()
  |  | 
 |   -$0186  -390            RethinkDisplay ()
  |  | 
 |   -$018C  -396            AllocRemember (RememberKey,Size,Flags) (A0,D0,D1)
  |  | 
 |   -$0192  -402            AlohaWorkBench (wbport) (A0)
  |  | 
 |   -$0198  -408            FreeRemember (RememberKey,ReallyForgot) (A0,D0)
  |  | 
 |   -$019E  -414            LockIBase (dontknow) (D0)
  |  | 
 |   -$01A4  -420            UnlockIBase (IBLock) (A0)
  |  | 
 | 
  |  | 
 |  LAYERS.LIBRARY
  |  | 
 |   -$001E  -30             InitLayers (li) (A0)
  |  | 
 |   -$0024  -36             CreateUpfrontLayer (li,bm,x0,y0,xl,yl,flags,
  |  | 
 |                           bm2) A0,A1,D0,D1,D2,D3,D4,A2)
  |  | 
 |   -$002A  -42             CreateBehindLayer (li,bm,x0,y0,xl,yl,flags,
  |  | 
 |                           bm2) (A0,A1,D0,D1,D2,D3,D3,A2)
  |  | 
 |   -$0030  -48             UpfrontLayer (li,layer) (A0,A1)
  |  | 
 |   -$0036  -54             BehindLayer (li,layer) (A0,A1)
  |  | 
 |   -$003C  -60             MoveLayer (li,layer,dx,dy) (A0,A1,D0,D1)
  |  | 
 |   -$0042  -66             SizeLayer (li,layer,dx,dy) (A0,A1,D0,D1)
  |  | 
 |   -$0048  -72             ScrollLayer (li,layer,dx,dy) (A0,A1,D0,D1)
  |  | 
 |   -$004E  -78             BeginUpdate (layer) (A0)
  |  | 
 |   -$0054  -84             EndUpdate (layer) (A0)
  |  | 
 |   -$005A  -90             DeleteLayer (li,layer) (A0,A1)
  |  | 
 |   -$0060  -96             LockLayer (li,layer) (A0,A1)
  |  | 
 |   -$0066  -102            UnlockLayer (li,layer) (A0,A1)
  |  | 
 |   -$006C  -108            LockLayers (li) (A0)
  |  | 
 |   -$0072  -114            UnlockLayers (li) (A0)
  |  | 
 |   -$0078  -120            LockLayerInfo (li) (A0)
  |  | 
 |   -$007E  -126            SwapBitRastPortClipRect (rp,cr) (A0,A1)
  |  | 
 |   -$0084  -132            WhichLayer (li,x,y) (A0,D0,D1)
  |  | 
 |   -$008A  -138            UnlockLayerInfo (li) (A0)
  |  | 
 |   -$0090  -144            NewLayerInfo ()
  |  | 
 |   -$0096  -150            DisposeLayerInfo (li) (A0)
  |  | 
 |   -$009C  -156            FattenLayerInfo (li) (A0)
  |  | 
 |   -$00A2  -162            ThinLayerInfo (li) (A0)
  |  | 
 |   -$00A8  -168            MoveLayerInfrontOf (layer_to_move,
  |  | 
 |                           layer_to_be_in_front_of) (A0,A1)
  |  | 
 | 
  |  | 
 |  MATHFFP.LIBRARY
  |  | 
 |   -$001E  -30             SPFix (float) (D0)
  |  | 
 |   -$0024  -36             SPFit (integer) (D0)
  |  | 
 |   -$002A  -42             SPCmp (leftFloat,right,Float) (D1,D0)
  |  | 
 |   -$0030  -48             SPTst (float) (D1)
  |  | 
 |   -$0036  -54             SPAbs (float) (D0)
  |  | 
 |   -$003C  -60             SPNeg (float) (D0)
  |  | 
 |   -$0042  -66             SPAdd (leftFloat,rightFloat) (D1,D0)
  |  | 
 |   -$0048  -72             SPSub (leftFloat,rightFloat) (D1,D0)
  |  | 
 |   -$004E  -78             SPMul (leftFloat,rightFloat) (D1,D0)
  |  | 
 |   -$0054  -84             SPDiv (leftFloat,rightFloat) (D1,D0)
  |  | 
 | 
  |  | 
 |  MATHIEEEDOUBBAS.LIBRARY
  |  | 
 |   -$001E  -30             IEEEDPFix (integer,integer) (D0,D1)
  |  | 
 |   -$0024  -36             IEEEDPFit (integer) (D0)
  |  | 
 |   -$002A  -42             IEEEDPCamp (integer,integer,integer,integer)
  |  | 
 |                           (D0,D1,D2,D3)
  |  | 
 |   -$0030  -48             IEEEDPTst (integer,integer) (D0,D1)
  |  | 
 |   -$0036  -54             IEEEDPAbs (integer,integer) (D0,D1)
  |  | 
 |   -$003C  -60             IEEEDPNeg (integer,integer) (D0,D1)
  |  | 
 |   -$0042  -66             IEEEDPAdd (integer,integer,integer,integer)
  |  | 
 |                           (D0,D1,D2,D3)
  |  | 
 |   -$0048  -72             IEEEDPSub (integer,integer,integer,integer)
  |  | 
 |                           (D0,D1,D2,D3)
  |  | 
 |   -$004E  -78             IEEEDPMul (integer,integer,integer,integer)
  |  | 
 |                           (D0,D1,D2,D3)
  |  | 
 |   -$0054  -84             IEEEDPDiv (integer,integer,integer,integer)
  |  | 
 |                           (D0,D1,D2,D3)
  |  | 
 | 
  |  | 
 |  MATHTRANS.LIBRARY
  |  | 
 |   -$001E  -30             SPAtan (float) (D0)
  |  | 
 |   -$0024  -36             SPSin (float) (D0)
  |  | 
 |   -$002A  -42             SPCos (float) (D0)
  |  | 
 |   -$0030  -48             SPTan (float) (D0)
  |  | 
 |   -$0036  -54             SPSincos (leftFloat,rightFloat) (D1,D0)
  |  | 
 |   -$003C  -60             SPSinh (float) (D0)
  |  | 
 |   -$0042  -66             SPCosh (float) (D0)
  |  | 
 |   -$0048  -72             SPTanh (float) (D0)
  |  | 
 |   -$004E  -78             SPExp (float) (D0)
  |  | 
 |   -$0054  -84             SPLog (float) (D0)
  |  | 
 |   -$005A  -90             SPPow (leftFloat,rightFloat) (D1,D0)
  |  | 
 |   -$0060  -96             SPSqrt (float) (D0)
  |  | 
 |   -$0066  -102            SPTieee (float) (D0)
  |  | 
 |   -$006C  -108            SPFieee (float) (D0)
  |  | 
 |   -$0072  -114            SPAsin (float) (D0)
  |  | 
 |   -$0078  -120            SPAcos (float) (D0)
  |  | 
 |   -$007E  -126            SPLog10 (float) (D0)
  |  | 
 | 
  |  | 
 |  POTGO.LIBRARY
  |  | 
 |   -$0006  -6              AllocPotBits (bits) (D0)
  |  | 
 |   -$000C  -12             FreePotBits (bits) (D0)
  |  | 
 |   -$0012  -18             WritePotgo (word,mask) (D0,D1)
  |  | 
 | 
  |  | 
 |  TIMER.LIBRARY
  |  | 
 |   -$002A  -42             AddTime (dest,src) (A0,A1)
  |  | 
 |   -$0030  -48             SubTime (dest,src) (A0,A1)
  |  | 
 |   -$0036  -54             CmpTime (dest,src) (A0,A1)
  |  | 
 | 
  |  | 
 |  TRANSLATOR.LIBRARY
  |  | 
 |   -$001E  -30             Translate (inputString,inputLength,
  |  | 
 |                           outputBuffer,bufferSize) (A0,D0,A1,D1)
  |  | 
 | 
  |  | 
 | 
  |  | 
 |  Abbreviations (symbols) used:
  |  | 
 | 
  |  | 
 |           label     A label or address
  |  | 
 |           reg       Register
  |  | 
 |           an        Address register n
  |  | 
 |           dn        Data register n
  |  | 
 |           source    source operand
  |  | 
 |           dest      destination operand
  |  | 
 |           <ea>      address of register
  |  | 
 |           #n        direct value
  |  | 
 | 
  |  | 
 | 
  |  | 
 |  GENERAL INSTRUCTIONS
  |  | 
 | 
  |  | 
 |           BCC   label         Conditional branch, depends on condition.
  |  | 
 |           BRA   label         Unconditional branch (Similar to JMP).
  |  | 
 |           BSR   label         Branch to subprogram. Return address is
  |  | 
 |                               deposited on the stack, RTS causes return to
  |  | 
 |                               that address.
  |  | 
 |           CHK   <ea>,dx       Check data register for limits, activate the
  |  | 
 |                               CHK instruction exception.
  |  | 
 |           DBCC  reg,label     Check condition, decrement on branch.
  |  | 
 |           JMP   label         Jump to address (Similar to BRA).
  |  | 
 |           JSR   label         Jump to a subroutine. Return address is deposited
  |  | 
 |                               on stack, RTS causes return to that address.
  |  | 
 |           NOP                 No operation.
  |  | 
 |           RESET               Reset peripherals (Caution!).
  |  | 
 |           RTE                 Return from exception.
  |  | 
 |           RTR                 Return with loading of flags.
  |  | 
 |           RTS                 Return from subroutine (After BSR or JSR).
  |  | 
 |           SCC   <ea>          Set a byte to -1 when condition is met.
  |  | 
 |           STOP                Stop processing (Caution!).
  |  | 
 |           TRAP  #n            Jump to an exception.
  |  | 
 |           TRAPV               Check overflow flag, then TRAPV exception.
  |  | 
 | 
  |  | 
 | 
  |  | 
 |  ARITHMETIC OPERATIONS WITH WHOLE NUMBERS
  |  | 
 | 
  |  | 
 |           ADD   source,dest   Binary addition.
  |  | 
 |           ADDA  source,an     Binary addition to an address register.
  |  | 
 |           ADDI  #n,<ea>       Addition with a constant.
  |  | 
 |           ADDQ  #n,<ea>       Fast addition of a constant which can be only
  |  | 
 |                               from 1 to 8.
  |  | 
 |           ADDX  source,dest   Addition with transfer in X flag.
  |  | 
 |           CLR   <ea>          Clear an operand.
  |  | 
 |           CMP   source,dest   Comparison of two operands.
  |  | 
 |           CMPA  <ea>,an       Comparison with an address register.
  |  | 
 |           CMPI  #n,<ea>       Comparison with a constant.
  |  | 
 |           CMPM  source,dest   Comparison of two memory operands.
  |  | 
 |           DIVS  source,dest   Sign-true division of a 32 bit destination by
  |  | 
 |                               a 16 bit source operand. The result of the
  |  | 
 |                               division is stored in the LO word of the
  |  | 
 |                               destination, the remainder in the HI word.
  |  | 
 |           DIVU  source,dest   Division without regard to sign, similar to DIVS.
  |  | 
 |           EXT   dn            Sign-true expansion to twice original size
  |  | 
 |                               (width) data unit.
  |  | 
 |           MULS  source,dest   Sign-true multiplication of two words into one
  |  | 
 |                               word.
  |  | 
 |           MULU  source,dest   Multiplication without regard to sign, similar
  |  | 
 |                               to MULS.
  |  | 
 |           NEG   <ea>          Negation of an operand (twos complement).
  |  | 
 |           SUB   source,dest   Binary subtraction.
  |  | 
 |           SUBA  <ea>,an       Binary subtraction from an address register.
  |  | 
 |           SUBI  #n,<ea>       Subtraction of a constant.
  |  | 
 |           SUBQ  #n,<ea>       Fast subtraction of a three bit constant.
  |  | 
 |           SUBX  source,dest   Subtraction with transfer in X flag.
  |  | 
 |           TST   <ea>          Test operand and set N and Z flag.
  |  | 
 | 
  |  | 
 | 
  |  | 
 |  BINARY CODED DECIMAL NUMBERS
  |  | 
 | 
  |  | 
 |           ABCD  source,dest   Addition of two binary coded decimal numbers.
  |  | 
 |           NBCD  source,dest   Negation of a binary coded decimal number
  |  | 
 |                               (nine complement).
  |  | 
 |           SBCD  source,dest   Subtraction of two binary coded decimal numbers.
  |  | 
 | 
  |  | 
 | 
  |  | 
 |  LOGICAL OPERATIONS
  |  | 
 | 
  |  | 
 |           AND   source,dest   Logic AND.
  |  | 
 |           ANDI  #n,<ea>       Logic AND with a constant.
  |  | 
 |           EOR   source,dest   Exclusive OR.
  |  | 
 |           EORI  #n,<ea>       Exclusive OR with a constant.
  |  | 
 |           NOT   <ea>          Inversion of an operand.
  |  | 
 |           OR    source,dest   Logic OR.
  |  | 
 |           ORI   #n,<ea>       Logic OR with a constant.
  |  | 
 |           TAS   <ea>          Check a byte and set bit 7.
  |  | 
 | 
  |  | 
 | 
  |  | 
 |  SINGLE BIT MANIPULATION
  |  | 
 | 
  |  | 
 |           BCHG  #n,<ea>       Change bit n(0 is changed to 1 and vice versa).
  |  | 
 |           BCLR  #n,<ea>       Clear bit n.
  |  | 
 |           BSET  #n,<ea>       Set bit n.
  |  | 
 |           BTST  #n,<ea>       Test bit n, result is desplayed in Z flag.
  |  | 
 | 
  |  | 
 | 
  |  | 
 |  SHIFT AND ROTATE OPERANDS
  |  | 
 | 
  |  | 
 |           NOTE: n indicates a register, # indicates a direct value which
  |  | 
 |                 specifies the number of shiftings.
  |  | 
 | 
  |  | 
 |           AS    n,<ea>        Arithmetic shift to the left (*2^n)
  |  | 
 |           ASR   n,<ea>        Arithmetic shift to the right (/2^n)
  |  | 
 |           LSL   n,<ea>        Logic shift to the left.
  |  | 
 |           LSR   n,<ea>        Logic shift to the right.
  |  | 
 |           ROL   n,<ea>        Rotation left.
  |  | 
 |           ROR   n,<ea>        Rotation right.
  |  | 
 |           ROXL  n,<ea>        Rotation left with transfer in X flag.
  |  | 
 |           ROXR  n,<ea>        Rotation right with transfer in X flag.
  |  | 
 | 
  |  | 
 | 
  |  | 
 |  MOVE DATA INSTRUCTIONS
  |  | 
 | 
  |  | 
 |           EXG   rn,rn         Exchange two register contents (don't confuse
  |  | 
 |                               with swap!).
  |  | 
 |           LEA   <ea>,an       Load an effective address in address register an.
  |  | 
 |           LINK  an,#n         Build stack range.
  |  | 
 |           MOVE  source,dest   Carry value over from source to destination.
  |  | 
 |           MOVE  SR,<ea>       Transfer the status register contents.
  |  | 
 |           MOVE  <ea>,SR       Transfer the status register contents.
  |  | 
 |           MOVE  USP,<ea>      Transfer the user stack pointer.
  |  | 
 |           MOVE  <ea>,USP      Transfer the user stack pointer.
  |  | 
 |           MOVEA <ea>,an       Transfer a value to the address register an.
  |  | 
 |           MOVEM regs,<ea>     Transfer several registers at once.
  |  | 
 |           MOVEM <ea>,regs     Transfer several registers at once.
  |  | 
 |           MOVEP source,dest   Transfer data to peripherals.
  |  | 
 |           MOVEQ #n,dn         Quickly transfer an eight bit constant to the
  |  | 
 |                               data register dn.
  |  | 
 |           PEA   <ea>          Deposit an address on the stack.
  |  | 
 |           SWAP  dn            Swap the halves of the register (the upper 16 bit
  |  | 
 |                               with the lower).
  |  | 
 |           UNLK  an            Unlink the stack.
  |  |