„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))
 
(content moved to separate pages)
1. sor: 1. sor:
AMIGA MACHINE LANGUAGE
AMIGA MACHINE LANGUAGE
Typed by DEE JAY
Typed by DEE JAY


Wiki-ified by Charlie / Singular Crew, (a.k.a [[User:Chain-Q|Chain-Q]])


* [[Amiga_Machine_Language_(Chapter_1)|Chapter 1 - Introduction]]
* [[Amiga_Machine_Language_(Chapter_2)|Chapter 2 - The MC68000 processor]]
* [[Amiga_Machine_Language_(Chapter_3)|Chapter 3 - Working with assemblers]]
* [[Amiga_Machine_Language_(Chapter_4)|Chapter 4 - Our first programs]]
* [[Amiga_Machine_Language_(Chapter_5)|Chapter 5 - Hardware registers]]
* [[Amiga_Machine_Language_(Chapter_6)|Chapter 6 - The Amiga operating system]]
* [[Amiga_Machine_Language_(Chapter_7)|Chapter 7 - Working with Intuition]]
* [[Amiga_Machine_Language_(Chapter_8)|Chapter 8 - Advanced programming]]
* [[Amiga_Machine_Language_(Appendix_A)|Appendix A - Overview of library functions]]
* [[Amiga_Machine_Language_(Appendix_B)|Appendix B - Overview of the MC68000 Instructions]]


      Table of Contents.
 
      ------------------
Original contents table, will be gone as chapters will get Wiki formatting:
        1.    Introduction
        1.1    Why machine code?
        1.2    A look into the Amiga's memory
        1.2.1  RAM,ROM,hardware register
        1.2.2  Bits,bytes and words
        1.2.3  Number systems
        1.3    Inside the Amiga
        1.3.1  Components and libraries
        1.3.2  Memory
        1.3.3  Multi-tasking


         2      The MC68000 processor
         2      The MC68000 processor
91. sor: 93. sor:
               Overview of library functions
               Overview of library functions
               Overview of the MC68000 Instructions
               Overview of the MC68000 Instructions
             
      Chapter 2.
      ---------
      2.The MC68000 Processor.
      -----------------------
        The Amiga`s MC68000 processor is a 16/32 bit processor,which means
        that while it can process data of 32 bits,it"only"has a 16 bit
        data bus and a 24 bit address bus.Thus,it can access 2^24=16777216
        bytes(or 16 Mbytes)of memory directly.
      7.1 Megaherz;
        The Amiga 68000 processor,running at 7.1 megaherz,is quite fast,
        which is required for a computor with a workload as heavy as the
        Amiga`s.The Amiga also processes a number of custom chips that
        greatly ease the workload of the processor.These custom chips
        manage sound in/output,graphics and animation,thus freeing the
        processor for calculations.
       
      2.1.Registers.
      -------------
        In addition to the standard RAM,the processor contains internal
        memory called registers.There are eight data registers(D0-D7),
        eight address registers(A0-A7),a status register(SR),two stack
        pointers,a user stack pointer,a system stack pointer(USP and SSP)
        and the program counter(PC).
      Register Sizes;
        The data registers,the address registers,and the program counter
        are all 32 bits,while the status register is 16 bits.These
        registers are located dirctly in the processor so they are not
        accessed the same way memory would be accessed.There are special
        instructions for accessing these registers.
      Data Registers;
        The data registers are used for all kinds of data.They can handle
        operations with bytes(8 bits)words(16 bits)and longwords(32bits).
      Address Registers;
        The address registers are used for storing and processing
        addresses.This way they can be used as pointers to tables,in which
        case only words and longwords operations are possible.
      Stack Pointer;
        The address register A7 plays a special role:this register is
        utilized as the Stack Pointer(SR)by the processor,and thus is not
        recommended for normal use by the programmer.Which of the two
        possible stacks is being pointed to depends on the present mode of
        the processor,but more about that later.
        The stack,to whose actual position the stack pointer is pointing,
        is used to store temporary internal data.The stack works similar
        to a stack of notes on your desk:the note that was added to the
        stack last is the first one to come off the stack.This type of
        stack is known as LIFO(Last in,First out).There is another type of
        stack,the FIFO(First in,First out)which is not used by the
        processor itself.
        How these registers and the SP can be manipulated,or how to work
        with the stack,is presented in the next chapter.Lets continue with
        the registers for now.
      Status Register;
        The status register plays an important role in machine language
        programming.This 16-bit quality(word)contains important
        information about the processor status in 10 of its bits.The word
        is divided into two bytes,the lower byte(the user byte)and the
        upper byte(the system byte).The bits that signify that certain
        conditions are refered to as flags.This means that when a certain
        condition is present,a particular bit is set.
        The user byte contains five flags,which have the following meaning
                Bit    Name          Meaning
                -----------------------------------------------
                0      (C,Carry)      Carry bit,modified by math
                                      calculation,and shift instructions.
                1      (V,Overflow)  Similar to carry,indicates a change
                                      of sign,in other words,a carry from
                                      bit six to bit seven.
                2      (Z,Zero)      Bit is set when the result of an
                                      operation is zero.
                3      (N,Negative)  Is set when the result of an
                                      operation  is negative.
                4      (X,Extended)  Like carry,is set for arithmetic
                                      operations.
                5-7                  Not used.
        The system byte contains five significant bits:
                Bit    Nane          Meaning
                -----------------------------------------------
                8      I0            Interupt mask.Activates interupt
                9      I1            levels 0 to 7,where 0 is the lowest
                10    I2            and 7 is the highest priority.
                11                    not used.
                12                    not used.
                13    (S,Supervisor)  This bit indicates the actual
                                      pocessor mode(0=User,1=Supervisor
                                      mode).
                14                    not used.
                15    (T,Trace)      If this bit is set,the processor is
                                      in single step mode.
        Here's an overview of the status word;
               
                bit  : 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
                name :  T  -  S  -  - I2 I1 I0  -  -  -  X  N  Z  V  C
       
        Don't let the new terms,like mode and interupt confuse you.We'll
        talk about these in greater detail in the chapter dealing with the
        operating conditions of the processor.
      2.2.Addressing Memory.
      ---------------------
        In the standard Amiga 500's and 1000's,the processor has over 512k
        of RAM available.The Amiga 2000 has one mega-byte of RAM that can
        be accessed by the processor.How does the processor access all
        this memory?
        If you're programming in BASIC you don't have to worry about
        memory management.You can simply enter MARKER%=1,and the value is
        stored in memory by the BASIC interpreter.
        In assembler,there are two ways of accomplishing this task:
          1) Store the value in one of the data or address registers,or
          2)Write it directly into a memory location.
        To demonstrate these two methods let's get a little ahead and
        introduce a machine language instruction,which is probably the
        most common:MOVE.As its name states,this instruction moves values.
        Two parameters are required with the instruction:source and
        destination.
        Lets see what the example from above would look like if you
        utilize the MOVE instruction...
          1)  MOVE  #1,D0
        This instruction moves the value 1 into data register D0.As you
        can see,the source value is always entered before the destination.
        Thus,the instruction MOVE D0,#1 is not possible.
          2)  MOVE  #1,$1000
        deposits the value 1 in the memory location at $1000.This address
        was arbitrarily chosen.Usually addresses of this form won't be
        used at all in assembler programs,since labels that point to a
        certain address are used instead.Thus,the more common way of
        writing this would be:
            ...
            MOVE  #1,MARKER
            ...
          MARKER:DC.W 1
        These are actually two pieces of program:the first part executes
        the normal MOVE instruction whose destination is `MARKER`.This
        label is usually defined at the end of a program and specifies the
        address at which the value is stored.
        The paraneter DC.W 1 is a pseudo op,apseudo operation.This means
        that this isn`t an instruction for the processor,but an
        instruction for the assembler.The letters DC stand for`DeClare`and
        the suffix .W indicates that the data is a Word.The other two
        suffix alternatives would be .B for a byte(8 bits)and .L for a
        long word(32 bits).
        This suffix(.B.W or.L)is used with most machine language
        instructions.If the suffix is omitted,the assembler uses .W(word)
        as the default parameter.If you wanted a long word,you`d use an
        instruction that looks something like this:MOVE .L #$1234678,D0
        where as an instruction like MOVE.B #$12,D0 would be used for a
        byte of data.However,with this instruction there`s one thing you
        must be aware of...
        CAUTION:
        If the memory is accessed by words or long words,the address must
        be even(end digit must be 0,2,4,6,8,A,C,E)!
        Assemblers usually have a pseudo-op,`EVEN`or`ALIGN`,depending on
        the assembler,that aligns data to an even address.This becomes
        necessary in situations similar to this:
            ...
          VALUE1:    DC.B 1
          VALUE2:    DC.W 1
        If the VALUE1 is located at an even address,VALUE2 is automaticaly
        located at an odd one.If an ALIGN(EVEN)is inserted here,a fill
        byte(0)is inserted by the assembler,thus making the second address
        even.
            ...
          VALUE1:    DC.B 1
          ALIGN
          VALUE2:    DC.W 1
        Back to the different ways of addressing.The variations listed
        above are equivalent to the BASIC instruction MARKER%=1 where the
        % symbol indicates an integer value.
        Lets go a step further and translate the BASIC instruction MARKER
        %=VALUE% into assembler.You`ve probably already guessed the answer
        right?
                MOVE VALUE,MARKER
                ...
                ...
          MARKER:      DC.W 1
          VALUE :      DC.W 1
        In this case,the contents in the address at VALUE are moved into
        the address at MARKER.
        With the help of these simple examples,you`ve already become
        familiar with four different ways of addressing,in other words,
        ways that the processor can access memory.The first is
        characterized by the number sign(#)and represents a direct value.
        Thus,this method is also known as direct addressing,and is legal
        only for the source parameter!
        A further method in which a direct address(in our case,`MARKER`and
        `VALUE`)can be specified is known as absolute addressing.This
        method is legal for the source parameter as well as for the
        destination parameter.
        This method can be divided into two different types,between which
        the programmer usually does'nt notice a difference.Depending on
        whether the absolute address is smaller or larger than $FFFF,in
        other words if it requires a long word,it is called absolute
        addressing(for addresses above $FFFF)or otherwise absolute short
        addressing.The assembler generally makes the distinction between
        these two types,and thus,only general knowledge of absolute
        addressing is required.
        The fourth method of addressing that you've encountered so far is
        known as DATA REGISTER DIRECT.It was the first one introduced(MOVE
        #1,D0)in conjunction with direct addressing,the only difference
        being that this type accesses a data register(such as D0).
        These four methods aren't the only ones available to the MC68000
        processor,in fact there are a total of 12.One other variation
        called ADDRESS REGISTER DIRECT,is almost identical to data
        register direct,except that it accesses the address register
        instead of the data register.Thus,you can use MOVE.L #MARKER,A0 to
        access the address register A0 directly.
        You now know five ways to address memory with which quite a bit
        can be accomplished.Now,lets tackle something more complicated and
        more interesting.
        Lets take another example from BASIC:
           
            10  A=1000
            20  POKE A,1
        In this example the first line assigns the value 1000 to the
        variable A.This can be done in assembler as well:MOVE.L #1000,A0.
        In the assembler version the absolute value of 1000 ia stored in
        the address register A0.
        Line 20 doesn't assign a value to the variable A itself,but rather
        to the memory location at the address stored in A.This is an
        indirect access,which is quite easy to duplicate in assembler:
           
            MOVE.L  #1000,A0      ;bring address in A0
            MOVE    #1,(A0)        ;write 1 into this address
        The parentheses indicates an addressing known as ADDRESS REGISTER
        INDIRECT.This method only works with address registers,since a
        'data register indirect' does not exist.
        There are several variations of this method.For instance,a
        distance value can be specified,which is added to the address
        presently located in the address register before the register is
        actually accessed.The instruction MOVE #1,4(A0),if applied to the
        example above,writes the value 1 into the memory cell at 1000+4=
        1004.This distance value can be positive or negative.Thus,values
        from -32768 to +32768 are accepted.This specific variation of
        addressing is called ADDRESS REGISTER INDIRECT WITH A 16 BIT
        DISPLACEMENT value.
        There is another very similar variation:ADDRESS REGISTER INDIRECT
        WITH AN 8 BIT INDEX value.While this variation is limited to 8
        bits,it also brings another register into play.This second
        register is also a distance value,except that it is a variable as
        well.
        We'll try to clarify this with an example.Lets assume that a
        program includes a data list that is structured like this:
         
              ...
            RECORD:        DC.W 2  ;number of entries -1
                  DC.W 1,2,3        ;elements of list
       
        We'll use MOVE.L #RECORD,A0 to load the list into the address
        register A0.Then you can use MOVE (A0),D0 to pull the number of
        in the list into the data register.To access the last element of
        the listonly one instruction is needed.The whole thing looks
        something like this:
                  CLR.L  D0            ;erase D0 completely
                  MOVE.L  #RECORD,A0    ;address of list in A0
                  MOVE    (A0),D0      ;number of elements -1 in D0
                  MOVE    1(A0,D0),D1  ;last element in D1
                  ...
          RECORD: DC.W 2                ;number of entries -1
                  DC.W 1,2,3            ;elements of list
        This last instruction accesses the byte that is located at 1+A0+D0
        in other words,the record +1 where the data begins plus the
        contents of D0(in this case 2).
        This method of accessing is very useful.It works exquisitely for
        the processing of tables and lists,as the example demonstrates.If
        no distance value is needed,simply use a distance value of zero,
        which some assemblers automatically insert as the default value if
        for instance only MOVE (A0,D0)is entered.
        The latter two methods have a third variation,which as its own
        characteristic trait.It dosen't utilize an address register,but
        uses the Program Counter(PC)instead.The program counter with
        displacement method proves useful when a program must function
        without any changes in all address ranges.The following two
        statements(in the 15 bit limits)have the same effect:
                  MOVE  MARKER,D0
          and
                  MOVE  MARKER(PC),D0
        This method is actually rather imprecise,since the first
        instruction specifies the actual address of the marker with MARKER
        while the second line specifies the distance between the
        instruction and the marker.However since it would be quite
        cumbersome to constanly calculate the distance,the assembler takes
        this task off our hands and calculates the actual value automatic.
        Lets examine the difference between the two instructions.In a
        program they'll accomplish the same thing,although they are
        interpreted as two completely different things by the assembler.
        You'll assume a program being at the address $1000 and the marker
        is located at $1100.The generated program code looks something
        like this:
          $001000      30 39 00 00 11 00    MOVE  MARKER,D1
          or
          $001000      30 3A 00 FE          MOVE  MARKER(PC),D1
        As you can see,the generated code of the second line is two bytes
        shorter than the first line.In addition,if you were to shift this
        code to the address $2000,the first version still accesses the
        memory at $1100,while the second line using the PC indirect
        addressing accesses memory at $2000 correctly.Thus,the program can
        be transferred to almost any location.
        This,then,is PROGRAM COUNTER WITH 16 BIT DISPACEMENT value.As we
        mentioned,there is also PROGRAM COUNTER WITH 8 BIT INDEX value,
        which permits a second register as a distance value,also known as
        offset.
        There are two addressing modes left.These two are based on
        indirect addressing.They offer the capability of automatically
        raising or lowering the address register by one when memory is
        accessed with address register indirect.
        To automatically increase the register,you'd use ADDRESS REGISTER
        DIRECT WITH POST-INCREMENT.The address register raises this by the
        number of bytes used AFTER accessing memory.Thus if you write:
            MOVE.L  #1000,A0
            MOVE.B  #1,(A0)+
        the 1 is written in the address $1000 and then A0 is raised by one
        Instructions like this are very helpful when a memory range is to
        be filled with a specific value(for instance when the screen is
        cleared).For such purposes the instruction can be placed in a loop
        ...which we'll get to later.
        The counter part to post increment is ADDRESS REGISTER WITH PRE-
        DECREMENT.In this case the specified address register is lowered
        by one BEFORE the access to memory.The instructions:
            MOVE.L  #1000,A0
            MOVE.B  #1,-(A0)
        writes 1 in the address 999,since the contents of A0 is first
        decremented and the 1 is written afterwards.
        These two methods of addressing are used to manage the stack
        pointer(SP).Since the stack is filled from top to bottom,the
        following is written to place a word(s.aD0)on the stack:
            MOVE.B  D0,-(SP)
        and to remove it from the stack,again in D0:
            MOVE.B  (SP)+,D0
        This way the stack pointer always points to the byte last
        deposited on the stack.Here,again,you'll have to be careful that
        an access to the stack with a word or a long word is always on an
        even address.Thus,if you're going to deposit a byte on the stack,
        either use a whole word or make sure the byte is not followed by a
        JSR or BSR.The JSR or BSR instructions deposit the addresses from
        which they stem on the stack in the form of a long word.
        In the code above,the SP is generally replaced by the address
        register A7 in the program code,since this register is always used
        as the SP.Thus,you can write A7 as well as S,the resulting program
        is the same.However,we recommend the use of SP,since this makes
        the code somewhat easier to read.After all,quite often you'll want
        to employ your own stacks,in which case the difference between the
        processor stack and your own stacks become very important.
        These are the twelve ways of addressing the MC68000 processor,Here
        is a summary:
        No  Name                                                Format
        --  ----                                                ------
        1  data register direct                                Dn
        2  address register direct                            An
        3  address register indirect                          (An)
        4  address register indirect with post-increment      (An)+
        5  address register indirect with pre-decrement        -(An)
        6  address register indirect with 16 bit displacement  d16(An)
        7  address register indirect with 8 bit index value    8(An,Rn)
        8  absolute short                                      xxxx.W
        9  absolute long                                      xxxxxxxx.L
        10  direct                                              #'data'
        11  program counter indirect with 16 bit displacement  d16(PC)
        12  program counter indirect with 8 bit index value    d8(PC,Rn)
        The abbreviations above have the following meanings:
            An      address registers A0-A7
            Dn      data registers D0-D7
            d16    16 bit value
            d8      8 bit value
            Rn      register D0-D7,A0-A7
            'data'  up to 32 bit value,(either .B .W .L)
        These are the addressing modes used by the MC68000 processor.The
        bigger brother of this processor,the 32 bit MC68020,has six more
        methods which we won't discuss here.
        Next you're going to see under what conditions the processor can
        operate.
      2.3.Operating Modes.
      -------------------
        In the previous section about registers you encountered the Status
        Register(SR).The individual bits of this register reflect the
        present operating condition of the processor.You differentiated
        between the system byte(bits 8-15)and the user byte(bits 0-7).Now,
        lets take a closer look at the system byte and its effects upon
        the operation of the processor.
      2.3.1.User and Supervisor Modes.
      -------------------------------
        Isn't it rather strange that the processor classifies you either
        as a'user'or a 'supervisor'?Both of these operating modes are
        possible,the user mode being the more common mode.In this mode it
        is impossible to issue some instructions,and that in your own
        computor!
        Don't worry though,you can get around that,as well.The Amiga's
        operating system contains a function that allows us to switch the
        processor from one mode to the other.
        The mode is determined by bit 13 of the Status Register.Usually
        this bit is cleared(0),indicating that the processor is in user
        mode.It is possible to write directly into the status register,
        although this is a privileged instruction that can only be
        executed from the supervisor mode.Thus,this instructioncould only
        be used to switch from the supervisor mode into the user mode,by
        using AND #$DFFF,SR to clear the supervisor bit.However,it is
        quite preferable to let the operating system perform the switch
        between these two modes.
        Now what differentiates these two modes in terms of application?
        Well,we already mentioned the first difference:some instructions,
        such as MOVE xx,SR, are privileged and can only be executed from
        the supervisor mode.An attempt to do this in user mode would
        result in an exception and interruption of the program.Exceptions
        are the only way of switching to the supervisor mode,but more
        about later.
        A further difference is in the stack range used.Although A7 is
        still used as the stack pointer,another memory range is used for
        the stack itself.Thus,the SP is changed rach time you switch from
        one mode to the other.Because of this you differentiate between
        the User(USP)and the Supervisor SP(SSP).
        Accessing memory can also depend on these two modes.During such
        accessing,the processor sends signals to the peripheral components
        informing them of the current processor moce.This way a MC68000
        computor can protect(privilege)certain memory ranges so they can't
        be accessed by the user.
        In the supervisor mode it is possible to execute all instructions
        and access all areas of memory.Because of this,operating systems
        usually run in the supervisor mode.This is accomplished through
        the use of Exceptions.
      2.3.2.Exceptions.
      ----------------
        Exceptions are similar to interupts on 6500 computors.This allows
        stopping a program,running a sub-program,and then restarting the
        stopped program.When an exception occurs the following seps are
        taken:
          1)  The status register is saved.
          2)  The S bit in SR is set(supervisor mode)and the T bit is
                cleared(no trace).
          3)  The program counter and the user SP are saved.
          4)  The exception vector,which points to the needed exception
                routine,is retrieved.
          5)  The routine is executed.
        The vectors mentioned,which contain the starting addresses for the
        various routines,are located at the very beginning of the memory.
        Here is an overview of the vectors and their respective addresses:
          Number  Address      Used for
          -----    ------        --------
            0      $000          RESET:starting SSP
            1      $004          RESET:starting PC
            2      $008          bus error
            3      $00C          address error
            4      $010          illegal instruction
            5      $014          division by zero
            6      $018          CHK instruction
            7      $01C          TRAPV instruction
            8      $020          privilege violation
            9      $024          trace
          10      $028          Axxx-instruction emulation
          11      $02C          Fxxx-instruction emulation
                    $030-$038    reserved
          15      $03C          uninitialed interrupt
                    $040-$05F    reserved
          24      $060          unjustified interrupt
          25-31    $064-$083    level 1-7 interrupt
          32-47    $080-$0BF    TRAP instructions
                    $0C0-$0FF    reserved
          64-255  $100-$3FF    user interrupt vectors
        The individual entries in the table above need detailed
        explanation.So lets go through them one by one...
      RESET:staring SSP;
        At reset,the long word stored at this location is used as the
        stack pointer for the supervisor mode(SSP).This way you can
        specify the stack for the RESET routine.
      RESET:starting PC;
        Again at reset,the value at this location is used as the program
        counter.In other words,the RESET routine is started at the address
        stored here.
      Bus Error;
        This exception is activated by a co-processor when,for instance,a
        reserved or non-existant memory range is accessed.
      Address Error;
        This error occurs when a word or long word access is atempted at
        an odd address.
      Illegal Instruction;
        Since all MC68000 instructions consist of one word,a total 65536
        different instructions are possible.However,since the processor
        doesn't that many instructions,there are a number of words that
        are invalid instructions.Should such a word occur,the exception is
        prompted.
      Division by Zero;
        Since the processor has a division function,and the division of
        anything by zero is mathematically undefined and thus illegal,this
        exception occurs when such an operation is attempted.
      CHK Instruction;
        This exception only occurs with the CHK instruction.This
        instruction tests that a data registers contents are within a
        certain limit.If this is not the case,the exception is activated.
      TRAPV Instruction;
        If the TRAPV instruction is executed and the V bit(bit 1)in the
        status word is set,this exception is prompted.
      Privilege Violation;
        If a privileged instruction is called from the user mode,this
        exception is activated.
      Trace;
        If the trace bit(bit 15)in the status word is set,this exception
        is activated after each instruction that is executed.This method
        allows you to employ a step by step execution of machine programs.
      Axxx-Instruction Emulation;
      Fxxx-Instruction Emulation;
        These two vectors can be used for a quite interesting trick.If an
        instruction beginning with $A or $F(such as $A010 or $F200)is
        called the,the routine to which the corresponding vector is
        pointing is accessed.In these routines you can create chains of
        other instructions,in effect expanding the processors instruction
        vocaulary!
      Reserved;
        These vectors are not used.
      Uninitialized Interrupt;
        This exception is activated when a peripheral component that was
        not initialized sends an interrupt.
      Unassigned Interrupt;
        Is activated when a BUS error occurs during the interrupt
        verification of the activating component.However,the interrupt is
        usually only by some type of disturbance.
      Level 1-7 Interrupt;
        These seven vectors point to the interrupt routines of the
        corresponding priority levels.If the level indicated in the status
        word is higher than the level of the occuring interrupt,the
        interrupt is simply ignored.
      TRAP Instructions;
        These 16 vectors are used when a corresponding TRAP instruction
        occurs.Thus,TRAP instructions from TRAP #0 to TRAP #15 are
        possible.
      User Interrupt Vectors;
        These vectors are used for interrupts which are activated by
        several peripheral components that generate their own vector
        number.
       
        At this point you don't want to delve any deeper into the secrets
        of exceptions,since we'd be expanding this book beyond its frame
        work.However,there's one last thing to say about exceptions:the
        exception routines are ended with the RTE(ReTurn from Exception)
        instruction,with which the original status is restored and the
        user program is continued.
      2.3.3.Interrupts.
      ----------------
        Interrupts are processed similarly to exceptions.They are breaks
        (or interruptions)in the program which are activated through
        hardware(such as a peripherical component or an external trigger).
        The interrupt level is stored in bits 8-10 of the status register.
        A value between 0 and 7 indicates the interrupt level.There are
        eight possible interrupts,each of which as a different priority.If
        the level of this interrupt happens to be higher than the value in
        the status register,the interrupt is executed,or else ignored.
        When a valid interrupt occurs,the computor branches to the
        corresponding routine whose address is indicated in the exception
        vector table above.
        The interrupts are very important if you're trying to synchronize
        a program with connected hardware.In this manner,a trigger(s.a the
        keyboard)which is to feed the computor data,can signal the request
        for a legal value using an interrupt.The interrupt routine then
        simply takes the value directly.This method is also employed for
        the operation of the serial interface(RS232).
        We'll talk about the use of interrupts at a later time.The last
        thing we want to mention about interrupts at this time is that,
        like exceptions,interrupt routines are terminated with the RTE
        instruction.
      2.3.4.Condition Codes.
      ---------------------
        When you write a program in any language,the need for a
        conditional operation arises quite often.For instance,in a BASIC
        program
            IF D1=2 THEN D2=0
        represents a conditional operation.To write the equivalent in
        machine language,you first need to make the comparison:
            CMP  #2,D1
        CMP stands for compare and compares two operands,in this case D1
        and D2.How is this operation evaluated?
        For this purpose you have condition codes(CC's),which exist in the
        branch instructions of machine language.Because of this,you must
        specify when and where the program is to branch.
        The simplest variation of the branch instruction is an
        unconditional branch.The corresponding instruction is 'BRA address
        ',although this won't help you here.After all,you need a
        conditional branch.
        To retain the result of the operation,in this case a comparrison
        (CMP),several bits are reserved in the status word.Lets look at
        bit 2 first,which is the zero flag.This flag is set when the
        result of the previous operation was zero.
        To explain the relationship between CMP and the Z flag,you must
        first clarify the function of the CMP instruction.Actually this
        instruction performs the subtraction of the source operand from
        the destination operand.In the example above,the number 2 is
        subtracted from the content of the memory cell at D1.Before the
        result of this subtraction is discarded,the corresponding flags
        are set.
        If the contents of D1 in our example above happened to be 2,the
        result of the subtraction would be 0.Thus,the Z flag would be set,
        which can then be evaluated through a corresponding branch
        instruction.Our example would then look like this:
                  ...
                  CMP  #2,D1      ;comparison,or subtraction
                  BNE  UNEQUAL    ;branch,if not equal(Z flag not set)
                  MOVE  #0,D2      ;otherwise execute D2=0
       
          UNEQUAL:
                  ...            ;program branches to here
        BNE stands for Branch if Not Equal.This means,that if the Z flag
        was cleared(=0)by the previous CMP,the program branches to the
        address specified by BNE(here represented by UNEQUAL).The counter
        part to the BNE instruction is the BEQ(Branch if EQual)instruction
        which is executed if Z=1.
        Here's a list of condition codes,which allow you to form
        conditional branches using the Bcc(cc=condition code)format:
          cc      Condition                    Bits
          ---------------------------------------------------
          T        true,corresponds to BRA
          F        false,never branches
          HI      higher than                  C'* Z'
          LS      lower or same                C + Z
          CC,HS    carry clear,higher or same    C'
          CS,LO    carry set,lower              C
          NE      not equal                    Z'
          EQ      equal                        Z
          VC      overflow clear                V'
          VS      overflow set                  V
          PL      plus,positive
          MI      minus,negative
          GE      greater or equal              N*V+N'*V'
          LT      less than                    N*V'+N'*V
          GT      greater than                  N*V*Z'+N'*V'*Z'
          LE      less or equal                Z + N*V' + N'*V
          *=logic AND, +=logic OR, '=logic NOT
        Here are a few examples to demonstrate how these numerous
        conditions can be utilized:
          CMP  #2,D1
          BLS SMALLER_EQUAL
        This branches if the contents of D1<=2,whether D1 is 0,1 or 2.In
        this example,the BLE instruction would allow the program to branch
        even if D1 is negative.You can tell this by the fact that the V
        bit is used in the evaluation of this expression(see chart above).
        When the sign is changed during the operation,this V bit is
        compared with the N bit.Should both bits be cleared(N bit=0 and V
        bit=0)after the CMP subtraction(D1-2),the result has remained
        positive:the condition as not been met.
        The conditions EQ and NE are quite important for other uses,as
        well.For instance,they can be used to determine if particular bits
        in a data word are set,by writing the following sequence...
            ...
            AND  #%00001111,D1      ;masks bits out
            BEQ SMALLER              ;branches when none of the four
        ;                            ;lower bits is set
            CMP  #%00001111,D1
            BEQ ALL                  ;branches when all four bits set
        The AND instruction causes all bits of D1 to be compared with the
        bits of the parameter(in this case #%00001111).If the same bits
        are set in both bytes,the corresponding bits are also set in the
        result.If one bit of the pair is cleared,the resulting bit is zero
        as well.Thus,in the result,the only bits that are set are those
        bits of the lowest four that were set in D1.
        The technique is known as masking.In the example above,only the
        lowest four bits were masked out,which meansthat in the resulting
        byte,only the lowest four appear in their original condition.All
        other bits are cleared with the AND operand.Of course you can use
        any bit combination with this method.
        If no bit at all is set in the result,the zeroflag is set,thus
        fullfilling the BEQ condition and branching the program.Otherwise,
        the next instruction is processed,in which D1 is compared with
        %00001111.When both are equal,at leastall of the four lowest bits
        of the original byte have been set,in which case the following BEQ
        instruction branches.
        Aside from CMP,the CC and CS conditions can also be used to
        determine whether a HI bit was pushed out of the data word during
        data rotation with the ROL and ROR instructions.
        Before you move on the instruction vocabulary of the MC68000,we'd
        like to give you another tip:
        The AssemPro assembler makes it quite easy to try every command in
        posible situations.Take the CMP command which we've been talking
        about,for example.To test this command with various values and to
        receive the results of the comparisons directly via the flags,try
        the following.
        Type the following into the Editor.
            run:
            cmp  $10,d1
            bra run
            end
        Assemble it,save the resulting code and enter the debugger.After
        reloading the code you can then single step through the program
        observing the results the program has on the flags.Try changing
        the values in the register D1 and see how higher and lower values
        affect the flag.
        By the way,using the start command at this time causes it to run
        forever.Well,at least until reset is hit,which isn't exactly
        desirable,either...
        This procedure isn't limited to just the CMP instruction.You can
        use it to try any other instructions you're interested in.
      2.4.The 68000 Instructions.
      --------------------------
        Its about time to explain the MC68000 instructions.You don't have
        room for an in-depth discussion of each instruction in this book;
        for that purpose we recommend PROGRAMMING THE 68000 from Sybex by
        Steve Williams.
        The following tables show the required parameters and arguments
        for each instruction.AssemPro have access to built in help tables
        covering effective addressing modes and many of the Amiga
        Intuition calls.The following notation is used for arguments:
          Label    a label or address
          Reg      register
          An        address register n
          Dn        data register n
          Source    source operand
          Dest      destination operand
          <ea>      address or register
          #n        direct value
        Here is a short list of the instructions for the MC68000 processor
        AssemPro owners can simply place the cursor at the beginning of
        the instruction and press the help key to see the addressing modes
        allowed:
        Mnemonic            Meaning
        ---------------------------------------------------
      Bcc    Label        conditional branch,depends on condition
      BRA    Label        unconditional branch(similar to JMP)
      BSR    Label        branch to subprogram.Return address is
                            deposited on stack,RTS causes return to that
                            address.
      CHK    <ea>,Dx      check data register for limits,activate the
                            CHK instruction exception.
      DBcc    Reg,Label    check condition,decrement and branch
      JMP    Label        jump to address(similar to BRA)
      JSR    Label        jump to subroutine.Return address is
                            deposited on stack,RTS causes return to that
                            address.
      NOP                  no operation
      RESET                reset peripherals(caution!)
      RTE                  return from exception
      RTR                  return with loading of flags
      RTS                  return from subroutine(after BSR and JSR)
      Scc    <ea>          set a byte to -1 when condition is met
      STOP                  stop processing(caution!)
      TRAP #n              jump to an exception
      TRAPV                check overflow flag,the TRAPV exception
        Here are a few important notes...
        When a program jumps(JSR)or branches(BSR)to subroutine,the return
        address to which the program is to return is placed on the stack.
        At the RTS instruction,the address is pulled back off the stack,
        and the program jumps to that point.
        Lets experiment a little with this procedure.Please enter the
        following short program:
          run:
                pea    subprogram  ;address on the stack
                jsr    subprogram  ;subprogram called
                move.l  (sp)+,d1    ;get a long word from stack
          ;      illegal              ;for assemblers without
                                      ;debuggers
          subprogram:
                move.l  (sp),d0      ;return address in D0
                rts                  ;and return
                end
        The first instruction,PEA,places the address of the subprogram on
        the stack.Next,the JSR instruction jumps to the subprogram.The
        return address,or the address at which the main program is to
        continue after the completion of the subprogram,is also deposited
        on the stack at this point.
        In the subprogram,the long word pointed to by the stack pointer is
        now loaded into the data register D0.After that,the RTS
        instruction pulls the return address from the stack,and the
        program jumps to that address.
        Back in the main program,the long word which is on the top of the
        stack,is pulled from the stack and written in D1.Assemblers that
        do not have the debugging features of AssemPro may need the
        ILLEGAL instruction so they can break the program and allow you to
        view the register contents.
        Assemble the program and load the resulting code into the debugger
        Single step thru the program and examine the register contents.
        Here you can see that D0 contains the address at which the program
        is to continue after the RTS command.Also,D1 contains the address
        of the subprogram which you can verify by comparing the debugger
        listing.
        The STOP and RESET instructions are so powerful that they can only
        be used in supervisor mode.Even if you do switch to the supervisor
        mode,you should NOT use these instructions if there is any data in
        memory that has not been saved and you wish to retain.
        The TRAP instruction receives a number between 0 and $F,which
        determines the particular TRAP vector(addresses $0080-$00BF)and
        thus the corresponding exception routine.Several operating systems
        for the 68000 utilize this instruction to call operating system
        functions.You'll deal more with this instruction later.
        In the short sample program that compared two numbers,the CMP
        instruction performed an arithmetic function,namely a subtraction.
        This subtraction could be performed with an actual result as well
        using the SUB instruction.The counterpart to this is in addition,
        for which the ADD instruction is used.In 8 bit processors,like the
        6502,these arithmetic functions are the only mathematical
        operations.The MC68000 can also multiply,divide,and perform these
        operations with a variety of data sizes.
        Most of the functions require two parameters.For instance the ADD
        instruction...
            ADD source,destination
        where source and destination can be registers or memory addresses.
        Source can also be a direct value(#n).The result of the opoeration
        is placed in the destination register or the destination address.
        This is same for all operation of this type.These instructions can
        be tried out with the AssemPro assembler.In this case we recommend
        the use of a register as the destination.
        Heres an overview of the arithmetic operations with whole numbers:
        Mnemonic                  Meaning
        --------------------------------------------------------------
        ADD      source,dest      binary addition
        ADDA      source,An        binary addition to a address register
        ADDI      #n,<ea>          addition with a constant
        ADDQ      #n,<ea>          fast addition of a constant which can
                                  be only from 1-8
        ADDX      source,dest      addition with transfer in X flag
        CLR      <ea>            clear an operand
        CMP      source,dest      comparison of two operands
        CMPA      <ea>,An          comparison with an address register
        CMPI      #n,<ea>          comparison with a constant
        CMPM      source,dest      comparison of two memory operands
        DIVS      source,dest      sign-true division of a 32 bit
                                  destination by a 16 bit source operand.
                                  The result of the division is stored in
                                  the LO word of the destination,the
                                  remainder in the HI word.
        DIVU      source,dest      division without regard to sign,similar
                                  to DIVS
        EXT      Dn              sign-true expansion to twice original
                                  size(width)data unit
        MULS      source,dest      sign-true multiplication of two words
                                  into one long word
        MULU      source,dest      multiplication without regard to sign,
                                  similar to MULS
        NEG      <ea>            negation of an operand(twos complement)
        NEGX      <ea>            negation of an operand with transfer
        SUB      source,dest      binary subtraction
        SUBA      <ea>,An          binary subtraction from an address
                                  register
        SUBI      #n,<ea>          subtraction of a constant
        SUBQ      #n,<ea>          fast subtraction of a 3 bit constant
        SUBX      source,dest      subtraction with transfer in X flag
        TST      <ea>            test an operand and set N and Z flag
        For the processing of whole numbers,the processor can operate with
        BCD numbers.These are Binary Coded Decimal numbers,which means
        that the processor is working with decimals.In this method,each
        halfbyte contains only numbers from 0 to 9,so that these numbers
        can be easily processed.For this method,the following instructions
        are available:
        Mnemonic                  Meaning
        -----------------------------------------------------------------
        ABCD      source,dest      addition of two BCD numbers
        NBCD      source,dest      negation of a BCD number(nine
                                  complement)
        SBCD      source,dest      subtraction of two BCD numbers
        Again,we recommend that you try this out yourself.Although
        handling the BCD numbers is relatively easy,it can be rather
        awkward at first.Be sure that you enter only BCD numbers for
        source and destination,since the results are not correct
        otherwise.
        Next are the logical operations,which you might know from BASIC.
        With these functions,you can operate on binary numbers bit for
        bit.
        Mnemonic                  Meaning
        -----------------------------------------------------------------
        AND      source,dest      logic AND
        ANDI      #n,<ea>          logic AND with a constant
        EOR      source,dest      exclusive OR
        EORI      #n,<ea>          exclusive OR with a constant
        NOT      <ea>            inversion of an operand
        OR        source,dest      logic OR
        ORI      #n,<ea>          logic OR wuth a constant
        TAS      <ea>            check a byte and set bit 7
        Single bits can also be manipulated by the following set of
        instructions:
        Mnemonic                  Meaning
        ----------------------------------------------------------------
        BCHG      #n,<ea>          change bit n(0 is changed to 1 and vice
                                  versa)
        BCLR      #n,<ea>          clear bit n
        BSET      #n,<ea>          set bit n
        BTST      #n,<ea>          test bit n,result is displayed in Z
                                  flag
        These instructions are particularly important from the
        manipulation and evaluation of data from peripherals.After all,in
        this type of data,single bits are often very significant.You'll
        come across this more in later chapters.
        The processor can also shift and rotate an operand within itself
        ('n'indicates a register,'#'indicates a direct value which
        specifies the number of shiftings)...
        Mnemonic                  Meaning
        ----------------------------------------------------------------
        AS        n,<ea>          arithmetic shift to the left(*2^n)
        ASR      n,<ea>          arithmetic shift to the right(/2^n)
        LSL      n,<ea>          logic shift to the left
        LSR      n,<ea>          logic shift to the right
        ROL      n,<ea>          rotation left
        ROR      n,<ea>          rotation right
        ROXL      n,<ea>          rotation left with transfer in X flag
        ROXR      n,<ea>          rotation right with transfer in X flag
        All these instructions allow you to shift a byte,a word or a long
        word to the left or right.Its not too surprising that this is the
        equivalentof multipling(dividing)the number by a power of 2.Here's
        a little example to demonstrate why
        Lets take a byte containing the value 16 as an example.In binary,
        it looks like this:
            %00010000 =16
       
        Now,if you shift the byte to the left by inserting a 0 at the
        right,you'll get the following result...
            %00010000 shifted to the left equals
            %00100000 =32,in effect 16*2
        Repeated shifting results in repeated doubling of the number.Thus
        if you shift the number n times,the number is multiplied by 2^n.
        The same goes for shifting to the right.However,this operation as
        a slight quirk:here's a sample byte with the value 5:
            %00000101 =5,shifted once to the right equals
            %00000010 =2
        The answer in this case is not 2.5 as you might expect.The result
        such a division is always a whole number,since any decimal places
        are discarded.If you use the DIV instruction instead of shifting,
        you'll retain the digits to the right of the decimal point.However
        shifting is somewhat faster,and shifting can also receive long
        words as results.
        After explaining the principle of shifting,you still need to know
        why more than two instructions are required for the procedure.Well
        this is because there are several different types of shifting.
        First,you must differentiate between shifting and rotating.In
        shifting,the bit that is added to the left or the right side is
        always a zero.In rotating,it is always a specific value that is
        inserted.This means that with the ROR or the ROL instructions,the
        bit that is taken out on one side is the one that is inserted on
        the other.With the ROXR and the ROXL instructions this bit takes a
        slight detour to the X flag.Thus,the content of the flag is
        inserted into the new bit,while the old bit is loaded into the
        flag.
        Shifting as well,has two variations:arithmetic and logical
        shifting.You've already dealt with logical shifting.In this
        variation,the inserted bit is always a zero,and the extracted bit
        is deposited in the C flag and in the X flag.
        Although the highest bit,which always represents the sign,is
        shifted in arithmetic shifting,the sign is still retained by ASR.
        This has the advantage that when these instructions are used for
        division,the operation retains the correct sign(-10/2 equals-5).
        However,should an overflow or underflow cause the sign to change,
        this change is noted in the V flag,which always indicates a change
        in sign.With logical shifting this flag is always cleared.
        Now to the instructions that allow you to move data.These are
        actually the most important instructions for any processor,for how
        else could you process data?
        Mnemonic                  Meaning
        ------------------------------------------------------------------
        EXG      Rn,Rn            exchange of two register contents(don't
                                  confuse with swap)
        LEA      <ea>,An          load an effective address in address
                                  register An
        LINK      An,#n            build stack range
        MOVE      source,dest      carry value over from source to dest
        MOVE      SR,<ea>          transfer the status register contents
        MOVE      <ea>,SR          transfer the status register contents
        MOVE      <ea>,CCR        load flags
        MOVE      USP,<ea>        transfer the user stack point
        MOVE      <ea>,USP        transfer the user stack point
        MOVEA    <ea>,An          transfer a value to the address
                                  register An
        MOVEM    Regs,<ea>        transfer several registers at once
        MOVEM    <ea>,Regs        transfer several registers at once
        MOVEP    source,dest      transfer data to peripherals
        MOVEQ    #n,Dn            quickly transfer a 8 bit constant to
                                  the data register Dn
        PEA      <ea>            deposit an address on the stack
        SWAP      Dn              swap the halves of the register(the
                                  upper 16 bits with the lower)
        UNLK      An              unlink the stack
        The LEA or PEA instructions are often used to deposit addresses in
        an address register or on the stack.The instruction
            LEA  label,A0
        loads the address of the label'label' into the address register
        A0.In practice,this corresponds to
            MOVE.L  #label,A0
        which is equivalent to
            PEA  label
        All these instructions deposit the address of 'label' on the stack
        The following instruction also does this:
            MOVE.L  #label,-(SP)
        The LEA instruction becomes much more interesting when the label
        is replaced by indirect addressing.Here's an example:
            LEA  1(A0,D0),A1
        The address that's produced by the addition of 1(direct value
        offset)+A0+D0 is located in A1.To duplicate this instruction with
        MOVE would be quite cumbersome.Take a look:
            MOVE.L  A0,A1
            ADD.L  D0,A1
            ADDQ.L  #1,A1
        As you can see,the LEA instruction offers you quite some
        interesting possibilities.
        Those are all the instructions of the MC68000.Through their
        combination using the diverse methods of addressing,you can create
        a great number of different instructions,in order to make a
        program as efficent as possible.
        The following table is an overview of all MC68000 instructions
        along with their possible addressing types and the influence of
        flags.The following abbreviations are used:
            x=legal          s=source only    d=destination only
            -=not effected  0=cleared        *=modified accordingly
            1=set            u=undermined    P=privileged
        Mnemonic    1  2  3  4  5  6  7  8  9 10 11 12  X N Z V C  P
        -----------------------------------------------------------------
        ABCD        x
        ADD          s  s  x  x  x  x  x  x  x  s  s  s  * * * * *
        ADDA        x  x  x  x  x  x  x  x  x  x  x  x  - - - - -
        ADDI        x    x  x  x  x  x  x  x          * * * * *
        ADDQ        x  x  x  x  x  x  x  x  x          * * * * *
        ADDX        x          x                      * * * * *
        AND          s    x  x  x  x  x  x  x  s  s  s  - * * 0 0
        ANDI        x    x  x  x  x  x  x  x          - * * 0 0
        ASL, ASR    x    x  x  x  x  x  x  x          * * * * *
        Bcc                                              - - - - -
        BCHG        x    x  x  x  x  x  x  x          - - * - -
        BCLR        x    x  x  x  x  x  x  x          - - * - -
        BRA                                              - - - - -
        BSET        x    x  x  x  x  x  x  x          - - * - -
        BSR                                              - - - - -
        BTST        x    x  x  x  x  x  x  x  z  x  x  - - * - -
        CHK          x    x  x  x  x  x  x  x  x  x  x  - * u u u
        CLR          x    x  x  x  x  x  x  x          - 0 1 0 0
        CMP          x  x  x  x  x  x  x  x  x  x  x  x  - * * * *
        CMPA        x  x  x  x  x  x  x  x  x  x  x  x  - * * * *
        CMPI        x    x  x  x  x  x  x  x          - * * * *
        CMPM              x        x  x  x  x    x  x  - * * *
        cpGEN                                            - - - - -
        DBcc                                            - - - - -
        DIVS        x    x  x  x  x  x  x  x  x  x  x  - * * * 0
        DIVU        x    x  x  x  x  x  x  x  x  x  x  - * * * 0
        EOR          x    x  x  x  x  x  x  x          - * * 0 0
        EORI        x    x  x  x  x  x  x  x          - * * 0 0
        EORI CCR                                        * * * * *
        EORI SR                                          * * * * *
        EXG                                              - - - - -
        EXT                                              - * * 0 0
        EXTB                                            - * * 0 0
        ILLEGAL                                          - - - - -
        JMP                x        x  x  x  x    x  x  - - - - -
        JSR                x        x  x  x  x    x  x  - - - - -
        LEA                x        x  x  x  x    x  x  - - - - -
        LINK            x                                - - - - -
        LSL, LSR          x  x  x  x  x  x  x          * * * 0 *
        MOVE        x  s  x  x  x  x  x  x  x  s  s  s  - * * 0 0
        MOVEA        x  x  x  x  x  x  x  x  x  x  x  x  - - - - -
        MOVE to CCR  x    x  x  x  x  x  x  x  x  x  x  * * * * *
        MOVE from SR x    x  x  x  x  x  x  x          - - - - -  P
        MOVE to SR  x    x  x  x  x  x  x  x  x  x  x  * * * * *  P
        MOVE USP        x                                - - - - -  P
        MOVEM              x  s  d  x  x  x  x    s  s  - - - - -
        MOVEP        s  d                                - - - - -
        MOVEQ        d                                  - * * 0 0
        MULS        x    x  x  x  x  x  x  x  x  x  x  - * * 0 0
        MULU        x    x  x  x  x  x  x  x  x  x  x  - * * 0 0
        NBCD        x    x  x  x  x  x  x  x          * u * u *
        NEG          x    x  x  x  x  x  x  x          * * * * *
        NEGX        x    x  x  x  x  x  x  x          * * * * *
        NOP                                              - - - - -
        NOT          x    x  x  x  x  x  x  x          - * * 0 0
        OR          s    x  x  x  x  x  x  x  s  s  s  - * * 0 0
        ORI          x    x  x  x  x  x  x  x          - * * 0 0
        PEA                x        x  x  x  x    x  x  - - - - -
        RESET                                            - - - - -  P
        ROL, ROR          x  x  x  x  x  x  x          - * * 0 *
        ROXL, ROXR        x  x  x  x  x  x  x          - * * 0 *
        RTE                                              - - - - -  P
        RTR                                              * * * * *
        RTS                                              - - - - -
        SBCD        x          x                      * u * u *
        Scc          x    x  x  x  x  x  x  x          - - - - -
        STOP                                    x        - - - - -
        SUB          s  s  x  x  x  x  x  x  x  s  s  s  * * * * *
        SUBA        x  x  x  x  x  x  x  x  x  x  x  x  - - - - -
        SUBI        x    x  x  x  x  x  x  x          * * * * *
        SUBQ        x  x  x  x  x  x  x  x  x          * * * * *
        SUBX        x          x                      * * * * *
        SWAP        x                                  - * * 0 0
        TAS          x    x  x  x  x  x  x  x          - * * 0 0
        TRAP                                    x        - - - - -
        TRAPV                                            - - - - -
        TST          x    x  x  x  x  x  x  x          - * * 0 0
        UNLK            x                                - - - - -         
       
      Chapter 3.
      ---------
      3.Working With Assemblers.
      -------------------------
        The instructions that you've learned so far are incomprehensible
        to the MC68000 processor.The letters MOVE mean absolutely nothing
        to the processor-it needs the instructions in binary form.Every
        instruction must be coded in a word-which normally takes a lot of
        work.
        An assembler does this work for you.An assembler is a program that
        translates the instructions from text into the coresponding binary
        instructions.The text that is translated is called Mnemonic or
        Memcode.Its a lot easier working with text instructions-or does
        $4280 mean more to you than CLR.L D0?
        This chapter is about working with assemblers.We'll describe the
        following three:
      ASSEM;
        This is the assembler from the Amiga's development package.This
        assembler is quite powerful,but it is clearly inferior to its two
        fellow compilers in some areas.
      AssemPro;
        This is the Abacus assembler.It has a debugger in addition to the
        assembler.This lets you test and correct programs.In our opinion,
        it is the best one to use for writing and testing practice
        programs.For this reason,we wrote the programs in this book with
        this assembler.
      KUMA-SEKA;
        This is a popular assembler which also has a debugger.
        All assemblers perform a similar task-they translate memcode,so
        that you can write a runable program to disk.To test the program
        directly,you need a debugger which is something Assem doesn't
        have.
      3.1.The Development Assembler.
      -----------------------------
        This assembler is a plain disk assembler.That means that it can
        only assemble text files that are on disk and write the result
        back to disk.You can't make direct input or test run the new
        program.
        You can call ASSEM from the CLI by typing ASSEM followed by
        parameters that specify what you wish the assembler to do.
        In the simplest case,you call it like this:
            ASSEM Source -O Destination
        Source is the filename of the file containing the program text.
        Destination is the name of the file that contains the results of
        assembling after the process is over.The "-O"means that the
        following name is used for the object file.
        There are several other parameters that can be passed.These are
        written with their option(ie-O),so that the assembler knows what
        to do with the file that you've told it to use.The following
        possible options must be followed by a filename.
            -O    Object file
            -V    Error messages that occur during assembling are written
                  to a file.If this isn't given,the error messages appear
                  in the CLI window.
            -L    The output of the assembled program lines are sent to
                  this file.You can also use"PRT:"to have it printed.
            -H    This file is read in at the beginning of the assembled
                  file and assembled along with it.
            -E    A file is created that contains lines which have EQU
                  instructions.
            -C    This option isn't followed by a filename but by another
                  option.You can also use OPT to do this.The following
                  options are available:
                 
                  OPT S  A symbol table is created which contains all the
                        labels and their values.
                  OPT X  A cross reference list is created(where labels
                        are used).
                  OPT W  A number must follow this option.It sets the
                        ammount of workspace to be reserved.
        The assembler creates an object file.This is not runnable.To make
        it runnable,you need to call the linker,ALINK.This program can
        link several assembled or compiled object files together to make a
        runnable program.In the simplest case,you enter the following
        instruction in the CLI:
            ALINK Source TO Destination
        Source is the object file produced by the assembler.Destination is
        the name of the program.It can be started directly.
      3.2.AssemPro.
      ------------
        Abacus's AssemPro is a package which combines editor,assembler and
        debugger in an easy to use package.
        The AssemPro Program is divided into several windows-one for the
        assembler,the editor,the debugger and several help functions.
        Producing a program is very easy:
         
          1)  Write the program with the editor and then store it to disk.
          2)  Start the assembler,so that the program is translated.
          3)  If desired,start the debugger,load the program and test it.
        Within the debugger you can work through parts of the program or
        even through single commands.As after each one of these steps the
        debugger shows you the state of the registers and flags in the
        status register,you can easily try the programs presented in this
        book.
        You need to load AssemPro only once when working with machine
        language programs.Thus you don't need to save back and to between
        editor,assembler,linker and debugger.
        AssemPro has an especially interesting function:the reassembler.
        With this debugger function you are able to convert runnable
        programs into the source text of the program.Once you have made
        the source text,you can edit the program using the editor and
        assemble it again.AssemPro is equipped with functions other
        assemblers miss.There are however,some differences you should know
        about.As many programs you see were written for the K-SEKA,be
        aware of one difference:the EVEN command.AssemPro uses the ALIGN
        instruction.
        Note,that when entering and assembling one of the programs in
        AssemPro you must make sure that you place an END directive at the
        end of the source text.
        The following is an introduction into working with AssemPro and
        the programs in this book.
       
        Start AssemPro normally,next click on the editor window and start
        typing in your program.If the program is on disk already,load it
        by selecting the appropriate menu or by using the key combination
        right <AMIGA> key and <o>.To do this you only need to ckick on the
        filename in the displayed requester and click on the OK gadget.
        Once you have typed in or loaded the program into the editor,you
        can assemble it.It is best to save your source before assembling.
        You assemble your program by clicking on the assembler window
        displayed above the editor window and pressing <AMIGA> and <a>.You
        can then choose how to locate your program in the memory.Remember
        that data used by the co-processors must be located in CHIP RAM.
        By clicking OK you start the assembler process.If you additionally
        select "breakable",you can cancel the process by pressing both
        shift keys.If any error occurs during assembling,AssemPro uses a
        window to tell you this.Use this window to correct the error and
        continue with "Save and try again".
        Now the runnable program is located in the Amiga's memory.Use the
        menu item "Save as"to save it on disk.If you want to store it on
        RAM disk,click the given filename and enter RAM: in front of this
        name.In addition you can click on the menu item "ICON"and choose
        if you only want the program itself on disk but the icon too.Use
        this icon to start the program at a later time from Workbench.
        To test-run the program,you move the debugger window to the
        foreground of the screen(for instance by clicking on the back
        gadget).Use "Load"in the debugger menu or <AMIGA> <o> to call the
        select file window,where you select the saved program.The program
        is then loaded into the memory and its shown disassembled.
        The highlighted line(orange)represents the current state of the
        program counter.This is the line where the processor reads its
        next instruction,provided you tell the processor so.There are
        three ways to do so.
        The first one is to start the program with "Start".This
        alternative does not enable you to stop the program if anything
        goes wrong.
        The second possibility,"Start breakable"is better in this respect.
        After the program starts,it continuously displays the registers
        contents on the left side of the window.In addition to that you
        can cancel the process by pressing <ESC>.Note that this only works
        if your program doesn't use the <ESC>key itself.
        The third possibility enables you to only partly run your program.
        You can do this by stepping through the program or by placing
        breakpoints throughout the program.You place these by clicking on
        the desired address and then pressing <AMIGA> <b>."BREAKPOINT"is
        displayed where the command was displayed before.If you start the
        program now,it stops whenever it comes across any breakpoints.
        You can start a small part of the program by moving the mouse
        pointer to the orange line,clicking the left button and holding it
        down while you drag the mouse pointer downward.If you release the
        button,the processor works through this part of the program,
        stopping at the line,where you positioned the mouse pointer.This
        is a very useful method to step by step test a program.
        AssemPro as another helpful window:the Table.This window lists the
        valid address methods for instructions and the parameters of Amiga
        functions.This is extremely helpful whenever you are not sure
        about one of the instructions.
      3.3.The K-SEKA Assembler.
      ------------------------
        The SEKA assembler,from KUMA,has a simple text editor and a
        debugger in addition to the assembler.This program is controlled
        by simple instructions and it is easy to use.It is also multi-
        functional and quick,so it is great for small test and example
        programs.You can use it to write bigger programs once you've got
        use to the editor.Now lets look at the editor.
        To load a program as source code(text)into the editor,enter"r"
        (read).The program asks you for the name of the file with the
        "<FILENAME>"prompt.You then enter the name of the text file.If you
        created the file with SEKA,the file is stored on disk with".s" on
        the end of its name.You don't need to include the".s"when you load
        the file.Thats taken care of automatically.("s"stands for source.)
        You can store programs you've just written or modified by using
        the"w"instruction.The program asks you for the name.If you enter
        "Test",the file is written to the disk with"Test.s"as its name.
        This is a normal text file in ASCII format.
        There are two ways to enter or change a programs:using the line
        editor or the screen editor.You can enter the second by hitting
        the <ESC>key.The upper screen section is then reserved for the
        editor.You can move with the cursor keys and change the text
        easily.The lines that you enter are inserted into the existing
        text and automatically numbered.By hitting the <ESC>key again,you
        leave the screen editor.
        There's really not much to say about this editor.It's really just
        for simple insertions and changes.Other functions are called in
        normal instruction mode,the mode in which">"is the input prompt.
        The following instructions are available to you for text editing
        (<n>stands for a number.The meaning of the instructions is in
        parenthesis.)
        Instruction        Function
        ----------------------------------------------------------------
        t(Target)          Puts the cursor on the highest line in the
                          text.
        t<n>              Puts the cursor on line n.
        b(Bottom)          Puts the cursor on the last line in the text.
        u(Up)              Go up one line.
        u<n>              Go up n lines.
        d(Down)            Go down one line.
        d<n>              Go down n lines.
        z(Zap)            Deletes the current line.
        z<n>              Deletes n lines starting at the cursor line.
        e(Edit)            Lets you edit the current line(and only that
                          line).
        e<n>              Edit from line n.
        ftext(Find)        Searches for the text entered starting at the
                          current line.The case of a letter makes a
                          difference,so make sure to enter it correctly.
                          Blanks that appear after the f are looked for
                          as well!
        f                  Continues searching beyond the text that was
                          previously given.
        i(Insert)          Starts the line editor.Now you can enter a
                          program line by line.However,you can't use the
                          cursor to move into another line.Line numbers
                          are generated automatically.The lines that
                          follow are moved down,not erased.
        ks(Kill Source)    The source text is deleted if you answer"y"
                          when the program asks if you are sure.Otherwise
                          nothing happens.
        o(Old)            Cancels the "ks"function and saves the old text
        p(Print)          Prints the current line.
        p<n>              Prints n lines starting at cursor line.
        Those are the K-SEKA's editor functions.In combination with the
        screen editor,they allow for simple text editing.You can,for
        example,delete the current line(and other lines)while working in
        the screen editor by hitting <ESC> to get into instruction mode
        and then entering"z"(or "z<n>").
        If you'd like to edit all lines that contain "trap",for example,
        you can do the following:
          -Jump to the beginning of the text using "t"
          -Search for a "trap"instruction by entering "ftrap" in the
            first line.
          -Press <ESC> and edit the line.
          -Press <ESC> again to get into instruction mode.
          -Search using "f",<ESC>,etc.until you get to the end of the
            text.
        This sounds very clumsy,but in practise it works quite well and
        goes quickly.Experiment with the editor bit,so you can get use to
        it.
        Now here are the instructions for working with disks:
        Instruction            Function
        -----------------------------------------------------------------
        v(View files)          Look at the disk's directory.You can also
                                include the disk drive or subdirectory
                                that interests you.For example,"vc"causes
                                the "c"subdirectory to be listed and makes
                                it the current directory.
        kf(Kill file)          The program asks for the name of the file.
                                The file is deleted(and you aren't asked
                                if your sure either-so be careful).
        r(Read)                After inputting this instruction,you'll be
                                asked which file to load(FILENAME>).The
                                file that you specify is then loaded.If
                                only "r"is entered,a text file is loaded
                                in the editor.
        ri(Read Image)          Loads a file into memory.After you've
                                entered the filename,SEKA asks for the
                                address the file should begin at in memory
                                (BEGIN>)and the highest address that
                                should be used for the file(END>).
        rx(Read from Auxillary) This works just like the "ri"function
                                except that it reads from the serial port
                                instead of from disk(You don't need a file
                                name).
        rl(Read Link file)      This instruction reads in a SEKA created
                                link file.First you'll be asked if you are
                                sure,because the text buffer is erased
                                when the link file is loaded.
        w(Write)                After entering this instruction,you'll be
                                asked for the name of the file the text
                                should be written to.A".s"is automatically
                                appended to the name,so that it can be
                                recognized as a SEKA file.
        wi(Write Image)        Stores a block of memory to disk after the
                                name,beginning and end are entered.
        wx(Write to Auxillary)  This is similar to"wi";the only difference
                                is that the output is to the serial inter-
                                face.
        wl(Write Link file)    Asks for the name and then stores a link
                                file that was assembled with the"I"option
                                to disk.If this isn't available,the
                                message "* * Link option not specified"
                                appears.
        Once you've typed in or loaded a program,you can call the
        assembler and have the program translated.Just enter"a"to do so.
        You'll then be asked which options you want to use.If you enter a
        <RETURN>,the program is assembled normally-ie the results of
        translating a program in memory is stored in memory.Then the
        program can be executed straight away.
        You can enter one or more of the following options,however:
          v    The output of the results goes to the screen.
          p    or
          e    goes to the printer with a title line.
          h    The output stops after every page and waits for a key
                stroke.This is useful for controlling output to the screen
                or for putting new sheets of paper in the printer.
          o    This option allows the assembler to optimize all possible
                branch instructions.This allows the program code to be
                shorter than it would otherwise be.Several messages appear
                but you can ignore them.
          l    This option causes linkable code to be produced.You can
                save it with the"wl"instruction and read it with the "rl"
                instruction.
        A symbol table is included at the end of the listing if desired.
        The table contains all labels and their values.It also contains
        macro names.A macro allows several instructions to be combined in
        to a single instruction.
        For example,suppose you wrote a routinethat outputs the text that
        register A0 points to.Every time you need to use the routine,you
        must type:
            lea  text,a0      ;pointer to text in A0
            bsr  pline        ;output text
        You can simplify this by defining a macro for this function.To do
        this,put the following at the beginning of the program:
            print:macro    ;Macro with the name "Print"
            lea  ?1,a0    ;Parameter in A0
            bsr  pmsg      ;Output text
            endm            ;End of macro
        Now,you can simply write the following in your program:
            print text      ;Output text
        This line is replaced using the macro during assembly.The
        parameter "text"is inserted where "?1"appears in the macro.You can
        have several parameters in a macro.You give them names like "?2",
        "?3",etc...
        You can also decide whether you'd like to see the macros in the
        output listing of the assembler.This is one of the pseudo-ops that
        are available in the assembler.The SEKA assembler has the
        following pseudo-ops:
          dc      Defines one or more data items that should appear in
                  this location in the program.The word length can be
                  specified with .B,.W,or .L-and if this is left off, .B
                  is used.Text can be entered in question marks or
                  apostrophes.For example:dc.b "Hello",10,13,0
          blk    Reserves a number of bytes,words or long words,depending
                  on whether .B,.W,or .L is chosen.The first parameter
                  specifies the number of words to be reserved.The second
                  (which is optional)is used to fill the memory area.For
                  example:blk.w 10,0
          org    The parameter that follows the org instruction is the
                  address from which the (absolute) program should be
                  assembled.For example: org $40000
          code    Causes the program to be assembled in relative mode,the
                  mode in which a program is assembled starting at address
                  0.The Amiga takes care of the new addressing after the
                  program is loaded.
          data    This means that from here on only data appear.This can
                  be left out.
          even    Makes the current address even by sometimes inserting a
                  fill byte.
          odd    The opposite of even-it makes the address odd.
          end    Assembling ends here.
          equ or  Used for establishing the value of a label
          =      For example: Value=123 or Value:equ 123
          list    Turns the output on again(after nlist).You can use the
                  following parameters to influence the output:
                    c    Macro calls
                    d    Macro definitions
                    e    Macro expansion of the program
                    x    Code expansions
                  For example: list e
          nlist  Turns off output.You can use the same parameters here as
                  with "list".
          page    Causes the printer to execute a page feed,so that you'll
                  start a new page.
          if      The following parameter decides whether you should
                  continue assembling.If it is zero,you won't continue
                  assembling.
          else    If the "if"parameter is zero,you'll begin assembling
                  here.
          endif  End of conditional assembling.
          macro  Start of a macro definition.
          endm    End of macro definition.
          ?n      The text in the macro that is replaced by the nth
                  parameter in the calling line.
          ?0      Generates a new three digit number for each macro call-
                  this is very useful for local labels.
                  For example: x?0:bsr pmsg
          illegal Produces an illegal machine language instruction.
          globl  Defines the following label as globel when the "I"option
                  of the assembler is chosen.
        Once you've assembled your program,the program code is in memory.
        Using the "h"instruction,you can find out how large the program is
        and where it is located in memory.The beginning and end address is
        given in hex and the length in decimal(according to the last
        executed operations):
          Work  The memory area defined in the beginning
          Src    Text in memory
          RelC  Relocation table of the program
          RelD  Relocation table of the memory area
          Code  Program code produced
          Data  The program's memory area
        You'll find program in memory at the location given by Code.It's a
        pain to have to enter this address whenever you want to start the
        program.It make's good sense to mark the beginning of the program
        with a label(for example,"run:").You can use the "g"instruction to
        run the program as follows:
          g run
        The"g"(GO)instruction is one of SEKA's debugger instrucions.Heres
        an overview:
        x    Output all registers.
        xr  Output and change of registers(ie xd0)
        gn  Jump to address n.You`ll be asked for break points,addresses
              at which the program should be terminate.
        jn  This is similar to the one above-a JSR is used to jump into
              the program.The program must end with a RTS instruction.
        qn  Output the memory starting at address n.You can also specify
              the word length.For example: q.w $10000
        nn  Disassembled output starting at address n.
        an  Direct assembling starting at address n.Direct program
              instructions are entered.
        nn  Modify the contents of memory starting at address n.Here too
              the word length can be given.You can terminate input with
              the <ESC> key.
        sn  Executes the program instruction that the PC points to.After
              you enter this instruction,n program steps are executed.
        f    Fill a memory area.You can choose the word width.All the
              needed parameters are asked for individually.
        c    Copies one memory area to another.All the needed parameters
              are asked for individually.
        ?    Outputs the value of an expression or a label.
              For example: ?run+$1000-256
        a    Sets an instruction sequence that is passed to the program
              when it starts as if it were started from CLI with this
              sequence.
        !    Leaves the SEKA assembler after being asked if your sure.
        You saw some of the calculations like SEKA can make in the "?"
        example.You can also use them in programming.The folowing
        operations work in SEKA:
          +  Addition
          -  Subtraction
          *  Multiplication
          /  Division
          &  Logic AND
          !  Logic OR
          ~  EXclusive OR (XOR)
        These operations can also be combined.You can choose the counting
        system.A "$"stands for hexadecimal,"@"for octal,and "%"for binary.
        If these symbols aren`t used,the number is interpreted as a
        decimal number.
        Lets go back to the debugger.As mentioned,after entering "g
        address",you`ll be asked for break points.You can enter up to 16
        addresses at which the program halts.If you don`t enter break
        points,but instead hit <RETURN>,the program must end with an
        ILLEGAL instruction.If it ends instead with a RTS,the next return
        address from the stack is retrieved and jumped to.This is usually
        address 4 which causes SEKA to come back with "**Illegal
        Instruction at $000004",but theres no guarantee that it will.Your
        computor can end up so confused that it can`t function.
        The SEKA program puts an ILLEGAL instruction in the place
        specified as break points after saving the contents of these
        locations.If the processor hits an illegal instruction,it jumps
        back to the debugger by using the illegal instruction vector that
        SEKA set up earlier.Then SEKA repairs the modified memory
        locations and then displays the status line.Here you can find out
        where the program terminated.
        Using break points is a good technique for finding errors in the
        program.You can,for example,put a break point in front of a
        routine that you`re not sure about and start the program.When the
        program aborts at this spot,you can go through the routine step by
        step using the "s"option.Then you can watch what happens to the
        status line after each instruction and find the mistake.
        Program errors are called bugs.That`s why the program that finds
        them is called a debugger. 
      Chapter 4.
      ---------
      4.Our First Programs.
      --------------------
        You`re getting pretty far along in your knowledge of machine
        language programming.In fact,you`re to the point where you can
        write programs,and not just programs for demonstration purposes,
        but ones that serve a real function.We`re assuming that you have
        the AssemPro assembler and have loaded it.
        If you`re using a different assembler,a few things must be done
        differently.We covered those differences already in the chapter on
        the different assemblers.
        We`ve written the example programs as subroutines so they can be
        tried out directly and used later.After assembling the program,you
        can put the desired values in the register.Then you can either
        single-step thru the programs or run the larger programs and
        observe the results in the registers directly.(using the SEKA
        assembler you can type "j program_name"to start the program.Then
        you can read the results from the register directly,or use "q
        address"to read it from memory.)
        Lets start with an easy example,adding numbers in a table.
      4.1.Adding Tables.
      -----------------
        Imagine that you have numbers in memory that you'd like to add.
        Lets assume that you have five numbers whose length is one word
        each.You want their sum to be written in register D0.The easiest
        way to do this is:
        ;(4.1A)
        adding1:
              clr.l  D0              ;Erase D0 (=0)
              move  table,d0        ;First entry in D0
              add    table+2,d0      ;Add second entry
              add    table+4,d0      ;Add third entry
              add    table+6,d0      ;Add fourth entry
              add    table+8,d0      ;add fifth entry
              rts                    ;Return to main program
        table: dc.w 2,4,6,8,10,
              end
        Try out the program using the debugger by single stepping thru the
        program until you get to the RTS instruction(left Amiga T).(SEKA
        owners use "j adding1").You see that data register D0 really
        contains the sum of the values.
        The method above only reads and adds numbers from a particular set
        of addresses.The Amigas processor has lots of different sorts of
        addressing modes that give us a shorter and more elegant solution.
        Lets add a variable to the address of the table,so that the
        program can add different tables.
        Lets put the addresses of the table in an address register(for
        example, A0)instead.This register can be used as a pointer to the
        table.You must use move.l since only long words are relocatable.By
        using a pointer to a table you can use indirect addressing.You can
        change the expression "table+x" to"x(A0)".
        ;(4.1B)
        adding1:
              clr.l  D0            ;Erase D0 (=0)
              move.l  #table,a0    ;Put table addresses in A0
              move    0(a0),d0      ;Put first entry in d0
              add    2(a0),d0      ;Add second entry
              add    4(a0),d0      ;Add third entry
              add    6(a0),d0      ;Add forth entry
              add    8(a0),d0      ;Add fifth entry
              rts                  ;Return to main program]
        table: dc.w 2,4,6,8,10
              end
        Assemble this program,load it into the debugger.Then single step
        (left Amiga T)thru this program and you'll see that this program
        adds five numbers in order just like the last one.The reason you
        used a step size of two for the ofset is that words are two bytes
        long.AssemPro also defaults to relocate code so that you must move
        #table as a long word.
        Lets improve the program more by using "(a0)+"instead of "x(a)".
        This way,every time you access elements of the table,the address
        register A0 is automatically incremented by the number of bytes
        that are read(in this case two).The difference between this and
        the last example is that here the registers contents are modified.
        The pointer is to the next unused byte or word in memory.
        Lets make it even better.Lets make the number of words to be added
        to a variable.You'll pass the number in register D1.Now you need
        to do a different sort of programming,since you can't do it with
        the old methods.
        Lets use a loop.You need to add D1 words.You can use(a0)+ as the
        addressing method(address register indirect with post increment),
        since this automatically gets you to the next word.
        Now for the loop.You'll have D1 decremented by one every time the
        contents of the pointer are added.If D1 is zero,then you're done.
        Otherwise,you need another addition.The program looks like this:
        ;(4.1C)
        adding2:
              clr.l    d0            ;Erase D0
              move.l  #table,a0    ;Put table addresses in A0
              move    #$5,d1        ;Put number of entries in D1
             
        loop:                        ;Label for loop beginning
              add      (a0)+,d0      ;Add a word
              subq    #1,d1        ;Decrement counter
              bne      loop          ;Continue if non-zero
              rts                    ;Else done
        table: dc.w 2,4,6,8,10
              end
        Lets take a close look at this program.Load the pointer A0 with
        the addresses of the data and the counter D1 with the number of
        elements.Then you can single step thru the program and watch the
        results.Make sure not to run the final command,the RTS command,
        because otherwise a return address is popped from the stack,and
        the results of this are unpredictable.(SEKA owners can use"x pc"
        to point the program counter to "adding2".You can then step thru
        the program by using the "s"command and watch the results).
        To finish up this example,your assigning a little homework.Write
        the program so that it adds single bytes or long words.Try to
        write a program that takes the first value in a table and
        subtracts the following values.For example,the table
            table: dc.w 50,8,4,6
        should return the value 50-8-4-6, ie 32 ($20).
      4.2.Sorting a Table.
      -------------------
        Lets keep working with tables.You don't want to just read data
        from one this time.You want to change it.You'll assort the table
        in assending order.
        You need to decide how to do the sorting.The simplest method is to
        do the following.
        Compare the first and the second value.If the second value is
        larger than the first one,things are OK so far.Do the next step,
        compare the second and third values,and so on.If you come to the
        final pair and in each case the preceding value was smaller than
        the following value,then the sorting is done(it was unnescessary).
        If you find a pair where the second value is smaller than the
        first,the two values are exchanged.You then get a flag(here let's
        use a register)that is checked once you're done going thru the
        table.If it is set,the table probably isn't completely sorted.You
        then erase the flag and start again from the beginning.If the flag
        is still zero at the end,the sorting is complete.
        Now let's write a program to do this.First let's figure out the
        variables you need.You'll use registers for the variables.You need
        a pointer to the table you're sorting(A0),a counter(D0)and a flag
        (D1).While the program is running,change these values,so you'll
        need two more registers to store the starting values(address and
        the number of the table entries).You'll use A1 and D2.
        Let's start writing the program,each section will be written and
        then explained.Then the complete program will be given.You put the
        tables address in A1 and the number of entries in D2.
        ;(4.2A) part of sort routine
        sort:                      ;Start address of the program
                move.l  #table,a1  ;Load pointer with address
                move.l  a1,a0      ;Copy pointer to working register
                move.l  #5,d2      ;Number in the counter
                move.l  d2,d0      ;Copy number of elements
                subq    #2,d0      ;Correct conter value
                clr    d1          ;Erase flag
        table: dc.w 3,6,9,5
              end
        Now the preparations are complete.The pointer and the counter are
        ready and the flag is cleared.The counter is decremented by two
        because you want to use the DBRA command(take one off)and only X-1
        comparrisons are needed for X numbers(take off one more).
        Next let's write the loop that compares the values.You compare one
        word with another.It looks like this:
        loop:
              move  2(a0),d3  ;Next value in register D3
              cmp    (a0),d3    ;Compare values
        You need to use register D3 because CMP (A0),2(A0) isn't a legal
        choice.If the second value is greater than or equal to the first
        value,you can skip an exchange.
              bcc    noswap      ;Branch if greater than or equal
                                ;to
        Now you need to do the exchanging(unfortunatly you can't use EXC
        2(a0),(a0) since this form of addressing does not exist).
        doswap:
              move  (a0),d1      ;Save first valus
              move  2(a0),(a0)  ;Copy second into first word
              move  d1,2(a0)    ;Move first into second
              moveq  #1,d1        ;Set flag
        noswap:
        Now increment the counter and continue with the next pair.You do
        this until the counter is negative.
              addq.l  #2,a0      ;Pointer+2
              dbra    d0,loop    ;Continuing looping until the end
        Now you'll see if the flag is set.You start again at the beginning
        if it is.
              tst    d1        ;Test flag
              bne    sort      ;Not finished sorting yet!
              rts                ;Otherwise done.Return
        If the flag is zero,you're done and the subroutine ends.You jump
        back to the main program using the RTS command.
        Now a quick overview of the complete program.
        ;(4.2B)
        sort:                      ;Start address of the program
              move.l  #table,a1    ;Load pointer with address
              move.l  a1,a0        ;Copy pointer to working register
              move.l  #5,d2        ;Number in the counter
              move.l  d2,d0        ;Copy number of elements
              subq    #2,d0        ;Correct counter value
              clr    d1          ;Erase flag
        loop:
              move    2(a0),d3    ;Next value in register D3
              cmp    (a0),d3      ;Compare values
              bcc    noswap      ;Branch if greater than or equal to
        doswap:
              move    (a0),d1      ;Save first value
              move    2(a0),(a0)  ;Copy second into first word
              move    d1,2(a0)    ;Move first into second
              moveq  #1,d1        ;Set flag
        noswap:
              addq.l  #2,a0        ;Pointer+2
              dbra    do,loop      ;Continue looping until the end
              tst    d1          ;Test flag
              bne    sort        ;Not finished sorting yet!
              rts                  ;Otherwise done.Return
        table:
              dc.w    10,8,6,4,2  ;When finished acceding
              end
        To test this subroutine,assemble the routine with AssemPro,save it
        and then load it into the debugger.The table is directly after the
        RTS,notice its order.Set a breakpoint at the RTS,select the
        address with the mouse and press left-Amiga-B sets a breakpoint in
        AssemPro.Start the program the redisplay the screen by selecting
        "Parameter-Display-Dissassem-bled"and examine the order of the
        numbers in the table,they should now be ascending order.
        You use several registers in this example for storing values.
        Usually in machine language programming your subroutines cannot
        change any register or can only change certain registers.For this
        reason,there is a machine language command to push several
        registers onto the stack at the same time.This is the MOVEM ("MOVE
        multiple")command.If you insert this command twice in your program
        then you can have the registers return to the main program with
        the values they had when the subroutine was called.To do this,you
        need one more label.Let's call it"start";the subroutine is started
        from here.
        start:
              movem.l  d0-d7/a0-a6,-(sp)    ;save registers
             
        sort:
              etc...
              ...
              ...
              bne      sort                ;not finished sorting yet!
              movem.l  (sp)+,d0-d7/a0-a6    ;retrieve registers
              rts                          ;finished
        The powerful command moves several registers at the same time.You
        can specify which registers should be moved.If you want to move
        the D1,D2,D3,D7,A2 and A3 registers,just write
              movem.l  d1-d3/d7/a2-a3,-(sp)
        Before you quit sorting,do one little homework assignment.Modify
        the program,so that it sorts the elements in descending order.
      4.3.Converting Number Systems.
      -----------------------------
        As we mentioned in the chapter on number systems,converting
        numbers from one base to another can be rather difficult.There is
        another form of numeric representation-as a string that can be
        entered via the keyboard or output on the screen.
        You want to look at some of the many conversions possible and
        write programs to handle the task.You'll start by converting a hex
        number into a string using binary numbers and then print the value
        in hex.
      4.3.1.Converting Hex To ASCII.
      -----------------------------
        First you need to set the start and finish conditions.In this
        example,let's assume that data register D1 contains a long word
        that should be converted into a 8-digit long string of ASCII
        characters.You'll write it to a particular memory location so that
        you can output it later.
        The advantage of using hex instead of decimal is pretty clear in
        this example.To find out the hexadecimal digit for a particular
        spot in the number,you just need to take the corresponting 4 bits
        (half byte)and do some work on it.A half byte(also called a
        nibble)contains one hex digit.
        You'll work on a half byte in D2.To convert this to a printable
        character,you need to use the correct ASCII code.The codes of the
        16 characters that are used as hex digits are the following:
          0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
        $30 $31 $32 $33 $34 $35 $36 $37 $38 $39 $41 $42 $43 $44 $45 $46
        To convert the digits 0-9,you just need to add $30.For the letters
        A-F that correspond to the values 10-15,you need to add $37.The
        program to evaluate a half byte must make a destinction between
        values between 0 and 9 and those between A and F and add either
        $30 or $37.
        Now let's write a machine language subroutine that you'll call for
        each digit in the long words hex representation.
        nibble:
              and    #$0f,d2    ;just keep low byte
              add    #$30,d2    ;add $30
              cmp    #$3a,d2    ;was it a digit?
              bcs    ok          ;yes:done
              add    #7,d2      ;else add 7
        ok:
              rts                ;done
        This routine converts the nibble in D2 to an ASCII character that
        corresponds to the hex value of the nibble.To convert an entire
        byte,you need to call the routine twice.Here is a program to do
        this.The program assumes that A0 contains the address of the
        buffer that the characters are to be put in and that D1 contains
        the byte that is converted.
        ;(4.3.1a) bin-hex
        ;                            ;your program
                lea    buffer,a0  ;pointer to buffer
                move    #$4a,d1    ;byte to be converted(example)
                bsr    byte        ;and convert
                rts
        ;        ...                ;more of your program
        byte:
                move    d1,d2      ;move value into d2
                lsr    #4,d2      ;move upper nibble into lower nibble
                bsr    nibble      ;convert d2
                move.b  d2,(a0)+    ;put character into buffer
                move    d1,d2      ;value in d2
                bsr    nibble      ;convert lower nibble
                move.b  d2,(a0)+    ;and put it in buffer
                rts                ;done
        nibble:
                and    #$0f,d2    ;just keep low byte
                add    #$30,d2    ;add $30
                cmp    #$3a,d2    ;was it a digit?
                bcs    ok          ;yes:done
                add    #7,d2      ;else add 7
        ok:
                rts                ;done
        buffer:
                blk.b  9,0        ;space for long word data
                end
        To test this subroutine,use AssemPro to assemble the routine,save
        the program and load it intoi the debugger.Next set a breakpoint
        at the first RTS,to set the breakpoint in AssemPro select the
        correct address with the mouse and press the right-Amiga-B keys.
        Start the program and watch the contents of D2,it is first $34
        (ASCII 4)and finally $41(ASCII A).Select "Parameter-Display-HEX-
        Dump"and you'll see that 4A has been moved into the buffer.
        This is how the routine operates.First,you move the value that you
        wish to convert into D2.Then you shift the register four times to
        the right to move the upper nibble into the lower four bits.After
        the subroutine call,you use "move.b d2,(a0)+"to put the HI nibble
        in the buffer.Then the original byte is put in D2 again.It is
        converted.This gives us the LO nibble as an ASCII character in D2.
        You put this in the next byte of the buffer.
        The buffer is long enough to hold a long word in characters and
        closing the null byte.The null byte is usually required by screen
        output routines.Screen output will be discussed in a later
        chapter.Now let's worry about converting a long word.
        When converting a long word,you need to be sure to deal with the
        nibbles in the right order.Before calling the "nibble"routine for
        the first time,you need to move the upper nibble into the lower 4
        bits of the long word.You need to do this without losing anything.
        The LSR command isn't very good for this application.If you use it
        you'll lose bits.Its better to use the rotation commands like ROR
        or ROL,since they move the bits that are shifted out,back in on
        the other side.
        If you shift the original long word in D1 four times to the left,
        the upper four bits are shifted into the lower four bits.Now you
        can use our "nibble"routine to evaluate it and then put the
        resulting ASCII character in the buffer.You repeat this eight
        times and the whole long word has been converted.You even have D1
        looking exactly the way it did before the conversion process began
        ;(4.3.1B) bin-hex-2
        hexlong:
              lea    buffer,a0      ;pointer to the buffer
              move.l  #$12345678,d1  ;data to convert
              move    #7,d3          ;counter for the nibbles:8-1
        loop:
              rol    #4,d1          ;move upper nibble into lower
              move    d1,d2          ;write in d2
              bsr    nibble        ;and convert it
              move.b  d2,(a0)+      ;character in buffer
              dbra    d3,loop        ;repeat 8 times
              rts                    ;finished!
        nibble:
              and    #$0f,d2        ;just keep low byte
              add    #$30,d2        ;add $30
              cmp    #$3a,d2        ;was it a digit?
              bcs    ok            ;yes:done
              add    #7,d2          ;else add 7
        ok:
              rts                    ;done
        buffer:
              blk.b  9,0            ;space for long word,null byte
              end
        To test this subroutine,use AssemPro to assemble the routine,save
        the program and load it into the debugger.Next set a breakpoint at
        the first RTS,to set the breakpoint in AssemPro select the correct
        address with the mouse and press the right-Amiga-B keys.Start the
        program and when it is finished redisplay the output by selecting
        "Parameter-Display-HEX-dump"so you can examine the new buffer
        contents.
        You'll find that there's an error in the program-the buffer
        contains the digits "56785678"instead of "12345678".Try to find
        the error.
        Have you found it?This is the sort of error that causes you to
        start pulling your hair out.This sort is hard to find.The
        assembler assumes that the rotation operation should be done on a
        word,because the ".l"was left off.As a result,only the lower word
        of D1 was rotated-so you get the same value twice.If you change
        the "rol.l",things work just right.
        The error shows how easy it is to convert the program above into
        one that converts four digit hex numbers into ASCII characters.
        Just leave off the ".l"on the "rol"command and change the counter
        from seven to three.The program is done.
        Now for a little homework:change the program so that it can handle
        six digit hex numbers(D1 doesn't nescessarily have to stay the
        same...)!
        Now lets look at a different conversion problem:converting a four
        digit decimal number.
      4.3.2.Converting Decimal To ASCII.
      ---------------------------------
        It's not quite as easy to convert decimal as hex.You can't group
        the bits to form individual digits.You need to use another method.
        Lets look at how a decimal number is constructed.In a four digit
        number,the highest place is in the thousands place,the next is the
        hundreds place,etc...
        If you have the value in a register and divide by 1000,you'll get
        the value that goes in the highest place in the decimal number.
        Since the machine language command DIV not only gives us the
        result of the division but also gives us the remainder,you can
        work out the remainder quite easily.You divide the remainder by
        100 to find the hundreds place,divide the remainder by 10 and get
        the tens place,and the final remainder is the ones place.
        This isn't so hard after all!Heres the program that follows the
        steps above to fill the buffer with D1's ASCII value.
        main:
              lea    buffer,a0    ;pointer to the buffer
              move    #1234,d1    ;number to convert
              jsr    deci_4      ;test subroutine
              illegal              ;room for breakpoint
        deci_4:                    ;subroutine-four digit numbers
              divu    #1000,d1    ;divide by 1000
              bsr    digit        ;evaluate result-move remainder
              divu    #100,d1      ;divide by 100
              bsr    digit        ;evaluate result and move
              divu    #10,d1      ;divide by 10
              bsr    digit        ;evaluate result-move remainder
                                    ;evaluate the remainder directly
        digit:
              add    #$30,d1      ;convert result into ASCII
              move.b  d1,(a0)+    ;move it into buffer
              clr    d1          ;erase lower word
              swap    d1          ;move the remainder down
              rts                  ;return
        buffer:blk.b 5,0            ;reserve bytes for result
              end
        To test this subroutine,use AssemPro to assemble the routine,save
        the program and load it into the debugger.Next set a breakpoint at
        the illegal instruction.To set the breakpoint in AssemPro select
        the correct address with the mouse and press the right-Amiga-B
        keys.This breakpoint stops the program.Start the program and when
        it is finished redisplay the output by selecting"Parameter-Display
        -HEX-dump"so you can examine the ASCII values now in the buffer.
        You use a little trick in this program that is typical for machine
        language programming.After calling"digit"three times from the sub-
        routine"deci_4",you go right into the"digit"subroutine.You don't
        use a BSR or JSR command.Once the processor hits the RTS command,
        it returns to the main program,not the "deci_4"subroutine.Doing
        this,you save a fourth "bsr digit"command and an "rts"command for
        the "deci_4"routine.
        Try the program out.Make sure that you use values that are smaller
        than 9999,because otherwise strange things can happen.
        Now let's reverse what you've been doing and convert strings into
        binary numbers.
      4.3.3.Converting ASCII To Hex.
      -----------------------------
        In a string,each hex digit represents a half byte.You just need to
        write a program that exactly reverses what the hex conversion
        program did.
        You have two choices
          1.  The number of hex digits is known in advance
          2.  The number is unknown
        The first is easier to program,but has the disadvantage that if,
        you assume the strings are four digits in length and want to enter
        the value 1,you must enter 0001.That is rather awkward,so you'll
        use the second method.
        Let's convert a single digit first.You'll pass a pointer to this
        digit in address register A0.You want the binary value to come
        back in data register D0.
        The program looks like this:
              move.l  #string,a0    ;this example
              jsr    nibblein      ;test routine
              nop                  ;set breakpoint here
        nibblein:                    ;*convert the nibble from (A0)
              clr.l  d0            ;erase D0
              move.b  (a0)+,d0      ;get digit,increment A0
              sub    #'A',d0      ;subtract $41
              bcc    ischar        ;no problem:in the range A-F
              add    #7,d0        ;else correct value
        ischar:
              add    #10,d0        ;correct value
              rts
        string:dc.b 'B',0            ;character to convert
              end
        To test this subroutine,use AssemPro to assemble the routine,save
        the program and load it into the debugger.Next set a breakpoint at
        the first NOP,to set the breakpoint in AssemPro select the correct
        address with the mouse and press the right-Amiga-B keys.Start the
        program and watch the contents of D0.
        Let's see how the program works.A0 points to a memory location
        that contains the character "B"that is represented by the ASCII
        value $42.This number is loaded into D0 right after this register
        is erased.
        After subtracting $41,you end up with the value $1.Now you're
        almost done.Before returning to the main program,you add 10 to get
        the correct value 11,$B.
        If the buffer has a digit in it,the subtraction causes the
        register to become negative.The C flag is set.Let's take the digit
        5 as an example.
        The ASCII value of 5 is $35.After subtracting $41,you end up with
        -12 and the C flag is set.In this case,you won't branch with the
        BCC command.Instead you'll add 7 to get -5.Then 10 is added,and
        you end up with 5.Done!
        The routine as a disadvantage.If an illegal character is given,one
        that doesn't represent a hex digit,you'll get some nonsense result
        Let's ignore error checking for the moment though.
        Let's go on to multi-digit hex numbers.The first digit that you
        convert has the highest value and thus represents the highest
        nibble.To allow for this and to allow for an arbitrarily long
        number(actually not arbitrarily long,the number should fit in a
        long word-so it can only be eight digits long),you'll use a trick.
        Take a look at the whole program.It handles the calculations and
        puts the result in D1.It assumes that A0 is a pointer to a string
        and that this string is ended by null byte.
        hexin:                      ;converting a hex number
              clr.l  d1            ;first erase D1
              move.l  #string,a0    ;address of the string in A0
              jsr    hexinloop    ;test subroutine
              nop                  ;set breakpoint here
        hexinloop:
              tst.b  (a0)          ;test digit
              beq    hexinok      ;zero,then done
              bsr    nibblein      ;convert digit
              lsl.l  #4,d1        ;shift result
              or.b    d0,d1        ;insert nibble
              bra    hexinloop    ;and continue
        hexinok:
              rts
        nibblein:
              clr.l  d0            ;convert the nibble from (A0)
              move.b  (a0)+,d0      ;get digit,increment A0
              sub    #'A',d0      ;subtract $41
              bcc    ischar        ;no problem:in range A-F
              add    #7,d0        ;else correct value
         
        ischar:
              add    #10,d0        ;correct value
              rts
        string:DC.B "56789ABC',00    ;eight digit string,null byte
                                    ;to be converted
              end
        To test this subroutine,use AssemPro to assemble the routine,save
        the program and load it into the debugger.Next set a breakpoint at
        the NOP,to set the breakpoint in AssemPro select the correct
        address with the mouse and press the right-Amiga-B keys.Start the
        program and watch the contents of D1,the hex value is placed in
        this register.
        The trick is to shift left four times,to shift one nibble.In this
        way,the place of the last digit is incremented by one and there is
        room for the nibble that comes back from the "nibblein"routine.The
        program uses the TST.B instruction to check for the null byte at
        the end of the string,when it encounters the null byte the program
        ends.The result is in the D1 long word already!
        To do some error checking,you need to make some changes in the
        program.You'll do this right after you come back from the"nibblin"
        routine with the value of the current character.
        If the value in D0 is bigger than $F,there is an error.You can
        detect this in several ways.You chose the simplest one-you'll use
        CMP #$10,D0 to compare D0 with $10.If it smaller,then the C flag
        is set(since CMP uses subtraction)and everything is fine.If C is
        zero,there is an error.
        You can use this trick to skip the test for a null byte,since its
        an invalid character as well.The program looks like this:
        ;(4_3_3C) hex-conv2        optional disk name
        hexin:                      ;converting a hex number
              clr.l  d1          ;first erase D1
              move.l  #string,a0  ;address of string in A0
              jsr    hexinloop    ;test subroutine
              nop                  ;set breakpoint here
        hexinloop:
              bsr    nibblein    ;convert digit
              cmp    $10,d0      ;test if good
              bcc    hexinok      ;no,then done
              lsl.l  #4,d1        ;shift result
              or.b    d0,d1        ;insert nibble
              bra    hexinloop    ;and continue
        hexinok:
              rts
        nibblein:                  ;convert the nibble from (A0)
              clr.l  d0          ;erase D0
              move.b  (a0)+,d0    ;get digit,increment A0
              sub    #'A',d0      ;subtract $41
              bcc    ischar      ;no problem:in the range A-F
              add    #7,d0        ;else correct value
        ischar:
              add    #10,d0      ;correct value
              rts
        string:DC.B "56789ABC',00  ;8 digit string ending with a
                                    ;null byte to be converted
              end
        To test this subroutine,use AssemPro to assemble the routine,save
        the program and load it into the debugger.Next set a breakpoint at
        the NOP,to set the breakpoint in AssemPro select the correct
        address with the mouse and press the right-Amiga-B keys.Start the
        program and watch the contents of D1,the hex value is placed in
        this register.
        This is the method for converting hex to binary.If you convert
        decimal to binary,the conversion is not much harder.
      4.3.4.Converting ASCII To Decimal.
      ---------------------------------
        You can use a very similar method to the one used above.Since you
        are not sure how many digits there are,you'll use a similar method
        for putting digits of a number in the next place up.You can't do
        this with shifting,but you can multiply by 10 and add the value of
        the digit.
        Heres the program for converting decimal numbers.
        decin:                      ;converting a decimal number
              clr.l  d1          ;first erase D1
              move.l  #string,a0  ;the string to convert
              jsr    decinloop    ;test subroutine
              nop                  ;breakpoint here
        decinloop:
              bsr    digitin      ;convert digit
              cmp    #10,d0      ;test,if valid
              bcc    decinok      ;no,then done
              mulu    #10,d1      ;shift result
              add    d0,d1        ;insert nibble
              bra    decinloop    ;and continue
        decinok:
              rts                  ;end of conversion
        digitin:                    ;converting the nibble from (A0)
              clr.l  d0          ;erase D0
              move.b  (a0)+,d0    ;get digit,increment A0
              sub    #'0',d0      ;subtract $30
              rts
        string:dc.b '123456'        ;ASCII decimal string to convert
              end
        To test this subroutine,use AssemPro to assemble the routine,save
        the program and load it into the debugger.Next set a breakpoint at
        the NOP,to set the breakpoint in AssemPro select the correct
        address with the mouse and press thr right-Amiga-B keys.Select
        "Parameter-Output-numbers-Decimal"so the registers are displayed
        as decimal numbers.Then start the program and watch the contents
        of D1,the decimal value is placed in this register.
        This program can ONLY convert numbers upto 655350,although the hex
        conversion routine can go higher.Thats because the MULU command
        can only multiply 16-bit words.The last multiplication that can be
        done correctly is $FFFF*10--65535*10,which gives us the value
        655350.Normally this is a large enough range,so you won't
        complicate the program further.
      CHAPTER 5.
      ---------
      5.Hardware Registers.
      --------------------
        You can get information about hardware functions without using
        library functions.You can use the hardware registers instead.These
        are memory locations at particular addresses that are neither in
        RAM nor in ROM.They are direct interfaces between the processor
        and its peripheral devices.
        Each device has a number of hardware registers that the processor
        accesses to control graphics,sound and input/output.There are lots
        of possibilities for assembly language programmers.We'll only be
        able to go into a few examples.
        The registers are generally used in byte-wise fashion.You'll find
        an example in the next chapter.
      5.1.Checking For Special Keys.
      -----------------------------
        Load AssemPro and enter the debugger,select "Parameter-Display-
        From-Address"and enter $BFEC00.Next select "Parameter-Display-Hex
        -Dump"to display the memory.(To use the SEKA assembler or a similar
        monitor program,enter "q $bfec00".)
        Yoy'll see a byte-wise listing of the addresses starting at
        $BFEC00 in which two bytes always repeat.These two bytes represent
        the status of the two hardware registers.
        The mirroring occurs because not all the address bits are used in
        decoding the address.In addressing this register,only the upper
        two bytes of the address and the low bit,bit 0,are used.The
        address of the two registers goes like this:$BFECxx,where the
        lower address byte xx doesn't contain any information in bits 1-7.
        Only bit 0 contains information about the desired register.You'll
        find this odd form of addressing with most hardware registers.
        Let's look at the information in these registers.Let's look at the
        second register,$BFEC01.Hold down the<ALT>key and select"Parameter
        -Display-HEX-Dump"to redisplay the screen.(SEKA owners must enter
        "q $bfec00"and press the<ALT>key right after pressing the<Return>
        key.)You'll see that contents of every two bytes($BFEC01,$BFEC03,
        etc...)have been changed to $37.This is the status of the special
        keys.This is also true for the other special keys.The following
        keys produce the bytes:
            Shift left      $3F
            Shift right    $3D
            Control        $39
            Alternate      $37
            Amiga left      $33
            Amiga right    $31
        You can use this register to have a machine language program check
        if one of these keys was pressed and then respond by calling or
        ending a function.A program section might look like this:
        skeys=$bfec01
              ...
              cmp.b  #$37,skeys  ;Alternate pressed?
              beq    function1    ;Yes!
              cmp.b  #$31,skeys  ;or right Amiga?
              beq    function2    ;Yes!
              ...                  ;and so on...
      5.2.Timing.
      ----------
        If you want to find out how much time elapsed between two events,
        you can use a hardware register to keep track of time quickly and
        precisely.The Amiga contains just such a timekeeper:the I/O port
        componant.The chip has a 24 bit wide counter that has a 60 Hertz
        clock.
        These 24 bits can't be read at once,for instance with a MOVE.L
        command,because the register is divided into three bytes.The low
        byte is at address $BFE801,the middle at $BFE901,and the high byte
        with bits 16-23 at $BFEA01.
        Here's an example of a way to use this register:finding out how
        long a subroutine takes to run.
        test:
              bsr    gettime    ;put current time in D7
              move.l  d7,d6      ;save it in D6
              bsr    routine    ;routine to be timed
              bsr    gettime    ;get the time again
              sub.l  d6,d7      ;elapsed time in
              ...                ;1/50 seconds in D7!
              nop                ;set break point here to stop
        routine:                  ;test routine
              move    #500,d0    ;delay counter
         
        loop:
              dbra    d0,loop    ;count down
              rts
        gettime:
              move.b  $bfea01,d7  ;hi-byte in D0
              lsl.l  #4,d7      ;shift twice by 4 bits
              lsl.l  #4,d7      ;(8 bits shifted)
              move.b  $bfe901,d7  ;get mid-byte
              lsl.l  #4,d7     
              lsl.l  #4,d7      ;shift again
              move.b  $bfe801,d7  ;get the lo-byte
              rts                ;done
       
      5.3.Reading The Mouse-Joystick.
      -------------------------------
        There are two hardware registers for the mouse and the joystick.
        They contain the state(or the position)of these input devices.Its
        interesting that the same port is used with both the mouse and the
        joystick even through they work completely different.
        The joystick as four switches that are closed during movement and
        give off a potential(-)that is related to the movement of the
        joystick/mouse.The mouses movements give off lots of quick signals
        -two for horizontal and two for vertical movements.
        The computor must keep an eye on the ports so that it can evaluate
        the signals and calculate the new mouse position.This isn't the
        work of the processor though;it already has too much to do.
        You find the status of the mouse/joystick port at address $DFF00A
        for port 1 and $DFF00C for port 2.The information in these words
        is for vertical mouse movement in the lower byte and for
        horizontal movement in the upper byte.
        AssemPro owners be careful!Don't read these addresses,because for
        some reason that causes the computor to crash.This looks
        interesting(the screen begins to dance)but you can only recover by
        pressing <RESET>and losing all your data.
        To read this register,lets write a short program:
        ;(5.3A) mouse
        test:
              jsr    run      ;test subroutine
              jmp    test      ;continue until broken
              nop              ;breakpoint here
        joy= $dff00a
       
        run:
              move    joy,d6    ;data item 1 in D6
              move    joy+2,d7  ;data item 2 in D7
              jmp    run      ;rts for SEKA and other
              end
        If you assemble the program and start breakable in the debugger
        (SEKA-"j run"),D6 and D7 contain the contents of the two registers
        Move the mouse a bit and watch the register contents.
        As you see,the value in D6 is different.If you just move the mouse
        horizontaly,only the upper bytes value is different,if just moved
        vertically only the upper byte is different.
        You are not getting the absolute position of the mouse pointer on
        the screen.You can see that easily by moving the mouse in the
        upper left corner,then reading the value by restarting the program
        and moving the mouse left again.As you can see,the registers
        contents are always relative.
        Change the program as follows:
        ;(5.3B)                  mouse difference
        test:
              jsr      run        ;test subroutine
              jmp      test      ;continue until broken
              nop                ;breakpoint here
        joy= $dff00a
        run:
              move    d7,d6      ;old position in D6
              move    joy,d7    ;new position in D7
              sub      d7,d6      ;difference in D6
              jmp      run        ;rts for SEKA and other
              end
        Start Breakable(right-Amiga-A)in the AssemPro debugger and watch
        D6,the result is zero or D7.(SEKA owners have to start the program
        two times.The result in D6 is zero.)If you move the mouse,D6
        contains the difference between the old and new positions since
        the start.You'll find the vertical and horizontal positions of the
        mouse relative to the last time you looked.In this way,you can use
        this register to find the relative mouse movement between two
        checks.
        Now to check the joysticks.Put a joystick in port 2 and change the
        address $DFF00A to $DFF00C in the program.Start Breakable in the
        AssemPro debugger and watch D6,the result is zero or D7.(SEKA
        owners have to start the program two times.The result in D6 is
        zero.)
        Move the joystick up.You'll get the value $FF00.One was subtracted
        from the upper byte.Let the joystick loose.This time you get the
        value $100-one is added.You'll get the same effect if you move the
        joystick left-after you let go,one is subtracted.
        The individual movements and their effects on the joystick program
        are:
                      UP      $FF00      HI-BYTE -1
                      DOWN    $FFFF      LO-BYTE -1
                      LEFT    $0100      HI-BYTE +1
                      RIGHT  $0001      LO-BYTE +1
        These values aren't terribly reliable.If you move the joystick a
        lot and then look at the value,you'll find a crazy value in D6.
        This is because the input driver thinks that a mouse is attached.
        Nevertheless,this is the quickest way to read a joystick.In this
        way,an external device that gives off evaluatable TTL signals can
        be connected to the port and watched by a machine language
        program.
        Now you just need to find out whether the fire button has been
        pressed,and you'll know how to get all the information you need
        from the joystick.The buttons state is in bit 7 of the byte that
        is in memory location $BFE001.If the bit is set,the button was'nt
        pressed.That's true for the joystick connected to port 2.Bit 6 of
        this byte contains the buttons state when the joystick is in port
        1 or the state of the left mouse button.
        Let's stay on port 2.You can test bit 7 to execute a function when
        the joystick button is pressed without any problems.Bit 7 is the
        sign bit.You can use this program segment:
            tst.b  $bfe001    ;was fire button 2 hit?
            bpl    fire        ;yes!branch
        The TST.B instruction tests the addressed byte and sets the Z and
        the N flag.If the N flag is set,you know that bit 7 of the tested
        byte is set.Since the fire button turns on LO potential,the bit is
        erased when the button is pressed.The N flag works that way with
        the TST command as well.The BPL command in the program above
        branches if the button was pressed.The PL stands for plus and is
        set when the sign bit is cleared.
        Here is the complete program to check the fire button and joystick
        difference:
        ;(5.3C) fire button and joy difference
        test:
              jsr    run        ;test subroutine
              tst.b  $bfe001    ;was fire button 2 hit?
              bpl    fire      ;yes! branch
              jmp    test      ;continue until broken
        joy = $dff00a
        run:
              move    d7,d6      ;old position in D6
              move    joy,d7    ;new position in D7
              sub    d7,d6      ;difference in D6
              jmp    run        ;rts for SEKA and other
        fire:
              nop                ;breakpoint here
              end
      5.4.Tone Production.
      -------------------
        It's fun to make noises and sounds.The Amiga lets you use Audio
        Devices and various I\O structures to play tones,noises and/or
        music pieces in the background.You'll leave this method to C or
        Basic programmers,since you can use short machine language
        programs to directly program the audio hardware.
        The Paula chip has all the capabilities needed for tone production
        This chip can be accessed using the hardware registers of the
        processor.No library of any high level language can do more than
        you can-program the chip.
        How does it work?Since the disk uses Direct Memory Access(DMA)to
        get information,you just need to tell it where to look for the
        tone or tone sequences that you would like played.You also need to
        tell it how to interpret the data.
        Lets start with the easiest case-producing a constant tone.A tone
        like this consists of a single oscillation that is repeated over
        and over.If you make a diagram of the oscillation,you see the wave
        form of the oscillation.There are several standard waves: sine,
        square,triangle and saw tooth.The simplest is the square wave.
        To produce a square wave,you just need to turn the loud speaker on
        and off.The frequency that occurs here is the frequency of the
        tone.
        You want to produce such a tone using the Amiga.First you need to
        make a table that contains the amplitude of the tone you wish to
        produce.For a square wave,you only need two entries in the table,a
        large and a small value.Since the sound chip in the Amiga has
        amplitude values between -128 and +127,our table looks like this:
        soundtab:
              dc.b -100,100
        You need to give the address of the table to the sound chip.You
        have four choices,since the Amiga as four sound channels.The
        address of the hardware register in which the table address for
        channel 0 must be written is $DFF0A0;for channel 1 it is $DFF0B0;
        for channel 2 its $DFF0C0;for channel 3 its $DFF0D0.For stereo
        output,channels 0 and 3 control the left loud speaker.Channels 1
        and 2 control the right loud speaker.For example,choose channel 0
        and write the following:
              move.l  #soundtab,$DFF0A0  ;address of the table
        Next you need to tell the sound chip how many items there are in
        the table.The data is read from beginning to end and sent to the
        loud speaker.Once it reaches the end,it starts over at the
        beginning.Since the sound chip gets this one word at a time,even
        though the data is in bytes,the table must always have an even
        number of bytes.The length that you give it is the number of words
        the number of bytes/2.
        You put the length for channel 0 in the register at address
        $DFF0A4(for channel x just add x*$10!):
              move  #1,$dff0a4  ;length of table in words
        Now you have to tell it how quickly to read the data and output it
        to the loud speaker.This word determines the frequency.However,it
        does this "backwards".The larger the value,the lower the frequency
        Choose the value 600 for this example:
              move  #600,$dff0a6  ;read in rate
        Now you need to decide the loudness level for the tone or noise.
        You have 65 different levels to choose from.Lets choose the middle
        value 40 for our example:
              move  #40,$dff0a8    ;loudness level
        Thats the data that the sound chip needs to produce the tone.
        However nothing happens yet.What next?The chip can't tell if the
        data thats in the registers is valid,so it doesn't know if it
        should use the data.
        You need to work with the DMA control register at address $DFF096
        to let it know.You only need six bits of this word for your
        purposes:
        Bit 15 ($8000)  If this bit is set,every bit that is written to
                        this internal register is set.Otherwise the bits
                        are erased.Zero bits aren't affected.This is very
                        useful because this word also contains DMA
                        information for disk operations that should'nt be
                        changed.
        Bit 9 ($200)    This bit makes it posible for the chip to access
                        DMA memory.If you want to start playing the tone,
                        you need to set this bit.
        Bit 0-3        Turn channel 0-3 on when bits are set.
        You'll start your tone by setting bits 15,9 and 0:
              move  #$8000+$200+1,$dff096  ;start DMA
        Heres an example of tone production-this time with tone using a
        sine wave:
        ;**Sound Generation using hardware registers** (5.5A)
        ctlw = $dff096              ;DMA control
        cothi = $dff0a0            ;table address HI
        c0tlo = $c0thi+2            ;table address LO
        c0tl = $c0thi+4            ;table length
        c0per = $c0thi+6            ;read in rate
        c0vol = $c0thi+8            ;loudness level
       
        run:                        ;*Produce a simple tone
            move.l  #table,c0thi  ;table beginning
            move    #8,c0tl        ;table length--8 words
            move    #400,c0per    ;read in rate
            move    #40,c0vol      ;loudness level (volume)
            move    #$8201,ctlw    ;DMA/Start sound
            rts
        data                        ;>500K place in CHIP memory
        table:                      ;sound table:sine
        dc.b -40,-70,-40,0,40,70,40,0
            end
        To test this subroutine,use AssemPro to assemble the routine,save
        the program and load it into the debugger.Next set a breakpoint at
        the RTS,to set the breakpoint in AssemPro select the correct
        address with the mouse and press the right-Amiga-B keys.Start the
        program and listen to the tone.You need another routine to turn
        the tone off,turn your sound down for now.
        To turn the tone off,you just need to erase bit 0 of the DMA
        control register.To do this,you just need to write a 0 in bit 15
        and all the set bits in this register are erased.To erase bit 0,
        just write a one to the memory location:bit 15=0=> bit 0 is erased
        Heres a small routine to stop the tone coming from channel 0:
        still:                  ;*turn off tone
              move    #1,ctlw  ;turn off channel 1
              rts
        Now lets use the routine in a program to produce a short peep tone
        that you culd,for instance,use as a key click:
        ;** Producing a Peep Tone **
        ctlw = $dff096                ;DMA control
        c0thi = $dff0a0              ;HI table address
        c0tlo = $c0thi+2              ;LO table address
        c0tl = $c0thi+4              ;table length
        c0per = $c0thi+6              ;read in rate
        c0vol = $c0thi+8              ;volume
        beep:                        ;*Produce a short peep tone
              move.l  #table,c0thi  ;table beginning
              move    #8,c0tl        ;table length
              move    #400,c0per    ;read in rate
              move    #65,c0vol      ;volume
              move    #$8201,ctlw    ;Start DMA (sound)
              move.l  #20000,d0      ;delay counter
        loop:
              dbra    d0,loop        ;count down
       
        still:
              move    #1,ctlw        ;turn off tone
              rts
        table:
              dc.b 40,70,90,100,90,70,40,0,-4,0
              end
        You can play upto four tones at the same time in such a way that
        they are independant of each other.The Amiga also offers another
        method of making the sound more interesting:you can modulate the
        tone.
        Lets produce a siren tone.You could do this by figuring out the
        entire sequence and programming it.However,as you can well imagine
        thats a lot of work.
        Its much easier to use two tone channels.Lets use channel 1 for
        the bass tone and channel 0 for its modulation.Channel 0 needs to
        hold the envelope of the siren tone.It needs to give the expanding
        and contracting of the tone at the right speed.
        You then have two ways that you can have channel zero work with
        channel one.You can control the volume via channel 0,the read in
        rate(frequency),or both.For our example,you'll use frequency
        modulation.
        Change the program as follows:
        ;** Modulated sound generation via hardware registers **
        ctlw = $dff096                  ;DMA control
        adcon = $dff09e                  ;Audio/Disk control
        c0thi = $dff0a0                  ;HI table address
        c0tlo = c0thi+2                  ;LO table address
        c0tl = c0thi+4                  ;table length
        c0per = c0thi+6                  ;read in rate
        c0vol = c0thi+8                  ;volume
        run:
                move.l  #table,c0thi+16  ;table start for channel 1
                move    #8,c0tl+16      ;table length--8 words
                move    #300,c0per+16    ;read in rate
                move    #40,c0vol+16    ;volume
                move.l  #table2,c0thi    ;table start for channel 0
                move    #8,c0tl          ;table length
                move    #60000,c0per    ;read in rate
                move    #30,c0vol        ;volume
                move    #$8010,adcon    ;modulation mode:FM
                move    #$8203,ctlw      ;start DMA
                rts
        still:                          ;*Turn Off Tone
                move    #$10,adcon      ;no more modulations
                move    #3,ctlw          ;turn off channels
                rts
        table:                          ;data for basic tone
        dc.b -40,-70,-90,-100,-90,-70,-40,0
        dc.b 40,70,90,100,90,70,40,0
        table2:                          ;data for modulation
        dc.w 400,430,470,500,530,500,470,430
                end
        When you start the program,you'll here a siren.You can change this
        tone to your hearts content.
        Did you notice the added "adcon"register.This register controls
        the modulation of the audio channel as well as handling disk
        functions.The same technique is used here as for the DMA control
        register,bits can only be set if bit 15 is.As a result,you don't
        have to worry about the disk bits.I'd recommend against
        experimentation.
        Control bit 15 isn't the only one of interest to you.You can also
        use bits 0-7,because they determine which audio channel modulates
        another channel.There is a restriction,though.A channel can only
        modulate the next higher numbered channel.For this reason you use
        channel 1 for the basic tone and channel 0 for the modulation in
        the example.You can't for example,modulate channel three with
        channel zero.Channel 3 can't be used to modulate any other
        channel.
        Here is an overview of bits 0-7 of the "adcon"register.
        Bit      Function
        -----------------------------------------------------------------
        0        Channel 0 modulates the volume of channel 1
        1        Channel 1 modulates the volume of channel 2
        2        Channel 2 modulates the volume of channel 3
        3        Turn of channel 3
        4        Channel 0 modulates the frequency of channel 1
        5        Channel 1 modulates the frequency of channel 2
        6        Channel 2 modulates the frequency of channel 3
        7        Turn off channel 3
        In the example,you set bit 4,which put channel 0 in charge of
        channel one's frequency modulations.
        When you've chosen a channel for use in modulating another channel
        some of the parameters of the channel change.You don't need to
        give volume for this channel,so you can omit it.Now the tables
        data is looked at as words instead of as bytes.These words are
        read into the register of the modulated register at a
        predetermined rate.The Read in Rate Register determines the rate.
        If you want to modulate the frequency and the volume of another
        channel,(In the example,set bits 0 and 4 of "adcon"),the data is
        interpreted a little differently.The first word in the table is
        the volume,the second is the read in rate,and so on.It alternates
        back and forth.In this way,you can for instance,produce the siren
        tone.
      5.5.Hardware Registers Overview.
      -------------------------------
        The following tables should give you an overview of the most
        important hardware registers.Theres not enough room to describe
        each register,so I'd recommend getting a hold of the appropriate
        literature.If you experiment with these registers,you should keep
        in mind that this can cause the computor to crash.Save your data
        to disk and then take the disk out of the drive,because you might
        cause the disk drive to execute some wierd functions.
        Lets start with the PIA's.This covers the PIA type 8520.You should
        keep in mind that some functions and connection of the 8520 are
        integrated into the Amiga and so there are limitations on what you
        can do with the PIA's.
        PIA A      PIA B      Registers Meaning
        ------------------------------------------------------------------
        BFE001      BFE000      Data register A
        BFE101      BFE100      Data register B
        BFE201      BFE200      Data direction register A
        BFE301      BFE300      Data direction register B
        BFE401      BFE400      Timer A LO
        BFE501      BFE500      Timer A HI
        BFE601      BFE600      Timer B LO
        BFE701      BFE700      Timer B HI
        BFE801      BFE800      Event register Bits 0-7
        BFE901      BFE900      Event register Bits 8-15
        BFEA01      BFEA00      Event register Bits 16-23
        BFEB01      BFEB00      Unused
        BFEC01      BFEC00      Serial data register
        BFED01      BFED00      Interrupt control register
        BFEE01      BFEE00      Control register A
        BFEF01      BFEF00      Control register B
        Some internal meanings:
        $BFE101    Data register for parallel interface
        $BFE301    Data direction register for the parallel interface
        $BFEC01    State of the keyboard,contains the last special key
                  pressed(Shift,Alternate,Control,Amiga)
        Now come the registers that are used for tone production.The first
        two registers should be treated especially carefully-if they are
        used wrong,very nasty effects can occur.
        These registers can be either read or written only.This
        information is included under R/W in the table.
        Address      R/W    Meaning
        ------------------------------------------------------------------
        DFF096        W    Write DMA Control
        DFF002        R    Read DMA Control and Blitter Status
        --Audio Channel 0--
        DFF0AA        W    Data register
        DFF0A0        W    Pointer to table beginning Bits 16-18
        DFF0A2        W    Pointer to table beginning Bits 0-15
        DFF0A4        W    Table length
        DFF0A6        W    Read in Rate
        DFF0A8        W    Volume
        --Audio Channel 1--
        DFF0BA        W    Data register
        DFF0B0        W    Pointer to table beginning Bits 16-18
        DFF0B2        W    Pointer to table beginning Bits 0-15
        DFF0B4        W    Table length
        DFF0B6        W    Read in Rate
        DFF0B8        W    Volume
        --Audio Channel 3--
        DFF0CA        W    Data register
        DFF0C0        W    Pointer to table beginning Bits 16-18
        DFF0C2        W    Pointer to table beginning Bits 0-15
        DFF0C4        W    Table length
        DFF0C6        W    Read in Rate
        DFF0C8        W    Volume
        --Audio Channel 4--
        DFF0DA        W    Data register
        DFF0D0        W    Pointer to table beginning Bits 16-18
        DFF0D2        W    Pointer to table beginning Bits 0-15
        DFF0D4        W    Table length
        DFF0D6        W    Read in Rate
        DFF0D8        W    Volume
        Now for the registers that contain information about the joystick,
        mouse or potentiometer.These addresses have been gone over in part
        previously.
        Address      R/W    Meaning
        ------------------------------------------------------------------
        DFF00A        R    Joystick/Mouse Port 1
        DFF00C        R    Joystick/Mouse Port 2
        DFF012        R    Potentiometer pair 1 Counter
        DFF014        R    Potentiometer pair 2 Counter
        DFF018        R    Potentiometer connection
        DFF034        W    Potentiometer port direction
       
      Chapter 6
      ---------
      6.The Operating System.
      -----------------------
        Now lets take a step forward in your ability to write assembly
        language programs.Its not enough to put a piece of text in memory
        someplace.You want to be able to put it on the screen.Do you know
        how to write a character on the screen?Do you know how to draw a
        window on the screen that can be modified by the mouse?Actually
        you don't have to have terribly precise knowledge about such
        topics.
        Fortunately,the Amigas operating system supplies routines that
        take care of common tasks like this.It can seem quite complicated
        due to the number of routines necessary.These routines are in
        libraries.We'll look at the libraries in some depth now.
      6.1.Load Libraries.
      -------------------
        Before you can use a library,it must be available.It has to be
        loaded into memory.Unfortunately,the whole library must be loaded,
        even if you only need one of the functions.
        First you need to decide what the program must be able to do,so
        you can see which libraries you'll need.For simple I/O text,you
        don't need a library that contains routines for moving graphics!
        There are a number of libraries onj a normal Workbench disk.Heres
        an overview of the names and the sort of functions they do:
 
      Exec.Library;
        This library is needed to load the other libraries.It is already
        in memory and doesn't need to be loaded.Its in charge of basic
        functions like reserving memory and working with I/O channels.
 
      Dos.Library;
        Contains all the functions for normal I/O operations,for instance
        screen or disk access.
 
 
      Intuition.Library;
        Used for working with screens,windows,menus,etc...
 
      Clist.Library;
        This contains routines for working with the Copper lists that are
        used for controlling the screen.
   
      Console.Library;
        Contains graphics routines for text output in console windows.
 
      Diskfont.Library;
        Used for working with the character fonts that are stored on the
        disk.
   
      Graphics.Library;
        This library contains functions to control the Blitter(or graphics
        )chip.Its used for basic graphics functions.
      Icon.Library;
        Used in the development and use of workbench symbols(icons).
      Layers.Library;
        Used for working with screen memory (layers).
      Mathffp.Library;
        Contains basic math floating point operations.
      Mathieeedoubbas.Library;
        Contains basic math functions for integers.
      Mathtrans.Library;
        Contains higher level mathmatical functions.
      Potgo.Library;
        Used for evaluating analog input to the Amiga.
      Timer.Library;
        Contains routines for time critical programs.They can be used to
        program exact time intervals.
      Translator.Library;
        Contains the single function "Translate",that translates normal
        text written phonetically for the narrator,the speech synthesisor.
        You can open(load)all these libraries of course.You should
        remember that this takes time and memory.For this reason,you
        should always think about which functions you need and which
        libraries they are in.
        For example,lets say you want to write a program that does text
        input/output.You need the "Dos.Library",so it can be loaded.
        The "exec.library"is in charge of loading.This library contains
        the OpenLib function that can be called once you've passed the
        needed parameters.AssemPro Amiga includes all the libraries
        necessary for the Amiga,it also includes files that contain the
        offsets for the operating system calls.The macros contained in
        AssemPro ease assembly language programming considerably.To make
        the programs in this book useful to the largest audience the
        following examples are written for generic assemblers and do not
        include AssemPro's macros.We have used the AssemPro ILABEL and the
        macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can start the
        programs from the desktop.(If you are using a different assembler
        check your documentation for instructions on linking programs).
      6.2.Calling Functions.
      ----------------------
        Since this chapter is rather complex we'll first describe the
        fundamental routines necessary to use the Amiga's operating system
        after a description a complete program is listed.Every library
        begins in memory with a number of JMP commands.These JMPs branch
        to the routines that are in the library.To call a function,you
        need to find the beginning of this JMP table and call function x
        by going to the xth JMP command.Usually you use an offset to get
        to the right JMP command.Normally,you don't start at the beginning
        but at the end of the JMP table,so use negative offsets.
        It works out very easily.Now lets open the "dos.library"by using
        "exec.library's"base address.This address is $000004.To call a
        fuction from another library,you need to use another base address.
        Now you need the offset for the function that you want.You want
        the OpenLib function that has -408 as an offset.You'll find a list
        of function offsets in the appendix.
        You need a pointer to the name of the library you are loading for
        the OpenLib function(in this case "dos.library")and a long word in
        memory that you can use to store the base address of the DOS
        library.You get this back from the OpenLib function.You need to be
        sure to write the library name in lower case letters(dos.library),
        otherwise you can't open it.I entered a name in capitol letters
        once and spent a lot of time finding this error.
        The routine looks like this:
        ;** Load the DOS library 'dos.library' (6.2A) **
        Execbase = 4                    ;base address of the EXEC library
        OpenLib  = -408                ;offset for the OpenLib function
        IoErr    = -132                ;offset for IoErr information
        init:
              move.l  Execbase,a6      ;base address in A6
              lea    dosname,a1      ;address of library name
              moveq  #0,d0            ;version number
              jsr    OpenLib(a6)      ;open DOS library
              move.l  d0,dosbase      ;save DOS base address
              beq    error            ;if zero,then error!
              ...                      ;your program goes here
              ...                      ;more program...
        error:                          ;error
              move.l  dosbase,a6      ;address of library name
              jsr    IoErr(a6)        ;call IoErr for error info
              move.l  d0,d5           
              ...                      ;your error routine goes here
              rts
        dosname:                        ;name of library to open
              dc.b    'dos.library',0,0
              align                    ;SEKA uses-even
        dosbase:                        ;storage for DOS base address
              blk.l  1
              end
        This is the way to load the DOS library so that you can use it.All
        library functions are called this way.Parameters are put in
        registers and passed to the function.When there is an error,when
        the function doesn't run correctly,a zero is usually put in data
        register D0.
        Once your program is done with its work,you need to close the
        libraries that are still open before you return to the CLI or
        Workbench.The CloseLib function (offset -414)takes care of this
        job.This function is in the EXEC library just like the OpenLib.The
        only parameter it needs is the base address of the library that is
        closed.To close "dos.library",do the following:
        CloseLib = -414              ; (6.2B)
              ...
              move.l  Execbase,a6    ;EXEC base address
              move.l  dosbase,a1    ;DOS base address
              jsr    CloseLib(a6)  ;close library
      6.3.Program Initialization.
      ---------------------------
        Before you can start a program,you need to initialize many things
        so that the program can run.
        Lets take an example program that does some text editing.A program
        like this must be able to store text,so it needs to be able to
        access memory.It also needs to be able to accept keyboard input
        and do screen output,so it needs an output window.
        To do this,you need to open one or more of the libraries that we
        talked about earlier.Lets assume that you've loaded the DOS
        library,so that you can do the next steps.
      6.3.1.Reserve Memory.
      ---------------------
        There are several ways to get the operating system to assign you a
        chunk of memory.You need to use one of them,so that during multi-
        tasking,you don't have one program overwriting another programs
        memory area.
        Lets look at the function that is normally used.This function is
        in the resident EXEC library and has the name AllocMem (offset
        -$c6).It reserves a memory area,using the value in D0 as the
        length.The address that the memory area begins at is returned in
        the D0 data register.If it returns zero,the program could'nt give
        you that much memory.
        You can also use a mode word in D1 to determine whether the memory
        area that is reserved should be erased or not.
        The routine looks like this:
        ExecBase = 4                  ; (6.3.1A)
        AllocMem = -$c6
              ...
              move.l  #number,d0    ;number of bytes to reserve
              move    #mode,a6      ;mode word
              move.l  ExecBase,a6    ;DOS base address in A6
              jsr    AllocMem(a6)  ;call function
              move.l  d0,address    ;save memory's start address
              beq    error          ;memory not reserved
              ...
        The second way to reserve memory is to use the AllocAbs function
        (offset -$CC).This function in contrast to the AllocMem function
        reserves a particular memory area.The D0 register contains the
        number of bytes that should be reserved.Address register A1
        contains the desired start address.This function returns a zero in
        D0 if the memory area can't be reserved.
        ExecBase = 4                  ; (6.3.1B)
        AllocAbs = -$cc
              ...
              move.l  #number,d0    ;number of bytes to reserve
              lea    address,a1    ;desired start address
              move.l  execbase,a6    ;EXEC base address
              jsr    AllocAbs(a6)  ;reserve memory
              tst.l  d0            ;everything ok?
              beq    error          ;no!
              ...
        When the program has done its work and must return to the CLI or
        the Workbench,it needs to return the memory it as reserved to the
        system.The FreeMem function (offset -$D2) handles this.
        The function works like AllocAbs in that the number of bytes is
        put in D0 and the start address of the memory area is put in A1.
        If you try to free up a memory area that was'nt reserved,you'll
        usually crash the computor.
        The routine to free up a memory area looks like this:
        ExexBase = 4                  ; (6.3.1C)
        FreeMem = -$d2
              ...
              move.l  #number,d0    ;number of bytes released
              lea    address,a1    ;start address from AllocAbs
              move.l  ExecBase,a6    ;ExecBase address
              jsr    FreeMem(a6)    ;free up memory
              tst.l  d0            ;everything ok?
              beq    error          ;no!
              ...
      6.3.2.Opening a Simple Window.
      ------------------------------
        The title of this chapter may sound a bit strange.However,the
        differences between the two different methods of opening a window
        are so great that they should be handled in seperate chapters.
        The method of opening a window presented here is very simple,but
        it doesn't allow you to work with all the gadgets.These gadgets
        include the close symbol in the upper left corner of a window and
        the size symbol in the lower left corner.
        If you open the window in the simple manner,almost all the gadgets
        are present.However,the close symbol is not.As a result,this
        method isn't appropriate for every application.Now lets look at
        the method.
        To open a window,use a function from the DOS library,so you need
        to open the library first (see the section "Load Library").This
        open function is an all purpose function that can be used for many
        things.For this reason,it makes good sense to put a "open"
        subroutine in your program.You can use it a lot.Lets do the basic
        steps:
        ;** Load the DOS Library 'dos.library'  (6.3.2A) **
        ExecBase = 4                  ;base addres of the EXEC library
        OpenLib = -408                ;offset of OpenLib function
        Open = -30                    ;Offset of the DOS function OPEN
        init:
              move.l  ExecBase,a6    ;base address in A6
              lea    dosname(pc),a1  ;address of library name
              move.q  #0,d0          ;version number:unimportant
              jsr    OpenLib(a6)    ;call the function
              move.l  d0,dosbase      ;save DOS base address
              beq    error          ;if zero,then error!
              ...                    ;more of your program
              ...                    ;now open window,etc...
        error:
              ...                    ;error occured
              ...                    ;your error routine
        openfile:                      ;general open function
              move.l  dosbase,a6      ;DOS base address in A6
              jsr    Open(a6)        ;call OPEN function
              tst.l  d0              ;test if ok
              rts                    ;done,evaluate test later
        dosname:                      ;name of library to be opened
              dc.b    'dos.library',0,0
              align                  ;even
        dosbase:                      ;spot for DOS base address
              blk.l  1
        You call the Openfile routine,because the label "Open"is already
        being used for the offset.This routine calls the Open function
        that is in the DOS library.
        This isn't everything.The function must be given some parameters
        so that it knows what to open.The parameters are sent in registers
        D1 and D2.D1 points to a definition block what specifies what
        should be opened.You need to have a filename ended with a null
        byte there.D1 must be passed as a long word like all addresses.D2
        contains the mode that the function should run in.There is an old
        (1005) and a new (1006) mode.This number must be passed in D2's
        long word.
        Heres an overview of how windows are opened.Fortunately,AmigaDos
        allows you to use input and output channels in the same way.The
        standard channels are disk files,the console (keyboard and screen)
        the printer interface and the serial RS232 interface.
        The console input/output is what you'll work with now.When you
        specify the console as the filename of the channel to be opened,a
        window is opened automatically.
        The name must begin with CON:to do this.Its similar to DF0:for
        disk operations.A little more infotmation about the window is
        still needed.
        You need to specify the X and Y coordinates of the upper left and
        lower right corners of the window as well as the name that should
        appear in the title line of the window.A complete definition block
        for a window like this would appear like the following line:
              consolname: dc.b 'CON:0/100/640/100/**Window**',0
        To open this window,the line above needs to be inserted in the
        following program:
        mode_old = 1005
        lea    consolname(pc),a1    ;consol definition
        move.l  #mode_old,d0        ;mode
        bsr    openfile            ;console open
        beq    error                ;didn't work
        move.l  d0,conhandle
        rts
                ...
        conhandle:  dc.l 1          ;space for handle
        There are two points to clear up yet.
        You should use mode_old as the the mode when you open a window.
        Logically the window doesn't exist before opening so this seems
        wierd but it doesn't hurt anything.
        The parameter that returns from "openfile"in D0 is zero in the
        case of an error,in the case that opening didn't work.Otherwise
        the value is the identification number (handle number) of the
        opened channel.You need to store it away,because every function
        that wants to use this channel must give the handle number.In the
        example,you stored this number in the "conhandle"long word.
        As mentioned,the window you've opened doesn't have a close symbol
        but it can be made bigger and smaller and moved forward and back.
        The manipulations that are carried out using the mouse are
        completely taken care of by the Amiga (in contrast to the ATARI ST
        where the programmer has to take care of these things).
        An important function that uses the handle number is the one that
        closes the channel (in your case the window).This function is also
        in the DOS library and is called "Close".Its offset is -36 and it
        only needs one parameter;the handle number of the channel that is
        closed must be in the D1 register.
        After your work is done,you need to put the following lines in
        your program to close the window:
        Close = -36                    ; (6.3.2C)
                ...
                move.l  conhandle,d1  ;handle number in D1
                move.l  dosbase,a6    ;DOS base address in A6
                jsr    Close(a6)      ;close channel!
        The window disappears!
        Now for a few remarks about opening and closing the window in this
        way.If you open several windows in the same way,you'll get several
        windows and thus several handle numbers.In this way,you can put as
        many windows on the screen as you like.You can do your work with
        them and close them individually.
        Here is the complete program to open and close a simple window in
        AssemPro format (We have used the AssemPro ILABEL and the macros
        INIT_AMIGA and EXIT_AMIGA so AssemPro owners can start the program
        from desktop.If you are using a different assembler check your
        documentation for instructions on starting and exiting programs):
        ;***** 6.3.2 S.D *****
        OpenLib        =-30-378
        closelib      =-414
        ;execbase      =4                ;defined in AssemPro macros
        *calls to Amiga DOS:
        open          =-30
        close          =-30-6
        IoErr          =-132
        mode_old      = 1005
        alloc_abs      =-$cc
        ILABEL AssemPro:includes/Amiga.l  ;AssemPro only
        INIT_AMIGA                        ;AssemPro only
        run:
              bsr    init              ;initialization
              bra    test              ;system-test
        init:                            ;system initialization and open
              move.l  execbase,a6        ;number of execute-library
              lea    dosname(pc),a1   
              moveq  #0,d0
              jsr    openlib(a6)        ;open DOS-Library
              move.l  d0,dosbase
              beq    error
              lea    consolname(pc),a1  ;consol definition
              move.l  #mode_old,d0
              bsr    openfile          ;consol open
              beq    error
              move.l  d0,conhandle
              rts
        test:
              bra qu                      ;quit and exit
        error:
              move.l  dosbase,a6
              jsr    IoErr(a6)
              move.l  d0,d5
              move.l  #-1,d7              ;flag
        qu:
              move.l  conhandle,d1        ;window close
              move.l  dosbase,a6
              jsr    close(a6)
              move.l  dosbase,a1          ;DOS.Lib close
              move.l  execbase,a6
              jsr    closelib(a6)
              EXIT_AMIGA                  ;AssemPro only
        openfile:                        ;open file
              move.l  a1,d1              ;pointer to I/O-Definition-Text
              move.l  d0,d2
              move.l  dosbase,a6
              jsr    open(a6)
              tst.l  d0
              rts
        dosname: dc.b 'dos.library',0,0
              Align.w
       
        dosbase: dc.l 0
        consolname: dc.b 'CON:0/100/640/100/**CLI-Test**',0
              Align.w
        conhandle: dc.l 0
              end
        There is another way to open a window easily.Just use RAW:instead
        of CON:as the channel designator.All the other parameters and
        operations remain the same.
        If you try them both out,you won't see any differences between the
        two windows.They both look the same and can be worked with in the
        same way with the mouse.The difference comes when you input to the
        window.In the RAW:window,the cursor keys are ignored.In the CON:
        window and in CLI,they do work.
      6.4.Input/Output.
      -----------------
        Besides managing and making calculations with data,the most
        important work of a program is to input and output the data.There
        are many methods of data transfer in and out of the computor,for
        instance screen or printer output,keyboard input,using the serial
        or the parallel interface,tone or speech output and finally disk
        operations.
        You want to learn about all these methods of data input and output
        for programming and applications.We've written some programs as
        subroutines that should be useful for later programs.It makes good
        sense to make a library of these subroutines that can either be
        directly integrated in a new program or linked to a program.At the
        end of the sections there is a list of a complete program so you
        can see how the subroutines are used.
        To prepare for input/output,you need to have data to output and
        space to input data.To get this ready,you need a correct program
        beginning in which the EXEC and DOS libraries are opened and
        memory is reserved.After this,you begin most programs by outputing
        some text.The text can be a program title or the instruction to
        input data over the keyboard.Lets start looking at screen output.
      6.4.1.Screen Output.
      --------------------
        For a computor like the Amiga the first question is where should
        the screen output be sent?The answer is simple for many computors;
        they only have one screen,and output goes there.You need to
        specify which window to write to when you use the Amiga,however.
        There are two possibilites:
        1.Output to CLI
        2.Output to another window
        The first posibillity only exists if the program that makes the
        output was started from CLI.If not,you need to open your own
        custom window for your program.If so,you can use the window that
        was opened by the CLI for output.
        If you use the second method,you need to open a window.As you've
        already seen,there are three methods.For simple text and character
        output,the difference between the three sorts of windows isn't
        very great.Here you have a free hand in determining which sort of
        window to use.Lets open a CON:window and put its handle number in
        "conhandle".
        You've opened your window and want to output a title.You choose
        text to output and then put it in memory using a code segment like
        this:
              title: dc.b "** Welcome to this Program! **"
              titleend:
              align              ;even
        The "align"(even) is a pseudo-op that should follow text when it
        is followed by either word data or program lines.It causes the
        assembler to insert a null byte if necessary to make the address
        even.
        To output this text you need another DOS function:Write.This has
        an offset of -48 and needs three parameters:
        In D1  the handle of an opened output channel that should be
                written to (in your case,this is the handle number that
                you go back from the Open command when you opened your
                window.).
        In D2  the address of the text to be output (in the example,the
                address "title").
        In D3  the number of characters to be output in bytes.
        To find the number of bytes to output,you need to count the number
        of characters in your text.Use "titleend"to calculate this.Using
        this label,the assembler can calculate the length of your text for
        itself (after all,why should you count when you have a computor?)
        if you write:
            move.l  #titleend-title,d3
        The advantage of specifying the length is that you can put control
        characters between the beginning and end of the text.In this way,
        you can execute certain functions using text output.You'll learn
        about the control characters in a bit.
        Heres the routine:
        Write = -48                          ; (6.4.1A)
                ...                          ;open window
                ...
                move.l  dosbase,a6          ;DOS base address
                move.l  conhandle,d1        ;pass handle
                move.l  #title,d2            ;text address
                move.l  #titleend-title,d3  ;and length
                jsr    Write(a6)            ;call function
                ...
        title: dc.b "** Welcome to this Program! **"
       
        titleend:
       
        align                                ;event
                end
        You'll certainly use this function a lot.You'll often want to
        output just one character though.To allow you to do this and
        similar text related tasks,there are four subroutines,each of
        which do a different sort of output:
      Pmsg;
        Outputs the text from (D2) to the first null byte.
      Pline;
        Is the same as the routine above except that the text is
        automatically followed by a CR,the cursor is positioned at the
        beginning of the next line.
      Pchar;
        Outputs the character in D0
      Pcrlf;
        Puts the cursor at the beginning of the next line.
        Heres the subroutine package:
        Write = -48                  ; (6.4.1B)
                ...
        pline:                      ;*output line and then a CR
                bsr    pmsg        ;output line
        pcrlf:
                move    #10,d0      ;line feed
                bsr    pchar        ;output
                move    #13,d0      ;and CR
        pchar:
                move.b  d0,outline  ;character in output buffer
                move.l  #outline,d2  ;address of the character
               
        pmsg:                        ;*output line (D2) upto null
                move.l  d2,a0        ;address in A0
                clr    d3          ;length = 0
        ploop:
                tst.b  (a0)+        ;null byte ?
                beq    pmsg2        ;yes:length found
                addq.l  #1,d3        ;else length + 1
                bra    ploop        ;and continue looking
        pmsg2:
                move.l  dosbase,a6  ;DOS base address in A6
                move.l  conhandle,d1 ;our window handle
                jsr    Write(a6)    ;call write function
                rts                  ;done!
        outline:        dc.w 0      ;output buffer for 'pchar'
        conhandle:      dc.l 0      ;windows handle
        Here is an example program to open and close a simple window and
        output a text message in AssemPro format (We have used the
        AssemPro macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can
        start the program from desktop.If you are using a different
        assembler check your documentation for instructions on starting
        and exiting programs.):
        Here is the complete program in AssemPro format:
        ;***** 6.4.1C.asm S.D. *****
        Openlib    =-30-378
        closelib    =-414
        ;execbase  = 4                    ;Defined in AssemPro
                                          ;Macros
        * calls to Amiga Dos:
        open        =-30
        close      =-30-6
        write      =-48
        IoErr      =-132
        mode_old    = 1005
        alloc_abs  =-$cc
              ILABEL AssemPro:include/Amiga.l ;AssemPro only
              INIT_AMIGA                  ;AssemPro only
        run:
              bsr    init                ;initialization
              bsr    test                ;system test
              nop
              bra qu                      ;quit and exit
        test:
              move.l  #title,d0
              bsr    pmsg
              bsr    pcrlf
              bsr    pcrlf
              rts
        init:                              ;system initialization and
                                          ;open
              move.l  execbase,a6        ;number of execute-library
              lea    dosname(pc),a1
              moveq  #0,d0
              jsr    openlib(a6)        ;open DOS-library
              move.l  d0,dosname
              beq    error
              lea    consolname(pc),a1  ;console definition
              move.l  #mode_old,d0
              bsr    openfile            ;console open
              beq    error
              move.l  d0,conhandle
              rts
        pmsg:                              ;print message (D0)
              movem.l d0-d7/a0-a6,-(sp)
              move.l  d0,a0
              move.l  a0,d2
              clr.l  d3
        ploop:
              tst.b  (a0)+
              beq    pmsg2
              addq.l  #1,d3
              bra    ploop              ;length calculate
        pmsg2:
              move.l  conhandle,d1
              move.l  dosbase,a6
              jsr    write(a6)
              movem.l (sp)+,d0-d7/a0-a6
              rts
        pcrlf:
              move    #10,d0
              bsr    pchar
              move    #13,d0
        pchar:                            ;output char in D0
              movem.l d0-d7/a0-a6,-(sp)  ;save all
              move.l  conhandle,d1
        pch1:
              lea    outline,a1
              move.b  d0,(a1)
              move.l  a1,d2
              move.l  #1,d3              ;1 letter
              move.l  dosbase,a6
              jsr    write(a6)
              movem.l (sp)+,d0-d7/a0-a6  ;restore all
        error:
              move.l  dosbase,a6
              jsr    IoErr(a6)
              move.l  d0,d5
              move.l  #-1,d7              ;flag
        qu:
              move.l  conhandle,d1        ;window close
              move.l  dosbase,a6
              jsr    close(a6)
              move.l  dosbase,a1          ;DOS.Lib close
              move.l  execbase,a6
              jsr    closelib(a6)
              EXIT_AMIGA                  ;AssemPro only
        openfile:                          ;open file
              move.l  a1,d1              ;pointer to I/O-definition-
                                          ;text
              move.l  d0,d2
              move.l  dosbase,a6
              jsr    open(a6)
              tst.l  d0
              rts
        dosname: dc.b 'dos.library',0,0
              align.w
        dosbase: dc.l 0
        consolname: dc.b 'CON:0/100/640/100/** CLI-Test **',0
              align.w
        conhandle: dc.l 0
        title: dc.b '** Welcome to this Program! **'
        titleend:
              align
        outline: dc.w 0                    ;output buffer for char
              end
        Using this program,you can very easily put whatever you want in
        the CON:window.These functions also work in RAW:window.You should
        rename "conhandle"as "rawhandle",so that you don't get things
        mixed up later.
        Lets stay with the CON:window.As mentioned earlier,you can output
        special characters that execute functions or change parameters for
        output.These characters are called control characters.
        You've already learned about one of these control characters,Line
        Feed ($A).This character isn't just output;instead,it calls a
        function that moves the cursor into the next line and moves the
        screen up.This is very useful,but there are much more interesting
        control characters.
        Here's a list of control characters that execute functions.These
        characters are given in hex.
      Control Sequence;
        Sequence    Function
        ------------------------------------------------------------------
        08          Backspace
        0A          Line Feed,Cursor down
        0B          Move Cursor up a line
        0C          Clear screen
        0D          Carrige return,cursor in the first column
        0E          Turn on normal characters (Cancel Of Effects)
        0F          Turn on special characters
        1B          Escape
        The following sequences begin with $9B,the CSI (Control Sequence
        Introducer).The characters that follow execute a function.The
        values in square brackets can be left off.The n's you see
        represent one or more digit decimal numbers given using ASCII
        characters.The value that is used when n is left off,is given in
        the parenthesis that follow n in the description of the function
        in the table.
      Control Sequence Introducer;
        Sequence      Function
        ------------------------------------------------------------------
        9B[n]40        Insert n blanks
        9B[n]41        Move cursor n (1) lines up
        9B[n]42        Move cursor n (1) lines down
        9B[n]43        Move cursor n (1) characters to the right
        9B[n]44        Move cursor n (1) characters to the left
        9B[n]45        Move cursor down n (1) lines into column 1
        9B[n]46        Move cursor up n (1) lines and into column 1
        9B[n][3B n]48  Cursor in line;Set column
        9B 4A          Erase screen from cursor
        9B 4B          Erase line from the cursor
        9B 4C          Insert line
        9B 4D          Delete line
        9B[n]50        Delete n characters starting at cursor
        9B[n]53        Move up n lines
        9B[n]54        Move down n lines
        9B 32 30 68    Line feed => Line feed + return
        9B 32 30 6C    Line feed => just Line feed
        9B 6E          Sends the cursor position!A string of the following
                      form is returned:
                      9B (line) 3B (column) 52
        9B(style);(foreground colour);(Background Colour)6D
                      The three parameters are decimal numbers in ASCII
                      format.They mean:
                      Style:  0 = normal
                              1 = bold
                              3 = italic
                              4 = underline
                              7 = inverse
                      Foreground colour: 30-37
                      Colour 0-7 for Text
                      Background colour: 40-47
                      Colour 0-7 for background
        9B(length)74  sets the maximum number of lines to be displayed
        9B(width)75    sets the maximum line length
        9B(distance)78 defines the distance in pixels from the left border
                      of the window to the place where output should
                      begin
        9B(distance)79 defines the distance in pixels from the upper
                      border of the window to the place where output
                      should begin
                      The last four functions yield the normal values if
                      you leave off the parameters.
        9B 30 20 70    Make cursor invisible
        9B 20 70      Make cursor visible
        9B 71          Sends window construction.A string of the following
                      form is returned:
                      9B 31 3B 31 3B (lines) 3B (columns) 73
        To see how the control characters work,have "pmsg"output this text
        to your window:
        mytext: dc.b $9b,"4;31;40m"                ; (6.3.2D)
                dc.b "underline"
                dc.b $9b,"3;33;40m",$9b,"5;20H"
                dc.b "** Hello World! **",0
        The parameters for the control sequence are put in quotation marks
        so they are treated as an ASCII string.Now you see,just how easy
        it is to do text output!
        Here is the complete program to open and output the text and
        control codes to your window in AssemPro format (We have used the
        AssemPro macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can
        start the programs from desktop.If you are using a different
        assembler check your documentation for instructions on starting
        and exiting programs):
        ; ***** 6.4.1D.ASM S.D. *****
        openlib    =-30-378
        closelib  =-414
        ;execbase  = 4                    ;defined in AssemPro macros
        * calls to Amiga Dos:
        open      =-30
        close      =-30-6
        write      =-48
        IoErr      =-132
        mode_old  = 1005
        alloc_abs  =-$cc
              ILABEL AssemPro:includes/Amiga.l  ;AssemPro only
              INIT_AMIGA                  ;AssemPro only
        run:
              bsr    init                ;initialization
              bsr    test                ;system test
              nop
              bra qu                      ;quit and exit
        test:
              move.l  #mytext,d0
              bsr    pmsg
              bsr    pcrlf
              bsr    pcrlf
              rts
        init:                              ;system initialization and open
              move.l  execbase,a6        ;number of execute-library
              lea    dosname(pc),a1
              moveq  #0,d0
              jsr    openlib(a6)        ;open DOS-Library
              move.l  d0,dosbase
              beq    error
              lea    consolname(pc),a1  ;console definition
              move.l  #mode_old,d0
              bsr    openfile            ;console open
              beq    error
              move.l  d0,conhandle
              rts
        pmsg:                              ;print message (D0)
              movem.l d0-d7/a0-a6,-(sp)
              move.l  d0,a0
              move.l  a0,d2
              clr.l  d3
        ploop:
              tst.b  (a0)+
              beq    pmsg2
              addq.l  #1,d3
              bra    ploop
        pmsg2:
              move.l  conhandle,d1
              move.l  dosbase,a6
              jsr    write(a6)
              movem.l (sp)+,d0-d7/a0-a6
              rts
        pcrlf:
              move    #10,d0
              bsr    pchar
              move    #13,d0
        pchar:                            ;output char in D0
              movem.l d0-d7/a0-a6,-(sp)  ;save all
              move.l  conhandle,d1
        pch1:
              lea    outline,a1
              move.b  d0,(a1)
              move.l  a1,d2
              move.l  #1,d3              ;one letter
              move.l  dosbase,a6
              jsr    write(a6)
              movem.l (sp)+,d0-d7/a0-a6  ;restore all
              rts
        error:
              move.l  dosbase,a6
              jsr    IoErr(a6)
              move.l  d0,d5
              move.l  #-1,d7              ;flag
        qu:
              move.l  conhandle,d1        ;window close
              move.l  dosbase,a6
              jsr    close(a6)
              move.l  dosbase,a1          ;DOS.Lib close
              move.l  execbase,a6
              jsr    closelib(a6)
              EXIT_AMIGA                  ;AssemPro only
        openfile:                          ;open file
              move.l  a1,d1              ;pointer to I/O-definition-
                                          ;text
              move.l  d0,d2
              move.l  dosbase,a6
              jsr    open(a6)
              tst.l  d0
              rts
        dosname: dc.b 'dos.library',0,0
              align.w
        dosbase: dc.l 0
        consolname: dc.b 'CON:0/100/640/100/ ** CLI-Test **',0
              align.w
        conhandle: dc.l 0
        mytext:
              dc.b $9b,'4;31;40m'
              dc.b 'underline'
              dc.b $9b,'3;33;40m',$9b,'5;20H'
              dc.b '** Hello World !! **',0
              align
        outline: dc.w 0                    ;output buffer for pchar
              end
        Now that you've done text and character output,its time to move on
        to text input.
      6.4.2.Keyboard Input.
      ---------------------
        You can read keyboard input very easily.You just need to open the
        I/O channel of the CON:window and read from it.You need the read
        function from the DOS library to do this.Its offset is -42.
        The function has three parameters just like the WRITE function.
        In D1  the handle number that you get from the WRITE function.
        In D2  the address that the data read in is to start.
        In D3  the number of bytes to read.
        Here is a subroutine that reads the number of characters from the
        keyboard that it finds in D3.It puts them in a buffer.
        read    = -42                ; (6.4.2A)
              ...
        getchr:                      ;* Get (D3) characters from the
                                      ;keyboard
              move.l  #inbuff,d2    ;address of buffer in D2
              move.l  dosbase,a6    ;DOS base address in A6
              move.l  conhandle,d1  ;our window handle
              jsr    read(a6)      ;call read function
              rts                    ;done!
        inbuff:        blk.b 80,0    ;buffer for keyboard input
        This routine returns to the main program when <Return> is entered.
        If more than D3 characters are entered,"inbuff"only gets the first
        characters.The routine gets the remaining characters when called a
        second time.
        This sort of input is fairly easy.You can backspace,because only
        the characters that should be there are put in the memory block
        starting at "inbuff".The number of characters moved into "inbuff"
        is put in D0.
       
        Try the program out as follows:
        After opening the CON:window,put the following lines in the main
        program:
              move  #80,d3          ;read 80 characters (6.4.2B)
              bsr    readchr        ;get line from keyboard
              lea    inline,a0      ;address of line in A0
              clr.b  0(a0,d0)        ;null byte on the end
              bsr    pmsg            ;output line again
       
        bp:
        After this comes the code segment that closes the window again.
        After loading the program into the AssemPro debugger,make "bp"a
        breakpoint and start the program.(SEKA users start the program
        with "g run"and enter "bp"as the breakpoint).The program quits at
        the breakpoint and you can take a look at the results on the
        screen.Then you can continue the program (SEKA with "j bp") and
        let the window close.
        After starting the program and opening the window,the cursor
        appears in the upper left corner of the window.Enter some text and
        press <Return>.The string that you just entered is output again on
        the screen.
        You use the "pmsg"routine from the previous chapter to do this
        output.This routine needs a null byte at the end of the text to be
        output.You put a null byte there by putting the address of the
        input buffer in A0 and then erasing the byte at A0+D0 using the
        CLR.B command.Since D0 contains the number of characters that were
        entered,this byte is the first unused byte.
        Since you're in the debugger you can redisplay the disassembled
        output when the program ends to see what "getchr"put in "inbuff"
        (SEKA owners can use "q inbuff"when the program ends to see what
        "getchr"put there.)You'll find the characters that you typed plus
        a closing $A.The $A stands for the <Return> key and its counted
        too,so if you entered a 12 and then hit <Return>,for example,D0
        will contain a 3.
        Try this again with a RAW:window.Change the window definition from
        CON: to RAW:and reassemble the program.You'll notice the diference
        right away.After you've entered one character,a return is executed
        D0 always as one bit in it.
        The advantage of this form of input is that cursor and function
        keys can be recognized.Using your own routine,you can repeatedly
        accept input of characters using "getchr"and then work with the
        special characters.
        Theres another form of keyboard input:checking for a single key.
        This is important when a program is about to execute an important
        function and the user must say he wants it executed by entering
        "Y"for yes.This can be treated as normal input,but in some cases,
        there is a better method.
        There is a function in the DOS library that waits a certain
        specified length of time for a key to be pressed,and returns a
        zero (FALSE) if no key was hit in this time period.It returns a -1
        ($FFFFFFFF = TRUE) if one was.To find out which key it takes
        another function.The WaitForChar function,is only good for tasks
        like waiting for the user to let the program know that it can
        continue scrolling text.
        The function needs two parameters:
        In D1    the handle number of the window or file from which the
                character should be read.It can also wait for a character
                from an interface.
        In D2    you pass the length of time in microseconds that you
                should wait for a key stroke.
        To wait one second for one key to be hit,you can use the following
        routine:
        WaitForCh=-30-174                ; (6.4.2C)
              ...
        scankey:                          ;* Wait for a key stroke
              move.l  conhandle,d1      ;in our window
              move.l  #1000000,d2        ;waiting time 1 second
              move.l  dosbase,a6        ;DOS base address
              jsr    waitforch(a6)      ;wait...
              tst.l  d0                ;test result
              rts
        The TST command at the end of the program allows the calling
        routine to use a BEQ or BNE command to evaluate the results of the
        routine-BEQ branches if no key was hit.BNE doesn't.
        Heres an example program in AssemPro format covering what you have
        learned so far.Opening and closing a window,displaying text in the
        window and inputting text:
        ;***** 6.4.2A.ASM S.D *****
        openlib    =-30-378
        closelib  =-414
        ;execbase  =4                      ;defined in AssemPro
                                          ;Macros
        * call to Amiga.Dos:
        open      =-30
        close      =-30-6
        read      =-42
        write      =-48
        IoErr      =-132
        mode_old  =1005
        alloc_abs  =-$cc
              ILABEL AssemPro:include/Amiga.l  ;AssemPro only
              INIT_AMIGA                  ;AssemPro only
        run:
              bsr    init                ;initialization
              bsr    test                ;system test
              nop                       
              bra    qu                  ;quit and exit
        test:
              move.l  #mytext,d0
              bsr    pmsg
              bsr    pcrlf
              bsr    pcrlf
              move.l  #80,d3              ;80 characters to read in (D3)
              bsr    getchr              ;get character
              bsr    pmsg                ;output line
              rts
        init:                              ;system initialization and open
              move.l  execbase,a6        ;number of execute-library
              lea    dosname(pc),a1
              moveq  #0,d0
              jsr    openlib            ;open DOS-Library
              move.l  d0,dosbase
              beq    error
 
              lea    consolname(pc),a1  ;console definition
              move.l  #mode_old,d0
              bsr    openfile            ;console open
              beq    error
              move.l  d0,conhandle
              rts
        pmsg:                              ;print message (D0)
              movem.l d0-d7/a0-a6,-(sp)
              move.l  d0,a0
              move.l  a0,d2
              clr.l  d3
        ploop:
              tst.b  (a0)+
              beq    pmsg2
              addq.l  #1,d3
              bra    ploop              ;check length
        pmsg2:
              move.l  conhandle,d1
              move.l  dosbase,a6
              jsr    write(a6)
              movem.l (sp)+,d0-d7/a0-a6
              rts
        pcrlf:
              move    #10,d0
              bsr    pchar
              move    #13,d0
        pchar:                            ;character in D0 output
              movem.l d0-d7/a0-a6,-(sp)  ;save all
              move.l  conhandle,d1
        pch1:
              lea    outline,a1
              move.b  d0,(a1)
              move.l  a1,d2
              move.l  #1,d3              ;1 letter
              move.l  dosbase,a6
              jsr    write(a6)
              movem.l (sp)+,d0-d7/a0-a6  ;restore all
              rts
        getchr:                            ;get character for keyboard
              move.l  #1,d3              ;1 character
              move.l  conhandle,d1
              lea    inbuff,a1          ;buffer address
              move.l  a1,d2
              move.l  dosbase,a6
              jsr    read(a6)
              clr.l  d0
              move.b  inbuff,d0
              rts
        error:
              move.l  dosbase,a6
              jsr    IoErr(a6)
              move.l  d0,d5
              move.l  #-1,d7              ;flag
        qu:
              move.l  conhandle,d1        ;window close
              move.l  dosbase,a6
              jsr    close(a6)
              move.l  dosbase,a1          ;DOS.Lib close
              move.l  execbase,a6 jsr    ;close lib (A6)
              EXIT_AMIGA                  ;AssemPro only
        openfile:                          ;open file
              move.l  a1,d1              ;pointer to I/O-Definition-
                                          ;Text
              move.l  d0,d2             
              move.l  dosbase,a6
              jsr    open(a6)
              tst.l  d0
              rts
        dosname: dc.b 'dos.library',0,0
              align.w
        dosbase: dc.l 0
        consolname: dc.b 'CON:0/100/640/100/** CLI-TEST **',0
              align.w
        conhandle: dc.l 0
        mytext: dc.b '** Hello World !! **',0
              align
        outline: dc.w 0                    ;output buffer for pchar
   
        inbuff: blk.b 8                    ;input buffer
              end
      6.4.3.Printer Control.
      ----------------------
        Now that you've looked at console I/O,lets look at outputting data
        from the computor.The first device that we'll discuss is the
        printer.
        Its very easy to use the printer.You just need to open another
        channel.It goes just the way you learned it with CON: and RAW:
        windows;the only difference is you enter PRT:instead.
        You open this channel using the same lines that you used above for
        the window except that the pointer is to the channel name PRT:in
        D1.You pass the mode "new"(1006) in D2 in the "do_open"routine as
        well.Save the handle number that comes back at a label called
        "prthandle".
        Now you can use the same output routines that you used with the
        windows to send text to the printer.You need to put "prthandle"
        instead of "conhandle"in the line with the "move.l conhandle,d1"
        command.
        Actually it would be better to eliminate this line from the
        routine totally.Then you can use the same routine for window and
        printer output.The calling procedure would then need to put
        "conhandle"in D1 for window output.It would put "prthandle" in D1
        for printer output.This is a very flexible output routine that can
        be used for window and printer output now.You can't accept input
        from the printer,because the printer doesn't send data.It just
        accepts it and prints it.
      6.4.4.Serial I/O.
      -----------------
        Its just as easy to use the serial interface as the printer.Just
        enter SER:as the filename.Now you can use the DOS functions READ
        and WRITE just as before to do I/O channels you've just opened.
        You can set the parameters for the interface (like Hand shake and
        Transfer rate) with the Preferences program.
      6.4.5.Speech Output.
      --------------------
        The Amiga has a speech synthesizer built in.This isn't quite as
        easy to program as the I/O devices discussed earlier,however.You
        use the "narrator.device"to do this.
        This device requires several program steps to install it and then
        causes it to speak.You need to open the device,start the I/O,etc..
        Lets look at how to translate the text into the proper form and
        then output the text.
        First we need to do some initialization.Lets define the constants
        now.Some of them are new.
        ;***** Narrator Basic Functions 3/87 S.D ***** (6.4.5A)
        openlib    =-408                 
        closelib    =-414
        execbase    = 4
        open        =-30                    ;open file
        close      =-36                    ;close file
        mode_old    = 1005                  ;old mode
       
        opendevice  =-444                  ;open device
        closedev    =-450                  ;close device
        sendIo      =-462                  ;start I/O
        abortIO    =-480                  ;abort I/O
        translate  =-30                    ;translate text
        ;The initialization routine follows:
             
        init:                              ;initialize and open system
        ;* open DOS library *
              move.l  execbase,a6          ;pointer to execbase
              lea    dosname,a1          ;pointer to DOS name
              moveq  #0,d0                ;version unimportant
              jsr    openlib(a6)          ;open DOS library
              move.l  d0,dosbase          ;save handle
              beq    error                ;error handle
        ;* Open translator.library *
              lea    transname,a1        ;pointer to translator name
              clr.l  d0
              jsr    openlib(a6)          ;open translator
              move.l  d0,transbase        ;save handle
              beq    error                ;error handling
        ;* Set up I/O area for Narrator *
              lea    talkio,a1            ;pointer to I/O area in A1
              move.l  #nwrrep,14(a1)      ;enter port address
              move.l  #amaps,48+8(a1)      ;pointer to audio mask
              move    #4,48+12(a1)        ;number of the mask
              move.l  #512,36(a1)          ;length of the output area
              move    #3,28(a1)            ;command:write
              move.l  #outtext,40(a1)      ;address of output area
        ;* Open Narrator device *
              clr.l  d0                  ;number 0
              clr.l  d1                  ;no flags
              lea    nardevice,a0        ;pointer to device name
              jsr    opendevice(a6)      ;open narrator.device
              tst.l  d0                  :error?
              bne    error                ;Yes!
        ;* Open Window *
              move.l  #consolname,d1      ;console definition
              move.l  #mode_old,d2        ;old mode
              move.l  dosbase,a6          ;DOS base address
              jsr    open(a6)            ;open window
              tst.l  d0                  ;error?
              beq    error                ;Yes!
              move.l  d0,conhandle        ;else save handle
        After you've done this initialization,you can have the computor
        save the text you have prepared for it.To see what the Amiga is
        saying,use the "pmsg"function to have the text written to the
        window:
              move.l  #intext,d2          ;text for the Amiga to say
              bsr    pmsg                ;output in window also
        sayit:                              ;have the text said
        ;*Translate the text into a form that the computor can use *
              lea    intext,a0            ;address of the text
              move.l  #outtext-intext,d0  ;length of the text
              lea    outtext,a1          ;address of output area
              move.l  #512,d1              ;length of output area
              move.l  tranbase,a6          ;translator base address
              jsr    translate(a6)        ;translate text
        ;* Speech output *
              lea    talkio,a1            ;address of I/O structure
              move.l  #512,36(a1)          ;length of output area
              move.l  execbase,a6          ;EXEC base address
              jsr    sendIO(a6)          ;start I/O (speech output)
        Once the program ends,the I/O stops as well,so you need to put in
        something that keeps the program going longer.You'll use the
        "getchr"function that you programmed earlier to take care of this:
              bsr    getchr              ;wait for keyboard input
        The computor waits until the <Return> key is pressed.Now you can
        listen to what the Amiga as to say.Once the <Return> key is
        pressed,the program stops.
        qu:                                ; (6.4.5C)
              move.l  execbase,a6          ;EXEC base address
              lea    talkio,a1            ;pointer to I/O area
              jsr    abortio(a6)          ;stop the I/O
              move.l  conhandle,d1       
              move.l  dosbase,a6
              jsr    close(a6)            ;close window
             
              move.l  dosbase,d1
              move.l  execbase,a6
              jsr    closelib(a6)        ;close DOS library
              lea    talkio,a1
              jsr    closedev(a6)        ;close narrator.device
              move.l  tranbase,a1             
              jsr    closelib(a6)        ;close translator library
              rts                          ;* end of program
        Now comes the data that you need for the program above:
        mytext:      dc.b  'This is a test text !',10,13,10,13,0,0
        dosmame:    dc.b  'dos.library',0,0
        transname:  dc.b  "translator.library",0
        consolname:  dc.b  'RAW:0/100/640/100/** Test window',0
        nardevice    dc.b  'narrator.device',0
          align
        dosbase:    dc.l  0
        tranbase    dc.l  0
        amaps:      dc.b  3,5,10,12
          align
        conhandle:  dc.l  0
        talkio:      blk.l 20,0
        nwrrep:      blk.l 8,0
        intext:      dc.b  'hello,i am the amiga talking to you',0
          align
        outtext:    blk.b 512,0
        This is quite a bit of work,but its worth it because it opens so
        many possibilities for you.There are a lot of variations possible
        if you modify parameters.These parameters are entries in the I/O
        area starting at the "talkio"label.The area is built as follows:
        Offset        Length      Meaning
        ----------------------------------------------------------------
        ** Port Data **
          0            L          Pointer to next block
          4            L          Pointer to last block
          8            B          I/O type
          9            B          Priority
          10            L          Pointer to I/O name
          14            L          Pointer to port
          18            W          Length
        ** I/O Data **
          20            L          Pointer to device
          24            L          Pointer to device unit
          28            W          Command word
          30            B          I/O flags
          31            B          I/O status
          32            L          I/O pointer
          36            L          I/O length
          40            L          Pointer to Data
          44            L          I/O offset
        ** Narrator data items **
          48            W          Speech speed
          50            W          Highness of voice
          52            W          Speech mode
          54            W          Sex (male/female voice)
          56            L          Pointer to audio mask
          60            W          Number of mask
          62            W          Volume
          64            W          Read in rate
          66            B          Flag for producing graphics (0=off)
          67            B          Actual mask (internal use)
          68            B          Channel used (internal use)
        We would'nt recommend experimenting with the data in the first two
        blocks.If you do,you can easily cause a system crash.You can use
        the last entries of the structure to produce some interesting
        effects though.
        Heres an overview of the parameters you can use to vary the speech
        output.The value in parenthesis is the standard value,the value
        set when narrator.device is opened.
      Speech speed (150);
        You can use this to set the speed of speech.The pitch of the voice
        is not affected by this value.
      Pitch of voice (110);
        You can choose a value between 65 and 320 for the pitch (from
        Goofy to Mickey Mouse). 
      Speech mode (0);
        The zero gives half-way naturel speech.A one lets the Amiga speak
        in monotone like a robot.
      Sex (0);
        A zero means masculine and a one means feminine (more or less..)
      Volume (64);
        The volume can range from 0 to 64.The standard value is the
        loudest possible.
      Read in rate (22200);
        By lowering this value,the voice is lowered.If you change this
        very much,you'll get some wierd voices!
        You can experiment a bit until you find a interesting voice.Have
        fun!
        Here is a complete talking program in AssemPro format:
        ;***** Speech output S.D. *****
        openlib      =-30-378
        closelib    =-414
        ;execbase    =4                    ;defined by AssemPro
        * calls to Amiga Dos:       
        open        =-30
        close        =-30-6
        opendevice  =-444
        closedev    =-450
        addport      =-354
        remport      =-360
        ;DoIo        =-456
        sendIo      =-462
        abortIo      =-480
        read        =-30-12
        write        =-30-18
        ;myinput    =-30-24
        ;output      =-30-30
        ;currdir    =-30-96
        ;exit        =-30-114
        waitforch    =-30-174
        findtask    =-294
        translate    =-30
        mode_old    = 1005
        ;mode_new    = 1006
        ;alloc_abs  =-$cc
        ;free_mem    =-$d2
        ;!!!when>500KB !!! or place in chip memory
        ;org $40000
        ;load $40000
        ;!!!!!!!!!!!!!!!!!!!!!!!
             
              ILABEL AssemPro:includes/Amiga.l  ;AssemPro only
              INIT_AMIGA                  ;AssemPro only
        run:
              bsr    init                ;initialization
              bra    test                ;system-test
        init:                              ;system initialization and
                                            ;open
              move.l  execbase,a6          ;pointer to exec library
              lea    dosname(pc),a1      ;pointer to dos name
              moveq  #0,d0                ;version:not important
              jsr    openlib(a6)          ;open DOS-Library
              move.l  d0,dosbase          ;save handle
              beq    error                ;error routine
        ;*                                  ;open translator library
              move.l  execbase,a6          ;pointer to exec library
              lea    transname,a1        ;pointer to translator library
              clr.l  d0
              jsr    openlib(a6)          ;open translator
              move.l  d0,tranbase          ;save handle
              beq    error                ;error routine
        ;*                                  ;set up
              sub.l  a1,a1
              move.l  execbase,a6
              jsr    findtask(a6)        ;find task
              move.l  d0,nwrrep+2
              lea    nwrrep,a1
              jsr    addport(a6)          ;add port
        ;*                                  ;open narrator device
              lea    talkio,a1            ;pointer to I/O area in A1
              move.l  #nwrrep,14(a1)      ;enter port address
              clr.l  d0                  ;number 0
              clr.l  d1                  ;no flags
              lea    nardevice,a0        ;pointer to device name
              jsr    opendevice(a6)      ;open narrator.device
              tst.l  d0                  ;error?
              bne    error                ;Yes!
        ;*                                  ;set up I/O for narrator
                                            ;device
        bp:
              lea    talkio,a1            ;pointer to I/O in A1
              move.l  #nwrrep,14(a1)      ;enter port address
              move.l  #amaps,48+8(a1)      ;pointer to audio mask
              move    #4,48+12(a1)        ;size of mask
              lea    consolname(pc),a1    ;console-definition
              move.l  #mode_old,d0
              bsr    openfile            ;console open
              beq    error       
              move.l  d0,conhandle
              rts
        test:
              move.l  #mytext,d0         
              bsr    pmsg                ;test-text output
              bsr    sayit                ;say text
              bsr    readin              ;input
              move    #10,d0
              bsr    pchar                ;LF output
              move.l  #inline+2,d0
              bsr    pmsg                ;and again
              bsr    pcrlf
              bra    qu
        error:
              move.l  #-1,d7              ;flag
        qu:
              move.l  execbase,a6
              lea    talkio,a1
              jsr    abortio(a6)
       
              move.l  conhandle,d1        ;window close
              move.l  dosbase,a6
              jsr    close(a6)
              move.l  dosbase,a1          ;DOS.Lib close
              move.l  execbase,a6
              jsr    closelib(a6)
              lea    nwrrep,a1
              jsr    remport(a6)          ;remove port
              lea    talkio,a1
              jsr    closedev(a6)        ;close narrator device
              move.l  tranbase,a1
              jsr    closelib(a6)        ;close translator library
              EXIT_AMIGA                  ;AssemPro only
        openfile:                          ;open file
              move.l  a1,d1                ;pointer to I/O definition-
                                            ;text
              move.l  d0,d2
              move.l  dosbase,a6
              jsr    open(a6)
              tst.l  d0
              rts
        pmsg:                              ;print message (D0)
              movem.l d0-d7/a0-a6,-(sp)   
              move.l  d0,a0
              move.l  a0,d2
              clr.l  d3
        mess1:
              tst.b  (a0)+
              beq    mess2
              addq.l  #1,d3
              bra    mess1                ;length calculate
        mess2:
              move.l  conhandle,d1
              move.l  dosbase,a6
              jsr    write(a6)
              movem.l (sp)+,d0-d7/a0-a6
              rts
        pcrlf:
              move    #10,d0
              bsr    pchar
              move    #13,d0
        pchar:                              ;output characters in D0
              movem.l d0-d7/a0-a6,-(sp)    ;save all
              move.l  conhandle,d1
        pch1:
              lea    chbuff,a1
              move.b  d0,(a1)
              move.l  a1,d2
              move.l  #1,d3                ;1 letter
              move.l  dosbase,a6
              jsr    write(a6)
              movem.l (sp)+,d0-d7/a0-a6    ;restore all
              rts
        scankey:                            ;test key
              move.l  conhandle,d1
              move.l  #500,d2              ;wait value
              move.l  dosbase,a6
              jsr    waitforch(a6)
              tst.l  d0
              rts
        readin:                            ;input from keyboard
              movem.l d0-d7/a0-a6,-(sp)    ;save registers
              lea    inline+2,a2          ;pointer to input buffer
              clr.l  (a2)
        inplop:
              bsr    getchr
              cmp.b  #8,d0
              beq    backspace
              cmp.b  #127,d0              ;delete?
              beq    backspace
              bsr    pchar                ;character output
              cmp.b  #13,d0
              beq    inputx
              move.b  d0,(a2)+
              bra    inplop
        inputx:
              clr.b  (a2)+
              sub.l  #inline,a2
              move    a2,inline            ;length in lines+1
              movem.l (sp)+,d0-d7/a0-a6    ;registers
              rts
        backspace:
              cmp.l  #inline,a2          ;at the beginning?
              beq    inplop              ;yes
              move.b  #8,d0
              bsr    pchar                ;backspace
              move    #32,d0
              bsr    pchar                ;blank
              move    #8,d0
              bsr    pchar                ;backspace
              clr.b  (a2)
              subq.l  #1,a2
              bra    inplop
        getchr:                            ;get one character from
                                            ;keyboard
              move.l  #1,d3                ;one character
              move.l  conhandle,d1     
              lea    inbuff,a1            ;buffer address
              move.l  a1,d2
              move.l  dosbase,a6
              jsr    read(a6)
              clr.l  d0
              move.b  inbuff,d0
              rts
        sayit:
              lea    intext,a0
              move.l  #outtext-intext,d0
              lea    outtext,a1
              move.l  #512,d1
              move.l  tranbase,a6
              jsr    translate(a6)
        p:
              lea    talkio,a1
              move    #3,28(a1)            ;??
              move.l  #512,36(a1)
              move.l  #outtext,40(a1)
              move.l  execbase,a6
              jsr    sendio(a6)
             
              rts
        mytext:        dc.b 'This is our Test-Text !',10,13,10,13,0,0
        dosname:      dc.b 'dos.library',0,0
        transname:    dc.b "translator.library",0
              align.w
        dosbase:      dc.l 0
 
        tranbase:      dc.l 0
        consolname:    dc.b 'CON:0/100/640/100/* Speech-Test S.D.* ',0
        nardevice:    dc.b 'narrator.device',0
        amaps:        dc.b 3,5,10,12,0,0
              align.w
        conhandle:    dc.l 0
        inbuff:        blk.b 8
        inline:        blk.b 180,0
   
        chbuff:        blk.b 82,0
        narread:      blk.l 20,0
 
        talkio:        blk.l 20,0
        nwrrep:        blk.l 8,0
        intext:        dc.b 'hello,i am the amiga computor',0
              align.w
        outtext:      blk.l 128,0
       
        end
      6.5.Disk Operations.
      --------------------
        The most important peripheral device for a computor like the Amiga
        is the disk drive.You use it to save data,so that you don't lose
        it when you turn off the computor.We'll look at saving and
        retrieving data in this chapter.                                 
        Lets first look at the simple disk operations that are used for
        data management.To gain access to a file,you must open it first. 
        This is done using the OPEN function from the DOS library,a
        function that you're already familiar with.I'll assume in the
        following examples,that you've already opened the DOS library.
      6.5.1.Open Files.
      -----------------
        The open function needs a parameter for the mode.The mode has a
        particular meaning.If the file is opened for reading,it must
        already exist.The mode for the OPEN function must be "old"(1005)
        in this case.
        If you want to produce a file,you must open it first.Since it does
        not exist,you use the "new"(1006) mode.If a file is opened for
        writing using this mode even though a file with this name already
        exists,the old file with this name is erased and replaced.To avoid
        loss of data,you should check if a file by that name already
        exists and then output an error message if it does.
        You're going to start with a subroutine that opens a file.Lets
        assume that the filename starts at the label "filename",and that
        it is closed with a null byte.You just need to pass the mode in
        register D2.
        The routine puts the file handle number in "filehd"and returns to
        the main program.Since the operation with the handle is the last
        one performed by the subroutine,the status of the operation can be
        evaluated once the return has been executed.If the operation went
        smoothly and the file is opened,the handle number has a non-zero
        value.If it is zero and "bsr openfile"is followed by "beq error",
        you can branch to an error handling routine when problems occur.
        Here is a subroutine for opening and closing a file:
        open      =-30                  ; (6.5.1A)                   
        close      =-36
        mode_old  = 1005
        mode_new  = 1006
            ...
        openfile:                      ;*open file,mode in D0
              move.l  dosbase,a6      ;DOS base address in A6
              move.l  #filename,d1    ;pointer to filename
              jsr    open(a6)        ;open file
              move.l  d0,filehd        ;save handle
              rts
        closefile:                      ;*close file
              move.l  dosbase,a6      ;DOS base address in A6
              move.l  filehd,d1        ;file handle in D1
              jsr    close(a6)        ;close file
              rts
        filehd:    dc.l  0            ;storage for file handle
        filename:  dc.b  "filename",0  ;file to be opened
              align                    ;even
        To use these subroutines,you must look at how you can load and
        save data.                                                       
                                                                         
      6.5.2.Reading and Writing Data.                                   
      -------------------------------                                   
        Lets write a new file.To start,write the following lines:     
                move.l  #mode_new,d2    ;open new file (6.5.2A)
                bsr    openfile        ;open file
                beq    error          ;did'nt work!
        For the filename,write a name like "Testfile"in the line labelled
        "filename".After calling the "openfile"routine,a file with this
        name is created on the disk.If one existed already,it is erased.
        Lets assume you want to write a short text file.For the example
        lets use:
        text:  dc.b  "This is a test text for the Testfile",0
        textend:
        The "textend"label is used so that you can calculate the number of
        data bytes by subtracting "text".
        You want to write this text in the file.Use the WRITE function
        which needs three parameters:
        In D1  the file handle that you got back from the OPEN function.
        In D2  a pointer to the data that should be written.
        In D3  the number of bytes to be written.
        For the example,you'll need another segment of code to put the
        pointer to the data in D2 and the number of bytes in D3:
        write  =-48                      ; (6.5.2B)
              ...
        writedata:                      ;*write data in the file
              move.l  dosbase,a6        ;DOS base address
              move.l  filehd,d1          ;file handle in D1
              jsr    write(a6)          ;write data
              rts
        After opening the file,you can call the subroutine from the main
        program with the following lines:
              move.l  #text,d2          ;pointer to data
              move.l  #textend-text,d3  ;number of bytes
              bsr    writedata          ;write data in the file
        Then close the file with:
              bsr    closefile          ;close file
              bra    end                ;end program
        After running the program,look at the directory of the diskette, 
        you should find the file "testfile".It is just as long as your
        text.You want to read this file in,to make sure it contains the
        right data.
        You need the DOS function READ,which needs the same parameters as
        the WRITE function.You can use parameters for the number of bytes
        to read just part of the file.If you give a larger number than the
        file contains,the whole file is loaded.You'll find the number of
        bytes read in D0.
        Lets set up a field that as enough space for the data you want to
        read.You can do this with the following line:
        field: blk.b  100    ;reserve 100 bytes
        For the example data,this is plenty.If you want to load another
        file,you may need to reserve more space.
        Now lets write a subroutine to read the data.You always want to
        load whole files.You just need to pass the address of the buffer
        so the data is loaded into the subroutine.In the example,its the
        address "field".
        Heres the subroutine that reads the entire opened file into the
        memory area pointed to by D2:
        read  = -42                  ; (6.5.2C)
              ...
        readdata:                    ;*read file
              move.l  dosbase,a6    ;DOS base address in A6
              move.l  filehd,d1      ;file handle in D1
              move.l  #$ffffff,d3    ;read an arbitrary number of bytes
              jsr    read(a6)      ;read data
              rts
        To use this routine to load the file into the buffer "field",use
        the following main program:
              move,l  #mode_old,d2  ;old file
              bsr    openfile      ;open file
              beq    error          ;did'nt work!
              move.l  #field,d2      ;pointer to data buffer
              bsr    readdata      ;read file
              move.l  d0,d6          ;save number of bytes in D6
              bsr    closefile      ;close file
              bra    end            ;program end
        After assembling and starting this program,you can use the
        debugger to look at the data buffer that you filled with data from
        the file.In D6,you'll find the number of bytes that were read from
        the file.
      6.5.3.Erase Files.
      ------------------
        Once you've experimented enough with the program above,you'll
        certainly want to erase the "Testfile"file.The DELETEFILE function
        in the DOS library has an offset of -72.It only needs 1 parameter.
        The parameter is passed in D1.The parameter is a pointer to the
        filename.The name must be closed with a null byte.
        To erase "Testfile",use the following lines:
        deletefile  =-72                ; (6.5.3)
              ...
              move.l  dosbase,a6      ;DOS base address in A6
              move.l  #filename,d1    ;pointer to filename in D1
              jsr    deletefile(a6)  ;erase file
        The file is deleted.You can't save the file with normal methods if
        you accidently erase it!You can use a trick that saves the data. 
        We'll take a look at this trick later.Its used in lots of programs
      6.5.4.Rename Files.
      -------------------
        When a text editing program writes a text that as be altered back
        to the disk,the old file usually isn't erased.Often the old file
        is renamed.For example,it might get the name "Backup".The new file
        is written to disk with the old name.
        The function in the DOS library that allows you to change the
        names of programs is called RENAME and has -78 as an offset.You
        need to pass two parameters-D1 as a pointer to the old name and D2
        as a pointer to the new name of the file.
        To rename "Testfile"as "Backup"(before you erase it),use the
        following lines:
        rename  =-78
              ...
              move.l  dosbase,a6    ;DOS base address in A6
              move.l  #oldname,d1  ;pointer to old name in D1
              move.l  #newname,d2  ;pointer to new name in D2
              jsr    rename(a6)    ;rename file
              ...
        oldname: dc.b "testfile",0
        newname: dc.b "backup",0
      6.5.5.CLI Directory.
      --------------------
        Lets pretend you've programmed a text editor and started it.Now
        you want to load a text from disk and edit it-but whats the name
        of that file?
        You need a function to read and display the directory of the disk.
        There are several ways to do this.First lets use the easiest
        method.It doesn't require much programming and can be quite
        useful.
        The trick is to call the Dir or List programs that are in the C 
        directory.You'll use the CLI commands.The DOS library contains a
        command called "Execute"with offset -222 that allows you to
        execute CLI commands.
        The function needs three parameters:
        In D1  a pointer to a string closed with a zero that contains the
                name of the command to be executed.This string must
                contain the same command that you would give in the CLI.It
                can be a null pointer as well.
        In D2  the input file is determined.Normally theres a zero here.
                If however,you give the file handle of a text file,though,
                this file is read and interpreted as a command sequence.If
                you define a window as the input medium,you've programmed
                a new CLI window!
        In D3  the output file is determined.If there a zero here,the
                output of the commands (for example,DIR output) is sent to
                the standard CLI window.
        To try this out,insert this subroutine in a program that has
        already opened the DOS library and a window.
        execute  = -222              ; (6.5.5)
              ...
        dir:
              move.l  dosbase,a6    ;DOS base address in A6
              move.l  #command,d1    ;pointer to command line
              clr.l  d2            ;no input (CLI window)
              move.l  conhandle,d3  ;output in our window
              jsr    execute(a6)    ;execute command
              rts
        command:
              dc.b    "dir",0
        This program works with the List command as well.The disadvantage
        of this method is that the disk that the Workbench is loaded from
        must be in the drive or the system requests you to put it in.The 
        Dir command is just a program,and the Amiga must load it before it
        can run.
        The disadvantage isn't too great.The program is short,and it
        allows you to use any CLI command in a program.
        Here is the complete program in AssemPro format that calls the dir
        program:
        ;***** 6.5.5A DIR.ASM S.D.***** 
       
        openlib      =-408
        closelib    =-414
        ;execbase    = 4                    ;defined in AssemPro
                                            ;macros
                     
                                     
        *calls to Amiga Dos:
        open        =-30
        close        =-36
        execute      =-222
        IoErr        =-132
        mode_old    = 1005
        alloc_abs    =-$cc
              ILABEL AssemPro:includes/Amiga.l  ;AssemPro only
              INIT_AMIGA                  ;AssemPro only               
                                                                         
        run:
              bsr    init                ;initialization
              bra    test                ;system test
        init:                              ;system initialization and
                                            ;open
              move.l  execbase,a6          ;number of execute-library
              lea    dosname(pc),a1
              moveq  #0,d0
              jsr    openlib(a6)          ;open DOS-library
              move.l  d0,dosbase
              beq    error
              lea    consolname(pc),a1    ;console definition
              move.l  #mode_old,d0
              bsr    openfile            ;console open
              beq    error
              move.l  d0,conhandle
              rts
        test:
              bsr    dir                  ;do directory
              bra    qu                  ;quit and exit
        dir:
              move.l  dosbase,a6          ;DOS base address in A6
              move.l  #command,d1          ;pointer to command line
              clr.l  d2                  ;no input (CLI window)
              move.l  conhandle,d3        ;output in our window
              jsr    execute(a6)          ;execute command
              rts
        error:
              move.l  dosbase,a6
              jsr    IoErr(a6)
              move.l  d0,d5
              move.l  #-1,d7              ;flag
        qu:
              move.l  conhandle,d1        ;window close
              move.l  dosbase,a6
              jsr    close(a6)
              move.l  dosbase,a1          ;DOS.Lib close
              move.l  execbase,a6
              jsr    closelib(a6)
              EXIT_AMIGA                  ;AssemPro only
        openfile:                          ;open file
              move.l  a1,d1                ;pointer to I/O-Definition-
                                            ;text
              move.l  d0,d2
              move.l  dosbase,a6
              jsr    open(a6)
              tst.l  d0
              rts
        dosname: dc.b 'dos.library',0,0
              align.w
        dosbase: dc.l 0
        consolname: dc.b 'CON:0/100/640/100/** CLI-Test **',0
              align.w
        conhandle: dc.l 0
        command:
              dc.b    "dir",0
              end
      6.5.6.Read Directory.
      ---------------------
        Now,lets look at another method that doesn't need the CLI.In this
        way,you can read the directory of any disk without having to play
        Disk Jockey.                                                     
        You need to writ a program that does what CLI's Dir program does.
        There are several steps.
        First you must give the system a key to the desired directory.That
        means you must call DOS'Lock function.It needs two parameters:
        In D1    pass a pointer to a text that contains the name of the
                directory you wish to read.If,for example,you want to
                read the contents of the RAM disk,the text would be
                'RAM:',0.
        In D2    put the mode that determines whether to read or write.Let
                us use the "Read"(-2) mode.
        You call the Lock function (offset -84) and get either a point to
        the key or a zero returned to you in the D0 register.If you get a
        zero,the call did'nt work,the file was'nt found.This function can
        be used to find if a file is on the disk.You use this function
        with the name and see if D0 comes back zero.If not,the file
        exists.
        Lets assume the file or path exists.You need to save the value
        that came back in D0.You'll need it for both functions that you'll
        call.
        The next function you need is called Examine.You use it to search
        the disk for an acceptable entry.It returns parameters like name,
        length and date that correspond to the entry.You need to reserve a
        memory block for this information and put the beginning of the
        block in D2 before calling the Examine function.Put the key you
        got from the Lock function in the D1 register.
        The memory area that is filled with information is called a
        FileInfoBlock.Its 260 bytes long and contains information about
        the file.The name starts in the 9th byte and ends with a null byte
        so you can easily print it with our "pmsg"routine.The information
        that Examine gives isn't about a particular file,but about the
        disk.The name in FileInfoBlock is the disk name.
        The Examine function sends the status back in the D0 register.
        Since the Lock function already tested if the file existed,evalua-
        ting the status really isn't necessary.
        Now to the function that you can use to read individual files from
        the directory.The function is called ExNext (Examine Next).This 
        function searches for the next entry that fits the key every time
        it is called.ExNext gets the same parameters as Examine gets.   
        However,the return parameter in D0 is more important here.
        The ExNext function is always called in the same way.It always
        gets the next entry of the directory.If no more entries exist in
        the directory,ExNext puts a zero in the D0 register.
        You need to continue performing this operation until there aren't
        any more entries.You can find this using the IoErr function from
        the DOS library.
        This function doesn't need any parameters.It returns the status of
        the last I/O operation that was performed in the D0 register.After
        the last ExNext,this value is 232,which means no_more_Entries.
        Heres a complete routine for reading the directory of the disk in
        DFO:and displaying the contents in the window.
        ; 6.5.5B.ASM
        ;***** DOS-Sample function  3/87 S.D. *****
        openlib      =-30-378
        closelib    =-414
        exbase      =4
        * calls to amiga dos:
        open        =-30
        close        =-30-6
        read        =-30-12
        write        =-30-18
        myinput      =-30-24
        output      =-30-30
        currdir      =-30-96
        lock        =-30-54
        examine      =-30-72
        exnext      =-30-78
        exit        =-30-114
        IoErr        =-30-102
        waitforch    =-30-174
        mode        = 0
        mode_old    = 1005
        mode_new    = 1006
        alloc_abs    =-$cc
        free_mem    =-$d2
              ILABEL AssemPro:includes/Amiga.l  ;AssemPro only
              INIT_AMIGA                  ;AssemPro only
        run:                                                             
              bsr    init                ;initialization
              bra    test                ;system-test
        init:                              ;system initialization and
                                            ;open
              move.l  exbase,a6            ;pointer to exec.library
              lea    dosname(pc),a1
              moveq  #0,d0
              jsr    openlib(a6)          ;open dos-library
              move.l  do,dosbase
              beq    error
              lea    consolname(pc),a1    ;console definition
              move.l  #mode_old,d0
              bsr    openfile            ;console open
              beq    error
              moveq  d0,conhandle
              rts
        test:
              move.l  #mytext,d0
              bsr    pmsg                ;test-text output
              move.l  dosbase,a6
              move.l  #name,d1
              move.l  #-2,d2
              jsr    lock(a6)
              move.l  d0,d5
              tst.l  d0
              beq    error
              move.l  d0,locksav
              move.l  dosbase,a6
              move.l  locksav,d1
              move.l  #fileinfo,d2
              jsr    examine(a6)
              move.l  d0,d6
              tst.l  d0
              beq    error
        loop:
              move.l  dosbase,a6
              move.l  locksav,d1
              move.l  #fileinfo,d2
              jsr    exnext(a6)
              tst.l  d0
              beq    error
              move.l  #fileinfo+8,d0
              bsr    pmsg
              bsr    pcrlf
              bra    loop
        error:
              move.l  dosbase,a6
              jsr    ioerr(a6)
              move.l  d0,d6
              move.l  #presskey,d0
              bsr    pmsg
              bsr    getch
              move.l  #-1,d7              ;flag
        qu:
              move.l  conhandle,d1        ;window close
              move.l  dosbase,a6
              jsr    close(a6)
              move.l  dosbase,a1          ;dos.lib close
              move.l  exbase,a6
              jsr    closelib(a6)
             
              EXIT_AMIGA                  ;AssemPro only
        openfile:                          ;open file
              move.l  a1,d1                ;pointer to I/O-Definition-
                                            ;Text
              move.l  d0,d2
              move.l  dosbase,a6
              jsr    open(a6)
              tst.l  d0
              rts
        pmsg:                              ;print message (D0)
              movem.l d0-d7/a0-a6,-(sp)
              move.l  d0,a0
              move.l  a0,d2
              clr.l  d3
        mess1:
              tst.b  (a0)+
              beq    mess2
              addq.l  #1,d3
              bra    mess1
        mess2:
              move.l  conhandle,d1
              move.l  dosbase,a6
              jsr    write(a6)
              movem.l (sp)+,d0-d7/a0-a6
              rts
        pcrlf:
              move    #10,d0
              bsr    pchar
              move    #13,d0
        pchar:                              ;character in D0 output
              movem.l d0-d7/a0-a6,-(sp)    ;save all
              move.l  conhandle,d1
        pch1:
              lea    chbuff,a1
              move.b  d0,(a1)
              move.l  a1,d2
              move.l  #1,d3
              move.l  dosbase,a6
              jsr    write(a6)
              movem.l (sp)+,d0-d7/a0-a6    ;restore all
              rts
     
        scankey:                            ;test key
              move.l  conhandle,d1
              move.l  #500,d2              ;wait value
              move.l  dosbase,a6
              jsr    waitforch(a6)
              tst.l  d0
              rts
        readin:                            ;input from keyboard
              movem.l d0-d7/a0-a6,-(sp)    ;registers
              lea    inline+2,a2          ;pointer to input buffer
              clr.l  (a2)
        inplop:
              bsr    getchr
              cmp.b  #8,d0
              beq    backspace
              cmp.b  #127,d0              ;delete?
              beq    backspace
              bsr    pchar                ;character output
              cmp.b  #13,d0
              beq    inputx
              move.b  d0,(a2)+
              bra    inplop
        input:
              clr.b  (a2)+
              sub.l  #inline,a2
              move    a2,inline            ;length in inline+1
              movem.l (sp)+,d0-d7/a0-a6    ;registers
              rts
        backspace:
              cmp.l  #inline,a2          ;at beginning?
              beq    inplop              ;yes
              move.b  #8,d0
              bsr    pchar                ;backspace
              move    #32,d0
              bsr    pchar                ;blank
              move    #8,d0
              bsr    pchar                ;backspace
              clr.b  (a2)
              subq.l  #1,a2
              bra    inplop
        getchr:                            ;get 1 character from keyboard
              move.l  #1,d3                ;1 character
              move.l  conhandle,d1
              lea    inbuff,a1            ;buffer-address
              move.l  a1,d2
              move.l  dosbase,a6
              jsr    read(a6)
              clr.l  d0
              move.b  inbuff,d0
              rts
        mytext:    dc.b 'Directory of Diskette: DFO:',10,13,10,13,0,0
        dosname:    dc.b 'dos.library',0,0
        presskey:  dc.b 'Press thr Return key!!',0
              align.w
        dosbase:    dc.l 0
        consolname: dc.b 'CON:0/100/640/100/** Directory-Test **',0
        name:      dc.b 'DFO:',0
              align.w
        locksav:    dc.l 0
        fileinfo:  ds.l 20
        conhandle:  dc.l 0
        inbuff:    DS.B 8
        inline:    DS.B 180
        chbuff      DS.B 82
              end
        The FileInfoBlock contains the following entries:
        Offset  Name            Meaning
        ----------------------------------------------------------------
          0      DiskKey.L        Disk Number
          4      DieEntryType.L  Entry Type (+=Directory,-=File)
          8      FileName        108 bytes with the filename
        116    Protection.L    File Protected?
        120    EntryType.L      Entry type
        124    Size.L          Length of file in bytes
        128    NumBlocks.L      Number of blocks
        132    Days.L          Creation day
        136    Minute.L        Creation time
        140    Tick.L          Creation time
        144    Comment          116 bytes with comments
        If you want to have the program output the file length as well,you
        can read the length with "move.l fileinfo+124,d0"and then use a
        conversion routine to produce a decimal number.You can output this
        result with the name.
      6.5.7.Direct Access To Disk.
      ----------------------------                                       
        There isn't a simple function in the library for accessing single
        disk sectors.Here,you must work with a device just like you did
        with speech output.This time you'll be working with the trackdisk.
        device.
        You want to work with this device to directly program the disk
        drives.Once you've built up the necessary program machinery,you
        can experiment with various commands for disk access.Remember that
        an error can cause the disk to be modified and thus unusable.Make
        sure you're using a non-essential disk.Don't use one which
        contains your only copy of something.                           
        The initialization here is similar to that for speech output.Here
        is the initialization routine for your program:
        ;** Direct disk access via trackdisk.device ** (6.5.7)
        openlib    =-408
        closelib  =-414
        execbase  = 4
        open      =-30
        close      =-36
        opendevice =-444
        closedev  =-450
        sendIo    =-462
        read      =-30-12
        write      =-30-18
        waitforch  =-30-174
        mode_old  = 1005
        run:                           
              bsr    init                ;initialization                   
              bra    test                ;system-test
        init:                              ;initialize and open system
              move.l  execbase,a6          ;pointer to exec.library
              lea    dosname,a1
              moveq  #0,d0
              jsr    openlib(a6)          ;open dos.library
              move.l  d0,dosbase
              beq    error
              lea    diskio,a1            ;pointer to disk I/O area
              move.l  #diskrep,14(a1)      ;pointer to port
              clr.l  d0                  ;drive 0 (built in)
              clr.l  d1                  ;no flags
              lea    trddevice,a0        ;pointer to device name
              jsr    opendevice(a6)      ;open trackdisk.device
              tst.l  d0                  ;error?
              bne    error                ;yes!
              move.l  #consolname(pc),d1  ;console definition
              move.l  #mode_old,d2        ;old mode
              move.l  dosbase,a6          ;dos base address
              jsr    open(a6)            ;open window
              tst.l  d0                  ;error?
              beq    error                ;yes!
              move.l  d0,conhandle        ;else save handle
              rts                          ;done
        test:                              ;place for test routine
        And now for the functions that take care of the various messages
        at the end of the program.
        error:
              move.l  #-1,d7              ;flag for error (for SEKA)
        qu:
              move.l  execbase,a6          ;exec base address
              lea    diskio,a1            ;pointer to disk I/O
              move.l  32(a1),d7            ;IO_ACTUAL in D7 (for testing)
              move    #9,28(a1)            ;command motor on/off
              move.l  #0,36(a1)            ;0=off,1=on,so turn motor
              jsr    sendio(a6)          ;off
              move.l  conhandle,d1        ;close window
              move.l  dosbase,a6
              jsr    close(a6)
              move.l  dosbase,d1          ;close dos.lib
              move.l  execbase,a6
              jsr    closelib(a6)
              lea    diskio,a1
              jsr    closedev(a6)        ;close trackdisk.device
              rts
        Lets not forget the routine that waits for the user to press
        <Return>,so that you can watch the effects of the test function in
        peace:
        getchr:                            ;get a character from keyboard
              move.l  #1,d3                ;1 character
              move.l  conhandle,d1        ;window handle
              move.l  #inbuff,d2          ;buffer address
              move.l  dosbase,a6          ;dos base address
              jsr    read(a6)            ;read character
              rts                          ;thats it
        The last thing you need is the section of code that declares the
        text and data fields that your program needs:                   
                                                                         
        dosname:      dc.b  'dos.library',0
              align
        consolname:    dc.b  'RAW:0/100/640/50/** Wait window',0
              align
        trddevice:    dc.b  'trackdisk.device',0
              align
        dosbase:      dc.l 0              ;dos base address
        conhandle:    dc.l 0              ;window handle
        inbuff:        blk.b 80,0          ;keyboard buffer
        diskio:        blk.l 20,0          ;I/O structure
        diskrep:      blk.l 8,0            ;I/O port
        diskbuff:      blk.b 512*2,0        ;place for 2 sectors
        There,now you've done with the set up work.Lets look at how you
        can give commands to the disk drives.The first and easiest command
        is the one for turning the drive motor on and off.You've already
        seen this command in the program.This is command number nine.This
        number goes in the command word of the I/O structure (bytes 28 and
        29 of the structure).
        You need to pass a parameter that lets the computor know whether
        to turn the motor off or on.This information goes in the I/O long
        word that starts at byte 36:its zero for off,and one for on.
        You already chose the motor that should be turned on or off when
        you opened the device.You put the number of the chosen disk drive
        in D0-in your case you put a zero there because you are using the
        DFO:disk drive.
        Heres an overview of the commands you can use to access
        information on the disk:
        No    Name          Function
        -----------------------------------------------------------------
        2    READ          Read one or more sectors
        3    WRITE        Write sectors
        4    UPDATE        Update the track buffer
        5    CLEAR        Erase track buffer
        9    MOTOR        Turn motor on/off
        10    SEEK          Search for a track
        11    FORMAT        Format tracks
        12    REMOVE        Initialize routine that is called when you
                            remove the disk
        13    CHANGENUM    Find out number of disk changes
        14    CHANGESTATE  Test if disk is in drive
        15    PROTSTATUS    Test if disk is write protected
        You've already learned about command number nine.Lets look at the
        three commands you can use to make tests.These are the last three
        commands.They put a return value in the long word that begins in
        the 32nd byte in the I/O structure.This value was written in D7 in
        the program above for testing purposes.You can read its contents 
        directly if you ran the program with AssemPro.
        Here is a simple routine that you can use to run one of these
        commands with:
        test:                              ; (6.5.7B)
              lea    diskio,a1            ;pointer to I/O structure
              move    #13,28(a1)          ;pass command (for example 13)
              move.l  execbase,a6          ;execbase address in A6
              jsr    sendio(a6)          ;call function
        If CHANGENUM (command 13) is executed,in D7 you'll get the number
        of times a disk was taken out and put in the drive.If you call the
        program,you'll get a value back.If you take the disk out and put
        it back in,the number is two higher the next time you call the
        program.
        The CHANGESTATE command (command 14) tells whether a disk is in
        the drive or not.If one is,a zero comes back.Otherwise,a $FF is
        returned.
        You get the same values back from the PROTSTATUS function (command
        15).Here a zero means that the disk isn't write protected,while
        $FF means that it is.
        Now lets look at the READ and WRITE functions.These operations
        need a few more parameters than the status functions.You need to
        pass the following parameters:
        The address of the I/O buffer in the data pointer,the number of
        bytes to be transfered in I/O length,and the data address on the
        disk in I/O offset.
        The number of data bytes must be a multiple of 512,since every
        sector is 512 bytes,and only whole sectors can be read.
        The data address is the number of the first byte in the sector.If
        you want to use the first sector,the offset is zero.For the second
        sector,its 512,etc...The formula is:
            offset = (sector_number -1) *512
        Here is a routine that loads the first two sectors of the disk
        into the buffer:
        test:  (6.5.7C)
              lea    diskio,a1         
              move    #2,28(a1)          ;command:READ
              move.l  #diskbuff,40(a1)    ;buffer
              move.l  #2*512,36(a1)      ;length:2 sectors
              move.l  #0*512,44(a1)      ;offset:0 sectors
              move.l  execbase,a6        ;exec base address
              jsr    sendio(a6)          ;start function
        Start the program from the debugger and then look at the buffers 
        contents after the program ends.You can find out the format of the
        disk here.If you want to read a sector thats being used,change the
        0 in the offset definition to 700 and start again.Its highly
        probable that theres some data there.
        To modify and write back the data that you've read from the disk,
        you need command number three,the WRITE command.The parameters are
        the same.
        If you've executed the WRITE commandyou're probably wondering why
        the disk light did'nt go on.Thats because the Amiga writes a track
        that as been read into a buffer on its own.It WRITE's data there
        as well.It won't write the data to disk until another track is
        accessed.
        You can have the data updated directly as well using command four,
        the UPDATE command.
        Command 11,the FORMAT command,is also quite interesting.This
        command needs a data field that is 11*512=5632 bytes long-the
        length of a track.The offset must be a multiple of this number so
        that you start at the beginning of a track.
        The length must be a multiple of 5632 as a result.If several
        tracks are formatted,each track is filled with the same data.
        You can use this function to easy write a disk copy program.You
        READ the source disk and then FORMAT the corresponding track on
        the destination disk.Thats how the DiskCopy program works-it
        reformats the destination disk.
        Command ten,the SEEK command,just needs the offset.It moves the
        Read/Write head of the drive to the position specified without
        making a disk access or testing if its at the right position.
        Command 12,the REMOVE command,is used to install an interrupt
        routine that is called when the disk is removed from the disk
        drive.The address of the interrupt structure is passed in the data
        pointer of the I/O structure.If theres a zero here,the interrupt 
        routine is turned off.
        Heres a complete example program in AssemPro format:
        ;***** Track disk-Basic function  10/86 S.D. *****
              ILABEL ASSEMPRO:includes/Amiga.l  :AssemPro only
        openlib      =-30-378
        closelib    =-414
        ;execbase    = 4                    ;defined in INIT_AMIGA
        * calls to amiga dos:
        open        =-30
        close        =-30-6
        opendevice  =-444
        closedev    =-450
        sendIo      =-462
        read        =-30-12
        write        =-30-18
        waitforch    =-30-174
        mode_old    = 1005
              INIT_AMIGA                  ;AssemPro only
        run:
              bsr    init                ;initialization
              bra    test                ;system test
        init:                              ;system initialization and
                                            ;open
              move.l  execbase,a6          ;pointer to exec-library
              lea    dosname,a1
              moveq  #0,d0
              jsr    openlib(a6)          ;open dos-library
              move.l  d0,dosbase
              beq    error
              lea    diskio,a1
              move.l  #diskrep,14(a1)
              clr.l  d0
              clr.l  d1
              lea    trddevice,a0
              jsr    opendevice(a6)      ;open trackdisk.device
              tst.l  d0
              bne    error
        bp:
              lea    consolname(pc),a1    ;console-definition
              move.l  #mode_old,d0
              bsr    openfile            ;console open
              beq    error
              move.l  d0,conhandle
              rts
        test:
              bsr    accdisk
              bsr    getchr              ;wait for character
              bra    qu
        error:
              move.l  #-1,d7              ;flag
        qu:
              move.l  execbase,a6
              lea    diskio,a1
              move    #9,28(a1)
              move.l  #0,36(a1)
              jsr    sendio(a6)
              move.l  conhandle,d1        ;window close
              move.l  dosbase,a6
              jsr    close(a6)
              move.l  dosbase,a1          ;dos.lib close
              move.l  execbase,a6
              jsr    closelib(a6)
              lea    diskio,a1
              move.l  32(a1),d7
              jsr    closedev(a6)
              EXIT_AMIGA                  ;AssemPro only
        openfile:                          ;open file
              move.l  a1,d1                ;pointer to the I/O-definition
                                            ;text
              move.l  d0,d2
              move.l  dosbase,a6
              jsr    open(a6)
              tst.l  d0
              rts
        scankey:                            ;test for key
              move.l  conhandle,d1                     
              move.l  #500,d2              ;wait value
              move.l  dosbase,a6
              jsr    waitforch(a6)
              tst.l  d0
              rts
        getchr:                            ;get one character from
                                            ;keyboard
              move.l  #1,d3                ;1 character
              move.l  conhandle,d1
              lea    inbuff,a1            ;buffer-address
              move.l  a1,d2
              move.l  dosbase,a6
              jsr    read(a6)
              clr.l  d0
              move.b  inbuff,d0
              rts
        accdisk:
              lea    diskio,a1
              move    #2,28(a1)            ;command:READ               
              move.l  #diskbuff,40(a1)    ;buffer
              move.l  #2*512,36(a1)        ;length:2 sectors
              move.l  #20*512,44(a1)      ;offset: n sectors
              move.l  execbase,a6
              jsr    sendio(a6)
              rts
        dosname:      dc.b 'dos.library',0,0
              align.w
        dosbase:      dc.l 0
        consolname:    dc.b 'RAW:0/100/640/100/** Test-Window S.D.V0.1',0
        trddevice:    dc.b 'trackdisk.device',0
              align.w
        conhandle      dc.l 0
        inbuff:        ds.b 8                                           
        diskio:        ds.l 20,0                                         
        diskrep:      ds.l 8,0                                         
        diskbuff:      ds.b 512*2,0                                     
                                                                         
              end
         
      Chapter 7.
      ----------
      7.Working With Intuition.
      -------------------------
        Now that you've learned so much about machine language,lets look
        at the special features of the Amiga.Lets look at the operating
        system Intuition that is in charge of windows,screens,the mouse
        and lots of other things.Beforetaking a look at these beautiful 
        features,theres some bad news.
        First,though,lets here the good news.Since Intuition has so many
        functions,it allows you to be very creative in programming your
        ideas.The disadvantage is that the flexibility means that you have
        to use a lot of parameters,and that makes for a lot of tedious
        work.
        However,this is no grounds for panic.Once you've built up the
        necessary routines,the programming and experimentation becomes
        increasingly interesting.Before you try out new program variations
        you should save your source code to disk,because Intuition gets
        fairly upset about bad parameters and often responds by crashing
        the system.
        Now lets get to work.To start working with Intuition,you need the
        Intuition library.You can load it with the OpenLibrary function
        from the EXEC library.Heres the subroutine that takes care of
        initialization.
        openlib  =-408
        execbase  = 4
        run:
              bsr    openint        ;load intuition library
              ...
        openint:                      ;*initialize and open system
              move.l  execbase,a6    ;exec base address
              lea    intname,a1      ;name of intuition library
              jsr    openlib(a6)    ;open intuition
              move.l  d0,intbase      ;save intuition base address
              rts
        intname: dc.b "intuition.library",0
              align
        intbase: dc.l 0                ;base address of intuition
        When your program is finished,you need to close the screens,the
        window and the library.To do this,use the CloseLibrary function
        from the EXEC library.It has an offset of -414.
        Heres the subroutine:
        closelibrary  =-414
              ...
        closeint:                        ;*close intuition
              move.l  execbase,a6      ;exec base address in A6
              move.l  intbase,a1        ;intuition base address in A1
              jsr    closelibrary(a6)  ;close intuition
              rts                      ;done
        Now that you've got that taken care of,you can finally start
        working with Intuition.
      7.1.Open Screen.
      ----------------
        Intuition is a graphics operating system.For this reason,you'll be
        working with the screen.Its even more interesting to work with
        several screens at the same time.However,you only have one monitor
        on the Amiga.
        You can open as many screens as you like (at least,as long as
        theres some memory available).You can open a window,display menus
        and do I/O's there.The individual screens are fully independant.
        You can work with all of them simultaneously on the monitor.
        You can move individual screens forward and back to your hearts
        content.You can also press the left <Amiga> key and then an "m"to
        return to the workbench screen after getting into the different
        screens.
        You want to begin programming Intuition by setting up a screen.You
        have already loaded the Intuition library,so you can use the Open-
        Screen function.
        Wait a minute!What should the screen look like,where should it go,
        and what form should it have?You need to look at the options for
        the form of the screen you have available.
        The input to the screen is in the form of a table that has 13
        entries.Lets take a look at the parameters that you need for our
        screen.
        You'll start the table with the label "screen_defs"which must be
        at an even address:
              align
        screen_defs:                ;The screen table begins here
        The first bit of information that the screen needs is the position
        and size.Lets have it start in the upper left corner and fill the
        entire screen.You'll use the positions X=0 and Y=0,the width 320
        and the height 200.This means that your screen is the maximum
        size.
        x_pos:    dc.w  0        ;X-Position
        y_pos:    dc.w  0        ;Y-Position
        width:    dc.w  320      ;width
        height:    dc.w  200      ;height
        Next you need to decide which colors should be displayed.That
        depends on the number of bitplanes,on the depth.Lets choose two. 
        That means you have 2^2 (4) colours available.Lets choose two,
        since four colours is usually plenty.
        depth:    dc.w  2        ;number of bitplanes
        Next you need to choose the colour of the title line and the
        function symbols.Give the number of the colour register:
        detail_pen:  dc.b  0      ;colour of text,etc...
        Now for the colour of the text background:
        block_pen    dc.b  1      ;background colour
        Make sure that these two inputs fit in a byte.The colours are
        normally the following (if the standard values have'nt been
        changed).You'll notice that the number of colours depends on the
        number of bit maps.
            Pen        Colour
        ---------------------------------------------------------
            0        Background (blue)
            1        White
          for two bit planes
            2        Black
            3        Red
          for three bit planes
            4        Blue
            5        Violet
            6        Turquoise
            7        White
          for four bit planes
            8        Black
            9        Red
            10        Green
            11        Brown
            12        Blue
            13        Blue
            14        Green
            15        Green
        The next word contains the bits that describe the appearance of
        the screen.The bits are:
        Bit    Value    Name            Meaning
        --------------------------------------------------------------- 
        1      2      GENLOCK_VIDEO   
        2      4      INTERLACE        Puts the screen in Interlace
                                        mode.The resolution and thus the
                                        maximum screen size are doubled.
        6    $40      PFBA
        7    $80      EXTRA_HALFBRITE
        8    $100    GENLOCL_AUDIO
        10    $400    DBLPF            Divides the screen into a border
        and                              character area.
        11    $800    HOLDNMODIFY      Turns on Hold-and-Modify mode.
        13    $2000    VP_HIDE
        14    $4000    SPRITES          Allows sprites to be used.
        15    $8000    MODE_640        Turns on the highest resolution 
                                        graphics for the screen(640x400).
        Choose the value two (normal) for your example screen:
        view_modes:  dc.w  2        ;representation mode
        The following word is constructed in such away that each bit as
        its own meaning.Use this to set what sort of screen it is.Choose
        15 so the screen is a "Custom screen",which allows you all of the
        options.
        screen_type:  dc.w  15      ;screen type:custom screen
        Next theres a pointer to the character set to be used for all
        output to the screen.If you don't want to install your own
        character set,just put a zero here,and the standard character set
        is used.
        font:  dc.l  0        ;character set:standard
        Next theres a pointer to the text thats used as the name of the
        screen.The text ends with a zero,just like window names must.
        title:  dc.l  name      ;pointer to title text
        Next comes a long word that defines the gadgets.These gadgets
        represent the functions,like "Bring forward",that can be accessed
        via a mouse click in the screen.The long word in this table is a
        pointer to a list which specifies the gadgets.These aren't the
        system gadgets.However,you're only using system gadgets here,so
        put a zero here.
        gadgets:  dc.l  0        ;no gadgets
        Finally theres a long word that you only need if you want to use
        the special bitmap just for your screen.Since this isn't the case,
        just put a zero here.
        bitmap:  dc.l  0        ;no bitmap
        Thats it for the list entries that you need to define the screen.
        You still need the text for the name of the screen.Enter the
        following:
        sname:  dc.b  'Our Screen',0    ;screen title
        Heres a quick overview of the list:
              align
        screen_defs:                  ;*The screen ta
        x_pos:        dc.w  0        ;X-position
        y_pos:        dc.w  0        ;Y-position
        width:        dc.w  320      ;width
        height:      dc.w  200      ;height
        depth:        dc.w  2        ;number of bitplanes
        detail_pen:  dc.b  0        ;colour of the text,etc...
        block_pen:    dc.b  1        ;background colour
        view_modes:  dc.w  2        ;representation mode
        screen_type:  dc.w  15        ;screen type:custom screen
        font:        dc.l  0        ;character set:standard
        title:        dc.l  sname    ;pointer to title text
        gadgets:      dc.l  0        ;no gadgets
        bitmap:      dc.l  0        ;no bit map
        sname:        dc.b  'Our Screen',0  ;screen title
        Once you've decided on the parameters,its very easy to open the
        screen.You need Intuitions OpenScreen function.Its offset is -198
        and it only needs one parameter,the address of the parameter
        table.The program fragment looks like this:
        openscreen =-198
              bsr    openint            ;open intuition
              bsr    scropen            ;open screen
              ...
        scropen:                          ;*open screen
              move.l  intbase,a6        ;intuition base address in A6
              lea    screen_defs,a0    ;pointer to table
              jsr    openscreen(a6)    ;and open
              move.l  d0,screenhd        ;save screen handle
              rts                        ;return to main program
              ...
        screen_defs:                      ;table info follows
        Now the Amigas Workbench screen is covered by your screen.Now you
        can do what you want with it until the program is done.Afterwards,
        the screen must be closed again,so that you can see the Workbench
        screen again.
        Use the CloseScreen function (offset -66) to do this.The only
        parameter it needs is the pointer to the screen structure you got
        back from the OpenScreen function.
        closescreen =-66
              ...
        scrclose:                        ;* close screen
              move.l  intbase,a6        ;intuition base address in A6
              move.l  screenhd,a0        ;screen handle in A0
              jsr    closescreen(a6)    ;clos screen
              rts                        ;done
        The long word that OpenScreen returned to you is a pointer to a
        screen structure that contains all the needed data about the
        screen.Besides the data which was given,there is a pointer in the
        screen area for individual bit planes,etc...
        The form of this structure is fairly complicated and contains some
        data that you can't use.Several of the parameters are interesting,
        however.Heres a selection of usable parameters:
        No    Name              Function
        ------------------------------------------------------------------
        0    (NextScreen.L)    Pointer to next screen.
        4    (FirstWindow)    Pointer to first window structure
        8    (LeftEdge.W)     
        $A    (TopEdge.W)      Position of screen
        $C    (Width.W)        Width
        $E    (Height.W)        Height
        $10  (MouseY.W)
        $12  (MouseX.W)        Mouse position in the screen
        $14  (Flags.W)        Screen flags
        $16  (Title.L)        Pointer to title text
        $1A  (DefaultTitle)    Pointer to normal title
        $28  (Font.L)          Pointer to character set
        $C0  (Plane0.L)        Pointer to bitplane 0
        $C4  (Plane1.L)        Pointer to bitplane 1
        $C8  (Plane2.L)        Pointer to bitplane 2
        $CC  (Plane3.L)        Pointer to bitplane 3
        An example of an application for the plane pointer is writing and
        using your own character routine.Next you want to move the address
        of the plane into an address register as follows:
              move.l  screenhd,a5        ;screen pointer in A5
              move.l  $c0(a5),a5        ;bitplane 0-pointer in A5
        If you want to try this,do the following:
              move.l  screenhd,a5        ;screen pointer in A5
              move.l  $c0(a5),a5        ;bitplane 0-pointer in A5
              move    #$20,d0            ;Counter D0=$20
        lop1:
              move    d0,(a5)            ;write counter bits in picture
              add.l  #80,a5            ;address+80,next line
              dbra    d0,lop1            ;continue until D0 < 0
        This program draws a white,square pattern that corresponds to the
        bit pattern for the numbers $20 to 0.This isn't a particularly
        useful program,but it shows how easy it is to write from a machine
        language program directly to the screen.If you change the offset
        in the second line to $C4,the pattern is read.
        You can move the entire screen with the normal technique of moving
        the mouse pointer into the upper border and moving it up and down
        with the left mouse key depressed.You can do the same with a
        program.
        Lets move the screen without the mouse.Use the joystick for
        demonstration purposes.Put the joystick in port two.As you saw in
        the chapter on the hardware register,you can read memory location
        $DFF00C to find information about the joystick.You can find the
        direction the screen should be moved here.
        Moving the screen requires another Intuition function.You use the
        MoveScreen function which as an offset of -162 and needs three
        parameters to do this.The parameters are:
        In A0  the pointer to the screen structure that you got back in
                D0 when you opened the screen.(You saved it in "screenhd")
        In D1  the desired movement in the Y-direction,the vertical
                direction.
        In D0  the horizontal movement in the X-direction.The varient
                doesn't work so you can only move the screen vertically.
        Insert the following lines in your program:
        MoveScreen =-162
              ...
        scrmove:                          ;*move screen D0 to the right
                                          ;and D1 down
              move.l  intbase,a6        ;intuition base address in A6
              move.l  screenhd,a0        ;screen handle in A0
              clr.l  d0                ;no horizontal movement
              jsr    movescreen(a6)    ;move screen
              rts                        ;done
        Now your looking at a complete program that goes through the
        following steps:
        1.  Opens the Intuition library
        2.  Opens the screen
        3.  Moves the screen in the direction specified by the joystick in
            port two
        4.  Closes the screen when the fire button is hit
        5.  Closes the Intuition library
        6.  Ends
        Here is the complete program including the subroutines,so you'll
        have it all in one spot:
        ;** Demo program to open and move a screen **
        movescreen  =-162
        openscreen  =-198
        closescreen  =-66
        closelibrary =-414
        openlib      =-408                ;open library
        execbase    = 4                  ;exec base address
        joy2        =$dff00c            ;joystick 2 data
        fire        =$bfe001            ;firebutton 2:bit 7
        run:
              bsr    openint            ;open intuition
              bsr    scropen            ;open screen
              move    joy2,d6            ;save joystick info
        loop:
              tst.b  fire              ;test fire button
              bpl    ende              ;pressed down:done
              move    joy2,d0            ;basic info in D0
              sub    d6,d0              ;subtract new data
              cmp    #$0100,d0          ;up?
              bne    noup              ;no
              move.l  #-1,d1            ;dy=-1 direction y
              bsr    scrmove            ;move up
              bra    loop
        noup:
              cmp    #$0001,d0          ;down?
              bne    loop              ;no
              move.l  #1,d1              ;dy=1
              bsr    scrmove            ;move down
              bra    loop
        ende:
              bsr    scrclose          ;close screen
              bsr    closeint          ;close intuition
              rts                        ;done!
        openint:                          ;*initialize and open system
              move.l  execbase,a6        ;exec base address
              lea    intname,a1        ;name of intuition library
              jsr    openlib(a6)        ;open intuition
              move.l  d0,intbase        ;save intuition base address
              rts
        closeint:                        ;*close intuition
              move.l  execbase,a6        ;exec base address in A6
              move.l  intbase,a1        ;intuition base address in A1
              jsr    closelibrary(a6)  ;close intuition
              rts                        ;done
        scropen:                          ;*open screen
              move.l  intbase,a6        ;intuition base address in A6
              lea    screen_defs,a0    ;pointer to table
              jsr    openscreen(a6)    ;open
              move.l  d0,screenhd        ;save screen handle
              rts                        ;return to main program
        scrclose:                        ;*close screen
              move.l  intbase,a6        ;intuition base address in A6
              move.l  screenhd,a0        ;screen handle in A0
              jsr    closescreen(a6)    ;close screen
              rts                        ;done
        scrmove:                          ;move screen D0 right/D1 down
              move.l  intbase,a6        ;intuition base address in A6
              move.l  screenhd,a0        ;screen handle in A0
              clr.l  d0                ;no horizontal movement
              jsr    movescreen(a6)    ;and move
              rts                        ;done
              align
        screen_defs:                      ;*screen table begins here
        x_pos:        dc.w  0            ;X-position
        y_pos:        dc.w  0            ;Y-position
        width:        dc.w  320          ;width
        height:        dc.w  200          ;height
        depth:        dc.w  2            ;number of bitplanes
        detail_pen:    dc.b  1            ;Text colour=white
        block_pen:    dc.b  3            ;background colour=red
        view_modes:    dc.w  2            ;representation mode
        screen_type    dc.w  15          ;screen type:custom screen
        font:          dc.l  0            ;standard character set
        title:        dc.l  sname        ;pointer to title text
        gadgets:      dc.l  0            ;no gadgets
        bitmap:        dc.l  0            ;no bit map
        intbase:      dc.l  0            ;base address of intuition
        screenhd:      dc.l  0            ;screen handle
        intname:      dc.b  'intuition.library',0
              align
        sname:        dc.b  'Our Screen',0  ;Screen title
              align
              end
        From this example,you can see how easy scrolling actually is.   
        Another easy thing to do is to use the DisplayBeep function.It as
        an offset -96;the only parameter it needs is the screen pointer
        that you stored in the "screenhd"memory block.This function covers
        the screen with an orange colour for a short while.The screen is 
        not changed.The beep function can be used as follows:
        DisplayBeep: =-96
              ...
              move.l  intbase,a6        ;intuition base address in A6
              move.l  screenhd,a0        ;screen pointer in A0
              jsr    displaybeep(a6)    ;light up screen
        If you put a zero instead of a screen pointer in A0,the whole
        screen blinks.
        Good,now you have your own screen that you can move up and down. 
        What good is it if you can't put anything on it?Lets open a window
        on the screen!
      7.2.Open Window.
      ----------------
        As you saw in the chapter on program initialization,its easy to
        open a window with the DOS library.You can't use this method on
        your own screen however.You need to use another method that can
        open any window on any screen.
        Intuition has a function called OpenWindow which handles this sort
        of work.It has an offset of -204 and needs only one parameter,a
        pointer to a window definition table.This pointer goes in register
        A0.
        This table is very similar to the one used to define the screen. 
        The first four values specify the X-and Y-positions,the width,and
        the height of the window to be opened.Heres an example:
              align
        window_defs:
                      dc.w  10          ;x-position
                      dc.w  20          ;y-position
                      dc.w  300          ;width
                      dc.w  150          ;height
        Next come two bytes that define the colour of the letters on the 
        background:
                      dc.b  1            ;white letter colour
                      dc.b  3            ;on a red background
        The next long word contains the IDCMP flags in its bits.The bits 
        determine the circumstances under which Intuition sends a message
        to the program.The bits have the following meanings:
        Bit  Value    Name            Meaning
        -----------------------------------------------------------------
        0  $000001  SIZEVERIFY
        1  $000002  NEWSIZE          Window size changed
        2  $000004  REFRESHWINDOW
        3  $000008  MOUSEBUTTONS    Mouse key hit
        4  $000010  MOUSEMOVE        Mouse moved
        5  $000020  GADGETDOWN      A special gadget chosen
        6  $000040  GADGETUP        Same as above
        7  $000080  REQSET
        8  $000100  MENUPICK        A menu item chosen
        9  $000200  CLOSEWINDOW      A window closed
        10  $000400  RAWKEY          A key pressed
        11  $000800  REQVERIFY
        12  $001000  REQCLEAR
        13  $002000  MENUVERIFY
        14  $004000  NEWPREFS        Preferences modified
        15  $008000  DISKINSERTED    A disk put in
        16  $010000  DISKREMOVED      A disk taken out
        17  $020000  WBENCHMESSAGE
        18  $040000  ACTIVEWINDOW    A window activated
        19  $080000  INACTIVEWINDOW  A window deactivated
        20  $100000  DELTAMOVE        Report relative mouse movement
        If you want your first window to respond only by clicking on the
        close symbol,write the following:
            dc.l  $200  ;IDCMP flags:CLOSEWINDOW
        Next comes a long word whose bits determine the windows type.You 
        can use this to construct a window to your exact specifications. 
        This is quite different from windows opened with the DOS function.
        The bits mean:
        Bit  Value    Name            Meaning
        ------------------------------------------------------------------
        0  $0000001  WINDOWSIZING    Window size is changeable
        1  $0000002  WINDOWDRAG      Window is moveable
        2  $0000004  WINDOWDEPTH      Window covering is posible
        3  $0000008  WINDOWCLOSE      Window close symbol
        4  $0000010  SIZEBRIGHT
        5  $0000020  SIZEBOTTOM
        6  $0000040  SIMPLE_REFRESH  New drawing manuel
        7  $0000080  SUPER_BITMAP    Save the windows contents
        8  $0000100  BACKDROP        Move window back
        9  $0000200  REPORTMOUSE      Report mouse co-ordinates
        10  $0000400  GIMMEZEROZERO
        11  $0000800  BORDERLESS      Window without border
        12  $0001000  ACTIVATE        Window active
        13  $0002000  WINDOWACTIVATE
        14  $0004000  INREQUEST
        15  $0008000  MENUSTATE
        16  $0010000  RMBTRAP          Right mouse key:no menu
        17  $0020000  NOCAREREFRESH    No refresh message
        24  $1000000  WINDOWREFRESH
        25  $2000000  WBENCHWINDOW
        To refresh is to rebuild the window contents when necessary,for
        instance when the windows size is changed.If none of the refresh
        bits are set,you're in Smart-Refresh-Mode.In this case,Intuition
        takes care of refreshing the window.This is the easiest method.
        If you choose the value $100F as the type for your example window,
        the window is active once its opened,and it has all the system
        gadgets:
            dc.l  $100F      ;ACTIVATE and all gadgets
        The next long word in the list allows you to use your own gadgets
        in the window.This long word is a pointer to the structure of a
        your gadget.Since you don't want this,just put a zero here.
            dc.l  0          ;first gadget:no gadgets of our own
        The next long word is a pointer to a graphics structure so you can
        design your own symbol for checking menu points.Put a zero here.
        You'll use the standard sign:
            dc.l  windowname  ;pointer to window name
        The next long word is a pointer to the screen structure that you
        got back after calling the OpenScreen function.The easiest way to
        do this is to save the pointer to this location in the buffer:
        screenhd:  dc.l 0  ;screen pointer
        The next long word is a pointer to a bit map if you want one of
        your own for the window.Since you don't want one,put a zero here.
                dc.l  0        ;no bit map of our own
        Next come four values that set the maximum and minimum width and 
        height of the window:
                dc.w  150      ;smallest width
                dc.w  50      ;smallest height
                dc.w  320      ;maximum width
                dc.w  200      ;maximum height
        The last value in the list is the screen type of the screen the
        window is located in.Put a 15 here.You're using our screen as a 
        custom screen:
                dc.w  15      ;screen type:custom screen
        Heres a quick overview of the whole list:
            align
        window_prefs:
                      dc.w  10          ;X-position
                      dc.w  20          ;Y-position
                      dc.w  300          ;width
                      dc.w  150          ;height
                      dc.b  1            ;white print colour
                      dc.b  3            ;on red background
                      dc.l  $200        ;IDCMP flags:CLOSEWINDOW
                      dc.l  $100f        ;ACTIVATE and all gadgets
                      dc.l  0            ;first gadget:no gadgets of
                                          ;our own
                      dc.l  0            ;checkmark:standard
                      dc.l  windowname  ;pointer to window name
        screenhd:    dc.l  0            ;screen pointer
                      dc.l  0            ;no bitmap of our own
                      dc.w  150          ;smallest width
                      dc.w  50          ;smallest height
                      dc.w  320          ;maximum width
                      dc.w  200          ;maximum height
                      dc.w  15          ;screen type:custom screen
        ;and here comes the window name:
        windowname:  dc.b  'Our Window',0
            align
        Insert these lines in the program you listed above.Here are two 
        subroutines for opening and closing the window:
        openwindow  =-204
        closewindow =-72
              ...
        windopen:
              move.l  intbase,a6        ;intuition base address in A6
              lea    windowdef,a0      ;pointer to window definition
              jsr    openwindow(a6)    ;open window
              move.l  d0,windowhd      ;save window handle
              rts
        windclose:
              move.l  intbase,a6        ;intuition base address in A6
              move.l  windowhd,a0      ;window handle
              jsr    closewindow(a6)  ;close window
              rts
              ...
        windowhd:      dc.l  0          ;window handle
        Now you can insert a "bsr windowopen"after the "bsr scropen"and a
        "bsr windclose"before the "bsr scrclose"command.Once you've
        started the program,move the window around in the screen.You'll
        find that you can't move the window out of the screen with the
        mouse.
        The window in the example has the close gadget in the upper left
        corner.Normally if you click it,the window is closed.Try clicking
        it.You'll find that nothing happens.
        The display of this and all other gadgets,as well as other events
        must be programmed in,since Intuition doesn't know which action
        causes which event.We'll take a look at how to handle this in the
        next chapter.
      7.3.Requesters.
      ---------------
        If you only have one disk drive,you've certainly seen the Amiga 
        message,"Please insert xxx in unit 0",a lot.This window is another
        that has two fields for clicking.This sort of message with a
        choice of options is called a requester.                         
        You want to take a look at how to program a requester.First,you
        need a window for the requester to appear in.You opened a window
        of this sort in the example program.
        To display a requester,use the Intuition function AutoRequest
        (offset -348).It takes care of drawing and managing the requester.
        This function needs the following parameters:
        In A0  The pointer to the window structure that you put in
                "windowhd".
        In A1  A pointer to the text structure that should stand over the
                choice buttons.
        In A2  Same as above for the text of the left button.
        In A3  Same as above for the right button.
        In D0  The IDCMP flag which lets you know what event should go
                with the clicking of the left button.
        In D1  Same as above for the right button.
        In D2  The width of the whole requester.
        In D3  The height of the requester.
        Insert the following lines in your program:
        autorequest =-348
              ...
        request:
              move.l  windowhd,a0      ;pointer to window structure
              lea    btext,a1         
              lea    ltext,a2          ;pointer to text structure
              lea    rtext,a3       
              move.l  #0,d0            ;left activates by clicking
              move.l  #0,d1            ;right activates by clicking
              move.l  #180,d2          ;width and
              move.l  #80,d3            ;height of requester
              move.l  intbase,a6        ;intuition base address
              jsr    autorequest(a6)  ;display requester
              rts
        The flags passed in D0 and D1 offer some interesting posibilites.
        The system messages that tells you to enter a particular disk are
        overlooked when the DISKINSERTED flag is similar.Putting a disk in
        brings about the same responce as clicking the "Retry"button.
        Whats new is the use of a text structure.Use three of them.Text 
        structures are lists that contain entries for the text that you
        need.
        These lists begin with two bytes that are used to define the
        colour.The first byte is the colour of the text.The second is for
        the background colour.Here this doesn't have any meaning.
        btext:
              dc.b    2                ;black text colour
              dc.b    0                ;background colour
        The next byte specifies the character mode.A zero means that the
        text is output normally.A four means the text is output inverted.
              dc.b    0                ;normal text representation
        The next entries are words.For this reason the addresses must be
        even,so you need to either insert another byte or use the "align"
        pseudo-op.The following words are the X-and Y-position of the text
        relative to the upper left corner of the requester.
              dc.w    10                ;X-position
              dc.w    5                ;Y-position relative to upper
                                        ;left corner
        Next,theres a pointer to the character set that is used.Put a zero
        here to use the standard set.
              dc.l    0                ;standard character set
        Next you need to give the address of the text that should be
        output.This text must be closed with a null byte.
              dc.l    text              ;pointer to text
        You need a long word at the end of the list that is either a
        pointer to another text or a zero if no more text is needed.
              dc.l    0                ;no more text
        Here are the three text structures that you need for the example:
        btext:                          ;text structure for the title
              dc.b    0,1              ;colour
              dc.b    0                ;mode
              align
              dc.w    10,10            ;text position
              dc.l    0                ;standard font
              dc.l    bodytxt          ;pointer to text
              dc.l    0                ;no more text
        bodytxt:
              dc.b    "Requester Text",0
              align
        ltext:                          ;text structure of left button
              dc.b    0,1              ;colour
              dc.b    0                ;mode
              align
              dc.w    5,3              ;text position
              dc.l    0                ;standard font
              dc.l    lefttext          ;pointer to text
              dc.l    0                ;no more text
        lefttext:
              dc.b    "left",0
              align
        rtext:
              dc.b    0,1              ;colour
              dc.b    0                ;mode
              align
              dc.w    5,3              ;text position
              dc.l    0                ;standard font
              dc.l    righttext        ;pointer to text
              dc.l    0                ;no more text
        righttext:
              dc.b    "right",0
              align
        After calling the requester,D0 contains the information about
        which of the buttons were pressed,and in which button the event
        took place.If D0 is zero,it was the right button.If it is one,it
        was the left button.
      7.4.Event Handling.
      -------------------
        Pretend you've opened a window that as a close symbol,and you want
        the program to react to this symbol being clicked.You need a
        signal from Intuition that lets you know that an event as taken
        place.The signal is called a message.
        The IDCMP flag of the window specifies which events should cause
        Intuition to send a message.By setting the bits for WINDOWCLOSE, 
        you can allow a message to be sent when the close symbol is
        clicked.
        To get the message,you can use the EXEC function GetMsg (offset
        -372).It needs the source address of the event as a parameter.Here
        the source is the User port (which doesn't have anything to do
        with the User port on old Commodore computors).
        The User port contains a table which has entrieswhich specify the
        events that have taken place and related things like mouse
        position and time.
        How do you find the User port?Use the pointer to the window
        structure that you got back from the OpenWindow function and
        stored in the "windowhd"memory block.
        This pointer points to the window structure of this window.This
        structure consists of a number of entries.Some are copies of the
        parameters from our window definition table.We won't cover all the
        entries,because most won't be interesting to you.You're more
        interested in the pointer to the User port.Its in the window
        structure.
        You can find this in the long word that begins in the 86th byte of
        the structure.You can get this long word with the following lines
        of code:
              move.l  windowhd,a0      ;pointer to structure in A0
              move.l  86(a0),a0        ;user port pointer in A0
        You can call the GetMsg function with this pointer in A0 by using
        the following lines of code in your program:
        GetMsg  = -372
              ...
              move.l  windowhd,a0      ;pointer to structure in A0
              move.l  86(a0),a0        ;user port pointer in A0
              move.l  execbase,a6      ;exec base address in A6
              jsr    getmsg(a6)        ;get message
        This function returns a value in the D0 register.This value is a 
        pointer to another structure,the Intuition Message Structure.If
        theres a zero in D0,no event as taken place.
        The long word that starts at the 20th byte in this structure
        contains the information about which event took place.Evaluating
        the information is easy,since the bits of this long word have the
        same meaning as the IDCMP flag that you described when you looked
        at opening windows.
        Put the lines above after "loop"and then insert the following:
              move.l  d0,a0            ;message pointer in A0
              move.l  20(a0),d6        ;save event in D6
              tst.l  d0                ;did the event take place?
              bne    end              ;yes!
        Now you can end this program by clicking the close symbol.This way
        you can find out if an event as taken place.You can use D6 to
        determine what event took place.In the example,D6 contains the
        number $00000200,which means that the close symbol was clicked.
        To see if this works with other events,change the $200 IDCMP flag
        to $10200 in the window definition table.When you've assembled and
        started this version,take the disk out of the drive-the program
        terminates.
        The IDCMP flags that you've got now cause the clicking of the
        close symbol and the taking out of the disk (DISKREMOVED) to be
        reported.If you want to find out which of the events took place, 
        you can look in D6.It has a $200 in it if the window is closed,a 
        $10000 if the disk was removed.
      7.5.Menu Programming.
      ---------------------
        Now lets look at one of Intuitions more interesting capabillities:
        menu programming.By using menus,you can make your programs very
        user friendly.
        There are a lot of ways for you to use menus.You can make menu
        points unusable,output sub-menus,choose the type of menu entries 
        (allow text or pictures to be output),etc..To have lots of options
        you need some parameters.
        Lets produce a menu with the SetMenuStrip function (offset -264)
        of Intuition.The function only needs two parameters,a pointer to
        the menu structure of the window to be drawn and a pointer to the
        window structure of the window in which the menu is to function. 
        Each window can have its own menu that is active when the window
        is activated.
        Heres the subroutine to set up the menu:
        SetMenuStrip =-264
              ...
        setmenu:                        ;* Initialize a menu
              move.l  intbase,a6        ;intuition base address in A6
              move.l  windowhd,a0      ;pointer to window structure
              lea    menu,a1          ;pointer to menu structure
              jsr    setmenustrip(a6)  ;call function
              rts
        Heres a routine to erase the menu:
        ClearMenuStrip =-54
              ...
        clearmenu:
              move.l  intbase,a6        ;intuition base address in A6
              move.l  windowhd,a0      ;pointer to window structure
              jsr    clearmenustrip(a6)
              rts
        You've already got the pointer to the window structure.Lets look
        at the menu structure you need for the menu.You need to build a
        structure like this for each menu--for each menu title that
        appears when you press the right mouse key.
        This structure is a table with the following form:
        First there is a long word that points to the menu structure of
        the next menu.If the current menu is the last one,a zero goes
        here.
              align
        menu:
              dc.l    menu1            ;pointer to the next menu
        Next come two words which contain tha X- and Y-position of the
        menu title:
              dc.w    20                ;X-position
              dc.w    0                ;Y-position
        Next,use two words to store the menu titles width and height in
        pixels:
              dc.w    50                ;width
              dc.w    10                ;height of menu title
        The next word contains the flag bit that determines whether the
        menu is available or not.An unavailable menu either as grey
        entries or they are drawn weakly.If the flag bit,bit 0,is set the
        menu is available.Otherwise,it is not.
              dc.w    1                ;menu available
        Now comes a long word which functions as a pointer to the text
        which is used as the menu title.Make sure the length isn't larger
        than the width entry allows!Otherwise unpleasent things will
        happen.
              dc.l    menutext          ;pointer to title text
        Next comes a long word which functions as a pointer to the
        structure of the first menu entry of this menu.Each menu entry
        needs its own structure.
              dc.l    menuitem01        ;pointer to the first menu item
        The last entries in the table are four words that are reserved for
        internal functions.They must be here.
              dc.w    0,0,0,0          ;reserved words
        Thats the structure of the first menu.This structures first long
        word points to the next structure which has the same form.The
        pointer is set to zero in the last menu.
        You still need the structure of the menu entries.These structure
        tables have the following form:
        They start with a pointer to the next menu item.This pointer is
        set to zero for the last entry.
              align
        menuitem01:
              dc.l    menuitem02        ;pointer to next menu item
        Next comes the four words:the X- and Y-position,the width and the
        height of the box the menu entry goes in.The size becomes obvious
        when the item is chosen by having the right mouse key clicked on
        it.Then the box becomes visible.As you can see,the next word is 
        determined in the flags.First lets set the position and size of
        the menu point,though:
              dc.w    0                ;X-position of entry
              dc.w    0                ;Y-position
              dc.w    90                ;width in pixels
              dc.w    10                ;height in pixels
        The position entries are relative to the upper left corner of the
        menu that is pulled down.
        The following word was described above:it contains flags for
        entries to this menu item.There are several interesting variations
        possible.The following flag bits are contained in this word:
        Bit  Value  Name          Meaning When Set
        ------------------------------------------------------------------
        0    $0001  CHECKIT      Point is checked when chosen
        1    $0002  ITEMTEXT      Text menu item
        2    $0004  COMMSEQ      Choice can be made with keys as well
        3    $0008  MENUTOGGLE    Check turned on and off
        4    $0010  ITEMENABLED  Menu item available
        6    $0040  HIGHCOMP      Item inverted when chosen
        7    $0080  HIGHBOX      Iten framed when chosen
        8    $0100  CHECKED      Item is checked
        Heres a description of the bits:
        Name          Description
        ------------------------------------------------------------------
        CHECKIT        If this bit is set,a check or a user-defined
                      drawing is put in front of the text when the item 
                      is chosen.The text should begin with two blanks.
       
        ITEMTEXT      The menu item is a normal text if this bit is set.
                      Otherwise a drawing is output.
        COMMSEQ        By setting this bit and entering a character,this 
                      menu point can be chosen by pressing the right
                      <Amiga> key and the key that was input.The input 
                      character is then displayed in the menu with the
                      Amiga symbol.There needs to be space available for
                      this.
        MENUTOGGLE    If this bit is set and checking is allowed (bit 0),
                      the second time this point is chosen the check is
                      erased,the next time it is displayed again,etc...
        ITEMENABLED    Erasing this bit makes the menu item available.
        HIGHCOMP      If this bit is set,the box you've defined is
                      inverted when this menu item is chosen by the mouse
                      pointer.
        HIGHBOX        In this mode,the box is framed whin its chosen.
        The two previous bits determine the mode of the chosen menu item.
        The following combinations are possible:
        HIGHIMAGE      If both bits are cleared,choosing the bit causes a
                      self-defined drawing to be output.
        HIGHNONE      When both bits are set,there isn't any reaction to
                      choosing this item.
        CHECKED        This bit can be set by either the program or
                      Intuition.It lets you know if the menu text has a
                      check next to it or not.You can use this to find
                      out if the item was checked by testing but eight.If
                      its set,the item was checked.You can also use it to
                      cause the item to be checked.
        You're choosing the mode CHECKIT,ITEMTEXT,COMMSEQ,MENUTOGGLE,ITEM-
        ENABLED and HIGHBOX for the example:
              dc.w    $10011111        ;mode flag
        Lets get back to the structure of the menu items.After the flag
        word,there is a long word whose flag bits determine whether this 
        menu point can be turn off another one.Set this to zero:
              dc.l    0                ;no connection
        Now comes the pointer to the structure of the text that should be
        displayed.If the ITEMTEXT bit isn't set,this pointer must point to
        the structure of the drawing.If nothing should be shown,you can
        set this to zero.Use a text in the example and write the
        following:
              dc.l    menu01text        ;pointer to menu text structure
        The following long word only has a meaning if the HIGHIMAGE flag
        is set.Then this long word points to the text or the drawing that
        should be displayed when the menu items box is clicked.Otherwise 
        the long word is ignored,so insert a zero:
              dc.l    0                ;no drawing when clicked
        The next entry is a byte that is used for input of keyboard
        characters,which together with the right <Amiga> key can be used
        to choose the menu item.This only works if the COMMSEQ bit is set.
        Place a character here:
              dc.b    'A'              ;choose item using <Amiga>/'A'
        Since the next item is a long word,you need an "align"peudo-op
        here.Next comes the long word that points to the menu item
        structure or a submenu.The submenu is automatically shown when
        this menu item is clicked.You can't nest them any deeper,however,
        so this long word is ignored for submenus.
        If you don't want a submenu to this item,put a zero here:
          align
              dc.l    0                ;no submenu
        The next and final long word is written to by Intuition if you
        choose several menu itens.In this case,the menu number of the next
        menu item chosen goes here:
              dc.l    0                ;preparation
        Thats the structure for a menu item.You still need the text
        structure for the text of the item.This isn't complicated,but it
        makes you get into fine details about the form of the menu.You've
        already learned about this text structure when you looked at
        requesters,so we'll skip an explanation.
        Heres the complete structure of an example menu.You can use two
        menus,each with two subpoints.The second menu point of the left
        menu has a submenu with two entries.You ought to type this program
        in,so that you can experiment with it.You can also use this
        example to evaluate the clicked menu item.
        ;**Complete menu structure foe example menu **
        menu:
              dc.l menu1        ;no next menu
              dc.w 10,30        ;X/Y
              dc.w 50,10        ;width/height
              dc.w 1            ;menu enabled
              dc.l menuname      ;menu title
              dc.l menuitem01    ;menu entry
        menuname:
              dc.b "Menu 1",0    ;first menu name
          align
        menu1:
              dc.l 0            ;no further menu
              dc.w 80,0          ;see above
              dc.w 50,10
              dc.w 1
              dc.l menuname1
              dc.l menuitem11
              dc.w 0,0,0,0
        menuname1:
              dc.b "Menu 2",0    ;second menu name
          align
        menuitem01:              ;first menu item
              dc.l menuitem02    ;pointer to next entry
              dc.w 0,0          ;X/Y
              dc.w 130,12        ;width/height
              dc.w $9f          ;flags
              dc.l 0            ;exclude
              dc.l text01        ;pointer to text structure
              dc.l 0            ;select fill
              dc.b "1"          ;command
          align
              dc.l 0            ;subitem:none
              dc.w 0            ;next select:no
        text01:
              dc.b 0,1          ;colours
              dc.b 0            ;mode:overwrite
          align
              dc.w 5,3          ;X/Y position
              dc.l 0            ;standard character set
              dc.l text01txt    ;pointer to text
              dc.l 0            ;no more text
        text01txt:
              dc.b "Point 0.1",0
          align
        menuitem02:              ;second menu item
              dc.l 0
              dc.w 0,10
              dc.w 130,12
              dc.w $57
              dc.l 0
              dc.l text02
              dc.l 0
              dc.b "2"          ;activate with <Amiga>/'2'
          align
              dc.l 0
              dc.w 0
        text02:
              dc.b 0,1
              dc.b 0
          align
              dc.w 5,3
              dc.l 0
              dc.l text02txt
              dc.l 0
        text02txt:
              dc.b "Point 0.2",0
          align
        menuitem11:              ;first menu point of the second menu
              dc.l menuitem12    ;pointer to second menu point
              dc.w 0,0
              dc.w 90,12
              dc.w $52
              dc.l 0
              dc.l text11
              dc.l 0
              dc.b 0
          align
              dc.l 0
              dc.w 0
        text11:
              dc.b 0,1
              dc.b 0
          align
              dc.w 5,3
              dc.l 0
              dc.l text11txt
              dc.l 0
        text11txt:
              dc.b "Point 1.1",0
          align
        menuitem12:              ;second menu item of second menu
              dc.l 0            ;no more items
              dc.w 0,10
              dc.w 90,12
              dc.w $92
              dc.l 0
              dc.l text12
              dc.l 0
              dc.b 0
          align
              dc.l submenu0      ;pointer to submenu
              dc.w 0
        text12:
              dc.b 0,1
              dc.b 0
          align
              dc.w 5,3
              dc.l 0
              dc.l text12txt
              dc.l 0
        text12txt:
              dc.b "Point 1.2",0
          align
        submenu0:                ;first point of submenu
              dc.l submenu1      ;pointer to next point
              dc.w 80,5
              dc.w 90,12
              dc.w $52
              dc.l 0
              dc.l texts0
              dc.l 0
              dc.b 0
          align
              dc.l 0
              dc.w 0
        texts0:
              dc.b 0,1
              dc.b 0
          align
              dc.w 5,3
              dc.l 0,texts0txt,0
        texts0txt:
              dc.b "S Point 1",0
          align
        submenu1:                ;submenu,second item
              dc.l 0
              dc.w 80,15
              dc.w 90,12
              dc.w $52
              dc.l 0
              dc.l texts1
              dc.l 0
              dc.b 0
          align
              dc.l 0
              dc.w 0
        texts1:
              dc.b 0,1
              dc.b 0
          align
              dc.w 5,3
              dc.l 0
              dc.l texts1txt
              dc.l 0
        texts1txt:
              dc.b "S Point 2",0
          align
        The menu items in this example have the following properties as a
        result of their flags:
      Menu 1;
        The first item,"Point 0.1",can be chosen using the right <Amiga>
        key and the "1" key.This point alternates between checked and not
        checked,which can easily be used to check out the key function.If
        the item is checked and you hit both keys,the check disappears and
        vice versa.The box at this point is framed when the mouse pointer
        clicks on it.
        The second item,"Point 0.2",can be chosen using the right <Amiga>
        key and the "2"key.This item is checked the first time it is
        chosen.However,in contrast to the item above,it can't be erased. 
        The box of this item is inverted when clicked.
      Menu 2;
        These two points can't be chosen using keys.The box of the upper 
        item is inverted when clicked on:the lower one is framed.When you
        click the second item,"Point 1.2",a submenu with two entries is
        displayed.
        Experiment with this structure a little bit.Change some values and
        see what happens.As you can see,menu programming isn't as bad as
        you thought,and it offers a lot of options (but you'll have to do
        lots of typing!).
        When you've done experimenting,you'll want to produce your own
        program with menus.How does the program find whether a menu item
        in a menu has been clicked on?
        You already looked at one way to find out the menus state.You can
        test the CHECKED bit in the flag word of a menu item.If this is
        set,the user clicked on this item with the mouse.
        This only works if checking is allowed for the item being tested.
        You could allow all the menu items to be checked,but this still
        isn't a good solution--it requires testing all the flag bits of
        all the menus one after the other.That makes very boring
        programming.
        You've already learned about finding about events from Intuition.
        You've moved the message about which event took place into D6,and
        you can look at it to find out what happend.
        If you set the eight bit,the MENUPICK bit,of the IDCMP flag long
        word in the window definition,the choice of the menu point is
        reported.Put the following lines in your loop in the main program.
        loop:
              move.l  execbase,a6      ;exec base address in A6
              move.l  windowhd,a0      ;window structure pointer
              move.l  86(a0),a0        ;user point pointer in A0
              jsr    getmsg(a6)      ;get message
              tst,l  d0              ;whay happend?
              beq    loop            ;nothing happend
              move.l  d0,a0            ;message pointer in A0
              move.l  $14(a0),d6      ;event in D6
        If the program makes it out of the loop,an event as taken place. 
        You have the events flag in the D6 register.You can evaluate the 
        event using CMP or BTST to find out which flag bits are set.You
        can then execute the function corresponding to the set bit.You can
        use lines like the following ones:
              cmp    #$200,d6        ;WINDOWCLOSE?
              beq    ende            ;yes:program end
        These lines terminate the program when the window is closed.
        If the user chose a menu item,there is a $100 in the D6 register.
        You now need to determine which item it was.
        You can find this information in a word that comes right after the
        long word with the event flags in the message structure.Write:
              move    $18(a0),d7
        You now have the code for the clicked menu item in the D7
        register.If the user just pressed the right key and let it go
        without choosing a menu item,you'll find a $FFFF here.This word
        doesn't contain just one,but three pieces of information:
          Which menu was the item chosen from?
          Which menu item?
          Which submenu?
        The information is divided in three bit groups.The division is as
        follows:
        Bits  0-4  Menu title number
        Bits  5-10  Menu item number
        Bits 11-15  Submenu item number
        The numbering begins with zero-ie the first menu point of the
        first menu has the numbers 0 and 0.
       
        To try this out insert the following lines:
              move    d7,d6            ;move code into D6
              lsr    #8,d7            ;shift right 11 times
              lsr    #3,d7            ;submenu item now in D7
              clr.l  d5
              roxr    #1,d6            ;bit 0 in X-flag
              roxl    #1,d5            ;menu number now in D5
              and.l  #$7f,d6          ;issolate lower bits
              cmp    #$7f,d6          ;no menu item?
              beq    loop            ;no:continue
              lsr    #4,d6            ;else menu item in D6
              ende
        By making a test run with AssemPro,you can easily see if this
        works right-just look at the registers after the program is over.
        If you,for example,want to write a program with four menus with 10
        menu items each,this sort of method is too much work-there are 44
        tables.For this reason,lets look at a short program that takes
        care of the necessary structure table itself.
        The menu structure is built very simply-it doesn't offer submenus
        or the option of choosing items via the keyboard.If you want these
        extras,you can still use this program,but you'll have to use MOVE
        commands to insert the desired flags and pointers.
        The input that this program needs is a list of the menu names and
        the items in each menu.The addresses of the menu texts go in a
        table with the following simple form:
              dc.l  Menu title 1
              dc.l  Point1,Point2,Point3,...,0
              dc.l  Menu title 2
              dc.l  Point1,Point2,Point3,...,0
              dc.l  Menu title 3 oder 0
        This program is set up in such a way that up to four menus can lie
        next to each other (in normal screen resolution),which is often
        plenty.The table above ends by putting a zero instead of a pointer
        to the nxt menu title.As you can see,its pretty simple.
        This program is inserted in your big program right behind the
        "setmenu"label.After the "bsr setmenu"command is executed,the menu
        structure is built and initialized at the same time.You don't need
        to change the rest of the program,it'll be shorter that way.
        Heres the program fragment for the complete "setmenu"routine:
        setmenu:                        ;*initialize menu structure
              lea    mentab,a0        ;pointer to text pointer in A0
              lea    menu,a1          ;pointer to menu field in A1
              move    #10,d1          ;horizontal menu position=10
        menuloop:
              clr.l  d2              ;vertical menu position=0
              move.l  a1,a2            ;save address of pointer
              tst.l  (a0)            ;another menu there?
              beq    setmenu1        ;no:quit
              clr.l  (a1)+            ;"no more menus"preperations
              move    d1,(a1)+        ;set X-position
              add.l  #70,d1          ;and increment
              move.l  #50,(a1)+        ;Y-position and width
              move.l  #$a0001,(a1)+    ;height and flag
              move.l  (a0)+,(a1)+      ;menu title
              lea    12(a1),a3
              move.l  a3,(a1)+        ;pointer to menu item
              clr.l  (a1)+            ;reserved words
              clr.l  (a1)+
        itemloop:
              tst.l  (a0)            ;last entry?
              beq    menuend          ;yes:menu done
              lea    54(a1),a3
              move.l  a3,(a1)+        ;pointer to next item
              move.l  d2,(a1)+        ;X- and Y-positions
              add    #10,d2          ;Y-position+10
              move.l  #$5a000a,(A1)+  ;WIDTH/HEIGHT
              move    #$52,(a1)+      ;flag:normal
              clr.l  (a1)+            ;no connection
              lea    16(a1),a3
              move.l  a3,(a1)+        ;text structure pointer
              clr.l  (a1)+            ;no fill structure
              clr.l  (a1)+            ;no command,no submenu
              clr.l  (a1)+            ;and no continuation
              move    #$1,(a1)+        ;set text structure:colour
              clr.l  (a1)+            ;mode 0
              move.l  #$50003,(a1)+    ;X- and Y-position
              clr.l  (a1)+            ;standard character set
              move.l  (a0)+,(a1)+      ;text pointer
              clr.l  (a1)+            ;no continuation
              bra    itemloop        ;next item...
        menuend:                        ;eventual transfer to next menu
              clr.l  -54(a1)          ;erase pointer to next item
              tst.l  (a0)+            ;increment table pointer
              tst.l  (a0)            ;another menu there?
              beq    setmenu1        ;no:done
              move.l  a1,(a2)          ;pointer to next menu
              bra    menuloop        ;and continue
        setmenu1:                      ;*initialize menu (like before)
              move.l  intbase,a6      ;intuition base address in A6
              move,l  windowhd,a0      ;window structure in A0
              lea    menu,a1          ;pointer to menu structure
              jsr    setmenustrip(a6)
              rts
        You need three things yet for this program:the memory to be used
        for the structure,the table of text pointers and the text.Heres an
        example:
        mentab:
              dc.l menu1              ;first menu title
              dc.l mp11,mp12,mp13      ;menu items
              dc.l 0                  ;end of menu 1
              dc.l menu2              ;second menu title
              dc.l mp21,mp22,mp23      ;menu items
              dc.l 0                  ;end of menu 2
              dc,l 0                  ;you're out of menus!
        ;** Menu Text **
        menu1: dc.b "Menu 1",0
        mp11:  dc.b "Point11",0
        mp12:  dc.b "Point12",0
        mp13:  dc.b "Point13",0
        menu2: dc.b "Menu 2",0
        mp21:  dc.b "Point21",0
        mp22:  dc.b "Point22",0
        mp23:  dc.b "Point23",0
            align
        ;** Storage space for menu structure **
        menu:  blk.w 500
        Make sure that the memory area reserved for the menu structure is
        big enough and change the entry "blk.w 500"to the calculated
        value.
        If you use this program,and want to build some special features
        into the menu (for instance key commands),you can make entries in
        the menu structure table while the program is running.You can find
        the word (or byte or long word) that interests you in the table as
        follows:
        For example,to find the keyboard command byte of the second entry
        in the first menu,calculate as follows:
        Address = Start_address+Menu*30+(entry-1)*54+26
        which in the example comes to:
        Address = menu+30+54+26
                = menu+110
        The 26 is the distance from the beginning of the MenuItem
        structure to the desired byte,the command byte.In this way,you can
        calculate the addresses and use MOVE commands to modify the menu
        to fit your wishes.By the way,in the example above,the correspond-
        ing flag bit must be set as well,so that the keyboard command is 
        recognized.
        Now lets get back to the window.Its nice to have a window that you
        can change and close,but you really want to be able to output text
        in a window!
      7.6.Text Output.
      ----------------
        Its very easy to use Intuition's text output function.Use the
        PrintIText function (offset -216).It needs four parameters.
        In A0    A pointer to the RastPort of the window.You can find this
                in the window structure.
        In A1    A pointer to the text structure of the text that should
                be output.
        In D0    The X-position.
        In D1    The Y-position of the text in the window.
        Its very easy to enter the X- and Y-positions.You've already used
        the text structure twice (for requesters and menus).
        Whats new is accessing the windows RastPort.The RastPort is a
        structure that describes the window.The address is needed by
        several Intuition functions.
        The pointer to the RastPort starts at the 50th byte in the window
        structure.You can access it as follows:
            move.l  windowhd,a0          ;address of window structure
            move.l  50(a0),a0            ;RastPort address in A0
        Now you've got the address of the RastPort.Lets write a routine
        that prints a text.The X- and Y-positions are in D0 and D1
        respectively and the address of the text structure in A1 before
        the routine is called:
        PrintIText = -216
              ...
        print:
              move.l  intbase,a6      ;intuition base address in A6
              move.l  windowhd,a0      ;address of window structure
              move.l  50(a0),a0        ;rastport address in A0
              jsr    printitext(a6)  ;call function
              rts
        You can try out this routine by using the requesters text that is
        still in a structure of the program.Write the following lines
        before the "loop"label:
              lea    btext,a1        ;pointer to text structure in A1
              move.l  #10,d0          ;X-position
              move.l  #30,d1          ;Y-position of text
              bsr    print            ;output text
        Start the program and the text appears in the middle of the window
        If this doesn't happen,check the colour of the text in the text 
        structure.Its probably zero.Just change it to three,and the text 
        appears in red the next time you start the program.
      7.7.Images.
      -----------
        An image is a drawing that goes in a rectangular field and is
        defined bitwise.The disk symbol of the Intuition screen and the 
        system gadgets in the screen and window borders are examples of
        such Images.
        The rectangle that the drawing goes in can be arbitrarily large, 
        but each pixel in the rectangle needs its own bit,so programming 
        screen-sized Images isn't advisable.You'll stick to an Image that
        requires about 32x16 bits-an Image thats about 3x1cm.
        You can make all sorts of images as you've seen looking at window
        gadgets.There is an Intuition functionthat draws an Image:It is
        the DrawImage function (offset -114) and it needs 4 parameters:
        In A0  The address of the rastport image is drawn in.You've
                already learned how to access this address in the section
                on the text function.
        In A1  The structure address of the image to be drawn.
        In D0  The relative X-position
        In D1  The relative Y-position of the drawing.
        Lets draw this picture in your window.It justs takes a simple
        routine.You just need to put the address of the image structure in
        A1 and the position of the image in D0 and D1 before you call it.
        DrawImage =-114
              ...
        draw:                          ;*draw image
              move.l  intbase,a6      ;intuition base address in A6
              move.l  windowhd,a0      ;pointer to window structure
              move.l  50(a0),a0        ;now,rastport address in A0
              jsr    drawimage(a6)    ;draw image
              rts
        Now you need the structure of the image.The structure contains
        nine entries which have the following meanings:
        The first two entries are words which specify the distance in the
        X- and Y-direction from the co-ordinates that were given to tell 
        where the image should be drawn.You'll just put two zeros here:
        image:
              dc.w  0,0                ;X- and Y-position
        Next come two words which specify the width and height of the
        image in pixels.Lets draw a 32x13 point image.Enter:
              dc.w  32,13              ;width and height of image
        The next word in the list specifies the number of planes in the
        drawing.If its a simple image that only uses two colours,just
        enter a one.For more colours,you'll need a correspondingly bigger
        number.When more colurs are worked with,the bit pattern of the
        image must have more data.Lets just have one bit plane:
              dc.w  1                  ;one bitplane:2^1=2 colours
        Next comes a long word that points to the data of the image:
              dc.l  imgdata            ;pointer to image data
        The next two bytes are very interesting.The first byte,the
        PlanePick byte,tells which plane of the window or screen the image
        data should be written in.Since you only have one plane,you need
        to enter the bit plane of the window.This information is found in
        the bits of the byte-bit0 stands for plane 0,bit 1 for plane 1,etc
        ..You also define the colour of the image with this input.If you
        enter a two,every set bit of your image represents a red point.
              dc.b  2                  ;drawing red:plane 1
        The second byte,the PlaneOnOff byte,is an interesting enhancement.
        Each bit of the window bit plane corresponds to a whole number
        here.The only bytes that are interesting though are the ones that
        are cleared in the PlanePick byte.If the bit is set in PlaneOnOff,
        evert bit of the image in the corresponding plane is set.Otherwise
        they are cleared.To make sure that each bit of the image that
        isn't set appears white,enter a one.All the bits of the image that
        aren't set,are set in Plane 1 and appear white.
              dc.b  1                  ;background:white
        The last entry of the structure is a lobg word that points to
        another image.You don't need this,so set the long word to zero:
              dc.l  0                  ;no more images
        Heres a quick overview of the image structure:
     
        image:
              dc.w  0,0                ;X- and Y-positions
              dc.w  32,13              ;width and height of image
              dc.w  1                  ;one bitplane:2^1=2 colours
              dc.l  imgdata            ;pointer to image data
              dc.b  2                  ;drawing red:plane 1
              dc.b  1                  ;background:white
              dc.l  0                  ;no more images
        Now lets produce the image data.Each image row uses a word,long
        word,or several of these represent the pattern.The set points of
        the image correspond to the set bits.This is repeated as often as
        the height of the image requires.The data on each line must begin
        on a word border,on a even address.
        For the example,its easy to decide on the data,since you're going
        32 points across-that corresponds to exacty one long word.Its
        easiest to program the image using the binary representation of
        the data.
        Lets use,as an example,an image that represents a switch in "OFF"
        mode.This form is chosen for a good reason,so you should type it
        in.In the chapter on gadgets thats coming up,we'll show you how to
        turn the switch on.Here is the example data for the switch image:
        imgdata:  ;Data for switch in "OFF" mode
          dc.l    %00000000000000000000000000000000
          dc.l    %00000000000000000000111000000000
          dc.l    %00011101110111000001111100000000
          dc.l    %00010101000100000001111100000000
          dc.l    %00010101100110000001111000000000
          dc.l    %00011101000100000011100000000000
          dc.l    %00000000000000000111000000000000
          dc.l    %00000000000000001110000000000000
          dc.l    %00000000000111111111100000000000
          dc.l    %00000000001111111111110000000000
          dc.l    %00000000001111111111110000000000
          dc.l    %00000000000110000001100000000000
          dc.l    %00000000000000000000000000000000
        Once you've typed in this data,you can experiment with displaying
        it on the screen.Enter the following lines before the "loop"label:
            move.l  image,a1          ;pointer to image structure
            move    #30,d0            ;X-postion in window
            move    #50,d1            ;Y-position
            bsr    draw              ;draw image
        How do you like the image on the screen?You'll run into this
        switch again when we talk about putting the switch in the "ON"   
        state when discussing gadgets.You need to look at other methods of
        drawing in the window first,though.
      7.8.Borders.
      ------------
        A border is a collection of lines that are connected.They can be
        of any length or at any angle.Intuition lets you draw borders to
        do things like put frames around windows and screens.They are used
        to put borders around pictures or text,especially for use with
        string gadgets.We'll talk about that later,though.
        Its easy to draw borders.Just use the Intuition function
        DrawBorder (offset -108) which needs four parameters:
        In A0  The rastport address of the output medium the lines should
                be drawn in.Use your window.
        In A1  The address of the border structure.We'll look at the form
                of this structure shortly.
        In D0  The relative X-co-ordinate which is used with the X- and Y
                co-ordinate list to calulate the actual line co-ordinates.
        In D1  The relative Y-co-ordinates.Relative,here too,means that
                this is relative to the upper left corner of the screen.
        Lets write a short routine that is called with three parameters. 
        The structure address in A1 and the X and Y co-ordinates are in D0
        and D1 respectively when the routine is called.The border is drawn
        in the window whose structure address is in "windowhd".
        DrawBorder =-108
              ...
        borderdraw:                    ;* draw several lines
              move.l  inbase,a6        ;intuition base address in A6
              move.l  windowhd,a0      ;pointer to window structure
              move.l  50(a0),a0        ;now rastport address in A0
              jsr    drawborder(a6)  ;draw lines
              rts
        Now lets look at the border structure.The list needs the eight
        following parameters:
        First,you need two words for the vertical and horizontal distance
        from the co-ordinates given in the function call.To avoid losing 
        sight of some of the many distance entries,put two zeros here:
        border:
              dc.w  0                  ;horizontal distance
              dc.w  0                  ;vertical distance
        Next come two bytes that determine the colour.Use a red frame:
              dc.b  3                  ;red frame
              dc.b  0                  ;background (unused)
        As you can see,the background colour isn't used.You have two modes
        to choose between for drawing the lines.The following mode
        determines the mode that is used.If it is zero,each line is drawn
        in the colour chosen,no matter what was done before.This is the
        JAM1 mode.The other mode is the XOR mode which ignores both colour
        entries.In this mode,all the points that lie under the line have
        their colour value inverted.As a result,a white point becomes
        black,and a blue one becomes red.That is mode two.Lets use the
        JAM1 mode for the example:
              dc.b  0                  ;mode:JAM1 (2=XOR)
        The next entry specifies how many co-ordinate pairs there are in
        the list.Since this word must be on an even address,you need to
        use the "align"peudo-op first.Then enter the number of pairs.   
        Remember that you need three points to draw two lines:beginning, 
        corner and end point.To draw a rectangular frame,you need five
        pairs:
              dc.b  5                  ;5 X,Y pairs used together
        The next item is a pointer to the co-ordinate table that contains
        a list of points to be connected:
              dc.l  coord              ;pointer to cordinate table
        The border structures final entry is a long word that can point to
        another border structure.If you don't have any more structures to
        be pointed to,just enter a zero here.The pointer is useful for
        connecting two independant border structures-for example,to
        produce a two coloured frame that really stands out.You don't need
        this pointer in the example,though:
              dc.l  0                  ;no more structures
        Thats the border structure.Now lets look at the co-ordinate list.
        For the example,it consists of five pairs of numbers which
        represent a rectangle.I recommend entering these values,because
        you'll use them in example programs further down the line.
        coord:                          ;coordinates for rectangle frame
              dc.w  -2,-2
              dc.w  80,-2
              dc.w  80,9
              dc.w  -2,9
              dc.w  -2,-2
        Heres a quick overview of the border structure:
        border:
              dc.w  0                  ;horizontal distance
              dc.w  0                  ;vertical distance
              dc.b  3                  ;red frame
              dc.b  0                  ;background (unused)
              dc.b  0                  ;mode:JAM1 (2=XOR)
              dc.b  5                  ;5 X,Y pairs used together
              dc.l  coord              ;pointer to cordinate table
              dc.l  0                  ;no more structures
        coord:                          ;coordinates for rectangle frame
              dc.w  -2,-2
              dc.w  80,-2
              dc.w  80,9
              dc.w  -2,9
              dc.w  -2,-2
        Once you've typed this in,you can try the whole thing out.Type the
        following lines before the "loop"label in the program:
              lea    border,a1        ;address of the border structure
              move    #20,d0          ;X base position
              move    #80,d1          ;Y base position
              bsr    drawborder      ;draw frame
        As you can see,using enough X and Y co-ordinates,you can draw the
        Eiffel tower.Thats enough about simple drawings.You want to put
        some life into your drawings and text.Lets manipulate them with
        the mouse!
      7.9.Gadgets.
      ------------
        We already talked a bit about gadgets when you looked at screen
        construction.Looking at system gadgets like the window close
        symbol,you can activate by clicking and causes a program function
        to be executed.
        You can make your own gadgets as well.Intuition allows you a lot
        of interesting possibilities.
       
        There are four types of gadgets:
        Boolean gadgets are used in Yes/No situations.You can click and
        activate it (Yes) or deactivate it (No).
        String gadgets are used to accept input of text of a specified
        length.
        Integer gadgets are a special sort of string gadgets which accept
        the input of a decimal number.Intuition converts the value into a
        long word and sends it to the program.
        Proportional gadgets let you choose an analog value with the mouse
        You can move these around with the mouse.
      7.9.1.Boolean Gadgets.
      ----------------------
        Lets start with the simplest type,the boolean gadget.an example of
        this sort of gadget is the close symbol of the window.The only
        status it differenciates between are clicked and not clicked.Lets
        develop a gadget of this type step by step.The flags and other   
        parameters are similar for the other gadgets.
        Each gadget needs a structure containing fifteen entries.There is
        a pointer to this structure in window,screen or requester that the
        gadget is to appear in.Theres always a long word available for
        this purpose.Up to this point,you've just put a zero there.If
        there is an address of a gadget structure there,the gadget or
        gadgets are displayed when the window is opened.
        A gadget structure as the following entries:
        The first long word is a pointer to the next gadget to be
        installed.The gadgets are displayed in a row,like pearls on a
        string.This pointer is the first gadget in this linked list of
        gadgets.If you just want one gadget in your window,put a zero
        here:
     
        gadget1:
              dc.l  0                  ;no more gadgets
        The next two words determine the position of the gadget in the
        window.There are several ways to determine the position.Use flags
        to access the various possibilities.Lets start with a gadget that
        stays in one spot:
              dc.w  40                ;X and
              dc.w  50                ;Y position of the gadget
        The next two words determine the size of the gadgets Hit box.This
        box isn't the visible size of the gadget (that depends on the
        image data).It is the size of the rectangle that Intuition should
        watch.If the mouse pointer is moved into this box and the left
        button pressed,the gadget is activated.Clicking on parts of the
        gadget that are outside this box have no effect!
              dc.w  32                ;width and
              dc.w  13                ;height of the hit box
        Next comes the word whose bits determine the properties of the
        gadget.Bits 0 and 1 determine what should happen when this objects
        hit box is clicked on.The meanings of the various values of these
        bits go as follows:
        Bit 0  1  Value  Name          Meaning
        ------------------------------------------------------------------
        0      0    0    GADGHCOMP    The gadget inverted
        0      1    1    GADGHBOX      The gadget framed
        1      0    2    GADGHIMAGE    Another image appears
        1      1    3    GADGHNONE    No reaction
        Bit 2 determines whether the gadget should consist of a drawing or
        a border.If it is set(Value+4),it is treated as an image;otherwise
        its treated like a border.
        The next bit determines if the gadget should appear in the upper
        or lower border of the frame.If it is set(Value+8).the position is
        relative to the lower border;otherwise it is relative to the upper
        border.The next bit as the same meaning for the horizontal
        position.If set(Value+$10),it is a relative positioning.Otherwise,
        it is an absolute positioning.
        Notice that when you define a gadget to be relative,you must have
        a negative value in the position input in the first word of the
        structure.Since the desired position isn't under,but its over this
        position!
        In this way,you can choose either absolute or relative positioning
        of the gadget.An example of a gadget that is positioned absolutely
        is the system gadget,close window.An example of a relative gadget
        is the symbol for changing the size.
        The width and height of the gadgets hit box can also be relative
        to the window size.Specify this by using bit 5 for width (Value +
        $20)and bit 6 for the height (Value +$40).A set bit mens a
        relative size.
        Bit 7 (Value+$80)makes the object active as soon as the window is
        opened.
        Bit 8 (Value+$100)determines whether the gadget can be used or not
        If this bit is set,the gadget can't be activated.
        For the example,you'll use absolute positioning and size,the
        inverted appearance for the activated gadget,and the
        representation of the object as an image.That means you must use
        the value four:
              dc.w  4              ;flags:image,invert
        Next comes a word whose bits are used as flags.This flag is called
        the Activation Flag.It determines the functions of the gadget.The
        bits,their values and meanings follow:
        Bit  Value  Name            Meaning
        ------------------------------------------------------------------
        0    1      RELVERIFY      Causes the gadget to be activated
                                      only when the left mouse key is let
                                      loose over the gadget.
        1    2      GADGIMMEDIATE  Lets the gadget be active as soon as
                                      there is a click.
        2    4      ENDGADGET      Lets you choose to end this choice
                                      and have it disappear if this is a 
                                      requester gadget.
        3    8      FOLLOWMOUSE    Lets the gadget know the mouse
                                      position at regular intervals from
                                      the time it is selected until the
                                      time it is deselected.You can use
                                      this to move the gadget with the
                                      mouse when you want to change the
                                      gadget position.
        4    $10    RIGHTBORDER    This makes sure thay when borders
                                      are used that the page is adjusted
                                      to the size of the gadget so that it
                                      fits in the border.
        5    $20    LEFTBORDER
        6    $40    TOPBORDER
        7    $80    BOTTOMBORDER
        8    $100  TOGGLESELECT    Allows the objects state to change 
                                      every time it is clicked.If
                                      activated,it becomes deactivated and
                                      vice versa.
        9    $200  STRINGCENTRE    For a string gadget,these two bits 
                                      determine whether the string should
                                      appear centred or right justified.If
                                      neither is set,the string is output
                                      left justified.
        10    $400  STRINGRIGHT
        11    $800  LONGINT        Turns a string gadget into a Integer
                                      gadget (explanation later).
        12    $1000  ALTKEYMAP      Causes another ketboard placement to
                                      be in effect for string gadget input
        Thats it for the activation flags.Lets choose the TOGGLESELECT and
        GADGETIMMEDIATED flags for example:
            dc.w  $102            ;activation
        The next word of the gadget structure determines the gadget type.
        Heres the meaning of the individual bits:
        Bit  Value  Name            Meaning(report what circumstances)
        ----------------------------------------------------------------
        0    1      BOOLGADGET      This is a boolean gadget
        1    2      GADGET002     
        2    4      STRGADGET      String order Integer gadget
        0+1    3      PROPGADGET      Proportional gadget
        System gadgets:
        4    $10    SIZING          Size changing gadget
        5    $20    WDRAGGING      Moving gadget for window
        4+5    $30    SDRAGGING      Same for screen
        6    $40    WUPFRONT        Gadget to move window forward
        6+4    $50    SUPFRONT        Gadget to move screen forward
        6+5    $60    WDOWNBACK      Move window back
        6+5+4  $70    SDOWNBACK      Move screen back
        7    $80    CLOSE          Window close gadget
        Type definitions:
        12    $1000  REQGADGET      Requester gadget
        13    $2000  GZZGADGET      Border gadget in GIMMEZEROZERO
                                      window
        14    $4000  SCRGADGET      Screen gadget when set
        15    $8000  SYSGADGET      System gadget when set
        You want to use a simple boolean gadget for your example,so enter:
              dc.w  1                ;gadget type:boolean
        Next comes a pointer to the gadget structure.The first pointer
        contains the address of the image or border structure which should
        be used to represent the gadget.If no representation is needed,put
        a zero here.You want to represent the gadget as an image,so put a
        pointer to the image structure that you produced in the chapter
        about images:
              dc.l  image            ;gadget image
        The next pointer is only used if the GADGHIMAGE flag in the flag
        word of the structure is set.This is a pointer to another
        structure that should be put on the screen when the object is
        activated.If a border structure is used for the gadget represent-
        ation,this must be a border structure as well.You won't use a
        second image,so put a zero here:
              dc.l  0                ;no new gadget displayed
        The next pointer is to the text structure that should be output by
        the gadget.If no text is needed,just put a zero here.You want to
        use some text,however:
              dc.l  ggtext          ;gadget text
        Now comes a long word that determines which gadgets are
        deactivated when this is activated.This function still doesn't
        work right so put a zero here:
              dc.l  0                ;no exclude
        You'll set the next pointer to zero as well,because it is only
        used for String and Proportional gadgets.For these gadgets,this is
        a special structure to describe the characteristics of the gadget.
        Its called SpecialInfo.
              dc.l  0                ;no SpecialInfo
        The next word contains the Gadget Identification (ID) number:
              dc.w  1                ;gadget ID
        Finally there is a long word that doesn't have any function,so put
        a zero here:
              dc.l  0                ;user data (ignore)
        Thats it.Heres a quick overview of the gadget structure:
        gadget1:
              dc.l  0                ;no more gadgets
              dc.w  40              ;X and
              dc.w  50              ;Y position of gadget
              dc.w  32              ;width and
              dc.w  13              ;height of hit box
              dc.w  4                ;flags:image,invert
              dc.w  $102            ;activation flags
              dc.w  1                ;gadget type:boolean
              dc.l  image            ;gadget image
              dc.l  0                ;no new gadget displayed
              dc.l  ggtext          ;gadget text
              dc.l  0                ;no exclude
              dc.l  0                ;no SpecialInfo
              dc.w  1                ;gadget ID
              dc.l  0                ;user data (ignore)
        You've already prepared a structure that you can use for this
        image.Now you need the text that appears under the gadget.
        Since the gadget looks like a switch,label it "switch".The text
        structure looks like this:
        ggtext:
              dc.b  1,0              ;colours
              dc.b  1                ;mode
          align
              dc.w  -8,14            ;X and Y position
              dc.l  0                ;standard font
              dc.l  swtext          ;pointer to text
              dc.l  0                ;no more text
        swtext:
              dc.b  "switch",0
          align
        Once you've typed this in,save it,assemble it and start again.You
        can click the switch and cause it to be inverted.Click it again, 
        and it appears normal.
        Now you can experriment with the structure.If you change the flag
        from four to five,you can cause the gadget to be framed when it is
        activated.Set the RELVERIFY bit(bit0:+1)in the Activation Flag
        word.Then you can move the mouse pointer onto the object and press
        the button.It is activated.Keep the mouse button pressed down and
        move the mouse.Once you leave the hit box,the activation disapears
        This way,you can avoid accidently activating a gadget.
        Now you want to display the switch in an on state.This is easy.All
        you need to do is produce another image structure,one for the on 
        state.You put this pointer in the long word right after the
        pointer to the normal image structure.You can change the flag word
        to six which causes a second image to be displayed when the gadget
        is activated.
        Here is the image structure for the switch in the one state.
        image2:
              dc.w  0,0              ;no offset
              dc.w  32,13            ;32x13 pixels
              dc.w  1                ;mode 1
              dc.l  imgdata2        ;pointer to the data
              dc.b  2,1              ;same colours as before
              dc.l  0                ;nothing else
     
        imgdata2:                    ;data for switch in the On state
              dc.l  %00000000000000000000000000000000
              dc.l  %00000000011100000000000000000000
              dc.l  %00000000111110000011101001000000
              dc.l  %00000000111110000010101101000000
              dc.l  %00000000011110000010101011000000
              dc.l  %00000000000111000011101001000000
              dc.l  %00000000000011100000000000000000
              dc.l  %00000000000001110000000000000000
              dc.l  %00000000000111111111100000000000
              dc.l  %00000000001111111111110000000000
              dc.l  %00000000001111111111110000000000
              dc.l  %00000000000110000001100000000000
              dc.l  %00000000000000000000000000000000
        Now the state of the object can be determined by looking at the
        picture.If the gadget is activated,the switch is on.If not,the
        switch is off.
        Thats it for boolean gadgets.You can learn about the things you
        did'nt touch with some experimentation.You want to get to the
        string gadgets that also do some interesting things.
      7.9.2.String Gadgets.
      ---------------------
        Lets pretend you want a program to load data from the disk.To get
        the user to enter the filename,you need to output text telling the
        user to enter the name.Then you need to call an input routine to
        evaluate the keyboard input.
        Its easier and more elegant to use a String gadget.This function 
        allows for easy input and/or editingof short text.You have the
        option of having the text framed.The Undo function can be used by
        pressing the right <Amiga> key and a "Q",and the old contents of
        the gadget,the old text are restored.
        You can also vary the size of the text and the input field.If the
        text is longer than the input field is wide,the text is moved back
        and forth through the visible area when you move the cursor keys
        or the normal input to the border.
        You can also restrict input to just digits.This makes it posible
        to accept numeric input.Intuition even converts the digit string 
        into a binary number.This saves the machine language programmer
        some work.A specialized String gadget of this sort is called a   
        Integer gadget.
        The structure is similar to the Boolean gadgets structure.There
        are only two major differences:
        The type word of the structure must be a four to declare that this
        is a String gadget (STRGADGET).
 
        The pointer to the SpecialInfo structure is needed.Put a pointer
        to the StringInfo structure that you are going to design later
        here.
        The width and height entries in the gadget structure have a
        different meaning than they had previously.They do declare the
        area in which you can bring the mouse pointer to activate the
        String gadget.However,it is also used for representation of text.
        These values determine the size of the box in which the text is
        output.You should surround the box with a border using the Border
        function,so that the user can see where it is.
        If the text is longer than the box,only a portion of it is seen on
        the screen.You can move through the area by entering text or using
        the left/right cursor keys to move through the box.The characters
        that are entered are inserted at the cursor position,so the rest
        of the text is shifted by one character when you are on the right
        edge of the input area.The following functions can be used for
        editing this text:
        Cursor key left/right
              Moves the cursor over the text thats already on hand.Moves
              the text through the Container.
        Cursor keys with <Shift>
              Puts the cursor on the beginning or the end of the text.
        <Del> Deletes the character under the cursor.
        <Backspace>
              Deletes the character to the left of the cursor.
        <Return>
              Ends text input.
        <Amiga>right+"Q"
              This is the Undo function.It replaces the text with the
              original contents.
        The StringInfo structure only has a few entries:
        First theres a pointer to the memory area that is used to store
        the text that is input.The memory buffer must be big enough to
        handle all the text entered.
        strinfo:
              dc.l  strpuffer        ;pointer to text buffer
        Next comes the pointer to the Undo buffer.This pointer and this
        buffer are only needed if you want the Undo function.If you do,you
        must have a buffer that is at least as big as your text buffer. 
        Every time the string gadget function is called,the text buffers 
        contents are copied into this buffer.To get the old contents back,
        just press the right <Amiga>key and the "Q"key.The contents of the
        Undo buffer are copied back to the text buffer.If you use several
        string gadgets in a program,you can use the same Undo buffer for
        all of them,since only one string gadget is used at one time.
              dc.l  undo            ;pointer to undo buffer
        The following word contains the cursor position in the text.You 
        should set this word to zero,so that the user can see the
        beginning of the text when the string gadget appears.
              dc.w  0                ;cursor position
        The next word contains the maximum number of characters that can
        be input.If you type one more than this number of characters,the 
        screen blinks,to show that you can't enter a longer input string.
        The number of characters and the reserved space for the input
        field don't have to agree,since text can be scrolled by typing.
              dc.w  10              ;maximum # of characters
        The following word tells at which character of text in the buffer,
        the output to the box should begin.You should put a zero here,so
        that the user can see the beginning of the text.
              dc.w  0                ;output text from this character
        The next five words are used by Intuition,so you don't have to   
        initialize them.Just put zeros here.The words contain the
        following information:
              dc.w  0                ;character position in undo buffer
              dc.w  0                ;number of chars in text buffer
              dc.w  0                ;number of chars visible in box
              dc.w  0                ;horizontal box offset
              dc.w  0                ;vertical box offset
        The next two long words are initialized by Intuition as well:
              dc.l  0                ;pointer to rastport
              dc.l  0                ;long word with value of the input
        ;                            ;(for integer gadgets)
        The final entry is a pointer to the keyboard table that is used if
        the ALTKEYMAP flag of the gadget is set.
              dc.l  0                ;standard keyboard table
        Heres a quick overview of the StringInfo structure:
        strinfo:
              dc.l  strpuffer        ;pointer to text buffer
              dc.l  undo            ;pointer to undo buffer
              dc.w  0                ;cursor position
              dc.w  10              ;maximum # of characters
              dc.w  0                ;output text from this character
              dc.w  0                ;character position in undo buffer
              dc.w  0                ;number of chars in text buffer
              dc.w  0                ;number of chars visible in box
              dc.w  0                ;horizontal box offset
              dc.w  0                ;vertical box offset
              dc.l  0                ;pointer to rastport
              dc.l  0                ;long word with value of input
        ;                            ;(for integer gadgets)
              dc.l  0                ;standard keyboard table
        Here are the text and undo buffers:
        strpuffer:
              dc.b  "Hello!",0,0,0
        undo:
              dc.l  0,0,0,0
          align
        Once you've entered these lines,you can either alter the old
        gadget structure or build a new one.We'd recommend building
        another gadget structure so that you can have the switch and use
        it later.Change the first pointer in the old structure from zero
        to "gadget1"and insert this new structure.Here is an example
        strucure for the string gadget.It as the following entries:
        gadget1:                      ;*structure for string gadget
              dc.l  0                ;no more gadgets
              dc.w  20,80            ;position
              dc.w  80,10            ;width and height of box
              dc.w  0                ;flags:normal
              dc.w  2                ;activation($802 for long int)
              dc.w  4                ;type:string gadget
              dc.l  border          ;pointer to border
              dc.l  0                ;no drawing selected
              dc.l  0                ;no text
              dc.l  0                ;no exclude
              dc.l  strinfo          ;pointer to stringinfo structure
              dc.w  2                ;gadget ID
              dc.l  0                ;no user data
        border:                      ;*border for box frame
              dc.w  0,0              ;no offset
              dc.b  3,3              ;red colour
              dc.b  0                ;mode:JAM1
              dc.b  5                ;5 X,Y pairs
              dc.l  coord            ;pointer to coordinates table
              dc.l  0                ;no more structures
        coord:                        ;*coordinates for frame
              dc.w  -2,-2            ;start in upper left corner
              dc.w  80,-2            ;upper right
              dc.w  80,9            ;lower right
              dc.w  -2,9            ;lower left
              dc.w  -2,-2            ;back to beginning
        This data causes a red rectangle,the border,to appear around the 
        "Hello!"text.You can change the text by clicking in the field and
        editing once the cursor appears.If you type something wrong,you
        can use the undo function(the right <Amiga> key and the Q key),to
        get "Hello!"back.
        Once you've done some typing and deactivated the gadget by
        pressing <Return> or by clicking outside the field (cursors
        disapear),you can terminate the program.
        Change the activation flag to $802 and the "strbuffer"to "dc.l
        0,0,0,0",assemble,and then start the program.You can type in the
        string gadget once it has been activated,but you can only enter
        digits.The screen blinks if you enter letters.
        Enter a number,and then end the program after deactivating the
        gadget.If you look at the stringinfo structure you can look at the
        value of the number you input(in hex)in the eight long word.
        After looking at boolean,text and numeric input to gadgets,lets
        look at Proportional gadgets which allow the user to enter analog
        values by moving a symbol.
      7.9.3.Proportional Gadgets.
      ---------------------------
        You've seen the advantages of slider devices over knobs that you
        turn,maybe on a hifi,maybe on a toaster,but certainly someplace.
        Its easier to tell the state the item is in with a slider,
        especially if several such devices are next to each other(for
        example graphic equalizers).You can represent sliders on the
        Amigas screen and work with them with the mouse.This offers a nice
        way to represent information graphically in your programs.
        You can do this with gadgets.Using Proportional gadgets,you can
        put a symbol in a frame and move horzontally and/or vertically.The
        size of the frame and the slider can be variable size,so that the
        frame size is relative to the screen size so when the window
        changes size,it will also.The slider can be set up so that its
        size in the grows or shrinks.
        These are best seen via example and experimentation.(The
        posibilities mentioned do not form a complete list by any stretch
        of the imagination.)You want to set up a simple Proportional
        gadget that can be moved horizontally.
        You need a gadget structure that as the same form as others.To
        show the differences,heres a complete example structure for your 
        gadget.You can connect this gadget to the other one,by changing
        the first long word in the last structure to "dc.l gadget2".
        gadget2:                      ;*structure for Proportional gadget
              dc.l  0                ;no more gadgets
              dc.w  150,30          ;position
              dc.w  100,10          ;width and height of frame
              dc.w  4                ;flags:GADGIMAGE
              dc.w  2                ;activation:GADGIMMEDIATE
              dc.w  3                ;type:proportional gadget
              dc.l  mover            ;pointer to slider data
              dc.l  0                ;no select structure
              dc.l  0                ;no text
              dc.l  0                ;no exclude
              dc.l  propinfo        ;pointer to propinfo structure
              dc.w  3                ;gadget ID
              dc.l  0                ;no user data
        You see two special features.Use an image structure for the mover
        and put a pointer to another structure in the spot for the Special
        Info pointer.
        First,lets look at the "mover"structure,the sliders image
        structure.Heres an example of this structure:
        mover:                        ;*structure for slider image
              dc.w  0,0              ;no offset
              dc.w  16,7            ;16x7 pixels big
              dc.w  1                ;one bit plane
              dc.l  moverdata        ;pointer to image data
              dc.b  1,0              ;colour:white
              dc.l  0                ;don't continue
        moverdata:                    ;*image data for mover
              dc.w %0111111111111110
              dc.w %0101111111111010
              dc.w %0101011111101010
              dc.w %0101010110101010
              dc.w %0101011111101010
              dc.w %0101111111111010
              dc.w %0111111111111110
        Up till now,there was'nt anything new.Now lets look at the
        PropInfo structure that describes the properties of the
        Proportional gadget.
        The structure starts with a flag word that contains the following
        bits:
        Bits  Value  Name              Meaning
        -----------------------------------------------------------------
        0      1    AUTOKNOB          Mover is set up automatically
        1      2    FREEHORIZ        Allows horizontal movement
        2      4    FREEVERT          Allows vertical movement
        3      8    PROPBORDERLESS    Turns off automatic framing
        8      $100  KNOBHIT          Set when the mover is touched
        You can set the first four bits to get the representation that you
        want.Bit 8 is set by Intuition when the mover is clicked with the
        mouse pointer.
        Bit 0,AUTOKNOB,allos for the simplest sort of Proportional gadget.
        If this bit is set,no move data are used for the mover image.
        Instead,a white mover is generated that is adjusted to the size of
        the box and the values to be represented.When you use this slider
        to represent the displayed lines in a long text of a program,the
        displayed lines are a percentage of the total text.The
        relationship between the total number of lines and the lines shown
        is represented by an AUTOKNOB as the relationship between the
        frame and the slider.The bigger the percentage,the bigger the
        slider is.You don't want to work with this though,even though it
        is simple and interesting,because a simple white button isn't
        particularly attractive.If you experiment with it,make sure that
        the pointer to the image data points to a four word long buffer
        that Intuition can use to store values.The buffer is of the
        following form:
        buffer:
              dc.w  0                ;X position of the slider in the box
              dc.w  0                ;Y position in the box
              dc.w  0                ;width of slider
              dc.w  0                ;height of slider
        Leys look at the PropInfo structure.Since you're not using
        AUTOKNOB and wish to allow horizontal movement only,put two in as
        a flag:
        propinfo:
              dc.w  2                ;flags:FREEHORIZ
        In the next two words of the structure,the horizontal (HorizPot)
        and vertical (VertPot) position of sliders are stored.A value of 
        zero means left or upper,while the value $FFFF means right or
        lower.The value that results from movement is in this range.You
        set these values to zero at the start of the program.After moving
        the mouse,there is different values here.
              dc.w  0,0              ;X and Y position of the slider
        Next come two words which determine the size of the AUTOKNOB or
        the step size of the slider(this determines how far the slider
        moves when you click in the box next to the slider).These words
        are called HorizBody (horizontal movement) and VertBody (vertical
        movement).
              dc.w  $ffff/16        ;horizontal step size:1/16
              dc.w  0                ;no vertical movement
        ;The next six words are initialized by Intuition.
              dc.w  0                ;box width
              dc.w  0                ;box height
              dc.w  0                ;absolute step size horizontal
              dc.w  0                ;and vertical
              dc.w  0                ;left border of box
              dc.w  0                ;upper border of box
        Thats it.Heres a quick overview of the PropInfo structure:
       
        prpoinfo:
              dc.w  2                ;flags:FREEHORIZ
              dc.w  0,0              ;X and Y position of slider
              dc.w  $ffff/16        ;horizontal step size:1/16
              dc.w  0                ;no vertical movement
              dc.w  0                ;box width
              dc.w  0                ;box height
              dc.w  0                ;absolute step size horizontal
              dc.w  0                ;and vertical
              dc.w  0                ;left border of box
              dc.w  0                ;upper border of box
        Once you've typed this in,you can start the program and try it
        out.
        You can also try vertical movement by setting the flag word equal
        to six,the vertical step size to $FFFF/10,and the height of the
        gadget to 80,for the example.To try out the AUTOKNOBs,change the 
        flag value to seven.
      7.10.Example Program.
      ---------------------
        Here is a complete example program using what you have learned in
        this chapter:
        ;7_Intuition.asm
        ;** Demo-Program for working with Intuition **
        movescreen    =-162
        openscreen    =-198
        closescreen  =-66
        openwindow    =-204
        closewindow  =-72
        autorequest  =-348
        setmenustrip  =-264
        clearmenustrip=-54
        printitext    =-216
        drawimage    =-144
        drawborder    =-108
        displaybeep  =-96
        closelibrary  =-414
        openlib      =-408
        execbase      = 4
        getmsg        =-372
        joy2          =$dff0c
        fire          =$bfe001
        ;!!!when > 500kb !!!
        ;org $40000
        ;load $40000
        ; or use AssemPro to place in CHIP RAM
        ;!!!!!!!!!!!!!!!!!!!!!!!
        run: 
              bsr    openint
              bsr    scropen
              bsr    windopen
              bsr    setmenu
              bsr    print
              lea    border,a1
              move    #22,d0
              move    #30,d1
              bsr    borderdraw
             
              bsr    draw
             
              bsr    request
        loop:
              move.l  execbase,a6
              move.l  windowhd,a0
              move.l  86(a0),a0        ;user port
              jsr    getmsg(a6)
              tst.l  d0
              beq    loop            ;no event
              move.l  d0,a0
              move.l  $16(a0),msg      ;event:LO=item,HI=Event
              move.l  msg,d6          ;to test
              move.l  d6,d7
              lsr    #8,d7
              lsr    #3,d7            ;sub menu point in D7
              clr.l  d5
              roxr    #1,d6
              roxl    #1,d5            ;menu number in D5
              and.l  #$7f,d6
              cmp    #$7f,d6          ;no menu point?
              beq    loop            ;no:continue
              lsr    #4,d6            ;menu point in D6
              cmp    #1,d6            ;point 2?
              bne    no1
              move,l  intbase,a6
              move.l  screenhd,a0
              jsr    displaybeep(a6)
        no1:
              cmp    #0,d6
              bne    loop
        ende:
              bsr    clearmenu
              bsr    windclose
              bsr    scrclose
              bsr    closeint
              rts
        openint:
              move.l  execbase,a6
              lea    intname,a1
              jsr    openlib(a6)
              move.l  d0,intbase
              rts
        closeint:
              move.l  execbase,a6
              move.l  intbase,a1
              jsr    closelibrary(a6)
              rts
        scropen:
              move.l  inbase,a6
              lea    screen_defs,a0
              jsr    openscreen(a6)
              move.l  d0,screenhd
        scrclose:
              move.l  inbase,a6
              move.l  screenhd,a0
              jsr    closescreen(a6)
              rts
        scrmove:
              move.l  intbase,a6
              move,l  screenhd,a0
              jsr    movescreen(a6)
              rts
        windopen:
              move.l  intbase,a6
              lea    windowdef,a0
              jsr    openwindow(a6)
              move.l  d0,windowhd
              rts
        windclose:
              move.l  intbase,a6
              move.l  windowhd,a0
              jsr    closewindow(a6)
              rts
        request:
              move.l  windowhd,a0
              lea    btext,a1
              lea    ltext,a2
              lea    rtext,a3
              move.l  #0,d0
              move.l  #0,d1
              move.l  #180,d2
              move.l  #80,d3
              move.l  intbase,a6
              jsr    autorequest(a6)
              rts
        setmenu:
              lea    mentab,a0        ;pointer to text pointer in A0
              lea    menu,a1          ;pointer to menu field in A1
              move    #10,d1          ;menu position = 10
        menuloop:
              clr.l  d2              ;menu point-Y=0
              move.l  a1,a2            ;save pointer
              tst.l  (a0)
              beq    setmenu1        ;end
              clr.l  (a1)+
              move    d1,(a1)+
              add.l  #70,d1
              move.l  #50,(a1)+
              move.l  #$a0001,(a1)+
              move.l  (a0)+,(a1)+      ;menu title
              lea    12(a1),a3
              move.l  a3,(a1)+        ;menu point
              clr.l  (a1)+
              clr.l  (a1)+
        itemloop:
              tst.l  (a0)            ;last one?
              beq    menuend          ;yes
              lea    54(a1),a3
              move.l  a3,(a1)+        ;pointer to next point
              move.l  d2,(a1)+        ;X/Y
              add    #10,d2
              move.l  #$5a000a,(a1)+  ;width/height
              move    #$52,(a1)+
              clr.l  (a1)+
              lea    16(a1),a3
              move.l  a3,(a1)+        ;text structor-pointer
              clr.l  (a1)+
              clr.l  (a1)+
              clr.l  (a1)+
              move    #$1,(a1)+        ;text-structor set
              clr    (a1)+
              move.l  #$50003,(a1)+
              clr.l  (a1)+
              move.l  (a0)+,(a1)+      ;text pointer
              clr.l  (a1)+
              bra    itemloop        ;next point...
        menuend:
              clr.l  -54(a1)
              tst.l  (a0)+
              tst.l  (a0)            ;still in menu?
              beq    setmenu1        ;no:ready
              move.l  a1,(a2)          ;pointer to next menu
              bra    menuloop        ;and continue
        setmenu1:
              move.l  intbase,a6
              move.l  windowhd,a0
              lea    menu,a1
              jsr    setmenustrip(a6)
              rts
        clearmenu:
              move.l  intbase,a6
              move.l  windowhd,a0
              jsr    clearmenustrip(a6)
              rts
        print:
              move.l  intbase,a6
              move.l  windowhd,a0
              move.l  50(a0),a0
              lea    ggtext,a1
              move.l  #30,d0          ;X
              move.l  #16,d1          ;Y
              jsr    printitext(a6)
              rts
        draw:
              move.l  intbase,a6
              move.l  windowhd,a0
              move.l  50(a0),a0
              lea    image,a1
              move.l  #200,d0
              move.l  #100,d1
              jsr    drawimage(a6)
              rts
        borderdraw:
              move.l  intbase,a6
              move.l  windowhd,a0
              move.l  50(a0),a0
              jsr    drawborder(a6)
              rts
        screen_defs:
              dc.w  0,0
              dc.w  640,200
              dc.w  4
              dc.b  0
              dc.b  1
              dc.w  $800
              dc.w  15
              dc.l  0
              dc.l  tite1
              dc.l  0
              dc.l  0
        windowdef:
              dc.w  10,20
              dc.w  300,150
              dc.b  0,1
              dc.l  $300
              dc.l  $100f
              dc.l  gadget
              dc.l  0
              dc.l  windname
        screenhd:
              dc.l  0
              dc.l  0
              dc.w  200,40,600,200
              dc.w  $f
        btext:
              dc.b  3,3
              dc.b  0
              align
              dc.w  10,10
              dc.l  0
              dc.l  bodytxt
              dc.l  0
     
        bodytxt:dc.b  "Requester-Text",0
              align
        ltext:
              dc.b  3,1
              dc.b  0
              align  dc.w 5,3
              dc.l  0
              dc.l  lefttext
              dc.l  0
        lefttext: dc.b "left",0
              align
        rtext:
              dc.b  0,1
              dc.b  0
              align  dc.w 5,3
              dc.l  0
              dc.l  righttext
              dc.l  0
        righttext: dc.b "right",0
              align
        tite1: dc.b  "User Screen",0
        windname: dc.b "Window-Title",0
              align  windowhd: dc.l 0
        intbase:dc.l  0
        intname:dc.b  "intuition.library",0
              align  msg:dc.l 0
        mentab:
              dc.l  menu1
              dc.l  mp11,np12,mp13,mp14,mp15,mp16,mp17,mp18,mp19,0
              dc.l  menu2
              dc.l  mp21,mp22,mp23,0
              dc.l  menu3
              dc.l  mp31,mp32,0
              dc.l  menu4,mp41,0
              dc.l  0
        menu1: dc.b  "Menu 1",0
        mp11:  dc.b  "Point 11",0
        mp12:  dc.b  "Point 12",0
        mp13:  dc.b  "Point 13",0
        mp14:  dc.b  "Point 14",0
        mp15:  dc.b  "Point 15",0
        mp16:  dc.b  "Point 16",0
        mp17:  dc.b  "Point 17",0
        mp18:  dc.b  "Point 18",0
        mp19:  dc.b  "Point 19",0
        menu2: dc.b  "Menu 2",0
        mp21:  dc.b  "End!",0
        mp22:  dc.b  "Beep",0
        mp23:  dc.b  "Point 23",0
 
        menu3: dc.b  "Menu 3",0
        mp31:  dc.b  "Point 31",0
        mp32:  dc.b  "Point 32",0
        menu4: dc.b  "Menu 4",0
        mp41:  dc.b  "Point 41",0
              align
        gadget:
              dc.l  gadget1
              dc.w  20,80,80,10
              dc.w  0
              dc.w  $2              ;activation,$802 for longint
              dc.w  4
              dc.l  border
              dc.l  0
              dc.l  0
              dc.l  0
              dc.l  strinfo
              dc.w  2
              dc.l  0
        border:
              dc.w  0,0
              dc.b  1,0,0
              dc.d  5              ;XY-pair
              dc.l  koord
              dc.l  0
        koord:
              dc.w  -2,-2,80,-2,80,9,-2,9,-2,-2
        strinfo:
              dc.l  strpuffer
              dc.l  undo
              dc.w  0              ;cursor position
              dc.w  10              ;max.char
              dc.w  0 
              dc.w  0,0,0,0,0
              dc.l  0,0,0
        strpuffer:
              dc.b  "Hello!",0,0,0
       
        undo:  dc.l  0,0,0
              align
        gadget1:
              dc.l  gadget2          ;more gadget
              dc.w  40,50,32,13
              dc.w  $6                ;flags:invert
              dc.w  $103              ;activate
              dc.w  1                ;gadget type
              dc.l  image            ;gadget image
              dc.l  image2            ;select gadget
              dc.l  ggtext            ;gadget text
              dc.l  0                ;no exclude
              dc.l  0                ;special info
              dc.w  1                ;ID
              dc.l  0                ;user data
        ggtext:
              dc.b  1,0,1
              align
              dc.w  -8,14
              dc.l  0
              dc.l  swtext
              dc,l  0
     
        swtext:
              dc.b  "Switch",0
              align
        image:
              dc.w  0,0
              dc.w  32,13
              dc.w  1
              dc.l  imgdata
              dc.b  2,1
              dc.l  0
        image2:
              dc.w  0,0
              dc.w  32,13
              dc.w  1
              dc.l  imgdata2
              dc.b  2,1
              dc.l  0
        imgdata:
              dc.l 0
              dc.l %00000000011100000000000000000000
              dc.l %00000000111110000011101001000000
              dc.l %00000000111110000010101101000000
              dc.l %00000000011110000010101011000000
              dc.l %00000000000111000011101001000000
              dc.l %00000000000011100000000000000000
              dc.l %00000000000001110000000000000000
              dc.l %00000000000111111111100000000000
              dc.l %00000000001111111111110000000000
              dc.l %00000000001111111111110000000000
              dc.l %00000000000110000001100000000000
              dc.l 0
        imgdata2:
              dc.l 0
              dc.l %00000000000000000000111000000000
              dc.l %00011101110111000001111100000000
              dc.l %00010101000100000001111100000000
              dc.l %00010101100110000001111000000000
              dc.l %00011101000100000011100000000000
              dc.l %00000000000000000111000000000000
              dc.l %00000000000000001110000000000000
              dc.l %00000000000111111111100000000000
              dc.l %00000000001111111111110000000000
              dc.l %00000000001111111111110000000000
              dc.l %00000000000110000001100000000000
              dc.l 0
        gadget2:
              dc.l  0
              dc.w  150,30,100,50
              dc.w  5
              dc.w  2
              dc.w  3                  ;prop.gadet
              dc.l  mover              ;border
              dc.l  0,0,0
              dc.l  specinfo
              dc.w  3
              dc.l  0
        specinfo:
              dc.w  6                  ;flags:free horiz
              dc.w  0,0
              dc.w  $ffff/10,$ffff/5
              dc.w  0,0,0,0,0,0
        mover:
              dc.w  0,0,16,7
              dc.w  1
              dc.l  moverdata
              dc.b  1,0
              dc.l  0
        moverdata:
              dc.w %0111111111111110
              dc.w %0101111111111010
              dc.w %0101011111101010
              dc.w %0101010110101010
              dc.w %0101011111101010
              dc.w %0101111111111010
              dc.w %0111111111111110
        menu:blk.w  500
              end
             
             
      Chapter 8.
      ----------
      8.Advanced Programming.
      -----------------------
        You've learned a lot about machine language programming on the
        Amiga.What you need yet are a few routines that can be used as
        programming tools.We'll work on that right now.They'll be easy to
        use in your own program.The sky's the limit now!
      8.1.Supervisor Mode.
      --------------------
        As mentioned in the chapter on the MC68000 processor,there are two
        operating modes:the User and the Supervisor mode.It is often
        necessary to move between the two modes.However,this isn't a
        simple process.
        The reason you want to do this,is that in User mode,you can't
        access the Status register.If you write to one of them,an
        Exception is executed which crashes the program.
        How can you get in Supervisor mode?
        No problem.The operating system of the Amiga contains a function
        in the EXEC library that lets you get into supervisor mode.Its
        called SuperState and it doesn't need any parameters.You can
        easily call this program by using the following lines:
        execbase    = 4                ;exec base address
        superstate  =-150              ;turn on function
              ...
              move.l  execbase,a6      ;exec base address in A6
              jsr    superstate(a6)  ;turn on supervisor mode
              move.l  d0,savesp        ;save return value
              ...
        savesp:blk.l  1                ;space for sp value
        You get the value of the Stack Pointer(SP)back in the D0 register.
        You'll also find it in register A7,but this register is changed 
        regularly.The reason is that in Supervisor mode,the Amiga works
        with all the Interrupts and with the SP,and there are lots of   
        Interrupts for this computor.We'll talk about interrupts in a bit.
        After this call,you'll use the user stack instead of the
        supervisor stack.In this way,you can access the old user stack.You
        need to make sure that the user stack is large enough since the 
        interrupts must have enough room for their data on the stack.
        You need to save the value returned in D0,because you'll need this
        value later.You need to return to user mode sometime.Theres a
        function for this in the exec library as well.It is called the   
        UserState function.It needs one parameter,the SP value that comes
        back from the SuperState function.
        Since you've saved this value in the long word starting at
        "savesp",you can write the following:
        userstate    =-156
              ...
              move.l  execbase,a6      ;exec base address in A6
              move.l  savesp,d0        ;put old sp in D0
              jsr    userstate(a6)    ;return to user mode
        Now you are back in the user mode.The user stack point(USP)is the
        same as before.You can write functions that need to be run from
        the supervisor mode as subroutines.First you call superstate,save
        the return value,execute the desired function,call userstate,and 
        end with a RTS command.If the USP was changed,the RTS command   
        would'nt work right,and the computor would jump who knows where
        and perhaps crash.Here it works though.
        Now comes the question:how does the operating system get the
        supervisor mode?Thats not too difficult;it goes like this:
        The superstate function attempts to access a Status Register.This
        causes an Exception to occur and a routine is called whose address
        begins at the long word starting at $20.It is the Exception Vector
        for Privilege Violation.The routine that it branches to is called
        in supervisor mode.Then it tests where this exception came from.If
        the routine finds that the exception comes from the superstate   
        routine whose address it knows,the matter is settled.It just
        branches to the routine without turning off the user mode.Thats
        all there is to it.
      8.2.Exception Programming.
      --------------------------
        The exceptions described in the processor chapter offer you a lot
        of oppertunities to control the Amiga's functions.You can use them
        to specify how errors should be handled and even list a crash
        program.
        Here is a list of vectors that are used to jump to the exception 
        routines:
        Number      Address          Use with
        ------------------------------------------------------------------
          2        $008            Bus error
          3        $00C            Address eror
          4        $010            Illegal command
          5        $014            Division by zero
          6        $018            CHK command
          7        $01C            TRAPV command
          8        $020            Privilege Violation
          9        $024            Trace
        10        $028            Axxx command emulation
        11        $02C            Fxxx command emulation
                    $030-$038        Reserved
        15        $03C            Uninitialized interrupt
                    $040-$05F        Reserved
        24        $060            Unauthorised interrupt
        25-31      $064-$083        Level 1-7 interrupt
        32-47      $080-$0BF        TRAP commands
                    $0C0-$0FF        Reserved
        64-255      $100-$3FF        User interrupt vector
        Lets look at the TRAP commands as an example.They aren't used in
        the Amiga operating system.A TRAP command and a number between
        zero and fifteen are used to call one of the 16 posible TRAP
        routines.If the command TRAP #0 is executed,the processor (in
        supervisor mode)branches to the routine whose address lies at $80
        in memory.This routine must end with a RTE(ReTurn from Exception)
        command.
        Some operating systems,for example,the ATARI ST's TOS operating 
        systems,are completely callable via these TRAP's.Parameters are
        put on the stack,and then a TRAP command is executed.The advantage
        is that you don't have to know any of the operating systems
        addresses.In the Amiga you must know the addresses(Execbase=4).
        Lets write your own TRAP routine to demonstrate the use of the
        TRAP command.You'll need three program sections:
        1.The initialization of the TRAP vector.
        2.The TRAP routine itself(It must end with RTE).
        3.A test routine that calls the TRAP command.
        Initialization is very short:
        init:
              move.l  #trap0,$80        ;set vector for TRAP #0
              rts
        Now you need to write the trap0 routine.Lets use the example from
        the hardware chapter that produced a beep.
        Lets write this routine using as little effort as possible.Change
        the RTS to a RTE at the end,erase the line in which the loop
        counter D0 was loaded for the tone production,and change the loop
        so that it works with long words.Now you can load the register
        with an arbitrary value and have the TRAP #0 followed by a peep of
        arbitrary duration.
        ;** beep tone production after a TRAP #0 **
        ctlw  =$dff096                  ;DMA control
        c0thi  =$dff0a0                  ;HI table address
        c0tlo  =c0thi+2                  ;LO table address
        c0tl  =c0thi+4                  ;table length
        c0per  =c0thi+6                  ;read in rate
        c0vol  =c0thi+8                  ;volume
        trap0:                          ;* produce a short peep
              move.l  #table,c0thi      ;table beginning
              move    #4,c0tl          ;table length
              move    #300,c0per        ;read in rate
              move    #40,c0vol        ;volume
              move    #$8201,ctlw      ;start DMA (sound)
        loop:
              subq.l  #1,d0            ;counter -1
              bne    loop              ;count dwn to zero
        still:
              move    #1,ctlw          ;turn on tone
              rte                      ;exception end
        table:                          ;sound table
              dc.b    -40,-70,-40,0,40,70,40,0
        You need to make sure that "table"is in CHIP RAM($00000-$7FFFF),
        otherwise the sound chip can't access the data!
        After entering this,you can test it out using the following
        routine:
        test:
              move.l  #$2ffff,d0        ;pass tone length in D0
              trap    #0                ;carry out exception:peep
              rts
        Now assemble both routines and start the initialization routine, 
        init.Nothing happens.
        Start the second routine,test.A beep that lasts about one second
        is output.
        One thing you must keep in mind is that if you change the program
        and reassemble it,the address of the trap0 routine can change.   
        Before you execute the TRAP command,you must repeat the initializ-
        ation,so that the computor doesn't jump to the wrong location!             
       
      Appendices.
      -----------
      Overview of Library Functions.
      ------------------------------
        The following table gives you an overview of the available
        libraries and their functions.Each sublist of functions is
        preceded by the name of the library it is found in.
        These functions are listed with their negative offset in hex and 
        decimal.Their name and their parameters are also specified.The   
        parameter names are in parenthesis behind the function name.The 
        second set of parenthesis includes a list of registers that
        correspond to the parameter names.If no parameters are needed,we 
        put () to let you know.
CLIST.LIBRARY
  -$001E  -30            InitCLPool (cLPool,size) (A0,D0)
  -$0024  -36            AllocCList (cLPool) (A1)
  -$002A  -42            FreeCList (cList) (A0)
  -$0030  -48            FlushCList (cList) (A0)
  -$0036  -54            SizeCList (cList) (A0)
  -$003C  -60            PutCLChar (cList,byte) (A0,D0)
  -$0042  -66            GetCLChar (cList) (A0)
  -$0048  -72            UnGetCLChar (cList,byte) (A0,D0)
  -$004E  -78            UpPutCLChar (cList) (A0)
  -$0054  -84            PutCLWord (cList,word) (A0,D0)
  -$005A  -90            GetCLWord (cList) (A0)
  -$0060  -96            UnGetCLWord (cList,word) (A0,D0)
  -$0066  -102            UnPutCLWord (cList) (A0)
  -$006C  -108            PutCLBuf (cList,buffer,length) (A0,A1,D1)
  -$0072  -114            GetCLBuf (cList,buffer,maxLength) (A0,A1,D1)
  -$0078  -120            MarkCList (cList,offset) (A0,D0)
  -$007E  -126            IncrCLMark (cList) (A0)
  -$0084  -132            PeekCLMark (cList) (A0)
  -$008A  -138            SplitCList (cList) (A0)
  -$0090  -144            CopyCList (cList) (A0)
  -$0096  -150            SubCList (cList,index,length) (A0,D0.D1)
  -$009C  -156            ConcatCList (sourceCList,destCList) (A0,A1)
CONSOLE.LIBRARY
  -$002A  -42            CDInputHandler (events,device) (A0,A1)
  -$0030  -48            RawKeyConvert (events,buffer,length,keyMap)
                                        (A0,A1,D1,A2)
DISKFONT.LIBRARY
  -$001E  -30            OpenDiskFont (textAttr) (A0)
  -$0024  -36            AvailFonts (buffer,bufBytes,flags) (A0,D0,D1)
DOS.LIBRARY
  -$001e  -30            Open (name,access mode)(d1,d2)
  -$0024  -36            Close (file)(d1)
  -$002a  -42            Read (file,buffer,length)(d1,d2,d3)
  -$0030  -48            Write (file,buffer,length)(d1,d2,d3)
  -$0036  -54            Input()
  -$003c  -60            Output()
  -$0042  -66            Seek(file,position,offset)(d1,d2,d3)
  -$0048  -72            DeleteFile (name)(d1)
  -$004e  -78            Rename(oldname,newname)(d1,d2)
  -$0054  -84            Lock(name,type)(d1,d2)
  -$005a  -90            UnLock(lock)(d1)
  -$0060  -96            DupLock(lock)(d1)
  -$0066  -102          Examine(lock,fileinfoblock)(d1,d2)
  -$006c  -108          ExNext(lock,fileinfoblock)(d1,d2)
  -$0072  -114          Info(lock,parameterblock)(d1,d2)
  -$0078  -120          CreateDir(name)(d1)
  -$007e  -126          CurrentDir(lock)(d1)
  -$0084  -132          IoErr()
  -$008a  -138          CreateProc(name,pri,seglist,stacksize)(d1,d2,d3,d4)
  -$0090  -144          Exit(returncode)(d1)
  -$0096  -150          LoadSeg(filename)(d1)
  -$009c  -156          UnLoadSeg(segment)(d1)
  -$00a2  -162          Getpacket(wait)(d1)
  -$00a8  -168          Queuepacket(packet)(d1)
  -$00ae  -174          DeviceProc(name)(d1)
  -$00be  -180          SetComment(name,comment)(d1,d2)
  -$ooba  -186          SetProtection(name,mask)(d1,d2)
  -$00c0  -192          DateStamp(date)(d1)
  -$00c6  -198          Delay(timeout)(d1)
  -$00cc  -204          WaitForChar(file,timeout)(d1,d2)
  -$00d2  -210          ParentDir(lock)(d1)
  -$00d8  -216          IsInteractive(file)(d1)
  -$00de  -222          Execute(string,file,file)(d1,d2,d3)
EXEC.LIBRARY
  -$001e  -30            Supervisor()
  -$0024  -36            ExitIntr()
  -$002a  -42            Schedule()
  -$0030  -48            Reschedule()
  -$0036  -54            Switch()
  -$003c  -60            Dispatch()
  -$0042  -66            Exception()
  -$0048  -72            InitCode(startclass,version)(d0,d1)
  -$004e  -78            InitStruct(inittable,memory,size)(a1,a2,d0)
  -$0054  -84            MakeLibrary(funcinit,structinit,libinit,datasize,
                          codesize)(a0,a1,a2,d0,d1)
  -$005a  -90            MakeFunctions(target,functionarray,funcdispbase)
                          (a0,a1,a2)
  -$0060  -96            FindResident(name)(a1)
  -$0066  -102          InitResident(resident,seglist)(a1,d1)
  -$006c  -108          Alert(alertnum,parameters)(d7,a5)
  -$0072  -114          Debug()
  -$0078  -120          Disable()
  -$007e  -126          Enable()
  -$0084  -132          Forbid()
  -$008a  -138          Permit()
  -$0090  -144          SetSR(newsr,mask)(d0,d1)
  -$0096  -150          SuperState()
  -$009c  -156          UserState(sysstack)(d0)
  -$00a2  -162          setIntVector(intnumber,interrupt)(d0,d1)
  -$00a8  -168          AddIntServer(intnumber,interrupt)(d0,d1)
  -$00ae  -174          RemIntServer(intnumber,interrupt)(d0,d1)
  -$00b4  -180          Cause(interrup)(a1)
  -$00ba  -186          Allocate(freelist,bytesize)(a0,d0)
  -$00c0  -192          Deallocate(freelist,memoryblock,bytesize)(a0,a1,d0)
  -$00c6  -198          AllocMem(bytesize,requirements)(d0,d1)
  -$00cc  -204          AlloAbs(bytesize,location)(d0,a1)
  -$00d2  -210          FreeMem(memoryblock,bytesize)(a1,d0)
  -$00d8  -216          AvailMem(requirements)(d1)
  -$00de  -222          AllocEntry(entry)(a0)
  -$00e4  -228          FreeEntry(entry)(a0)
  -$00ea  -234          Insert(list,node,pred)(a0,a1,a2)
  -$00f0  -240          AddHead(list,node)(a0,a1)
  -$00f6  -246          AddTail(list,node)(a0,a1)
  -$00fc  -252          Remove(node)(a1)
  -$0102  -258          RemHead(list)(a0)
  -$0108  -264          RemTail(list)(a0)
  -$010e  -270          Enqueue(list,node)(a0,a1)
  -$0114  -276          FindName(list,name)(a0,a1)
  -$011a  -282          AddTask(task,initpc,finalpc)(a1,a2,a3)
  -$0120  -288          RemTask(task)(a1)
  -$0126  -294          FindTask(name)(a1)
  -$012c  -300          SetTaskPri(task,prority)(a1,d0)
  -$0132  -306          SetSignal(newsignals,signelset)(d0,d1)
  -$0138  -312          SetExcept(newsignals,signalset)(d0,d1)
  -$013e  -318          Wait(signalset)(d0)
  -$0144  -324          Signal(task,signalset)(a1,d0)
  -$014a  -330          AllocSignal(signalnum)(d0)
  -$0150  -336          FreeSignal(signalnum)(d0)
  -$0156  -342          AllocTrap(trapnum)(d0)
  -$015c  -348          FreeTrap(trapnum)(d0)
  -$0162  -354          AddPort(port)(a1)
  -$0168  -360          RemPort(port)(a1)
  -$016e  -366          PutMsg(port,message)(a0,a1)
  -$0174  -372          GetMsg(port)(a0)
  -$017a  -378          ReplyMsg(message)(a1)
  -$0180  -384          WaitPort(port)(a0)
  -$0186  -390          FindPort(name)(a1)
  -$018c  -396          AddLibrary(library)(a1)
  -$0192  -402          RemLibrary(library)(a1)
  -$0198  -408          OldOpenLibrary(libname)(a1)
  -$019e  -414          CloseLibrary(library)(a1)
  -$01a4  -420          Setfunction(library,funcoffset,funcentry)(a1,a0,d0)
  -$01aa  -426          SumLibrary(library)(a1)
  -$01b0  -432          AddDevice(device)(a1)
  -$01b6  -438          RemDevice(device)(a1)
  -$01bc  -444          OpenDevice(devname,unit,iorequest,flags)(a0,d0,a1
                          ,d1)
  -$01c2  -450          CloseDevice(iorequest)(a1)
  -$01c8  -456          DoIO(iorequest)(a1)
  -$01ce  -462          SendIO(iorequest)(a1)
  -$01d4  -468          CheckIO(iorequest)(a1)
  -$01da  -474          WaitIO(iorequest)(a1)
  -$01e0  -480          AbortIO(iorequest)(a1)
  -$01e6  -486          AddResource(resource)(a1)
  -$01ec  -492          RemResource(resource)(a1)
  -$01f2  -498          OpenResource(resname,version)(a1,d0)
  -$01f8  -504          RawIOInit()
  -$01fe  -510          RawMayGetChar()
  -$0204  -516          RawPutChar(char)(d0)
  -$020a  -522          RawDoFmt()(a0,a1,a2,a3)
  -$0210  -528          GetCC()
  -$0216  -534          TypeOfMem(address)(a1)
  -$021c  -540          Procedure(semaport,bidmsg)(a0,a1)
  -$0222  -546          Vacate(semaport)(a0)
  -$0228  -552          OpenLibrary(libname,version)(a1,d0)
GRAPHICS.LIBRARY
  -$001e  -30            BltBitMap(scrbitmap,scrx,scry,destbitmap,destx,
                          desty,sizex,sizey,minterm,mask,tempa)
                          (a0,d0,d1,a1,d2,d3,d4,d5,d6,d7,a2)
  -$0024  -36            BltTemplate(source,scrx,scrmod,destrastport,destx,
                          desty,sixex,sizey)(a0,d0,d1,a1,d2,d3,d4,d5)
  -$002a  -42            ClearEOL(rastport)(a1)
  -$0030  -48            ClearScreen(rastport)(a1)
  -$0036  -54            TextLength(rastport,string,count)(a1,a0,d0)
  -$003c  -60            Text(rastport,string,count)(a1,a0,d0)
  -$0042  -66            SetFont(rastportid,textfont)(a1,a0)
  -$0048  -72            OpenFont(textattr)(a0)
  -$004e  -78            CloseFont(textfont)(a1)
  -$0054  -84            AskSoftStyle(rastport)(a1)
  -$005a  -90            SetSoftStyle(rastport,style,enable)(a1,d0,d1)
  -$0060  -96            AddBob(bob,rastport)(a0,a1)
  -$0066  -102          AddVSprite(vsprite,rastport)(a0,a1)
  -$006c  -108          DoCollision(rastport)(a1)
  -$0072  -114          DrawGList(rastport,viewport)(a1,a0)
  -$0078  -120          InitGels(dummyhead,dummytail,gelsinfo)(a0,a1,a2)
  -$007e  -126          InitMasks(vsprite)(a0)
  -$0084  -132          RemIBob(bob,rastport,viewport)(a0,a1,a2)
  -$008a  -138          RemVSprite(vsprite)(a0)
  -$0090  -144          SetCollision(type,routine,gelsinfo)(d0,a0,a1)
  -$0096  -150          SortGList(rastport)(a1)
  -$009c  -156          AddAnimObj(obj,animationkey,rastport)(a0,a1,a2)
  -$00a2  -162          Animate(animationkey,rastport)(a0,a1)
  -$00a8  -168          etGBuffers(animationobj,rastport,doublebuffer)(a0,
                          a1,d0)
  -$00ae  -174          InitGMasks(animationobj)(a0)
  -$00b4  -180          GelsFuncE()
  -$00ba  -186          GelsFuncF()
  -$00c0  -192          LoadRGB4(viewport,colurs,count)(a0,a1,d0)
  -$00c6  -198          InitRastPort(rastport)(a1)
  -$00cc  -204          InitVPort(viewport)(a0)
  -$00d2  -210          MrgCop(view)(a1)       
  -$00D8  -216            MakeVPort (view,viewPort) (A0,A1)
  -$00DE  -222            LoadView (view) (A1)
  -$00E4  -228            WaitBlit ()
  -$00EA  -234            SetRast (rastPort,color) (A1,D0)
  -$00F0  -240            Move (rastPort,x,y) (A1,D0,D1)
  -$00F6  -246            Draw (rastPort,x,y) (A1,D0,D1)
  -$00FC  -252            AreaMove (rastPort,x,y) (A1,D0,D1)
  -$0102  -258            AreaDraw (rastPort,x,y) (A1,D0,D1)
  -$0108  -264            AreaEnd (rastPort) (A1)
  -$010E  -270            WaitTOF ()
  -$0114  -276            QBlit (blit) (A1)
  -$011A  -282            InitArea (areaInfo,vectorTable,vectorTableSize)
                          (A0,A1,D0)
  -$0120  -288            SetRGB4 (viewPort,index,r,g,b) (A0,D0,D1,D2,D3)
  -$0126  -294            QBSBlit (blit) (A1)
  -$012C  -300            BltClear (memory,size,flags) (A1,D0,D1)
  -$0132  -306            RectFill (rastPort,xl,yl,xu,yu)
                          (A1,D0,D1,D2,D3)
  -$0138  -312            BltPattern (rastPort,ras,xl,yl,maxX,maxY,
                          fillBytes) (A1,A0,D0,D1,D2,D3,D4)
  -$013E  -318            ReadPixel (rastPort,x,y) (A1,D0,D1)
  -$0144  -324            WritePixel (rastPort,x,y) (A1,D0,D1)
  -$014A  -330            Flood (rastPort,mode,x,y) (A1,D2,D0,D1)
  -$0150  -336            PolyDraw (rastPort,count,polyTable) (A1,D0,A0)
  -$0156  -342            SetAPen (rastPort,pen) (A1,D0)
  -$015C  -348            SetBPen (rastPort,pen) (A1,D0)
  -$0162  -354            SetDrMd (rastPort,drawMode) (A1,D0)
  -$0168  -360            InitView (view) (A1)
  -$016E  -366            CBump (copperList) (A1)
  -$0174  -372            CMove (copperList,destination,data) (A1,D0,D1)
  -$017A  -378            CWait (copperList,x,y) (A1,D0,D10
  -$0180  -384            VBeamPos ()
  -$0186  -390            InitBitMap (bitMap,depth,width,height)
                          (A0,D0,D1,D2)
  -$018C  -396            ScrollRaster (rastPort,dX,dY,minx,miny,maxx,
                          maxy) (A1,D0,D1,D2,D3,D4,D5)
  -$0192  -402            WaitBOVP (viewPort) (A0)
  -$0198  -408            GetSprite (simpleSprite,num) (A0,D0)
  -$019E  -414            FreeSprite (num) (D0)
  -$01A4  -420            ChangeSprite (vp,simpleSprite,data) (A0,A1,A2)
  -$01AA  -426            MoveSprite (viewPort,simpleSprite,x,y)
                          (A0,A1,D0,D1)
  -$01B0  -432            LockLayerRom (layer) (A5)
  -$01B6  -438            UnlockLayerRom (layer) (A5)
  -$01BC  -444            SyncSBitMap (1) (A0)
  -$01C2  -450            CopySBitMap (11,12) (A0,A1)
  -$01C8  -456            OwnBlitter ()
  -$01CE  -462            DisownBlitter ()
  -$01D4  -468            InitTmpRas (tmpras,buff,size) (A0,A1,D0)
  -$01DA  -474            AskFont (rastPort,textAttr) (A1,A0)
  -$01E0  -480            AddFont (textFont) (A1)
  -$01E6  -486            RemFont (textFont) (A1)
  -$01EC  -492            AllocRaster (width,height) (D0,D1)
  -$01F2  -498            FreeRaster (planeptr,width,height) (A0,D0,D1)
  -$01F8  -504            AndRectRegion (rgn,rect) (A0,A1)
  -$01FE  -510            OrRectRegion (rgn,rect) (A0,A1)
  -$0204  -516            NewRegion ()
  -$020A  -522            ** reserved **
  -$0210  -528            ClearRegion (rgn) (A0)
  -$0216  -534            DisposeRegion (rgn) (A0)
  -$021C  -540            FreeVPortCopLists (viewPort) (A0)
  -$0222  -546            FreeCopList (coplist) (A0)
  -$0228  -552            ClipBlit (srcrp,srcX,srcY,destrp,destX,destY,
                          sizeX,sizeY,minterm) (A0,D0,D1,A1,D2,D3,D4,D5,D6)
  -$022E  -558            XorRectRegion (rgn,rect) (A0,A1)
  -$0234  -564            FreeCprList (cprlist) (A0)
  -$023A  -570            GetColorMap (entries) (D0)
  -$0240  -576            FreeColorMap (colormap) (A0)
  -$0246  -582            GetRGB4 (colormap,entry) (A0,D0)
  -$024C  -588            ScrollVPort (vp) (A0)
  -$0252  -594            UCopperListInit (copperlist,num) (A0,D0)
  -$0258  -600            FreeGBuffers (animationObj,rastPort,
                          doubleBuffer) (A0,A1,D0)
  -$025E  -606            BltBitMapRastPort (srcbm,srcx,srcy,destrp,
                          destX,destY,sizeX,sizeY,minter)
                          (A0,D0,D1,A1,D2,D3,D4,D5,D6)
ICON.LIBRARY
  -$001E  -30            GetWBObject (name) (A0)
  -$0024  -36            PutWBObject (name,object) (A0,A1)
  -$002A  -42            GetIcon (name,icon,freelist) (A0,A1,A2)
  -$0030  -48            PutIcon (name,icon) (A0,A1)
  -$0036  -54            FreeFreeList (freelist) (A0)
  -$003C  -60            FreeWBOject (WBOject) (A0)
  -$0042  -66            AllocWBOject ()
  -$0048  -72            AddFreeList (freelist,mem,size) (A0,A1,A2)
  -$004E  -78            GetDiskObject (name) (A0)
  -$0054  -84            PutDiskObject (name,diskobj) (A0,A1)
  -$005A  -90            FreeDiskObj (diskobj) (A0)
  -$0060  -96            FindToolType (toolTypeArray,typeName) (A0.A1)
  -$0066  -102            MatchToolValue (typeString,value) (A0,A1)
  -$006C  -108            BumbRevision (newname,oldname) (A0,A1)
INTUITION.LIBRARY
  -$001E  -30            OpenIntuition ()
  -$0024  -36            Intuition (ievent) (A0)
  -$002A  -42            AddGadget (AddPtr,Gadget,Position) (A0,A1,D0)
  -$0030  -48            ClearDMRequest (Window) (A0)
  -$0036  -54            ClearMenuStrip (Window) (A0)
  -$003C  -60            ClearPointer (Window) (A0)
  -$0042  -66            CloseScreen (Screen) (A0)
  -$0048  -72            CloseWindow (Window) (A0)
  -$004E  -78            CloseWorkbench ()
  -$0054  -84            CurrentTime (Seconds,Micros) (A0,A1)
  -$005A  -90            DisplayAlert (AlertNumber,String,Height)
                          (D0,A0,D1)
  -$0060  -96            DiplayBeep (Screen) (A0)
  -$0066  -102            DoubleClick (sseconds,smicros,cseconds,
                          cmicros) (D0,D1,D2,D3)
  -$006C  -108            DrawBorder (Rport,Border,LeftOffset,TopOffset)
                          (A0,A1,D0,D1)
  -$0072  -114            DrawImage (RPort,Image,LeftOffset,TopOffset)
                          (A0,A1,D0,D1)
  -$0078  -120            EndRequest (requester,window) (A0,A1)
  -$007E  -126            GetDefPref (preferences,size) (A0,D0)
  -$0084  -132            GetPrefs (preferences,size) (A0,D0)
  -$008A  -138            InitRequester (req) (A0)
  -$0090  -144            ItemAddress (MenuStrip,MenuNumber) (A0,D0)
  -$0096  -150            ModifyIDCMP (Window,Flags) (A0,D0)
  -$009C  -156            ModifyProp (Gadget,Ptr,Reg,Flags,HPos,VPos,
                          HBody,VBody) (A0,A1,A2,D0,D1,D2,D3,D4)
  -$00A2  -162            MoveScreen (Screen,dx,dy) (A0,D0,D1)
  -$00A8  -168            MoveWindow (Window,dx,dy) (A0,D0,D1)
  -$00AE  -174            OffGadget (Gadget,Ptr,Req) (A0,A1,A2)
  -$00B4  -180            OffMenu (Window,MenuNumber) (A0,D0)
  -$00BA  -186            OnGadget (Gadget,Ptr,Req) (A0,A1,A2)
  -$00C0  -192            OnMenu (Window,MenuNumber) (A0,D0)
  -$00C6  -198            OpenScreen (OSArgs) (A0)
  -$00CC  -204            OpenWindow (OWArgs) (A0)
  -$00D2  -210            OpenWorkBench ()
  -$00D8  -216            PrintIText (rp,itext,left,top) (A0,A1,D0,D1)
  -$00DE  -222            RefreshGadgets (Gadgets,Ptr,Req) (A0,A1,A2)
  -$00E4  -228            RemoveGadgets (RemPtr,Gadget) (A0,A1)
  -$00EA  -234            ReportMouse (Window,Boolean) (A0,D0)
  -$00F0  -240            Request (Requester,Window) (A0,A1)
  -$00F6  -246            ScreenToBack (Screen) (A0)
  -$00FC  -252            SCreenToFront (Screen) (A0)
  -$0102  -258            SetDMRequest (Window,req) (A0,A1)
  -$0108  -264            SetMenuStrip (Window,Menu) (A0,A1)
  -$010E  -270            SetPointer (Window,Pointer,Height,Width,
                          XOFFset, YOFFset) (A0,A1,D0,D1,D2,D3)
  -$0114  -276            SetWindowTitles (Window,windowTitle,
                          screenTitle) (A0,A1,A2)
  -$011A  -282            ShowTitle (Screen,ShowIt) (A0,D0)
  -$0120  -288            SizeWindow (Windowmdx,dy) (A0,D0,D1)
  -$0126  -294            ViewAddress ()
  -$012C  -300            ViewPortAddress (Window) (A0)
  -$0132  -306            WindowToBack (Window) (A0)
  -$0138  -312            WindowToFront (Window) (A0)
  -$013E  -318            WindowLimits (Window,minwidth,minheight,
                          maxwidth, maxheight) (A0,D0,D1,D2,D3)
  -$0144  -324            SetPrefs (preferences,size,flag) (A0,D0,D1)
  -$014A  -330            IntuiTextLength (itext) (A0)
  -$0150  -336            WBenchToBack ()
  -$0156  -342            WBenchToFront ()
  -$015C  -348            AutoRequest (Window,Body,PText,NText,PFlag,
                          NFlag,W,H) (A0,A1,A2,A3,D0,D1,D2,D3)
  -$0162  -354            BeginRefresh (Window) (A0)
  -$0168  -360            BuildSysRequest (Window,Body,PosText,NegText,
                          Flags,W,H) (A0,A1,A2,A3,D0,D1,D2)
  -$016E  -366            EndRefresh (Window,Complete) (A0,D0)
  -$0174  -372            FreeSysRequest (Window) (A0)
  -$017A  -378            MakeScreen (Screen) (A0)
  -$0180  -384            RemakeDisplay ()
  -$0186  -390            RethinkDisplay ()
  -$018C  -396            AllocRemember (RememberKey,Size,Flags) (A0,D0,D1)
  -$0192  -402            AlohaWorkBench (wbport) (A0)
  -$0198  -408            FreeRemember (RememberKey,ReallyForgot) (A0,D0)
  -$019E  -414            LockIBase (dontknow) (D0)
  -$01A4  -420            UnlockIBase (IBLock) (A0)
LAYERS.LIBRARY
  -$001E  -30            InitLayers (li) (A0)
  -$0024  -36            CreateUpfrontLayer (li,bm,x0,y0,xl,yl,flags,
                          bm2) A0,A1,D0,D1,D2,D3,D4,A2)
  -$002A  -42            CreateBehindLayer (li,bm,x0,y0,xl,yl,flags,
                          bm2) (A0,A1,D0,D1,D2,D3,D3,A2)
  -$0030  -48            UpfrontLayer (li,layer) (A0,A1)
  -$0036  -54            BehindLayer (li,layer) (A0,A1)
  -$003C  -60            MoveLayer (li,layer,dx,dy) (A0,A1,D0,D1)
  -$0042  -66            SizeLayer (li,layer,dx,dy) (A0,A1,D0,D1)
  -$0048  -72            ScrollLayer (li,layer,dx,dy) (A0,A1,D0,D1)
  -$004E  -78            BeginUpdate (layer) (A0)
  -$0054  -84            EndUpdate (layer) (A0)
  -$005A  -90            DeleteLayer (li,layer) (A0,A1)
  -$0060  -96            LockLayer (li,layer) (A0,A1)
  -$0066  -102            UnlockLayer (li,layer) (A0,A1)
  -$006C  -108            LockLayers (li) (A0)
  -$0072  -114            UnlockLayers (li) (A0)
  -$0078  -120            LockLayerInfo (li) (A0)
  -$007E  -126            SwapBitRastPortClipRect (rp,cr) (A0,A1)
  -$0084  -132            WhichLayer (li,x,y) (A0,D0,D1)
  -$008A  -138            UnlockLayerInfo (li) (A0)
  -$0090  -144            NewLayerInfo ()
  -$0096  -150            DisposeLayerInfo (li) (A0)
  -$009C  -156            FattenLayerInfo (li) (A0)
  -$00A2  -162            ThinLayerInfo (li) (A0)
  -$00A8  -168            MoveLayerInfrontOf (layer_to_move,
                          layer_to_be_in_front_of) (A0,A1)
MATHFFP.LIBRARY
  -$001E  -30            SPFix (float) (D0)
  -$0024  -36            SPFit (integer) (D0)
  -$002A  -42            SPCmp (leftFloat,right,Float) (D1,D0)
  -$0030  -48            SPTst (float) (D1)
  -$0036  -54            SPAbs (float) (D0)
  -$003C  -60            SPNeg (float) (D0)
  -$0042  -66            SPAdd (leftFloat,rightFloat) (D1,D0)
  -$0048  -72            SPSub (leftFloat,rightFloat) (D1,D0)
  -$004E  -78            SPMul (leftFloat,rightFloat) (D1,D0)
  -$0054  -84            SPDiv (leftFloat,rightFloat) (D1,D0)
MATHIEEEDOUBBAS.LIBRARY
  -$001E  -30            IEEEDPFix (integer,integer) (D0,D1)
  -$0024  -36            IEEEDPFit (integer) (D0)
  -$002A  -42            IEEEDPCamp (integer,integer,integer,integer)
                          (D0,D1,D2,D3)
  -$0030  -48            IEEEDPTst (integer,integer) (D0,D1)
  -$0036  -54            IEEEDPAbs (integer,integer) (D0,D1)
  -$003C  -60            IEEEDPNeg (integer,integer) (D0,D1)
  -$0042  -66            IEEEDPAdd (integer,integer,integer,integer)
                          (D0,D1,D2,D3)
  -$0048  -72            IEEEDPSub (integer,integer,integer,integer)
                          (D0,D1,D2,D3)
  -$004E  -78            IEEEDPMul (integer,integer,integer,integer)
                          (D0,D1,D2,D3)
  -$0054  -84            IEEEDPDiv (integer,integer,integer,integer)
                          (D0,D1,D2,D3)
MATHTRANS.LIBRARY
  -$001E  -30            SPAtan (float) (D0)
  -$0024  -36            SPSin (float) (D0)
  -$002A  -42            SPCos (float) (D0)
  -$0030  -48            SPTan (float) (D0)
  -$0036  -54            SPSincos (leftFloat,rightFloat) (D1,D0)
  -$003C  -60            SPSinh (float) (D0)
  -$0042  -66            SPCosh (float) (D0)
  -$0048  -72            SPTanh (float) (D0)
  -$004E  -78            SPExp (float) (D0)
  -$0054  -84            SPLog (float) (D0)
  -$005A  -90            SPPow (leftFloat,rightFloat) (D1,D0)
  -$0060  -96            SPSqrt (float) (D0)
  -$0066  -102            SPTieee (float) (D0)
  -$006C  -108            SPFieee (float) (D0)
  -$0072  -114            SPAsin (float) (D0)
  -$0078  -120            SPAcos (float) (D0)
  -$007E  -126            SPLog10 (float) (D0)
POTGO.LIBRARY
  -$0006  -6              AllocPotBits (bits) (D0)
  -$000C  -12            FreePotBits (bits) (D0)
  -$0012  -18            WritePotgo (word,mask) (D0,D1)
TIMER.LIBRARY
  -$002A  -42            AddTime (dest,src) (A0,A1)
  -$0030  -48            SubTime (dest,src) (A0,A1)
  -$0036  -54            CmpTime (dest,src) (A0,A1)
TRANSLATOR.LIBRARY
  -$001E  -30            Translate (inputString,inputLength,
                          outputBuffer,bufferSize) (A0,D0,A1,D1)
Abbreviations (symbols) used:
          label    A label or address
          reg      Register
          an        Address register n
          dn        Data register n
          source    source operand
          dest      destination operand
          <ea>      address of register
          #n        direct value
GENERAL INSTRUCTIONS
          BCC  label        Conditional branch, depends on condition.
          BRA  label        Unconditional branch (Similar to JMP).
          BSR  label        Branch to subprogram. Return address is
                              deposited on the stack, RTS causes return to
                              that address.
          CHK  <ea>,dx      Check data register for limits, activate the
                              CHK instruction exception.
          DBCC  reg,label    Check condition, decrement on branch.
          JMP  label        Jump to address (Similar to BRA).
          JSR  label        Jump to a subroutine. Return address is deposited
                              on stack, RTS causes return to that address.
          NOP                No operation.
          RESET              Reset peripherals (Caution!).
          RTE                Return from exception.
          RTR                Return with loading of flags.
          RTS                Return from subroutine (After BSR or JSR).
          SCC  <ea>          Set a byte to -1 when condition is met.
          STOP                Stop processing (Caution!).
          TRAP  #n            Jump to an exception.
          TRAPV              Check overflow flag, then TRAPV exception.
ARITHMETIC OPERATIONS WITH WHOLE NUMBERS
          ADD  source,dest  Binary addition.
          ADDA  source,an    Binary addition to an address register.
          ADDI  #n,<ea>      Addition with a constant.
          ADDQ  #n,<ea>      Fast addition of a constant which can be only
                              from 1 to 8.
          ADDX  source,dest  Addition with transfer in X flag.
          CLR  <ea>          Clear an operand.
          CMP  source,dest  Comparison of two operands.
          CMPA  <ea>,an      Comparison with an address register.
          CMPI  #n,<ea>      Comparison with a constant.
          CMPM  source,dest  Comparison of two memory operands.
          DIVS  source,dest  Sign-true division of a 32 bit destination by
                              a 16 bit source operand. The result of the
                              division is stored in the LO word of the
                              destination, the remainder in the HI word.
          DIVU  source,dest  Division without regard to sign, similar to DIVS.
          EXT  dn            Sign-true expansion to twice original size
                              (width) data unit.
          MULS  source,dest  Sign-true multiplication of two words into one
                              word.
          MULU  source,dest  Multiplication without regard to sign, similar
                              to MULS.
          NEG  <ea>          Negation of an operand (twos complement).
          SUB  source,dest  Binary subtraction.
          SUBA  <ea>,an      Binary subtraction from an address register.
          SUBI  #n,<ea>      Subtraction of a constant.
          SUBQ  #n,<ea>      Fast subtraction of a three bit constant.
          SUBX  source,dest  Subtraction with transfer in X flag.
          TST  <ea>          Test operand and set N and Z flag.
BINARY CODED DECIMAL NUMBERS
          ABCD  source,dest  Addition of two binary coded decimal numbers.
          NBCD  source,dest  Negation of a binary coded decimal number
                              (nine complement).
          SBCD  source,dest  Subtraction of two binary coded decimal numbers.
LOGICAL OPERATIONS
          AND  source,dest  Logic AND.
          ANDI  #n,<ea>      Logic AND with a constant.
          EOR  source,dest  Exclusive OR.
          EORI  #n,<ea>      Exclusive OR with a constant.
          NOT  <ea>          Inversion of an operand.
          OR    source,dest  Logic OR.
          ORI  #n,<ea>      Logic OR with a constant.
          TAS  <ea>          Check a byte and set bit 7.
SINGLE BIT MANIPULATION
          BCHG  #n,<ea>      Change bit n(0 is changed to 1 and vice versa).
          BCLR  #n,<ea>      Clear bit n.
          BSET  #n,<ea>      Set bit n.
          BTST  #n,<ea>      Test bit n, result is desplayed in Z flag.
SHIFT AND ROTATE OPERANDS
          NOTE: n indicates a register, # indicates a direct value which
                specifies the number of shiftings.
          AS    n,<ea>        Arithmetic shift to the left (*2^n)
          ASR  n,<ea>        Arithmetic shift to the right (/2^n)
          LSL  n,<ea>        Logic shift to the left.
          LSR  n,<ea>        Logic shift to the right.
          ROL  n,<ea>        Rotation left.
          ROR  n,<ea>        Rotation right.
          ROXL  n,<ea>        Rotation left with transfer in X flag.
          ROXR  n,<ea>        Rotation right with transfer in X flag.
MOVE DATA INSTRUCTIONS
          EXG  rn,rn        Exchange two register contents (don't confuse
                              with swap!).
          LEA  <ea>,an      Load an effective address in address register an.
          LINK  an,#n        Build stack range.
          MOVE  source,dest  Carry value over from source to destination.
          MOVE  SR,<ea>      Transfer the status register contents.
          MOVE  <ea>,SR      Transfer the status register contents.
          MOVE  USP,<ea>      Transfer the user stack pointer.
          MOVE  <ea>,USP      Transfer the user stack pointer.
          MOVEA <ea>,an      Transfer a value to the address register an.
          MOVEM regs,<ea>    Transfer several registers at once.
          MOVEM <ea>,regs    Transfer several registers at once.
          MOVEP source,dest  Transfer data to peripherals.
          MOVEQ #n,dn        Quickly transfer an eight bit constant to the
                              data register dn.
          PEA  <ea>          Deposit an address on the stack.
          SWAP  dn            Swap the halves of the register (the upper 16 bit
                              with the lower).
          UNLK  an            Unlink the stack.

A lap 2009. május 25., 13:42-kori változata

AMIGA MACHINE LANGUAGE

Typed by DEE JAY

Wiki-ified by Charlie / Singular Crew, (a.k.a Chain-Q)


Original contents table, will be gone as chapters will get Wiki formatting:

       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