              _____          _________________________________
             /    /\        /                                 \
            /    / /       /    ___________________________    \
           /    / /       /    / _________________________/\    \
          /    / /       /    /_/___________      _____   \ \    \
         /    / /       /                   \    /\    \   \ \    \
        /    / /       /_________________    \   \ \    \   \ \    \
       /    / /        \________________/\    \   \ \    \   \ \    \
      /    /_/__________________________\_\    \   \ \    \___\/     \
     /                                          \   \ \              / 
    /____________________________________________\   \ \____________/
    \____________________________________________/    \/___________/FISH

                                P R E S E N T

                 AMIGA MACHINE LANGUAGE - FROM ABACUS BOOKS

                                 P A R T  I


                     Typed by DEE JAY of X-CELL for LSD




      Table of Contents.
      ------------------
        1.     Introduction
        1.1    Why machine code?
        1.2    A look into the Amiga's memory
        1.2.1  RAM,ROM,hardware register
        1.2.2  Bits,bytes and words
        1.2.3  Number systems
        1.3    Inside the Amiga
        1.3.1  Components and libraries
        1.3.2  Memory
        1.3.3  Multi-tasking

        2      The MC68000 processor
        2.1    Registers
        2.2    Addressing memory
        2.3    Operating modes
        2.3.1  User and supervisor modes
        2.3.2  Exceptions
        2.3.3  Interrupts
        2.3.4  Condition codes
        2.4    The 68000 Instructions

        3      Working with assemblers
        3.1    The development assembler
        3.2    AssemPro
        3.3    The K-SEKA assembler

        4      Our first programs
        4.1    Adding tables
        4.2    Sorting tables
        4.3    Converting number systems
        4.3.1  Converting hex to ASCII
        4.3.2  Converting decimal to ASCII
        4.3.3  Converting ASCII to hex
        4.3.4  Converting ASCII to decimal

        5      Hardware registers
        5.1    Checking for special keys
        5.2    Timing
        5.3    Reading the mouse or joystick
        5.4    Tone production
        5.5    Hardware registers overview

        6      The Amiga operating system
        6.1    Load libraries
        6.2    Calling functions
        6.3    Program initialization
        6.3.1  Reserve memory
        6.3.2  Opening a simple window
        6.4    Input/output
        6.4.1  Screen output
        6.4.2  Keyboard input
        6.4.3  Printer control
        6.4.4  Serial I/O
        6.4.5  Speech output
        6.5    Disk operations
        6.5.1  Open files
        6.5.2  Reading and writing data
        6.5.3  Erase files
        6.5.4  Rename files
        6.5.5  CLI directory
        6.5.6  Read directory
        6.5.7  Direct access to disk

        7      Working with Intuition
        7.1    Open screen
        7.2    Openwindow
        7.3    Requesters
        7.4    Event handling
        7.5    Menu programming
        7.6    Text output
        7.7    Images
        7.8    Borders
        7.9    Gadgets
        7.9.1  Boolean gadgets
        7.9.2  String gadgets
        7.9.3  Proportional gadgets
        7.10   Example program

        8      Advanced programming
        8.1    Supervisor mode
        8.2    Exception programming

        Appendix
               Overview of library functions
               Overview of the MC68000 Instruction
               



      CHAPTER 1
      ---------
      1.Introduction.
      --------------  
        Before you tackle machine language,you should take a closer
        look at several things that are vital to machine language
        programming.
    
      1.1.Why Machine Language.
      ------------------------
        Machine language is actually the only language the MC68000
        processor understands.All other languages,such as Basic,Pascal
        or C,must first be translated(interpreted or compiled) into
        machine code.This process can take place either when the 
        program is executed(the BASIC interpreter),or before program
        execution(the Pascal and C compilers).
      Advantages;
        The great advantage of machine language over an interpreted
        and compiled program is machine language programs are faster.
        With an interpreter like BASIC,each line must first be 
        interpreted before it is executed,which requires a great deal
        of time.A Pascal or C compiler translates the source into
        machine language.This translation procedure does not produce
        programs that are as fast as pure machine language programs.
        Another advantage machine language has over BASIC is that an
        interpreter is not needed for the execution of a machine
        language program.
        Machine language can access all the capabilities of the 
        computor since it is the language native to the computor.It
        is possible that machine subroutines are required by a higher
        level language to access functions that aren't directly 
        accessible by that language.
      
      1.2.A Look Into The Amiga's Memory.
      ----------------------------------
        Before a machine language program can be written,you must 
        know exactly what the program is required to do.You must also
        be aware of what resources are needed and available to achieve
        those goals.The most important of these resources is the 
        memory in the Amiga.

      1.2.1.RAM,ROM,Hardware Register.
      -------------------------------  
        Random Access Memory,referred to as RAM,allows information to
        be placed in it and then withdrawn at a later time.This memory
        consists of electronic componants that retain data only while
        the computor is turned on(or until power failure).
        So that the computor is able to do something when it is first
        turned on,such as promting the Workbench or Kickstart disk,a
        program has to remain in memory when the power is off.A memory
        type which can retain data in memory without any power being
        needed.This second memory type is known as ROM.
      ROM;
        ROM stands for Read Only Memory,indicating that data can only
        be read from this memory,not written to it.The Amiga contains
        a ROM,that loads the Workbench or Kickstart disk into RAM.The
        first version of the Amiga did not contain the Kickstart in
        ROM.
      PROM;
        One variation of ROM is the PROM,or Programmable Read Only
        Memory.This special type of ROM can actually be programmed
        once.Since it cannot be erased once programmed,it isn't
        encountered very often.More often you will see EPROM's. or
        Erasable Programmable ROM's.These special chips,which can be
        erased with ultraviolet light,have a little window on the
        surface of the chip usually covered with tape.
      EEROM;
        Although not available on the consumer market and much more 
        expensive than RAM,the EEROM(Electically Erasable ROM) offers
        another alternative to programmable ROM.These chips function
        like RAM,except that information is not lost when the power
        is turned off.
      WOM;
        With the birth of the Amiga,another type of memory,WOM,was
        created.This particular type of memory is Write Once Memory.
        The Kickstart disk is read into this memory when the computor
        is first booted.After this,no more data can be read into that
        memory.Actually this isn't a completely new component,but
        simply RAM that is locked once data has been read into it,
        after which the data can only be read from that memory.
      Registers;
        In addition to RAM and these variations of ROM there is another
        type of memory situated between those two groups.This memory
        is connected to the processor through a group of peripheral
        controllers.Thus it is commonly refered to as the Hardware
        Register,since the computor's hardware is managed by this 
        system.We'll go into greater detail on how to use these hardware
        registers later in this book.
        Lets take a closer look at the structure and use of the memory
        most familiar to us,RAM.

      1.2.2.Bits,Bytes,and Words.
      --------------------------
      Kilobyte;
        The standard size in which memory is measured is a Kilobyte
        (Kbyte).One kilobyte consists of 1024 bytes,not 1000 as you 
        might expect.This unusual system stems from the computor's
        binary mode of operation,where numbers are given as powers of
        2,including kilobytes.
        To access a memory block of one kilobyte,the processor requires
        10 connections which carry either one volt or zero volts.Thus
        2^10=1024 combinations or 1024 bytes of memory,are possible.
      Byte;
        A byte,in turn,consists of yes/no,on/off information as well.
        A byte can be one of 2^8 different values,and thus it can
        represent any one of 256 numbers.The individual numerical
        values that make up a byte,which also are the smallest and
        most basic unit encountered in any computor,are called bits
        (short for binary coded digit).
        A 512 kbyte memory,such as the Amiga's,contains 2^19=524288
        bytes and 4194304 bits.It may seem unimaginable,but a memory
        of that size has 2^4194300 different combinations.
      Word;
        Back to the basics...bits and bytes are sufficent to program
        an eight bit processor like the 6500,since it can only work
        with bytes.To program a 16/32 bit processor like the Amiga's
        MC68000,you'll need to know two new data forms:words,consisting
        of 16 bits(the equivalent of two bytes),and long words,which
        are 32 bits(the equivalent of four bytes,or 2 words).
        A word can be any number between 0 and 65536,a long word can
        0 to 4294967295.The MC68000 processor can process these
        gigantic numbers with a single operation.
        Once in a while you need to use negative numbers as well as
        positive ones.Since a bit can only be 1 or 0 and not -1,an
        alternative system has been adopted.If a word is to have a
        specific sign,the highest value digit or 15th bit in the word
        (positions are always counted from zero) determines the sign
        of the word.With this method words can carry values from -32768
        to +32768.One byte can range from -127 to +127.In a byte,the
        value -1 is given by $FF; in a word it's $FFFF,-2 is $FE(FFFE),
        etc.
        Lets stick with positive values for the time being,to aid in
        the visualization of a bit in relation to its bit pattern.
        Machine language does not use the familiar decimal system.
        Instead,it commonly employs the binary as well as the octal and
        hexadecimal number systems.

      1.2.3.Number Systems.
      --------------------
        Lets take a look at the decimal system:its base number is 10.
        This means that every digit represents a power of 10.This means
        that the 246 represents 2*10^2+4*10^1+6*10^0.The decimal system
        offers a selection of 10 characters,namely 0-9.
      Binary;
        This procedure is different for the binary system.The binary
        system offers only two different characters:1 and 0.Thus the
        systems base number is two.The decimal value of 1010 would be:
          1*2^3+0*2^2+1*2^1+0*2^0=2^3+2^1=8+2=10 (in decimal system)
        Generally binary numbers are identified by having a percentage
        symbol as a prefix.See if you can determine the decimal value of
        this number:110010...
        Well did you get 50?.Thats the right answer.The most simple 
        method to arrive at this result is to simply add up the values
        of the digits contained at 1.The values of the first eight digits
        are as follows:
            digit       8     7     6     5     4     3     2     1
            value     128    64    32    16     8     4     2     1
      Octal;
        The octal system whose base is eight,is similar.The character set
        consists of numbers 0 to 7.The decimal equivalent of the octal
        number 31 is: 3*8^1+1*8^0=25.However the octal system isn't 
        nearly as important as the next one...
        The base number of the hexadecimal system is 16,and its character
        set ranges from 0 to F.Thus,A would be equivalent of a decimal 10
        and F would be 15.The dollar sign($) indicates a hexadecimal
        number.The binary and hexadecimal systems are the most important
        numerical systems for assembly language programming.
      Hex;
        The hexadecimal representation of a byte ranging from 0 to 256
        always has two digits:$00 to $FF.A word ranges from $0000 to $FFFF
        and a longword from $00000000 to $FFFFFFFF.
        Its quite easy to convert binary numbers into hexadecimal:simply
        split up the binary numbers into groups of four digits.Each of 
        these groups of four digits then corresponds to one hexadecimal
        digit.Heres an example:
                binary number  %110011101111
                split up       %1100 %1110 %1111
                result           $C    $E    $F
                thus:          %110011101111=$CEF 
        The opposite operation is just as easy...
                hexadecimal   $E30D
                split up      $E     $3     $0     $D
                result        %1110  %0011  %0000  %1101
                thus:         $E30D = %1110001100001101
        This method can also be used to convert binary into octal and vice
        versa,except that groups of three digits are used in that case:
                octal number   7531
                split up       7     5     3     1
                result         %111  %100  %011  %001
                thus:          octal 7531=%111101011001
        This binary number can the be converted into hexadecimal,as well:
                binary number  %111101011001
                split up       %1111 %0101 %1001
                result         $F    $5    $9
                thus:          octal 7531=$F59
        The following calculation can then be used to convert the number
        into the familiar decimal system:
                hexadecimal    $F59
                split up       $F     $5     $9
                result         15*16^2+5*16+9
                thus:          $F59=3929 decimal
        Although this conversions are quite simple ,they can get to be
        rather annoying.Many assemblers can ease this task somewhat:they
        allow you to enter a value with '?'upon which it returns the
        value in decimal and hexadecimal forms.There are even calculators
        that perform number base conversions.
        Often this conversion as to be performed in a program,for instance
        when a number is entered by the user and then processed by the
        computor.In this case the number entered,being simply a
        combination of graphic symbols,is evaluated and the usually
        converted into a binary number,in effect,a word or a longword.
        This process is often required in reverse order,as well.If the
        computor is to display a calculated value in a specific number
        system,it must first convert that number into a series of
        characters.In a later chapter you will develop machine language
        routines to solve these problems.You can then use these routines
        in your own programs.First you still have to cover some things
        that are fundamental to machine language programming on the Amiga.

      1.3.Inside the Amiga.
      --------------------  
        In order to program machine language,it is not sufficent to know
        only the commands of the particular processor,one must also have
        extensive knowledge of the Amiga being programmed.Lets take a
        look inside the Amiga.

      1.3.1.Components and Libraries.
      ------------------------------
        The Amiga is a very capable machine,due to the fact that there
        are components that do a large part of the workload,freeing up
        the 68000 processor.These are refered to as the"custom"chips,
        which perform various tasks independantly of the 68000 processor.
      Custom Chips;
        This task force is comprised of three chips,whose poetic names
        are Agnus,Denice,and Paula.The main task of Agnus,alias blitter,
        is the shifting of memory blocks,which is helpful for operations
        such as quick screen changes.Denise is responsible for transfering
        the computors thoughts on to the screen.Paula's tasks consist of
        input/output jobs,such as disk operation or sound.
        These chips are accessed by the processor through several adresses
        starting at $DFF000,which are also known as the hardware registers
        (you'll find more detailed information about the registers in the
        corresponding chapter).To simplify the otherwise complicated
        procedure of utilizing these chips,several programs have been
        included in the Kickstart and Workbench libraries.These programs
        can be called by simple routines and then take over the respective
        chips.
        If only these library functions are used to program the Amiga,the
        parameters are the same,regardless of the language used.Only the
        parameter notations differs from language to language.BASIC is an
        exception in this respect,since its interpreter translates the
        program calls,which is why you don't need to know how the Amiga
        executes these functions in order to use them.
        The library functions are written in machine language and are thus
        closely related with your own machine language programs.Actually
        you could do without the library programs and write all of the
        functions yourself.However the incredible workload of this task is
        so discouraging,that you'd rather stick with the library functions

      1.3.2.Memory. 
      ------------   
        First lets look at the RAM of the Amiga 1000.The standard version
        of this computor has over 512 kbytes of RAM,ranging from the
        address $00000 to $7FFFF,or 0 to 524287.If the memory is expanded
        to one megabyte,the first address still starts at $00000,however
        the start of anything greater than 512k can go anywhere in the
        address space between $200000 to $9FFFFF.With the release of
        AmigaDOS 1.2,the Amiga figures out where to put the memory 
        expansion by using a special`Autoconfig`scheme.This allows you to
        add memory and I/O without worrying about addresses and dip
        switches.
      Chip RAM;
        The chips that support the Amiga`s processor access RAM almost
        totally independantly and thus ease the workload of the processor.
        However there is a draw back:these chips can only access the first
        512k bytes of RAM.Thus graphics and sound data handled by these
        chips MUST be stored in this memory range.Because of this,that
        memory range is referred to as `Chip RAM`.
      Fast RAM;
        The counterpart to chip RAM is the remaining RAM which,if the
        computor is equipped with it,begins at $200000.Since only the
        processor itself as access to this part of memory it is known has
        `Fast RAM`.
        Here`s an overview of the Amiga`s memory:
                $000000-$07FFFF      chip RAM
                $080000-$1FFFFF      reserved
                $200000-$9FFFFF      potential fast RAM
                $A00000-$BEFFFF      reserved
                $BFD000-$BFDF00      PIA B (even addresses)
                $BFE001-$BFEF00      PIA C (odd addresses)
                $C00000-$DFEFFF      reserved for expansion
                $DFF000-$DFFFFF      custom chip registers
                $E00000-$E7FFFF      reserved
                $E80000-$EFFFFF      expansion ports
                $F00000-$F7FFFF      reserved
                $F80000-$FFFFFF      system ROM
        Since the Amiga is multi-tasking,when a program is loaded into
        memory,it is simply loaded into another memory location.The memory
        range thus occupied is added to a list of occupied memory and the
        memory range is then considered barred from other uses.If another
        program is loaded,which is quite possible with the Amiga,it is
        read into another memory location which is then marked on the 
        occupied list.If the first program should require additional
        memory,to use a text buffer for example,that memory first has to
        be reserved.Otherwise another program could accidently be loaded
        into the memory needed for this task.
        What`s interesting about this procedure is that when the first
        loaded has ended,the memory occupied by it is freed for further
        use.As a result,RAM is then chopped up into occupied and free
        parts,which are no longer related to each other.The Amiga can
        still utilize these chunks of memory as if they were one
        continuous chunk.After all,parts is parts.An example of this is
        the dynamic RAM disk which is always available under the name RAM:
        This RAM disk is actually quite a phenomenon,since it is always
        completely filled.If a program is erased from RAM disk,the memory
        allocated to that program,regardless of its location or structure,
        is given back to the system.Thus,if you reserved and filled 100
        kbytes of memory,it would be quite posible that the 100kbytes
        actually consists of various pieces of memory independant of one
        another.You never notice this since the Amiga automatically
        corrects the difference between apparent and actual memory.

      1.3.3.Multi-Tasking.
      -------------------
        The Amiga is truly an amazing machine,being capable of doing
        several things at one time.A red and white ball might be bouncing
        around in one window while you`re working on text in another
        window and watching a clock tick away in a third.
        At least that`s the impression most people get when they recieve
        their first Amiga demonstration.However,there is a catch to this:
        even the Amiga as only one processor,which can really only do one
        thing at a time.
        The tricky part is when more than one program is running,each
        program is executed part by part,and the Amiga is constantly
        switching from one program back to the other program.In the
        example above,the ball would first be moved by one pixel,then
        the processor would check for a text entry and if necessary display
        it,after which it would move the clock`s second hand.This
        procedure would be repeated over and over,as the three programs
        are executed together.The problem is,that the greater the work
        load on the processor,the slower the things happen.Thus,programs
        run slower during heavy multi-tasking.
      Tasks;
        Each of these jobs that the Amiga has to execute are commonly
        referred to has tasks...thus,multi-tasking.During multi-tasking,
        each task is assigned a special time segment during which that
        particular task is executed.These time segments can be controlled,
        so that more time consumming programs can be allotted somewhat
        more processing time.
        The programmer actually doesn`t need to know how this time slicing
        works.You can write aprogram without paying any attension to
        multi-tasking and then run it simultaneously with another program
        running in the background.The only restriction is that you`ll have
        to start the program from the CLI with`run`,or from the Workbench.
        If you execute the program from the CLI by simply typing its name,
        the processor allots all the time it can get from the CLI to that
        program,until the execution is complete.Starting the program with
        run free`s the CLI for other uses while the program is being
        executed.
        There is another restriction regarding multi-tasking that applies
        to assembler programmers.Aside from the use of extra memory,which
        must first be reserved,the hardware registers should not be
        directly accessed.Instead the library functions should be used.The
        reason for this is quite simple:
        Should you,for instance,specify the printer port as the input line
        and are reading data in,another task might suddenly think its
        supposed to be printing.The line would thus be switched to output
        and data would be written out.After this,your program would try to
        read more data in,which would not be possible.
        This is an oversimplified example,but it points out the problem
        nevertheless.In real programming situations the effects of
        multiple direct programming of the hardware registers can be much
        more catastrophic.If your program still needs to access the
        hardware registers directly(which can have some advantages),then
        make sure that the program always runs by itself.

        


      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. 

        

                            NOW LOAD PART 2
end.
