Amiga Machine Language

A amigaspirit.hu - pegasos.hu Wiki wikiből

(Változatok közti eltérés)
(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