home *** CD-ROM | disk | FTP | other *** search
/ APDL Public Domain 1 / APDL_PD1A.iso / program / assembler / armmaker / !ARMmaker / ARMmakeDOX < prev    next >
Encoding:
Text File  |  1994-08-08  |  28.1 KB  |  742 lines

  1. ARMmaker
  2. An ARM assembler, including AOF and floating point assembly
  3. (C) Steven Haslam 1994
  4. -----------------------------------------------------------------------------
  5. This program may be used with Acorn Computers' Desktop Development
  6. Environment, but may also be used as a standalone for any suitable
  7. application, e.g. ANSI C release 3. It may also be used to assemble code to
  8. run from RiscOS without other supporting programs.
  9. -----------------------------------------------------------------------------
  10. All of the program code was written by Steven Haslam.
  11. Floating point instruction format deduced from BASIC library by TJ Chappell
  12. Coprocessor and SWP instruction format deduced from !AS by Niklas Röjemo
  13. My thanks to these authors.
  14. -----------------------------------------------------------------------------
  15. ARMmaker is "FreeWare": its copying and distribution are permitted provided
  16. that no profit is being made: see the end of the file for details.
  17. -----------------------------------------------------------------------------
  18.  
  19. Programmers will be aware of the ARM assembler built into BBC BASIC. However,
  20. this assembler has limitations, including, but not limited to:
  21.  
  22.    Inability to export to AOF files: for use with C, Pascal or very large
  23. machine code projects.
  24.    Floating point/coprocessor functions not built in.
  25.    Range of ADR limited to single-instruction capability
  26.  
  27. Of course, if you want a DDE assembler with all the features, you can buy
  28. Acorn's own Desktop Assembler. A snip; costs >=£100, I believe. By
  29. comparison, ARMmaker is *FREE* (see end of file for details).
  30.  
  31. ARMmaker is not a mega-assembler. It's an assembler "what I wrote" to cover
  32. the points above (although all but AOF export can be handled (just about) in
  33. BASIC). It was written after I got fed up with "TLA", another PD AOF
  34. assembler (ok, but no floating-point, nasty syntax (IMHO), I keep losing the
  35. documentation, no throwback &c. &c.)
  36.  
  37. Basically, ARMmaker can:
  38.  
  39.    Read an assembly listing from one or more files (using the INCLUDE command
  40. to read from a different file).
  41.    Assemble the code, offering features such as macro expansion, symbol
  42. import and export (with AOF), register bindings, multiple areas (AOF),
  43. floating point instructions, local labels &c.
  44.    Report errors in a vaguely sensible manner (mre detailed messages than
  45. with the BASIC assembler most of the time), including via the "throwback"
  46. mechanism where errors are sent to your text editor
  47. (SrcEdit/StrongED/Zap/DeskEdit &c.)
  48.    Export the assembled machine code to any of the standard code formats on
  49. Risc-OS; i.e. straight code with types Utility, Module, Absolute, code with
  50. load/execution addresses set directly, or AOF (written as a Data-type file).
  51.  
  52. ARMmaker is supplied as a DDE tool, the application !ARMmaker. This
  53. application contains the actual program, and includes some standard
  54. definitions that can be included into your source file.
  55.  
  56. ARMmaker and the DDE
  57. ====================
  58.  
  59. If you intend to use ARMmaker with the DDE, then you will want to copy the
  60. !ARMmaker application into your DDE directory, along with !CC, !Link and so
  61. on. You can add ARMmaker as a tool to !Make. Load the file
  62. "!Make.choices.tools" and go to the bottom of the file. Now add the following
  63. six lines to the end of the file:
  64.  
  65. ARMmaker
  66. arm
  67. -d !Depend -t
  68. ARMmaker $(ARMmakerflags) -o $@ $<
  69. <ARMmaker$Dir>.Desc
  70. <ARMmaker$Dir>.!Setup
  71.  
  72. Resave the file. You will have to quit !Make and re-run it before you can use
  73. the new option. ARMmaker files should go in a directory called "arm" (in the
  74. same directory as "c", "o" and "h") to be automatically recognised as
  75. ARMmaker source files.
  76.  
  77. ARMmaker without the DDE
  78. ========================
  79.  
  80. The !ARMmaker application defines an alias to run the ARMmaker executable
  81. from inside itself whenever the command "armmaker" is executed, e.g. from a
  82. makefile.
  83.  
  84. The command to assemble a file is:
  85.  
  86.    armmaker <filename> [-o <outputfile>][-t]
  87.  
  88. The "-t" option enables throwback.
  89. A default will be used if the "-o" option is omitted, but you will be warned.
  90.  
  91. ARMmaker other details
  92. ======================
  93.  
  94. ARMmaker is a one-pass assembler. Therefore, when you use a symbol that isn't
  95. understood, ARMmaker remembers the reference. When you finally define the
  96. symbol, all the references are put into the code (relocate branches, ADRs
  97. &c.) and then deactivated.
  98.  
  99. One point is that if you do an ADR as a forward reference, and then when the
  100. symbol is defined it's out of range, it will only be detected at the symbol
  101. definition. However, ARMmaker WILL tell you the line number of the reference
  102. that cannot be resolved: but your throwback window will not necessarily have
  103. the line numbers is monotonically ascending order! You have been warned!
  104.  
  105. ARMmaker source files
  106. =====================
  107.  
  108. ARMmaker source files differ greatly from BASIC source code, being modelled
  109. more on the Desktop Assembler, itself modelled on the accepted layouts of
  110. assembler code on other platforms (ptui!).
  111.  
  112. At any point in the file, a semicolon (';') indicates a comment, starting at
  113. and including the semicolon up to and excluding the end-of-line character.
  114.  
  115. If the first character on a line is not a space or a tab (collectively called
  116. "whitespace") then it is the start of a label. Notice that labels are not
  117. preceded by a character (unlike BASIC) and must not be suffixed with a
  118. character (unlike TLA).
  119.  
  120. The start of the line is called the label "field".
  121.  
  122. After the label field is the "instruction/directive field". This is separated
  123. from the label field by whitespace. This field might be followed by a
  124. "parameter field" (separated, again, by whitespace).
  125.  
  126. Let's see how that looks in practice. This is an example with all three
  127. fields:
  128.  
  129. loop           MOV   R0, #0      ; This is a comment
  130.  
  131. Because "loop" is right at the start of the line, it's a label definition.
  132. ARMmaker defines a symbol called "loop" and sets it to point to the current
  133. position in the file. You can't have another symbol called "loop"; if you
  134. want lots of loops in your code, use local labels (see below) or call them
  135. all something different (mind-boggling!).
  136.  
  137. The instruction field is "MOV", which you should recognise as an ARM
  138. instruction. The parameters field is "R0, #0". The comment is stripped off
  139. before the fields are looked at.
  140.  
  141. So, this line will define a label, called "loop". The first instruction of
  142. the loop will be "MOV R0, #0".
  143.  
  144. Here is a silly chunk of code:
  145.  
  146. label1         STMFD    R13!, {R14}
  147.                MOV      R0, #32
  148.                MOV      R1, #127
  149. loop           SWI      "OS_WriteC"
  150.                ADD      R0, R0, #1
  151.                CMP      R0, R1
  152.                ADDEQ    R0, R0, #1
  153.                CMP      R0, #256
  154.                BNE      loop
  155.                LDMFD    R13!, {PC}^
  156.  
  157. Try deciding what this piece of code does, and what ARMmaker does when it
  158. assembles it.
  159.  
  160. It is perfectly OK to have just a label on a line, and no instruction. So,
  161. replacing the 3rd to 5th lines of the above code with the following four will
  162. actually have no effect on the finished machine code:
  163.  
  164.                MOV      R1, #127
  165. loop
  166.                SWI      "OS_WriteC"
  167.                ADD      R0, R0, #1
  168.  
  169. As well as machine code instructions, there are "directives" (as opposed to
  170. instructions) that are processed by ARMmaker. These may produce output
  171. directly, or may affect it in some more subtle way.
  172.  
  173. Every properly-written source file will have some directives, certainly at
  174. the top of the file. You ought to have a directive telling ARMmaker what type
  175. of file you are making, for example.
  176.  
  177. The first directive that I'll show you is called "OUTPUT". You use it just
  178. like an instruction called OUTPUT, except that you can't use it on the same
  179. line as a label, which wouldn't be very useful anyway.
  180.  
  181. OUTPUT is to specify what kind of file you are making; you give it one
  182. parameter, which may be one of the following:
  183.  
  184.       ABSOLUTE    Code that loads to and starts at address &8000, type &FF8.
  185.       MODULE      A relocatable module, type &FFA, with a special header.
  186.       UTILITY     Transient code that is must be completely relocatable, type
  187. &FFC.
  188.       AOF         Acorn Object File, an input file that is sent to "link",
  189. and contains functions that can be shared with C or Pascal programs.
  190.       DIRECT      "Directly executable" code that loads to a specific area of
  191. memory and starts at some user-specified point within memory. Also called
  192. "untyped" files, since they don't have a standard filetype.
  193.  
  194. For example, to tell ARMmaker that you are writing an "Absolute" file, you
  195. would have this line at the top of your file:
  196.  
  197.             OUTPUT   ABSOLUTE
  198.  
  199. To "include" another file inside your source file (i.e. go process another
  200. file and then come back to the one before), use the "INCLUDE" directive. Give
  201. the name of the file as a parameter. ARMmaker will first look in the locality
  202. of the source file, and then on ARM$Path.
  203.  
  204.             INCLUDE  inc.APCS-R
  205.  
  206. If you are writing an AOF file, you will need to declare an area. All object
  207. files are separated into areas. Most have two: one for code, and one for
  208. data.
  209.  
  210. Areas all have names, which are unique within an object file, and local to
  211. it. They are normally "<lang>$$Code" and "<lang>$$Data": C creates areas
  212. called "C$$Code" and "C$$Data", for example.
  213.  
  214. Use the "AREA" directive to declare an area. You must give the areas name,
  215. and some flags telling ARMmaker (and therefore link) about the area.
  216.  
  217. Generally, you will only need two, or maybe three kinds of areas. The first
  218. kind, a code area, is defined like this:
  219.  
  220.             AREA     ARM$$Code:CODE,READONLY
  221.  
  222. A data area is defined like this:
  223.  
  224.             AREA     ARM$$Data:DATA
  225.  
  226. The third kind of area is a zero-initialised area. This is slightly different
  227. in that you can't put code in a zero-initialised area, obviously. Instead,
  228. you must give the size of the area in the declaration, like this:
  229.  
  230.             AREA     ARM$$ZIData:DATA,ZINIT,SIZE=512
  231.  
  232. where 512 is replaced by the size of the zero-initialised data you want
  233. included.
  234.  
  235. An important feature of AOF files is importing and exporting symbols between
  236. different object files. But you must tell ARMmaker to do this. If you want to
  237. use the symbol "printf" in your machine code function, you must tell ARMmaker
  238. to import it, using the "IMPORT" directive:
  239.  
  240.             IMPORT   printf
  241.  
  242. Similarly, if you want to use a machine code function (e.g. "armfunc")
  243. outside your object file (e.g. from a C program), you must tell ARMmaker to
  244. export it, using the "EXPORT" directive:
  245.  
  246.             EXPORT   armfunc
  247.  
  248. There are limits on what you can do when using imported symbols. You can
  249. always branch straight to an imported symbol: no problem. But you can't use
  250. it directly with ADR or LDR. For example, if you've imported printf as above,
  251. then
  252.  
  253.             BL       printf
  254.  
  255. will work but
  256.  
  257.             ADR      R12, printf
  258.  
  259. will not. What you can do, however, is store the address of printf inside
  260. your code area, and load that. For this, use the "DCD" directive, which is a
  261. bit like BASIC's EQUD.
  262.  
  263. printf_ptr  DCD      printf
  264. ; And later on...
  265.             LDR      R12, printf_ptr
  266.  
  267. The same thing even occurs when accessing data from your data area: it can't
  268. be accessed directly using ADR or LDR! You can either have a pointer to
  269. everything, or you can just store a pointer to your data area, and add offset
  270. to that, e.g.:
  271.  
  272. data_ptr    DCD      ARM$$Data      ; ARMmaker defines this label for you
  273. ; When you need data...
  274.             LDR      R12, data_ptr
  275.             LDR      R12, [data_ptr, #data_offset]
  276.  
  277. You could even use the macro facilites of ARMmaker to do this more easily
  278. (see below).
  279.  
  280. Now, I'll explain the "DC..." directives in more detail. These are for
  281. storing Data Constants in the output, and are like BASIC's EQUB, EQUD, EQUW,
  282. EQUS &c. with the addition also of "DCF" (there is no EQUF).
  283.  
  284. DCD stores a 32-bit value, and can also store have the value of an imported
  285. symbol added to it during linking.
  286. DCW stores a 16-bit value, which must be a constant.
  287. DCB stores an 8-bit value, which must be a constant.
  288. DCS stores a string. It does not store a terminator.
  289. DCFS stores a single-precision floating point number.
  290. DCFD stores a double-precision floating point number.
  291. Storing extended-precision floating point numbers is not implemented.
  292.  
  293. These directives may take multiple values separated by commas to save space.
  294. For example, to store three 32-bit words containing 0 you can write:
  295.  
  296.          DCD   0, 0, 0
  297.  
  298. After you've used DCB, DCW or DCS you may want to word-align the current area
  299. offset. Use the "ALIGN" directive. You can align the offset to any multiple,
  300. not necessarily a power of 2 (although this is not brilliantly useful) by
  301. giving the multiple as a parameter. If you omit the parameter, "4" is
  302. assumed. e.g.:
  303.          ALIGN 8  ; align to double word boundary
  304.  
  305. You can reserve a block of memory using the "BLOCK" directive and giving a
  306. size. You can also give a byte to fill the block with. Examples:
  307.          BLOCK 1024        ; 1k of zeroes
  308.          BLOCK 512, &ff    ; 0.5k of 1's
  309.  
  310. You can also move up to a specific offset from the start of the current area.
  311. To do this, use the OFFSET directive giving the offset you wish to move to.
  312. An error will be reported if you are already past that offset. e.g.:
  313.  
  314.          OFFSET &100       ; Move to offset 256 in area
  315. label    OFFSET &180       ; Set label to offset 384, assemble at 384 too.
  316.  
  317. Finally, before I let the reference section out of its cage, here's an
  318. example C/ARM code program:
  319.  
  320. arm.armcode:
  321.  
  322.                OUTPUT   AOF
  323.                INCLUDE  APCS-R.inc
  324.  
  325.                AREA     ARM$$Code:CODE,READONLY
  326.  
  327.                EXPORT   armfunc
  328.                IMPORT   ARM$stack_overflow
  329.                EXPORT   floatout
  330.  
  331.                FNAME    "armfunc"
  332. armfunc        MOV      ip, sp
  333.                STMDB    sp!, {fp, ip, lr, pc}
  334.                SUB      fp, ip, #4
  335.                CMPS     sp, sl
  336.                BLLT     ARM$stack_overflow
  337.  
  338.                EXPD     f0, #1.0
  339.                STFD     f0, floatout
  340.  
  341.                LDMDB    fp, {fp, sp, pc}^
  342.  
  343. floatout       DCFD     0
  344.                ; EOF
  345.  
  346. c.ccode:
  347.  
  348. #include <stdio.h>
  349.  
  350. extern   void  armfunc (void);
  351. extern   double   floatout;
  352.  
  353. int   main (void)
  354. {
  355.    armfunc();
  356.  
  357.    printf ("The value of e is %g\n", floatout);
  358. }
  359.  
  360. /* EOF */
  361.  
  362. Remember: to assemble the file use "armmaker arm.armcode -o o.armcode -t" or
  363. use !ARMmaker or !Make if you have the DDE. Link the files with "C:o.stubs"
  364. and "ARM:o.ARMlib".
  365.  
  366. REFERENCE SECTION
  367. =================
  368.  
  369. Expression evaluation
  370. =====================
  371.  
  372. Expressions are similar to BASIC's expressions, in the naming of operators
  373. and so on. The operator types, in ascending priority, are:
  374.  
  375.    Conditional
  376.    Bitwise
  377.    Shift
  378.    Addition
  379.    Multiplication
  380.    Unary
  381.    Primary
  382.  
  383. Conditional is, in fact, the '?' operator from C. It is a ternary operator.
  384. Its syntax is "<expr> ? <choice1> : <choice2>". If <expr> is non-zero, then
  385. the value of the expression is <choice1>, otherwise it is <choice2>. You will
  386. be warned if <choice1> and <choice2> have different types.
  387.  
  388. Bitwise comprises bitwise AND, OR and exclusive-OR. They are named "AND",
  389. "OR" and "EOR", just like BASIC, e.g. "3 OR 5" or "2 EOR (3 AND 1)".
  390.  
  391. Shift operators are logical shift left and right, called "<<" and ">>", e.g.
  392. "1<<28".
  393.  
  394. Addition operators are normal addition and subtraction.
  395.  
  396. Multiplication operators comprise multiplication and division.
  397.  
  398. The unary operators are "NOT", "+" and "-". "+" and "-" are just to allow
  399. signed expressions to be given (e.g. "1+(+2)"). "NOT" is a bitwise NOT, not a
  400. logical one.
  401.  
  402. Primary expressions are literals and bracketed expressions. String literals
  403. are as in C (escapes, trigraphs and all) and are automatically concatenated,
  404. i.e. "ABC" "DEF" is identical to "ABCDEF". This actually makes addition of
  405. string redundant ("ABC"+"DEF" gives the same thing) but it's allowed anyway.
  406.  
  407. Integer literals are an unholy combination of C, BASIC and TLA. They may be
  408. prefixed with "0x" or "&" for hexadecimal, "0" for octal or "%" for binary.
  409. They may be postfixed with "H" for hexadecimal. Examples:
  410.  
  411.       12    Decimal 12
  412.       014   Same
  413.       0xa1  Hexadecimal 16_A1
  414.       a1H   Same
  415.       &a1   Same
  416.       %10   Decimal 2, given in binary
  417.  
  418. Constants are evaulated where possible, and may be used in instructions,
  419. e.g.:
  420.          ORRS  PC, R14, #(1<<28)
  421.  
  422. is a valid ARMmaker instruction.
  423.  
  424. Macros
  425. ======
  426.  
  427. ARMmaker allows you to define macros, sets of instructions/directives which
  428. are "expanded" into the file whenever you call on them.
  429.  
  430. For example, the text editor Zap requires that extension modes call an offset
  431. into a table quite often. To make it easier to call this, and to make the
  432. code more readble, it is nice if you can write "CALLZAP ..." rather than
  433. several lines of code.
  434.  
  435. To define a macro, give the macro name as a label, and use the directive
  436. "DEFM". Macros can take parameters: list the paramters' names in the
  437. parameters field, separated by commas. This particular example takes one
  438. parameter (the offset). So the first line of the definition is
  439.  
  440. CALLZAP        DEFM     offset
  441.  
  442. Now write the code that you want including whenever you ask for the macro. If
  443. you use a parameter ("offset" in this case) it will be replaced by the
  444. parameter value you give when you call the macro. (Don't Panic; all will
  445. become clear!).
  446.  
  447. So, now write:
  448.  
  449.                LDR      R14, [R12]
  450.                ADD      R14, R14, #offset
  451.                STMFD    R13!, {R14}
  452.                MOV      R14, PC
  453.                LDMFD    R13!, {PC}
  454.  
  455. This is the end of the macro code, so tell ARMmaker by using the "ENDM"
  456. directive:
  457.  
  458.                ENDM
  459.  
  460. Now, if you want to call the offset "Zap_AddMode" (where Zap_AddMode has
  461. been defined as a constant), you would write:
  462.  
  463.                CALLZAP  Zap_AddMode
  464.  
  465. When ARMmaker sees this, it looks up the macro and actually assembles this
  466. instead:
  467.  
  468.                LDR      R14, [R12]
  469.                ADD      R14, R14, #Zap_AddMode
  470.                STMFD    R13!, {R14}
  471.                MOV      R14, PC
  472.                LDMFD    R13!, {PC}
  473.  
  474. Another example is when you are writing a module, and wish to get the word at
  475. offset <x> in your workspace. You can define a macro for this. If you call it
  476. LDW, it will look like an instruction:
  477.  
  478. LDW            DEFM     Rd, ofs
  479.                LDR      Rd, [R12, #ofs]
  480.                ENDM
  481.  
  482. And then you can use
  483.  
  484.                LDW      R0, wkFlag
  485.  
  486. Instruction set extensions
  487. ==========================
  488.  
  489. There are several "extensions" made to the instruction set by ARMmaker. These
  490. are not actually new instructions, but a refined form of macro.
  491.  
  492. One is a copy of BASIC'S ADR instruction. This instruction doesn't actually
  493. exist, as you may know, it is actually a "ADD Rd, PC, #const" or "SUB Rd, PC,
  494. #const" instruction.
  495.  
  496. One problem with this is that the constant has a limited range of values. I
  497. call a constant that can't be put straight into an ADD or SUB "ill-formed".
  498. This is because it isn't just because the constant is too large (&ff000000 is
  499. not ill-formed), but because all the data must be in 8 consecutive bits,
  500. which must start at an even bit... it's nasty (but necessary).
  501.  
  502. So, ARMmaker implements an "extended ADR", called "ADRL". This assembles to
  503. TWO instructions, the first loading the first 8 bits and the second, the
  504. second. In practice, this extends the addressing range of ADR to 64k, or 256k
  505. for word-aligned addresses. (Comparision: normal ADR's range is 256 bytes or
  506. 1k).
  507.  
  508. Another useful addition is "MOVL". This is an extension of an immediate MOV
  509. "MOV Rd, #const" which will load any 32-bit constant in as few instructions
  510. as possible. I mean it: it will get &010801fc in in two instructions, unlike
  511. most implementations which require four. Although you'll rarely notice this.
  512.  
  513. MOVL is invaluable in macros. Take an adaption of the LDW macro above. To
  514. make an ADW (load address of offset within workspace) you would use:
  515.  
  516. ADW         DEFM  Rd, ofs
  517.             ADD   Rd, R12, #ofs
  518.             ENDM
  519.  
  520. But this would be limited to the first 256 bytes of workspace (1k for
  521. word-aligned data). This might not be a problem. If it is, you can use a MOVL
  522. to help you out:
  523.  
  524. ADWL        DEFM  Rd, ofs
  525.             MOVL  Rd, #ofs
  526.             ADD   Rd, Rd, R12
  527.             ENDM
  528.  
  529. Which will work for any constant. Obviously, if the offset is not ill-formed,
  530. then this will waste an instruction, since it will compile to a normal MOV
  531. and the ADD.
  532.  
  533. Register bindings
  534. =================
  535.  
  536. By default, the registers are named R0 to R15 (and PC) and F0 to F7. These
  537. names can always be used. However, you can give alternative names using the
  538. BINDREG directive. Put the alternative name in the label field and the
  539. register name in the parameters field, e.g.:
  540.  
  541. a1    BINDREG  R0
  542. SP    BINDREG  R13
  543. LR    BINDREG  R14
  544. f0    BINDREG  F0
  545. f5    BINDREG  F5
  546. c3    BINDREG  C3
  547.  
  548. The file "inc.APCS-R" binds the registers to their APCS-R names.
  549.  
  550. You may bind any of the sixteen CPU registers, the eight FPU registers or the
  551. sixteen coprocessor "registers" (how they relate to actual processor
  552. registers may vary, e.g. FPU uses bit 3 of some register fields to store
  553. rounding/precision, and also uses immediates...)
  554.  
  555. Function names 
  556. ==============
  557.  
  558. The directive "FNAME" stores the string given as its parameter, followed by a
  559. zero and aligned to a word boundary. It then stores &ff000000 OR'ed with the
  560. length of the preceding string field. This is the same format used by the C
  561. compiler to store function names. Example:
  562.  
  563.                FNAME "myfunc"
  564. myfunc         MOV   ip, sp
  565.                ; and so on...
  566.  
  567.  
  568. becomes
  569.                DCS   "myfunc"
  570.                DCB   0
  571.                ALIGN
  572.                DCD   &ff000008
  573. myfunc         MOV   ip, sp
  574.  
  575. If you link an object file with the supplied file "ARM:o.ARMlib", then if
  576. your C program crashes (don't laugh) the stack backtrace function will be
  577. able to get the name of your function, e.g.:
  578.  
  579. 80dc in ARM procedure myfunc
  580. 81b8 in function main
  581.  
  582. etc..
  583.  
  584. if you follow the APCS-R documentation given in the PRM and the DDE manuals,
  585. then you should get a proper backtrace (albeit with no arguments...)
  586.  
  587. Local labels
  588. ============
  589.  
  590. If you start a label with a backslash character "\", then it is called a
  591. "local label". It is internally renamed, including a sequence number. This
  592. sequence number is increased whenever a blank line is processed. The point is
  593. that you can have lots of labels called "loop", for example, without having
  594. to worry about naming them all ("serv_04_loop_1" &c.). So you can do:
  595.  
  596. CodeStart      ; some code
  597. \loop          ;
  598.                ; a loop
  599.                BMB   \loop       ; Branch MayBe
  600.  
  601.                ; notice the blank line
  602. \loop          ;
  603.                ; another, separate loop
  604.                ;
  605.                BMB   \loop       ; goes to second "\loop"
  606.  
  607. Supplied files
  608. ==============
  609.  
  610. Inside !ARMmaker are files named "inc.APCS-x" which binds registers to their
  611. names under the relevant ARM Procedure Call Standard.
  612.  
  613. There is a library file "o.ARMlib" which includes routines for use when
  614. exporting to link (obviously, wouldn't be much use otherwise...) including
  615. routines to allow your procedures to come up on the stack backtrace (see
  616. FNAME directive, above), a copy of the kernel (won't be loaded if you
  617. include C:o.stubs) and stack overflow handlers. For C users, there is a
  618. module called "fsutils" to provide utilities interfacing filing systems (also
  619. "h.fsutils": to include this, add "ARM:" to your include path, i.e. use
  620. parameter "-IC:,ARM:", or copy h.fsutils to your CLib directory).
  621.  
  622. The library should be referred to as "ARM:o.ARMlib", and treated rather like
  623. C:o.stubs is within makefiles.
  624.  
  625. The overflow handlers are called ARM$stack_overflow and
  626. ARM$stack_overflow_big: they act just like C's x$stack_overflow and
  627. x$stack_overflow_1, including the method of splitting stack frames; but using
  628. the ARM$... functions will ensure that the RTSK$$Data area for ARM areas is
  629. loaded.
  630.  
  631. Endian-ness
  632. ===========
  633.  
  634. ARM code is ordered as little-endian four-byte words; that is, groups
  635. ("words") of four bytes, least significant byte first. You can tell ARMmaker
  636. to write these words most-significant byte first ("big-endian" words) by
  637. adding "-fb" to the command line. This also affects the behaviour of the DCD
  638. and DCW directives, but not DCF.
  639.  
  640. Summary list of directives
  641. ==========================
  642.  
  643.         OUTPUT  <output> [<filetype>]           Set output type to <params>, actual
  644.                                                 filetype to <filetype>
  645.         BASE    <number>                        Set output base (for DIRECT files only)
  646.         ENTRY   <label>                         Set entry point (DIRECT or AOF files)
  647.         INCLUDE <filename>                      Include another source file
  648. <id>    BINDREG <register>                      Allow <id> to be used to mean <register>
  649.         AREA    <areaname>[':'<attributes>]     Define a new area
  650.         IMPORT  <label>                         Import a symbol
  651.         EXPORT  <label>                         Export a symbol (a label)
  652.         XREF    <label>                         Synonym for IMPORT
  653.         XDEF    <label>                         Synonym for EXPORT
  654.         DCB     <byte-val>[ <byte-val>]*        Write byte values into output
  655.         DCW     <short-val>[ <short-val>]*      Write short values into output
  656.         DCD     <word-val>[ <word-val>]*        Write word values into output
  657.         DCS     <string>                        Write a string into output
  658.         ALIGN   [<alignment>]                   Align to a given alignment
  659.         DCFD    <double>                        Write a double-precision FP into output
  660.         DCFS    <float>                         Write a single-precision FP into output
  661.         BLOCK   <size>[,<byte-val>]             Write an intialised block
  662.         FNAME   <string>                        Write a function name
  663.         CONST   <number>                        Define an internal constant
  664.         GLOBAL  <number>                        Define a global constant
  665.         OFFSET    <number>            Move to an offset within an area
  666.  
  667. And finally....
  668. ===============
  669.  
  670. "ARMmaker" refers to the ARMmaker executable, the !ARMmaker application and
  671. contents, and this documentation.
  672.  
  673. "You" refers to the user of ARMmaker.
  674.  
  675. "I" refers to the copyright holder.
  676.  
  677. ARMmaker is and remains copyright (C) Steven Haslam 1994.
  678.  
  679. You may copy and distribute ARMmaker, so long as you do not do so for a
  680. profit.
  681.  
  682. No charge is made by the copyright holder for the use of ARMmaker, nor may
  683. any third party make a charge for the use of ARMmaker.
  684.  
  685. No warranty, express or implied, is supplied with this product, including,
  686. but not limited to, warranty of merchantability or suitability for a
  687. particular purpose. Use is entirely at your own risk, I cannot be held
  688. responsible for loss or damage due to the action or inaction of ARMmaker.
  689.  
  690. .
  691.  
  692. Right, boring stuff over. Wake up.
  693.  
  694. ARMmaker is a "FreeWare" product. Your support and encouragement is welcome.
  695. The program isn't finished yet, so undoubtedly you'll find loads of things
  696. that will go wrong, or not work at all!
  697.  
  698. If you do, or if you get stuck using ARMmaker, then please don't hesitate to
  699. write me at this address:
  700.    Steven Haslam, 112 Keighley Road, Colne, Lancashire, BB8 0PH, ENGLAND
  701. Or, if you can take it, phone me on Colne (0282)-866835 (good luck).
  702.  
  703. Known things that need doing:
  704.  
  705.    o DCFE, DCFP (?)
  706.  
  707.    o Improve syntax checking
  708.  
  709.    o Labels local to a macro
  710.  
  711.    o Tidy up include file paths & "work directory"
  712.    
  713.    o Allow binding coprocessor names? (from CP1 to FPU, CP15 to ARM3 etc.)
  714.      e.g. MCR ARM3, 0, a1, ARM3ID, C0
  715.    
  716. Questions:
  717.  
  718. When I do a PCRelative coprocessor data transfer (ST[CF]/LD[CF), e.g. "LDF
  719. F0, mydata", the Debugger appears to get the address wrong... but I'm sure
  720. the offset's right! Even assembling instructions directly in the form "STFE
  721. F0,[PC,#12]" appears to give the "wrong" address (try it!). AFAICT, the
  722. Debugger does not multiply the offset by 4 to get words (I don't think it
  723. pays attention to the sign either). So now you know!
  724.  
  725. Why does the debugger report a precision code on WFS/RFS/WFC/RFC? And why
  726. does it give the parameters to FLT the wrong way round? ("All this, and more,
  727. in your next <Acorn bollocking...>") (<thinks> probably because these are
  728. just fancy names for MRC CP1,x,Rn,Cn,... and MCR CP1,x,Rn,Cn,...)
  729.  
  730. ARMmaker version 0.52
  731. Documentation: Aug 08 1994 22:13:23
  732.  
  733. Revision history:
  734.  
  735. 0.50    first version
  736. 0.50.1    Macro expansion on same line as label: label is now defined
  737.     CMP .... now assembled as CMPS ...., CMPP still only CMPP.
  738. 0.52    Erk! "^" on LDM/STM didn't work
  739.     Added OFFSET directive
  740.     Fixed trying to match single quotes inside literal strings
  741.     TEQP etc. now assembled as TEQPS (like BASIC)
  742.