home *** CD-ROM | disk | FTP | other *** search
/ Archive Magazine 1995 / ARCHIVE95.iso / discs / shareware / share_46 / sasm / Docs / Tutorial < prev    next >
Text File  |  1993-03-20  |  13KB  |  279 lines

  1.  
  2.                    --==>> Basic Assembler Tutorial <<==-- 
  3.  
  4.                            (C) D.J.Holden 1990 
  5.  
  6. This short text will not attempt to teach you how to write in Assembler for 
  7. the Archimedes. I assume that you are already familiar with ARM machine code 
  8. and the use of the Basic Assembler. If you are not I can recommend the book 
  9. 'Archimedes Assembly Language' by Mike Ginns published by Dabs Press. My 
  10. purpose is to describe some of the more advanced ways in which the Basic 
  11. Assembler can be used. My primary purpose is to help you to understand how 
  12. to use Macros with SAsm but everything in this text is written so that it 
  13. can be applied directly to the Basic Assembler. In fact SAsm has a more
  14. powerful type of Macro, the Expanded Macro, but this cannot be used by
  15. the Basic Assembler so will not be described here and you are refered to
  16. the Manual to find out about them.
  17.  
  18.        Simple use of Macros 
  19.        ~~~~~~~~~~~~~~~~~~~~ 
  20. A Macro in assembler terms is a way of writing a pre-defined piece of code 
  21. which the assembler uses when it finds a specific instruction in the source 
  22. code. This means that if you have a series of instructions that occur many 
  23. times in the program you need only write it once and each time you need that 
  24. routine you invoke the macro and the assembler will assemble the 
  25. instructions you have previously defined or 'expand' the macro. This not 
  26. only saves time and effort and makes the code easier to follow but also 
  27. avoids mistakes. Once you have written and tested a macro the chance of 
  28. error caused by mistyping a register number or mnemonic is minimised. 
  29.  
  30. There are as many different ways of defining and invoking macros as there 
  31. are assemblers, but most permit the passing of PARAMETERS so the macro 
  32. definition may be modified in some way each time it is expanded. 
  33.  
  34. The Basic Assembler allows the use of macros in assembly language by means 
  35. of Functions. These are perfectly normal Basic Functions and should be 
  36. defined after the END statement in your program. 
  37.  
  38. For example, suppose that you needed to repeatedly use the instructions; 
  39.  
  40.                MOV r0,#21 
  41.                MOV r1,#0 
  42.                SWI "OS_Byte" 
  43.  
  44. This is the familiar 'FX21,0' which flushes the keyboard buffer. To save 
  45. writing this over and over again define a function 'FNflush' 
  46.  
  47.        DEFFNflush 
  48.                [OPT PASS 
  49.                MOV r0,#21 
  50.                MOV r1,#0 
  51.                SWI "OS_Byte" 
  52.                ] 
  53.        =0 
  54.  
  55. Now each time you want to flush the keyboard buffer instead of writing the 
  56. actual instruction in your code you just write 
  57.  
  58.        FNflush 
  59.  
  60. and when the code is assembled Basic will look for the Function 'flush' and 
  61. do whatever is required, in this case assemble the three instructions. 
  62.  
  63. You can use the same principle to flush any buffer rather than just the 
  64. keyboard. In this case you could pass the number of the buffer you wish to 
  65. flush as a Parameter. 
  66.  
  67.        DEFFNflush (buffer_number) 
  68.                [OPT PASS 
  69.                MOV r0,#21 
  70.                MOV r1,#buffer_number 
  71.                SWI "OS_Byte" 
  72.                ] 
  73.        =0 
  74.  
  75. Now to flush the keyboard buffer you would use  FNflush (0)  or the printer 
  76. buffer  FNflush (3)  and so on. 
  77.  
  78. You can see that with sensibly chosen names your code can be made much 
  79. easier to follow and therefore to modify and debug. FNflush (0) is more 
  80. easily recognised as a macro to flush buffer number 0 than the actual code, 
  81. when you would first need to remember what OSByte 21 does. 
  82.  
  83. The previous examples are very simple and contain only a few lines of code 
  84. but sometimes macros can be quite complex and contain multi-option 
  85. conditional assembly and themselves call other macros. 
  86.  
  87.  
  88.        Writing Macros 
  89.        ~~~~~~~~~~~~~~ 
  90. You should take note of three things about the previous examples. The first 
  91. is that once Basic has entered the Function it has forgotten that it was 
  92. actually assembling machine code. It remembers again when it leaves the 
  93. Function but inside the Function you need to open the assembler brackets, 
  94. define the OPT setting and close them again before you finish. 
  95.  
  96. I have used the variable PASS to determine the OPT setting and you should 
  97. use whatever variable you have used in the main part of your code so that 
  98. the macro will be assembled with the same OPT setting as the rest. The 
  99. exception to this is where forward references are required in a macro and 
  100. this will be described later. 
  101.  
  102. The second thing is that the macro ends with '=0'. This is called a 'Null 
  103. Function' and it means that the assembler doesn't require any result to be 
  104. returned so it is just a way of ending the function. If you were writing 
  105. Basic you would normally use a Procedure rather than a Function in these 
  106. circumstances but you can't call Procedures from within the assembler so we 
  107. use a Null Function instead. 
  108.  
  109. The third thing, which follows on from the second, is that in 'normal' basic 
  110. a Function must always be called as <something>=FNwhatever. When using 
  111. Functions as Macros in assembler they are NOT called in this way which is 
  112. why the result returned is irrelevant.
  113.  
  114.  
  115.        Forward References in Macros 
  116.        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  117. You must remember that when a macro is expanded the code is assembled as a 
  118. part of the main code after substituting any parameters so any labels will 
  119. be defined EACH TIME THE MACRO IS CALLED. At first sight this might not seem 
  120. a problem but when Basic assembles a program it records all the labels on 
  121. the first pass and uses the definitions it has found on the second. This 
  122. means that if a label is defined twice then the LAST definition is the one 
  123. that will be used throughout the second pass. 
  124.  
  125. This is no problem when writing loops with backward branches because no 
  126. matter how many times the macro is expanded the current definition for a 
  127. backward label is the last definition which is the one that is required. I 
  128. often use this to avoid creating a new label for a simple loop by using the 
  129. label 'loop' at the start, then when I branch back to 'loop' the branch 
  130. instruction is assembled with the offset to the last 'loop'. Use this with 
  131. caution as it is easy to move or modify the code and upset everything. 
  132.  
  133. With a forward branch things are different. For example, consider this 
  134. simple macro; 
  135.  
  136.        DEFFNtest 
  137.                [OPT PASS 
  138.                MOV r3,#4 
  139.                MOV r4,#3 
  140.                CMP r0,r1 
  141.                BNE skip 
  142.                MOV r3,#3 
  143.                MOV r4,#4 
  144.        .skip   MOV r0,#&FF 
  145.                ] 
  146.        =0 
  147.  
  148. This would really be better using conditional instructions but consider what 
  149. happens during assembly if the macro has been used more than once. 
  150.  
  151. On the first pass the assembler will record the value of 'skip' as the 
  152. address of the label the LAST time the macro was expanded. When the second 
  153. pass is started the value of skip will therefore be wrongly set for the 
  154. FIRST time the macro was expanded and any branch will go straight to the 
  155. LAST macro expansion, not at all what was intended. 
  156.  
  157. Making the label a LOCAL variable doesn't help because it is the same LOCAL 
  158. variable each time the macro is called. To get around this problem we must 
  159. use subterfuge and force the assembler to do two passes within the macro 
  160. each time it assembles it, therefore ensuring that the labels are updated 
  161. whenever it is called. 
  162.  
  163. The code now becomes; 
  164.  
  165.        DEFFNtest 
  166.        old_P%=P% : old_O%=O% 
  167.        FOR pass%=4 TO 6 STEP 2 
  168.        P%=old_p% : O%=old_o% 
  169.                [OPT pass% 
  170.                MOV r3,#4 
  171.                MOV r4,#3 
  172.                CMP r0,r1 
  173.                BNE skip 
  174.                MOV r3,#3 
  175.                MOV r4,#4 
  176.        .skip   MOV r0,#&FF 
  177.                ] 
  178.        NEXT 
  179.        =0 
  180.  
  181. This will go into its own two pass loop each time it is assembled and so 
  182. ensure that the forward branch always goes to the correct 'skip'. 
  183.  
  184. It works as follows. Firstly the values of P% and O% are copied to old_O% 
  185. and old_P%. This is necessary so that the actual P% and O% can be reset to 
  186. the correct value for the second pass. Next a FOR-NEXT loop is created 
  187. around the code using the variable pass% instead of PASS which I normally 
  188. use in the main part of my code. You can of course make these variable LOCAL 
  189. if you wish to avoid conflict with others defined in the main part of the 
  190. program. I have used OPT settings of 4 and 6 to give offset assembly with no 
  191. listing but this can be changed if required. 
  192.  
  193. When Basic expands the Function it will make two passes for each pass of the 
  194. main code. The first pass will define the label 'skip' and the second pass 
  195. will set the branch offset, so each branch will go to the correct 'skip' 
  196.  
  197.        Conditional Assembly 
  198.        ~~~~~~~~~~~~~~~~~~~~ 
  199. This means writing a part of a program which can be assembled in more than 
  200. one way depending upon a CONDITION. You can use any condition you like, 
  201. whether you are holding down a certain key (my favourite), whether you have 
  202. set a certain variable at the start of the program, whether it's after 
  203. midnight on Friday or anything else you care to devise. 
  204.  
  205. There are two main uses for conditional assembly in stand-alone machine code 
  206. programs, although when you are assembling code to be used as a sub routine 
  207. within a Basic program there are lots of others. The main reasons are to 
  208. produce different versions and to assemble different code in a macro 
  209. depending upon the parameters passed. 
  210.  
  211. I make use of the first to assemble different versions of Shareware programs 
  212. for Registered and Unregistered users. For example the Standard and Advanced 
  213. versions of SAsm are both assembled from a single set of source files. This 
  214. means that when I improve the program or add features I need only change one 
  215. file. I just hold down the SHIFT key when assembling the files and use 
  216. conditional assembly to leave out the features I don't want the Standard 
  217. version to have. You can also use conditional assembly to create versions 
  218. for different countries by writing messages in alternative languages and 
  219. assembling the appropriate version. 
  220.  
  221. The second use is important because it enables you to use a single macro 
  222. definition to produce a whole series of different sets of code. For example 
  223. the FNmov macro which is built in to SAsm will load a register with any 32 
  224. bit positive or negative number. It does this by assembling different 
  225. instructions depending upon the sign of the number and will assemble from 
  226. one to four instructions depending upon it's size. All this is completely 
  227. transparent when you are writing the code of course, the macro uses 
  228. conditional assembly to make all the decisions for you. 
  229.  
  230. The simplest method is with an IF THEN - (ELSE) - ENDIF construct, although 
  231. you can use WHILE - ENDWHILE or CASE statements. As an example suppose that 
  232. you include the following line near the start of your program; 
  233.  
  234.        IF INKEY(-1) shift%=TRUE ELSE shift%=FALSE 
  235.  
  236. The variable shift% will return TRUE if the shift key was held down and 
  237. FALSE if not. Now consider the following code somewhere in the program. 
  238.  
  239.        ........                            ; some code 
  240.        ........
  241.        ]                                   : REM leave assembler 
  242.        IF shift%=TRUE THEN 
  243.        [OPT PASS                           ; back in assembler 
  244.        swi "OS_WriteS" 
  245.        equs "The SHIFT key was held"       ; display a message 
  246.        equb 0 : align 
  247.        ]                                   : REM back to Basic 
  248.        ELSE 
  249.        [OPT PASS                           ; back in assembler 
  250.        swi "OS_WriteS" 
  251.        equs "The SHIFT key was NOT held"   ; display a message 
  252.        equb 0 : align 
  253.        ]                                   : REM back to Basic 
  254.        ENDIF 
  255.        [OPT PASS 
  256.        ........                            ;back to the program 
  257.        ........ 
  258.  
  259. This will display a message which will be different depending upon whether 
  260. or not you held down the SHIFT key when the code was assembled. 
  261.  
  262. For another example; 
  263.  
  264.        DEFFNadd (reg_1,reg_2,number) 
  265.                [OPT PASS 
  266.                ADD reg_2,reg_1,#(number AND &FF) 
  267.                ] 
  268.        IF number AND &FF00 >0 THEN 
  269.                [OPT PASS 
  270.                ADD reg_2,reg_2,#(number AND &FF00) 
  271.                ] 
  272.        ENDIF 
  273.        =0 
  274.  
  275. This will assemble instructions to add a 16 bit number 'number' to register 
  276. 'reg_1' and put the result in 'reg_2'. The first 'ADD' instruction to add 
  277. the bottom 8 bits will always be assembled but the second instruction to add 
  278. the top 8 bits will only be assembled if there is something to add. 
  279.