home *** CD-ROM | disk | FTP | other *** search
- *******************************************************************************
- * *
- * Program Documentation *
- * *
- *******************************************************************************
-
-
- Copyright © 1991 by Bjørn Reese.
-
-
- This article may be distributed freely, as long as no charge is being made.
- Please note that the article is copyrighted, and may not be changed in any way
- without the knowledge and written approval of the author (address is stated
- somewhere below).
-
- Before we go on, I would like to apologize for any grammatical and spelling
- mistake, which you without doubt will encounter. This article was originally
- written in danish for a danish magazine. I later decided to translate it to a
- more universal language in the hope more people could benefit from it.
-
- The article presents some principles of how to make useful, understandable and
- self-evident names for labels, and how to comment sources.
-
- The article is specifically aimed at Amiga (M680x0) assembly programmers, but
- I believe that other programmers also may find something useful in the basic
- principles of the convention defined in this article.
-
-
- *******************************************************************************
- Contents
- *******************************************************************************
-
- 1. Introduction
- 2. Comments
- 3. Procedures
- 4. Variables
- 5. Constants
- 6. Various (Instructions, Assembly Directives & Macros)
- 7. Final Words
-
-
- *******************************************************************************
- 1. Introduction
- *******************************************************************************
-
- The purpose of this article is to present some guidelines for internal
- documentation of sources, i.e. comments and name assignment of labels
- (procedures, variables, constants etc.), which makes more readable sources.
- This text is primary aimed at Amiga assembly programmers, but other programmers
- may also study the basic priciples with advantage. The guidelines have been
- developed and tested over a longer period of time by yours truly. It may take
- some time to get used with them, but it's worth while in the long run.
-
- Whenever I use the term "procedure", it refers to a subroutine with a clearly
- limited and well-defined function. For instance, if I wanted to make a
- program, which sorts the contents of a file, it would consist of three
- procedures. The first procedure gets the file, the second sorts it and finally
- the third saves the result. We got three clearly limited and well-defined
- functions. These may be split into more procedures, like the sorting, which
- consists of an initializing part and a sorting part.
-
- Big sources offers an exellent opportunity to loose the general view,
- especially if you havn't been engaged in the program for some time and perhaps
- developed and/or changed your programming style. The situation is even worse
- if you have to decipher the sources of another programmer. Lack of
- documentation often put us in a situation where a disassembly would have been
- just as good as the source, and that is quite unsatisfactory.
-
- An unlucky habit of many programmers is, that they don't bother to write very
- much besides the instructions. Their sources contains a minimum of comments
- (if any) and short, meaningless names of procedures, variables and constants.
-
- Whenever you write comments or name labels, THINK about what you write. It
- is important to find something descriptive, significant and relevant to the
- matter. In the long run it pays to sit and consider, before you write any
- comments or name your labels.
-
- Unfortunately I often witness "over-abbreviations", that is abbreviations which
- are so extreme that there is no way telling what the abbreviation originally
- represented. For instance:
-
- "r" = "Rollover"
- "sfc1" = "Star Field Counter 1"
-
- Non-english people should also be alerted about mixing english and their native
- language. It is almost impossible to decipher these abbreviations. Please
- keep a clear style in your comments and labels.
-
-
- *******************************************************************************
- 2. Comments
- *******************************************************************************
-
- If other people should be able to read your sources, it is important to include
- as many explanatory comments as possible. You should also be able to profit by
- comments in your own sources. If you return to a source of yours after a
- certain period of time, it takes at least a couple of centuries to regain the
- necessary knowledge of the source (believe me, I am talking from experience!).
- With efficient comments this time can be considerably reduced.
-
- While developing a program, you are completely familiar with the problematic of
- your program and it may seem unnessesary to make comments of something which
- seems so obvious. But it is worth while, because something that seems so
- obvious during development, seldom seem so obvious a couple of weeks or months
- later. Also, the "obvious" may not seem so obvious to other programmers, who
- don't have the same knowledge, experience and/or thoughts as yourself.
-
- It is however also easy to go to the other extreme, and make meaningless and
- superfluous comments which most often confuses more than it helps whose who
- read your sources.
-
- Example of a meaningless comment:
-
- move.l d4,a0 ;Dingdong!
-
- Example of a superfluous comment:
-
- add.w #14,d0 ;Add 14 to D0
-
- One of the best and most efficient ways to document sources is a header, i.e.
- a introductory comment of a procedure or parts of a procedure. This header
- must include information about what this procedure does, what input is required
- and what output is delivered. The header may also include more informations,
- like a pseudocode for the procedure or parts of it, references, general
- comments about the purpose of the procedure and about the expected result
- (especially around boundaries). The header often contributes to a optimization
- of the development because it forces you to think and to get a general view of
- the procedure belonging to the header.
-
- Example of a header:
-
- ;------------------------------------------------------------------
- ; @DoFormat
- ;------------------------------------------------------------------
- ;
- ; Convert a string using Exec.RawDoFmt().
- ;
- ; D0 [Output] will point to the formatted string, which is the
- ; buffer specified by A3 [Input]. Since A3 currently is restored
- ; you can use either D0 or A3 to get the string, but for the sake
- ; of compatibility use D0.
- ;
- ;------------------------------------------------------------------
- ; IN a1.l = ^String
- ; a2.l = ^List of Arguments
- ; a3.l = ^Text Buffer
- ; USED -
- ; OUT d0.l = ^Formatted String
- ;------------------------------------------------------------------
-
- DoFormat:
- ...
- rts
-
-
- Remarks of the example above:
-
- o The character "@" is used as a keyword for searching (more about this in the
- "7. Final Word" chapter).
-
- o I took the character "^" from Pascal where it represents a pointer (APTR).
- This means "^String" is a POINTER TO String (C-fanatics will recognize the
- character "*").
-
- o If no INput or OUTput is specified, it is noted by the character "-" instead
- of the registers. Is there another INput/OUTput than the registers, i.e. an
- array, it is surrounded by the characters "{" and "}".
-
- o USED is used by many, but personally I'm to lazy to check which registers
- have been used. It should only be used to specify registers which are changed
- by the procedure.
-
- o I prefer to write the majority of my comments and labels in english, since it
- is the computerlanguage. I strongly urge others (non-english) also to do so.
-
-
- Template of a header:
-
- ;------------------------------------------------------------------
- ; @<Name>
- ;------------------------------------------------------------------
- ;
- ; ???
- ;
- ;------------------------------------------------------------------
- ; IN ???
- ; { ??? }
- ; USED ???
- ; OUT ???
- ; { ??? }
- ;------------------------------------------------------------------
-
- The midmost and the last section of the header may optionally be skiped if
- they are not used.
-
-
- When you use a header, it is not so important to use inline comments (those
- placed after the instructions). Inline comments are only used if some
- instructions require an extra description or to refer to certain parts of a
- possible pseudocode.
-
- Even though the comments have to be significant and descriptive, they don't
- have to be boring. Try to vary your language. I often used citations to spice
- my source. The citations must however have a relation to what they must
- comment. As example I could mention a citation from the movie Blade Runner:
- "Wake up, time to die" as a comment to a software reset.
-
-
- *******************************************************************************
- 3. Procedures
- *******************************************************************************
-
- To find a name for a label may be done in countless ways and especially if a
- label is compounded of more words. The underscore (_) is often used to
- seperate the words, because a space normally can't be used in labels:
-
- my_label: or MY_LABEL:
-
- The guidelines for programming in Modula-2 gives us an alternative to the ugly
- underscore. Instead of seperating the words with underscores, all words are
- written in lowercase and the first letter of each word is capitalized:
-
- MyLabel:
-
- This offers us a whole new prospecive. It is important to be consistent with
- the use of capital letters. Some assemblers offers as an option not to
- distinguish between the case of the letters. My advise: Turn this option off!
- Also, never use the same word with different cases.
-
- In assembly language it can be difficult to distinguish if a certain label
- refers to a procedure or a variable, as they are written in the same way
- (namely "Label:").
-
- We now define that all procedure must start with an uppercase letter, and all
- variables must start with a lowercase letter:
-
- MyProcedure:
-
- myVariable:
-
- Now it is easy to see what type our label is, without having to jump back and
- forth in our source all the time. Furthermore we shall extend the definition
- of variables later on.
-
- Most assemblers supports the use of local labels (in case of doubt, look in
- your manual). If you use a local label it is only known until the assembler
- encounters the next normal label. Local labels are only used in procedures.
- This way it is possible to use a name in different procedures, whereby we avoid
- all these "loop1", "loop2" etc. Therefore, use local labels in the procedures
- as often as possible (Save the environment! Recycle! ;-)
-
- Example of local labels:
-
- FirstProc:
- lea text,a0
- move.w #10,d0
- .Loop tst.b (a0)+
- beq.s .Exit
- dbra d0,.Loop
- .Exit rts
-
- SecondProc:
- lea text,a0
- move.w #10,d0
- .Loop clr.b (a0)+
- dbra d0,.Loop
- rts
-
-
- Even though local labels theoretically also may be used as variable, it is too
- troublesome in reality, where they consequently seldom are used.
-
-
- *******************************************************************************
- 4. Variables
- *******************************************************************************
-
- We now extend the convention concerning variables, inspired by the "Hungarian
- Convertion" (developed by some guy at Microsoft). This method is particularly
- aimed at assembly programmers - because it is the language I have the biggest
- experience with, and I don't want to force some weird, untested convention on
- other programming languages - but other programmers may gain advantage of the
- corresponding principles. First and foremost:
-
- ALL VARIABLES MUST START WITH A TYPE DESCRIPTION!
-
- This type gives us information about the concerning variable. This way we
- avoid jumping back and forth in the source, to determine for example whether a
- variable is word or byte sized. This type could be "p" for "Pointer" or "w" or
- "Word":
-
- pDosBase = Pointer (APTR) to DosBase
- wIntReq = Interrupt Request (size = Word)
-
- I have reached the following practical types, during longer time of experiments
- and daily use:
-
- b = Byte
- w = Word
- l = Long
- p = Pointer [APTR]
- h = Handler [BPTR]
- f = Flag
- a = Array
- s = String [Array of Chars]
- d = (Arbitrary) Data Structure
- x = Extern Data [ex: Binary/Modules/Pictures]
- i = Index / Offset
- u = Unsigned
- v = Local Data [ex: Variables on Stack]
-
- Please remember: the type must be placed in front of the variable and
- consequently must be written in lowercase to comply with the principle of the
- distinction of procedures and variables from the previous chapter.
-
- Of course, it is possible to combine some of the types to reach a better
- clarification. This could be:
-
- ub = UBYTE (Unsigned Byte)
- uw = UWORD
- ul = ULONG
- fl = Flag Long
- iw = Index Word
- ap = Array of Pointers
- ab = Array of Bytes
- afb = Array of Flag Bytes
- auw = Array of UWORD
-
- Some of the types are very unlikely to appear in these combinations (though
- they might):
-
- "d" covers arbitrary data structures, like Window and Screen structures.
- "x" covers external binary files, like tables, pictures and music-modules.
-
- All of the types may be combined with "v", which indicates local data, like
- variables on the stack. Some of the types, like "x" are however rather
- unlikely to appear together with "v".
-
- NB! "v" doesn't make a variable local, it only indicates that the variable
- should be used in a local context.
-
-
- Examples of variables:
-
- fbDelay dc.b -1
- iwSinus: dc.w 22 ;Index for Sinus Table
- hFile: dc.l 0 ;File Handle [BPTR]
- awBuffer: dcb.w 20,0
- dWindow: dcb.b nw_SIZE,0
- xMusic: INCBIN "ST-00:mod.freudian"
-
-
- *******************************************************************************
- 5. Constants
- *******************************************************************************
-
- Constants are classified as variables, but they have their own type:
-
- c = Constant
-
- There is nothing much to add about the constants as they are only a subtype of
- the variables in this convention. It is also possible to combine the constant
- type with some of the variable types.
-
- Examples of constants:
-
- cMaxSize = 128
- clAddressAlert = $00000003
- ciFirstEntry = 44
-
-
- *******************************************************************************
- 6. Various (Instructions, Assembly Directives & Macros)
- *******************************************************************************
-
- The last definitions we need to complete this convention are about the
- instructions, the assembly directives and the macros. They must also be
- unique, to make the the convention effective.
-
- We define all instruction to solely consist of lowercase letters, and the
- assembly directives and the macros to solely consist of uppercase letters. The
- only exceptions are the dc/ds/dcb directives which of comprehensibility reasons
- are classified as instructions.
-
- Macros are often used to facilitate the readabillity of sources. For instance:
-
-
- Execute a function in an arbitrary library
- -------------------------------------------------------------------------------
- Syntax: CALL <Library function>
-
- Ex: CALL Forbid = jsr _LVOForbid(a6)
-
-
- Push registers to the stack
- -------------------------------------------------------------------------------
- Syntax: PUSH <Registers>
-
- Ex: PUSH d0/a0-a4 = movem.l d0/a0-a4,-(sp)
-
-
- Pull registers from the stack
- -------------------------------------------------------------------------------
- Syntax: PULL <Registers>
-
- Ex: PULL d0/a0-a4 = movem.l (sp)+,d0/a0-a4
-
-
-
- *******************************************************************************
- 7. Final Words
- *******************************************************************************
-
- Then using modules (linkable object code) we have to specify external
- references of both procedures and variables. These are specified by using an
- underscore (_) at the first position of the label:
-
- XREF _LVOAddTask
- XDEF _ClearScreen
-
- [NOTE 2] contains a complete example of a source documented using this
- convention. It is an old source of mine which I have updated to comply with
- the principles of the convention.
-
- It is unfortunately not possible to use this convention a 100%. We get a
- problem when we use the includes from Commodore. It is a bad idea however to
- change the includes, but if we are attentive of this problem we may live with
- this restriction. Besides, I diverge from the principles of the convention in
- two specific points: "start" and "DataArea" (no rule without exception).
- These are however the ONLY exceptions! If you absolutely have to be
- inconsistent, when be consistent with the inconsistent!
-
- Another advise I will pass is not to choose a name for a label that is too
- difficult to spell or too hard to remember. Choose easy names. I have for
- instance always thought that words like "width", "height" and "depth" have
- increased the possibility for spelling mistakes. Hence I substituted the words
- with the following words: "xSize", "ySize" and "zSize".
-
- If you are working with a big source, you may define keywords for all the
- procedures, which may be placed in the header. This should speed up the search
- for a specific procedure. To avoid the searching to stop at each reference of
- the procedure (i.e. each time it is called or jumped to), you could let the
- keyword start with the character "@". If I want to find the "NewMenu"
- procedure, I have to search for "@NewMenu".
-
- The convention described in this text is only a couple of guidelines, and it is
- up to you, whether you will use them or not, but since I started using them and
- became familiar with them, my development- and debugging time has been hugely
- reduced. [NOTE 1] consists of a template which I use in my own programs
- (written for AsmOne - if you use another assembler delete the BASEREG line).
- The template may vary a little, depending on the type of program I have to
- write.
-
- Remember! Not matter what you do: BE CONSISTENT.
-
-
- - BReese
-
-
- My address is
-
- Bjørn Reese
- Stammen 55, -2
- DK-5220 Odense SØ
- Denmark
-
-
-
-
- *******************************************************************************
- [NOTE 1]
- *******************************************************************************
-
- ;==================================================================
- ;===
- ;=== Name: ???
- ;===
- ;=== Author: ???
- ;===
- ;=== Date: dd. mmm yyyy
- ;===
- ;==================================================================
-
-
- ;--- Comment ------------------------------------------------------
- ;
- ; TAB = 8 ; POINTER = ^
- ;
- ;------------------------------------------------------------------
-
-
- ;--- System -------------------------------------------------------
-
- BASEREG DataArea,a5
- INCDIR INCLUDE:
-
- ;--- Include ------------------------------------------------------
-
- ;--- Macro --------------------------------------------------------
-
- ;--- Constant -----------------------------------------------------
-
-
-
- ;==================================================================
- ;===
- ;=== CODE AREA
- ;===
- ;==================================================================
-
- SECTION Reese,CODE
-
- start:
- moveq #0,d0
- rts
-
-
- ;------------------------------------------------------------------
- ; @<Name>
- ;------------------------------------------------------------------
- ;
- ; ???
- ;
- ;------------------------------------------------------------------
- ; IN ???
- ; { ??? }
- ; OUT ???
- ; { ??? }
- ;------------------------------------------------------------------
-
-
-
- ;==================================================================
- ;===
- ;=== DATA AREA
- ;===
- ;==================================================================
-
- ;--- Structure ----------------------------------------------------
-
- ;--- SmallCode ----------------------------------------------------
-
- ;--- Variable -----------------------------------------------------
-
- DataArea:
-
-
- ;--- Text ---------------------------------------------------------
-
- ;--- Table --------------------------------------------------------
-
- ;--- Extern -------------------------------------------------------
-
-
- ;==================================================================
- ;===
- ;=== BUFFER AREA
- ;===
- ;==================================================================
-
- ; SECTION buffer,BSS
-
-
-
- *******************************************************************************
- [NOTE 2]
- *******************************************************************************
-
- ;==================================================================
- ;===
- ;=== Name: CountSort (Sort an array of integers)
- ;===
- ;=== Author: Bjørn Reese
- ;===
- ;=== Date: January 1991
- ;===
- ;==================================================================
- ;===
- ;=== Copyright © 1991 by Bjørn Reese
- ;===
- ;==================================================================
-
-
- ;--- Comment ------------------------------------------------------
- ;
- ; TAB = 8 ; POINTER = ^
- ;
- ; The numbers in awNumbers are sorted.
- ; NB! cMaxNum must be equal to or greater than the biggest number
- ; in awNumbers.
- ;
- ;------------------------------------------------------------------
-
-
- ;--- System -------------------------------------------------------
-
- BASEREG DataArea,a5
- INCDIR INCLUDE:
-
- ;--- Constant -----------------------------------------------------
-
- cMaxNum = 32 ;Biggest number in awNumbers ( [0..cMaxNum-1] )
- cLength = 16 ;Numbers of words in awNumbers
-
-
- ;==================================================================
- ;===
- ;=== CODE AREA
- ;===
- ;==================================================================
-
- SECTION CountSort,CODE
-
- start:
-
- ;--- Do the entire sorting
-
- bsr ClearBuffer
- bsr Count
- bsr CountResult
-
- ;--- Exit without error messages
-
- moveq #0,d0
- rts
-
-
- ;------------------------------------------------------------------
- ; @ClearBuffer
- ;------------------------------------------------------------------
- ;
- ; Clear awCountBuffer before use.
- ; cMaxNum must be even.
- ;
- ;------------------------------------------------------------------
- ; IN -
- ; USED d0/d1/a0
- ; OUT -
- ; { awCountBuffer empty }
- ;------------------------------------------------------------------
-
- ClearBuffer:
- lea awCountBuffer,a0
- moveq #0,d0
- move.w #cMaxNum/2-1,d1
- .Loop move.w d0,(a0)+
- move.w d0,(a0)+
- dbra d1,.Loop
- rts
-
- ;------------------------------------------------------------------
- ; @Count
- ;------------------------------------------------------------------
- ;
- ; Counts the appearence of the numbers in awNumbers and accumulate
- ; CountBuffer
- ;
- ; FOR cnt = 0 TO cLength-1
- ; num := awNumbers[cnt]
- ; awCountBuffer[num] += 1
- ; NEXT
- ;
- ; NB!!! [] indicates index (ex: Array[index])
- ;
- ;------------------------------------------------------------------
- ; IN -
- ; { Emtpy awCountBuffer }
- ; USED d0/d1/a0/a1
- ; OUT -
- ; { awCountBuffer accumulated }
- ;------------------------------------------------------------------
-
- Count:
- lea awNumbers(pc),a0
- lea awCountBuffer,a1
- move.w #cLength-1,d1
- .Loop move.w (a0)+,d0
- add.w d0,d0 ;Adjust to word boundary
- addq.w #1,(a1,d0.w) ;awCountBuffer[num] += 1
- dbra d1,.Loop
- rts
-
- ;------------------------------------------------------------------
- ; @MakeResult
- ;------------------------------------------------------------------
- ;
- ; Stores numbers in awNumbers according to numbers in awCountBuffer.
- ;
- ; cnt2 := 0
- ; FOR cnt = 0 TO cMaxNum-1
- ; WHILE awCountBuffer[cnt] > 0
- ; awNumbers[cnt2] := cnt
- ; awCountBuffer[cnt] -= 1
- ; cnt2 += 1
- ; WEND
- ; NEXT
- ;
- ; NB!!! The code has been optimized, so it doesn't look like the
- ; pseudocode above, but it's based on it. cLength is used instead
- ; of cMaxNum.
- ;
- ;------------------------------------------------------------------
- ; IN -
- ; { Accumulated awCountBuffer }
- ; USED d0/d1/d2/a0/a1
- ; OUT -
- ; { awNumbers sorted }
- ;------------------------------------------------------------------
-
- MakeResult:
- lea awCountBuffer,a0
- lea awNumbers(pc),a1
- moveq #0,d0
- move.w #cLength-1,d1
- bra.s .Loop
- .Next addq.w #1,d0 ;Next number
- addq.w #2,a0 ;Next entry in awCountBuffer
- .Loop subq.w #1,(a0) ;CountArray[cnt] -= 1
- blt.s .Next
- move.w d0,(a1)+
- dbra d1,.Loop
- rts
-
-
- ;==================================================================
- ;===
- ;=== DATA AREA
- ;===
- ;==================================================================
-
- ;--- Variable -----------------------------------------------------
-
- DataArea:
-
-
- ;--- Table --------------------------------------------------------
-
- awNumbers: ;An example
- dc.w 5,22,6,31,5,1,3,3,5,6,7,25,15,9,0,21
-
-
- ;==================================================================
- ;===
- ;=== BUFFER AREA
- ;===
- ;==================================================================
-
- SECTION buffer,BSS
-
- awCountBuffer ds.w cMaxNum
-
-
- *******************************************************************************
- [NOTE 3]
- *******************************************************************************
-
- ;==================================================================
- ;===
- ;=== Name: Another test example (which finds Dos Library)
- ;===
- ;=== Author: Bjørn Reese
- ;===
- ;=== Date: October 1991
- ;===
- ;==================================================================
-
-
- ;--- Comment ------------------------------------------------------
- ;
- ; TAB = 8 ; POINTER = ^
- ;
- ; a5 is a global pointer to the DataArea.
- ;
- ;------------------------------------------------------------------
-
-
- ;--- System -------------------------------------------------------
-
- BASEREG DataArea,a5
- INCDIR INCLUDE:
-
- ;--- Include ------------------------------------------------------
-
- INCLUDE exec/exec_lib.i
- INCLUDE exec/execbase.i
-
- ;--- Macro --------------------------------------------------------
-
- CALL: MACRO
- jsr _LVO\1(a6)
- ENDM
-
-
- ;--- Constant -----------------------------------------------------
-
- cSysBase = 4
-
-
- ;==================================================================
- ;===
- ;=== CODE AREA
- ;===
- ;==================================================================
-
- start:
- lea DataArea(pc),a5 ;GLOBAL
-
- lea sDosName(a5),a1
- bsr GetLibrary
- move.l d0,pDosBase(a5)
-
- moveq #0,d0
- rts
-
- ;------------------------------------------------------------------
- ; @GetLibrary
- ;------------------------------------------------------------------
- ;
- ; Find an already opened and initialized library in the LibList
- ; of Exec Library.
- ;
- ; NB!!! Only use this method for ROM-resident Libraries.
- ;
- ;------------------------------------------------------------------
- ; IN a1.l = ^Library Name
- ; OUT d0.l = ^Library Base
- ;------------------------------------------------------------------
-
- GetLibrary:
- move.l cSysBase,a6
- move.l LibList(a6),a0
- CALL FindName
- rts
-
- ;==================================================================
- ;===
- ;=== DATA AREA
- ;===
- ;==================================================================
-
- ;--- Variable -----------------------------------------------------
-
- DataArea:
- pDosBase: dc.l 0
-
- ;--- Text ---------------------------------------------------------
-
- sDosName: dc.b 'dos.library',0
- EVEN
-
-
- *******************************************************************************
- [NOTE 4]
- *******************************************************************************
-
- Types Meaning
- ------------------------------------------------------------------
- b = Byte
- w = Word
- l = Long
- p = Pointer [APTR]
- h = Handler [BPTR]
- f = Flag
- a = Array
- s = String [Array of Chars]
- d = (Arbitrary) Data Structure
- x = Extern Data [ex: Binary/Modules/Pictures]
- i = Index / Offset
- u = Unsigned
- v = Local Data [ex: Variables on Stack]
- c = Constant
- ------------------------------------------------------------------
-