Pl DEBUTS.DOC

From Atari Wiki
Jump to navigation Jump to search

                --------------------------
                    CHAPTER no. 3: 

                *   FIRST PROGRAMS   *

                --------------------------



            *** INTRODUCTION WITH AN EXAMPLE ***
            ------------------------------------

    - Consider the following 68000 ASSEMBly program (#1):


                          -------------------

; program #1 in 68000 Assembler

            TEXT                      ;start Text zone
                               
A           EQU      18               ;A=18
B           EQU      2                ;B=2

            move.w   A,destination    ;move word A to destination
            move.b   B,other          ;move bit B to other
            move.w   other,d0         ;move what's in other to
                                      ;register d0

            add.l    A,d0             ;add A to d0
            lea      A,a0             ;put A's address in
                                      ;register a0

            move.w   (a0)+,save_A     ;increment a0 and save a0
            add.l    save_A,d1        ;add save_A to d1
            add.l    d0,d1            ;add d0 to d1
            move.l   d1,result        ;put d1 as result
            move.w   DAT,d0           ;put dat in d0
            add.l    DAT,result       ;add dat to result
            clr.l    result           ;clear result

            DATA                      ;start Data zone

DAT         DC.W    6                 ;data 6 in DAT

            BSS                       ;start Bss zone

save_A      DS.L    1                 ;reserve a L-W in save_A
result      DS.L    1                 ;reserve a L-W in result
destination DS.L    1                 ;same in destination
other       DS.B    1                 ;reserve one BYTE in other


            END                       ;end of the listing

      
                        --------------------


1)  EXPLANATIONS:
    -------------

  - Don't look for any particular meaning in this listing, it is only meant
    to introduce the various concepts of ASS programming...

  - As you can see, an ASS. program is structured.
    This structure is divided into 3 columns.

          .1st column: LABELS or TAG names:
           -----------
           Their purpose is to set a memory address, so one
           can call an ADDRESS by naming the LABEL when an instruction
           requires it. (Like a line number in BASIC)

           The actual address assigned to the Label is given after linking,
           these addresses serve as reference points in
           the program, and do not aim at definable addresses.
           (Unless the program is relocated to a specific location in
           memory, but this is not of real interest)

          .2nd column: INSTRUCTIONS and their OPERANDS:
           -----------
           The instructions tell the computer the steps to follow, these
           instructions can be followed by operands if their syntax
           demands it (as for MOVE x,y)

           In ASS 68000, there are 56 basic instructions.

          .3rd column: COMMENTS:
           -----------
           All text located after the Operands is no longer recognized as
           an instruction, and can therefore be used to describe the listing
           by including useful information...
           With some editors (PROFIMAT), a comma must be put
           in front of comments, otherwise it causes an error during
           assembly.
           Blank (or empty) lines or those starting with *
           (for METACOMCO ) or ';' (for PROFIMAT) are also treated
           as COMMENTS.

     NB: .For a LABEL to be recognized as such, it must be written on
     ---  the first column, the other columns must be separated
          by at least one space (' ').

         .No more than one instruction per line.



2)  DETAILED COMMENTARY OF THE LISTING:
    --------------------------------

-line 1 : '; Program #1 in 68000 Assembler '
 ---------  
     .As you can see, it's a 'comment', here
      it refers to the name of the program...

-line 2 : '                                               '
 ---------
     .A blank line...        i.e. nothing at all (yes indeed!)


-line 3 : '           TEXT'
 ---------
     .There is an instruction (column 2).
     .In fact, it's an ASSEMBLY DIRECTIVE.
     .DIRECTIVES are functions specific to the ASSEMBLER used,
      hence their syntax can vary with the editor used.
      For most directives, the syntax is identical. (I will name
      the exceptions, but the manual of your assembler should
      contain the names and descriptions of directives it uses.)
     .DIRECTIVES are placed in the 2nd column of the listing, just like
      instructions or MACRO-INSTRUCTIONS.
     .The 'TEXT' directive forces the initialization of the P.C.,
      the Program Counter (to 0 or to its value at its last
      initialization if there are multiple 'text' sections)

                               ----------------


- But what is the 'P.C.'? :
                     ------------
- It's the Program Counter
  It is a 32-bit REGISTER which contains the address (even number) of the WORD
  in which the CODE (in BINARY) of the next instruction to be executed is found.
  In practice, only the 24 least significant bits are used in this
  particular register.

  Therefore, the P.C. is incremented after each instruction by an even number
  of bytes (depending on the size of the instruction).

  Jump (jmp...) or branch (bsr..) instructions aim to modify the P.C.
  and thus cause a jump to the address pointed to by the P.C.

  so:           PC      |    code of the instruction in BIN
  -----
                            ???????????????
             PC ---------->
                            ???????????????
             PC ---------->
                            ???????????????
             PC ---------->

                          etc...

    representation of the PC:
    ---------------------
             32       23                                             0
              ********[][][][][][][][][][][][][][][][][][][][][][][][]



                            ------------------

     .The 'TEXT' directive is therefore meant to initialize the P.C.:
      It precedes the instructions that form the listing, hence
      the name 'text'.



-line 4: ' A        EQU        18 '
 -------- (I stop counting blank lines)

         .We find a LABEL: A, a DIRECTIVE: EQU, and its OPERAND: 18
         .the directive EQU aims to assign a value to the label
          it is associated with (an integer number).
          In our listing: 18 is associated with 'A' address.

-line 5: ' B        EQU         2 '
 --------
          .2 is associated with 'B' address.

-line 6: '          move.w      A,destination '
 --------

          .There is an INSTRUCTION (move) and two operands (the source
           and the destination).
          .The 'move' instruction transfers data from a source operand
           to a destination operand.
          .The 'move' instruction is followed by the suffix '.w': this
           indicates that the instruction operates on a WORD (or Word)

          .There are 3 suffixes that can be added to certain instructions
           (we'll detail which ones)

               - .L  :the instruction deals with a L-W (Long)
               - .W  :it involves a WORD (Word)
               - .B  :it deals with a BYTE

NB: If an instruction accepts one of these suffixes and it's not included:
--- for example, if you write 'MOVE #1,d0', the .W suffix is implied by
    default, meaning if you write 'MOVE #3,d2', it equates to writing
    'MOVE.W #3,d2')


                              ----------------------

 What are ADDRESSING MODES?:
          -------------------------

       This is the most fundamental point of ASS programming.

 - ASS allows easy movement of data in memory (e.g.,
   with the 'move' instruction) or to 'point' to instructions or data
   identified in memory.
   One of the richnesses of ASS compared to other languages is that ASS
   utilizes several ADDRESSING MODES: 14 in 68000.
   That is, in ASS, it is possible to move (directly or indirectly)
   data in memory or act on data located in memory, in 14 different ways!

 - The elements that come into play in the different addressing modes
   are: The REGISTERS, the PC (and also the SR, a very special
   register, which we will study in detail)

                                the REGISTERS:
                                --------------

. We distinguish the DATA REGISTERS:
                   ---------------------
  There are 8 and they are designated by their addresses: d0,d1,d2,d3,d4,d5,d6,d7
  They are 32 bits in size and USED TO STORE NUMERICAL DATA.         ------------------------------
          so, if we write:    MOVE.L    #1,d0
                               ADD.L     #1,d0

  We place 1 in the 32-bit d0 register (all 32 bits of the register are
  affected by the 'move.l' instruction because of the suffix '.L'), then
  we add (add.l) 1 to this register (the 32 bits of the register are once
  again affected), so d0 will contain '2' and will be represented in
  memory as:

                      00000000000000000000000000000010       ( %10=2 )


           And the ADDRESS REGISTERS:
                   ---------------------

  There are 9, 8 are available to the programmer: they are designated
  by their addresses: a0,a1,a2,a3,a4,a5,a6,a7 and ARE USED TO STORE
  ADDRESSES.                                     -----------------------
  --------
            thus, if we write:  MOVE.L  NAME,a0

  The a0 register is loaded with the value of the address 'NAME' (the 32
  bits of a0 register are affected because of the suffix '.L')


  WARNING: Only WORDS or L-Ws can be transferred into an
  ---------- ADDRESS REGISTER (no BYTE, this is very important!)


NB  the a7 register is special, it is used as SYSTEM STACK pointer
--  (or SP from 'Stack Pointer') which is a special area of
    memory used by certain jump instructions that store there
    the return address to the instruction calling the subroutine (in real-
    ity it's the PC that is saved then reloaded, so put back to its initial
    value at the end of the subroutine which causes a return to the instr-
    uction following the jump instruction, we will study this in depth
    later)




       there is the PC, which is also A REGISTER:
              -----


.We have seen that it is composed of 32 bits of which 24 are used and that
 it points to the even-numbered address of the next instruction to execute.

       And the SR (the Status Register):
              --
  It is a 16-bit register that is divided into 2 distinct bytes:

     - A user byte (LSB)
     - A supervisor byte (MSB)

  Here is its structure:

                     supervisor        |       user
              --------------------------+------------------------

SR:           [T][ ][S][ ][ ][i2][i1][i0][ ][ ][ ][X][N][Z][V][C]
---
     Bits n° 15                        8  7                    0


  - The supervisor byte: is writable only in SUPERVISOR
    MODE by setting the 'S' bit. (There is a Gemdos function
    that does this when called)
    It is only in supervisor mode that one can access the SYSTEM
    STACK and certain privileged instructions.

    The 'T' bit allows or the microprocessor to function in TRACE
    mode (step-by-step program execution after each instruction, we
    will talk about it in the chapter on DEBUGGERS)

    The bits i2, i1, i0 constitute the interrupt mask.

    (I will come back to this in detail...)



  - The user byte: can be used in both MODES (user and supervisor)
    This BYTE is also called the CONDITION CODES REGISTER or CCR from
    'Condition Codes Register'                                   ---
                                                            
  - It is modified by most 68000 instructions.

    *   The 'N' bit (n°3) is 1 if the result of an arithmetic
        operation is Negative, otherwise it is set to 0.

    *   The 'Z' bit (n°2) is set to 1 if the result of an operation
        is zero (Zero), otherwise it is set to 0.
       
    *   The 'V' bit (n°1) is set to 1 if the result of an operation
        cannot be represented in the size of the defined operand (overflow)
        otherwise it is set to 0.

    *   The 'C' bit (n°0) is set to 1 if an operation causes a
        carry beyond the most significant bit of the result operand
        (such as division), otherwise it is set to 0.

    *   The 'X' bit (n°4) is the eXtension bit, its use is
        limited to certain instructions that we will study.



.Now that you have familiarized yourself with the different 68000 Registers,
 let's define the different ADDRESSING MODES.

 Addressing modes allow you to modify the values of the PC, SP, SR, and system stack.

 I will use the MOVE instruction (allows to move the source operand to the
 destination operand) and ADD (adds the source operand to its destination operand)
 to illustrate the different types of addressing modes.





                  *** THE ADDRESSING MODES OF THE 68000 ***
                      ------------------------------


1) IMMEDIATE addressing     (shown as #...)
   --------------------

   A) NUMERIC: (The source operand is data)
      ----------
      It's written:
      -----------
                    +-------------------------------------+
                    | Instruction     #data,destination    |
                    +-------------------------------------+

      And reads as:
      ----------
      Place the source data in (to) the destination operand



   Examples:
   ---------        MOVE    #12,d1

           ( i.e. MOVE.W  #12,d1)

    We place the number 12, coded on a WORD in the least significant WORD of
    the d1 register:

                           0000000000001100 ( WORD=%12 )

                                  |
                                 \|/

           ................0000000000000000( d1 register, only the least significant WORD is affected because
                                            we wrote:'move.W' )

                            and we get:
                            --------------

           ................0000000000001100 ( %12 In the least significant WORD of d1 )
Bits n°  31               15              0



          Exp 2:    ADD.L    #3,d1
          ------
    We add 3, coded on a L-W to the contents of d1 and all 32 bits of d1
    participate in the operation:


                   00000000000000000000000000000011  ( L-W=%3 )

                                 |
                                \|/

                   00000000000000000000000000000000  ( d1 register )

Bits n°           31                              0
                            and we get:
                            --------------

                   00000000000000000000000000000011  ( d1 register=%3)

Bits n°           31                              0



    B) SYMBOLIC:   (The source operand is a LABEL)
       ----------

        It's written:
        -----------      +--------------------------------------+
                         | Instruction       #Label,destination  |
                         +--------------------------------------+

        And reads as:
        ----------
        Place the address of the Label in (to) the destination operand.


   Example:
   --------
                    MOVE.L      #tag,a0

     We place the L-W (even number) containing the address of 'tag' in the
     address register a0, all 32 bits of the register are affected.

   if we take the address of 'tag' =00000000000000001101101011010000

          it would give us:

             00000000000000001101101011010000  ( address of 'tag')

                            |
                           \|/

             00000000000000000000000000000000  ( a0 register )

Bits n°     31                              0

                      and we would get:
                         ---------------

             00000000000000001101101011010000  ( address of 'tag'

                                                 in a0 register )
Bits n°     31                              0




2) SIMPLE INDIRECT addressing:       (shown as (an) )
   ----------------------------

      It's written:
      -----------
                    +-------------------------------------+
                    | Instruction        (an),destination |
                    +-------------------------------------+
                                     OR
                                     --
                    +-------------------------------------+
                    | Instruction             source,(an) |
                    +-------------------------------------+


      And reads as:
      ----------
      Move the data pointed by the address register an into
      (to) the destination operand.
                                    OR
                                    --
      Move the source data to the address pointed to by an


   Example:
   --------
                      MOVE.B       (a2),d2

   We place the BYTE located at the address pointed to by the address register a2
   in the least significant BYTE of the data register d2.

   If a2 points to an address that contains the byte 01101001

                  We get:

              ........................01101001    (d2 register)

   Bits n°   31                       7      0  


   NB: note that the .B operation size is allowed for this mode
       of addressing, whereas it is forbidden to move an address
       into a register.



3) INDIRECT ADDRESSING WITH POST-INCREMENTATION: (schematized (an)+)
   ---------------------------------------------

     It is written as:
     -----------
                  +-----------------------------------+
                  | Instruction     (an)+,destination |
                  +-----------------------------------+
                                   OR
                                   --
                  +-----------------------------------+
                  | Instruction          source,(an)+ |
                  +-----------------------------------+

     And is read as:
     ----------
     Take the data pointed by the address register 'an', then
     increment (increase) the value of 'an' according to the SUFFIX of
     the instruction (by 1 for .B, 2 for .W, 4 for .L) and move
     the pointed data to the destination operand.

                                   OR
                                   --
     Move the source operand to the address pointed by the regis-
     ter an, then increment the value of 'an' according to the SUFFIX
     of the instruction (by 1 for .B, 2 for .W, 4 for .L)


     That is to say:  If you write 'MOVE.B   #%10101011,(A2)+'
     -------------
     Place the BIT '10101011' at the address pointed by register a2,
     then the address register a2 is INCREMENTED by 1 unit (.B).

     If a2 points for example to the address $FFA0:

          we have:                10101011
                                   |
                                  \|/

                              |--------|--------| $FF9F
                        $FFA0 |--------|--------| $FFA1
          memory:       $FFA2 |--------|--------| $FFA3
          --------            |--------|--------|


          register a2:   00000000000000001111111110100000  (=$ffa0)
          ------------


                                 and we obtain:
                              

                              |--------|--------| $FF9F
                        $FFA0 |10101011|--------| $FFA1
          memory:       $FFA2 |--------|--------| $FFA3
          --------            |--------|--------|

          register a2:   00000000000000001111111110100001  (=$ffa1)
          ------------

          .The byte 10101011 is placed at $FFA0

          .The address of a2 is Incremented by 8 Bits (one Byte) because the
           suffix of the instruction is ' .B ', as memory is
           addressable by the byte, a2 is increased by one unit.



  And if we now wrote:        MOVE.B   #%11101010,(a2)

  What would happen?

  Answer: MOVE.B    #%11101010,(a2) is to place the byte 11101010 at
  -------- the address pointed by the register a2:
           As a2 now equals $FFA1, we would obtain:


                              |--------|--------| $FF9F
                        $FFA0 |10101011|11101010| $FFA1
          memory:       $FFA2 |--------|--------| $FFA3
          --------            |--------|--------|

          register a2:  00000000000000001111111110100001  (=$ffa1)
          ------------


  And if I now write:          MOVE    #%00000001,(a2) ?

  There would be an ERROR!, a2 points to $FFA1, it's an odd address,
  therefore improper for placing a WORD  (MOVE without suffix = MOVE.W)

  And if I wrote:                  MOVE.B     (a2)+,(a2) ?

  Take the byte that a2 points to, increase a2 by one unit (.B) i.e.,
  a2 points to $FFA2 and place this byte at the address pointed by
  a2, i.e., at $FFA2 since a2 has just been incremented.

             it gives:



                              |--------|--------| $FF9F
                        $FFA0 |10101011|11101010| $FFA1
          memory:       $FFA2 |--------|--------| $FFA3
          --------            |--------|--------|

          register a2:  00000000000000001111111110100001  (=$ffa1)
          ------------

                          after MOVE.B    (a2)+,(a2)

                              |--------|--------| $FF9F
                        $FFA0 |10101011|11101010| $FFA1
          memory:       $FFA2 |11101010|--------| $FFA3
          --------            |--------|--------|

          register a2:  00000000000000001111111110100001  (=$ffa1)
          ------------



  If now I change the value of a2, and a2 equals $FFA0 and if
  I write:     MOVE   (a2)+,(a2)+

  Take the WORD at $FFA0, increment a2, a2 therefore equals $FFA2 (as
  MOVE = MOVE.W and a WORD=2 Bytes, as memory is addressable at
  the byte level: a2=a2+2) and place it at the address pointed by
  register a2 (i.e., $FFA2) then increment the address register a2 by 2
  (Bytes) so a2 will finally equal $FFA4.



                              |--------|--------| $FF9F
                        $FFA0 |10101011|11101010| $FFA1
          memory:       $FFA2 |11101010|--------| $FFA3
          --------      $FFA4 |--------|--------|

          register a2:  00000000000000001111111110100000  (=$ffa0)
          ------------

                               MOVE  (a2)+,(a2)+

                              |--------|--------| $FF9F
                        $FFA0 |10101011|11101010| $FFA1
          memory:       $FFA2 |10101011|11101010| $FFA3
          --------      $FFA4 |--------|--------|

          register a2:  00000000000000001111111110100100  (=$ffa4)
          ------------



4) INDIRECT ADDRESSING WITH PRE-DECREMENTATION:     (schematized -(an) )
   --------------------------------------------

   It is written as:
   -----------      +------------------------------------+
                    | Instruction      -(an),destination |
                    +------------------------------------+
                                      OR
                                      --
                    +------------------------------------+
                    | Instruction            source,-(an)|
                    +------------------------------------+

   And is read as:
   ----------
  Decrement (decrease) the value of the address register an according to
  the suffix of the instruction (by 1, 2, or 4), take the data pointed
  by this new value of 'an' and place it in (to) the destination operand.

                                     OR
                                     --
  Take the source operand, decrement the value of the register 'an' according to
  the suffix of the instruction (by 1, 2, or 4) then place it in
  to the address pointed by this new value of 'an'.

NB: Important, note that for this addressing mode the decrement of 
--- 'an' occurs before (sign '-' before '(an)'), this is where the 
    name PRE-decrementation comes from.
    For the addressing mode (an)+, the '+' sign is placed after '(an)',
    explaining the name POST-incrementation.


    This addressing mode is very similar to the post-incrementation
    (an)+ mode, except that here the address register 'an' decreases in
    value according to the suffix of the instruction.


Example:      Consider the following memory portion:
--------

              If the a2 register points to $FFA4:

                              |--------|--------| $FF9F
                        $FFA0 |10101011|11101010| $FFA1
          memory:       $FFA2 |11101010|00000001| $FFA3
          --------      $FFA4 |--------|--------|

          register a2:  00000000000000001111111110100100  (=$ffa4)
          ------------

      and if I write:        MOVE.L   -(a2),-(a2)

      Decrement a2 by 4 (bytes) because we have move.L, a2 now points to
      $FFA0, take the L-M located at $FFA0, decrement a2 again
      by 4, a2 now points to $FF9C and move the L-M to $FF9C

      resulting in:



                              |--------|--------| $FF9B
                        $FF9C |10101011|11101010| $FF9D
                        $FF9E |11101010|00000001| $FF9F
                        $FFA0 |10101011|11101010| $FFA1
          memory:       $FFA2 |11101010|00000001| $FFA3
          --------      $FFA4 |--------|--------|

          register a2:  00000000000000001111111110011100  (=$ff9c)
          ------------



      If now I make a2 point to $FFA0 and write:

                            MOVE.B   #23,-(a2)

      Take the byte 23 (=%00010111), decrement a2 by 1 (.B), a2
      will then be $FF9F and place the byte 00010111 at this new ad-
      dress.

      So:

                              |--------|--------| $FF9F
                        $FFA0 |10101011|11101010| $FFA1
          memory:       $FFA2 |11101010|00000001| $FFA3
          --------      $FFA4 |--------|--------|

          register a2:  00000000000000001111111110100000  (=$ffa0)
          ------------
                                 MOVE.B   #23,-(a2)

                                     results in:

                              |--------|00010111| $FF9F  (23 at $FF9F)
                        $FFA0 |10101011|11101010| $FFA1
          memory:       $FFA2 |11101010|00000001| $FFA3
          --------      $FFA4 |--------|--------|

          register a2:  0000000000000000111111111011111  (=$ffa0)
          ------------


5) INDIRECT ADDRESSING WITH DISPLACEMENT:       (schematized  d(an) )
   --------------------------------------

   It is written as:
   -----------       +------------------------------------+
                     | Instruction      d(an),destination |
                     +------------------------------------+

   And is read as:
   ----------
   Add the value (signed) of the displacement 'd' to the contents of the
   address register 'an', the data pointed by this new value of 'an' is
   placed in (to) the destination operand.

   So d(an)= d+(an)

   'd' is a signed integer (+ if MSB is zero, - if it's active)
   contained in a WORD: ( -32768 <= d < 32768 ).


   Example:      If the address register a3 points to $FFA0
   --------

                              |--------|--------| $FF9F
                        $FFA0 |--------|--------| $FFA1
          memory:       $FFA2 |--------|--------| $FFA3
          --------      $FFA4 |--------|--------|

          register a3:  00000000000000001111111110100000  (=$ffa0)
          ------------

          and I write:      MOVE.W  #458,2(a3)

          Place 458=%0000000111001010 at the address $FFA0+2=$FFA2

                                   resulting in:

                              |--------|--------| $FF9F
                        $FFA0 |--------|--------| $FFA1
          memory:       $FFA2 |00000001|11001010| $FFA3
          --------      $FFA4 |--------|--------|

          register a3:  00000000000000001111111110100000  (=$ffa0)
          ------------
          The register a3 remains unchanged!



6) INDIRECT ADDRESSING WITH INDEX AND DISPLACEMENT:  (schematized d(an,rn) )
   -----------------------------------------------
   It is written as:
   -----------  +---------------------------------------+
                | Instruction      d(an,rn),destination |
                +---------------------------------------+

   And is read as:
   ---------- 
   Add the signed value of the displacement 'd' contained in a WORD and
   the value of register 'rn' (address or data) to the register 'an', then
   move the pointed data to (into) the destination operand.

   so d(an,rn)= d+(an)+(an)   or    =d+(an)+(dn)

   If the register rn takes the suffix .w, its low-order word participates in
   the operation, if it takes the suffix .l, it participates in full. (default size .w)

 Example: If the address register a2 points to $FFA0 and the data register
 -------- d5 equals 122.

            If I write       MOVE.B   #2,5(a2,d5)

          Place the byte 2=%00000010 at 5+$FFA0+122=$1001F

                                        00000010
                                            |
                                           \|/
                              |--------|--------| $FF9F
                        $FFA0 |--------|--------| $FFA1
          memory:       $FFA2 |--------|--------| $FFA3
          --------      $FFA4 |--------|--------|

          register a2:  00000000000000001111111110100000  (=$ffa0)
          ------------
          register d5:  00000000000000000000000001111010  (=122)
          ------------
                                  resulting in:

                              |--------|--------| $1001D
                       $1001E |--------|00000010| $1001F
          memory:      $10020 |--------|--------| $10021
          --------      $10022 |--------|--------| $10023

          register a2:  00000000000000001111111110100000  (=$ffa0)
          ------------
          register d5:  00000000000000000000000001111010  (=122)
          ------------
          Both registers a2 and d5 remain unchanged!


NB: ATTENTION, some Assemblers (Metacomco) do not accept the syntax 
--- (an,rn) if d=0, you must write 0(an,rn) when d=0!

                              -----------------

PIECHOCKI Laurent
8, impasse Bellevue
57980 TENTELING                                  continued in COURS.DOC
                                                            ---------

Back to ASM_Tutorial