„Amiga Machine Language” változatai közötti eltérés

Innen: amigaspirit.hu - pegasos.hu Wiki
Ugrás a navigációhozUgrás a kereséshez
(initial import for Amiga Machine Language .txt import... (heavily WIP, do not touch))
(Nincs különbség)

A lap 2009. május 23., 01:08-kori változata

AMIGA MACHINE LANGUAGE Typed by DEE JAY


     Table of Contents.
     ------------------
       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.1    Registers
       2.2    Addressing memory
       2.3    Operating modes
       2.3.1  User and supervisor modes
       2.3.2  Exceptions
       2.3.3  Interrupts
       2.3.4  Condition codes
       2.4    The 68000 Instructions
       3      Working with assemblers
       3.1    The development assembler
       3.2    AssemPro
       3.3    The K-SEKA assembler
       4      Our first programs
       4.1    Adding tables
       4.2    Sorting tables
       4.3    Converting number systems
       4.3.1  Converting hex to ASCII
       4.3.2  Converting decimal to ASCII
       4.3.3  Converting ASCII to hex
       4.3.4  Converting ASCII to decimal
       5      Hardware registers
       5.1    Checking for special keys
       5.2    Timing
       5.3    Reading the mouse or joystick
       5.4    Tone production
       5.5    Hardware registers overview
       6      The Amiga operating system
       6.1    Load libraries
       6.2    Calling functions
       6.3    Program initialization
       6.3.1  Reserve memory
       6.3.2  Opening a simple window
       6.4    Input/output
       6.4.1  Screen output
       6.4.2  Keyboard input
       6.4.3  Printer control
       6.4.4  Serial I/O
       6.4.5  Speech output
       6.5    Disk operations
       6.5.1  Open files
       6.5.2  Reading and writing data
       6.5.3  Erase files
       6.5.4  Rename files
       6.5.5  CLI directory
       6.5.6  Read directory
       6.5.7  Direct access to disk
       7      Working with Intuition
       7.1    Open screen
       7.2    Openwindow
       7.3    Requesters
       7.4    Event handling
       7.5    Menu programming
       7.6    Text output
       7.7    Images
       7.8    Borders
       7.9    Gadgets
       7.9.1  Boolean gadgets
       7.9.2  String gadgets
       7.9.3  Proportional gadgets
       7.10   Example program
       8      Advanced programming
       8.1    Supervisor mode
       8.2    Exception programming
       Appendix
              Overview of library functions
              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> ."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.
        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.