home *** CD-ROM | disk | FTP | other *** search
/ 8bitfiles.net/archives / archives.tar / archives / canada-remote-systems / c64 / utils / ace15-as.doc < prev    next >
Encoding:
Text File  |  2019-04-13  |  47.6 KB  |  991 lines

  1. ACE Assembler Documentation  for version 1.20   [December 17, 1995]
  2. ------------------------------------------------------------------------------
  3. 1. INTRODUCTION
  4.  
  5. The ACE assembler is a one-pass assembler.  The only real limitation on the
  6. size of assembly jobs is the amount of near+far memory you have available.
  7. Labels are "limited" to 240 characters (all significant), and the object
  8. size is limited to 64K (of course).  Numerical values are "limited" to
  9. 32-bits or less.  Relative labels ("+" and "-" labels) are implemented in
  10. the same way as in the Buddy assembler.  Add, subtract, multiply, divide,
  11. modulus, and, or, and xor dyadic operators are implemented for expressions
  12. with positive, negate, high-byte, and low-byte monadic oparators, and the
  13. planned macro and conditional assembly features are not yet implemented.
  14. Expressions are limited to 17 operands (with 255 monadic operators each) and
  15. are evaluates strictly left-to-right, but references to unresolved
  16. identifiers are allowed anywhere, including equate definitions.
  17. Hierarchical inclusion of source files is supported, and compatibility
  18. features have been implemented to allow this assembler to accept directives
  19. and syntax of other assemblers.  All of the ACE applications can be
  20. assembled using this assembler, including the assembler itself.
  21.  
  22. The assembler is designed to be a "heavy hitter", operates at moderate
  23. speed, and uses a fair amount of dynamically allocated memory.  In fact, on
  24. an unexpanded 64, you won't be able to assemble programs that are too large,
  25. including the assembler itself (89K of source).  You'll be able to do larger
  26. jobs on an unexpanded 64 if you deactivate the soft-80 screen in the
  27. configuration.  (Of course, one could argue that any serious 64 hacker would
  28. have expanded memory anyways...).
  29.  
  30. In addition to the regular 6502 instructions, this release of the assembler
  31. has the following directives:
  32.  
  33. label = value                ;assign given value to the label
  34. label:                       ;assign the current assembly address to label
  35. +                            ;generate a temporary label, assign cur address
  36. -                            ;generate a temporary label, assign cur address
  37. .org address                 ;set the origin of the assembly
  38. .buf size                    ;reserve "size" bytes of space,filled with zeroes
  39. .include "filename"          ;source-file inclusion (nestable)
  40. .byte val1, val2, ..., valN  ;put byte values into memory
  41. .word val1, val2, ..., valN  ;put word values into memory
  42. .triple val1, val2, ..., valN ;put "triple" (3-byte) values into memory, lo->hi
  43. .long val1, val2, ..., valN  ;put "long" (4-byte) values into memory, lo->hi
  44.  
  45. These features is described in more detail below.  Note that throughout the
  46. documentation, I use the terms "identifier", "symbol", and "label"
  47. interchangeably.
  48.  
  49. The official name of the assembler is "the ACE assembler", but unofficially,
  50. it can be called "ACEmbler" to give it a specific one-word name.
  51. ------------------------------------------------------------------------------
  52. 2. USAGE
  53.  
  54. The usage for the as command is, stated in Unix notation:
  55.  
  56. usage: as [-help] [-s] [-d] [-q] [file ...]
  57.  
  58. The "-help" flag will cause the assembler display the usage information and
  59. then exit, without assembling any code.  Actually, any flag that it doesn't
  60. understand will be taken as if you had said "-help", but note that if you
  61. type the "as" command alone on a command line that usage information will
  62. not be given.
  63.  
  64. The "-s" flag tells the assembler to generate a symbol-table listing when
  65. the assembly job is finished.  The table is formatted for an 80-column
  66. display.  indicates that a symbol table should be generated when the
  67. assembly job is done.  The table will look like:
  68.  
  69. The "-d" flag tells the assembler to produce debugging information while it
  70. is working.  It will generate a lot of output, so you can see exactly what
  71. is going on.
  72.  
  73. The "-q" flag tells the assembler to accept quoted text (strings) literally,
  74. without parsing backslash sequences inside of the strings.  This feature is
  75. provided for compatibility with source files from other assemblers.
  76.  
  77. The object-code module name will be "a.out" unless the name of the first
  78. source file ends with a ".s" extension, in which case the object module will
  79. be the base name of first source file (without the extension).  The object
  80. module will be written as a PRG file and will be in Commodore-DOS program
  81. format: the first two bytes will be the low and high bytes of the code
  82. address, and the rest will be the binary image of the assembled code.
  83.  
  84. If no source filename is given on the command line, then input is taken from
  85. the stdin file stream (and written to "a.out").  If more than one filename
  86. is given, the each is read, in turn, into the same assembly job (as if the
  87. files were "cat"ted together into one source file).  (This will change
  88. subtly when the assembler is completed).
  89.  
  90. This assembler does not produce a listing of the code assembled and will
  91. stop the whole assembly job on the first error it encounters.
  92. ------------------------------------------------------------------------------
  93. 3. TOKENS
  94.  
  95. While reading your source code, the assembler groups characters into tokens
  96. and interprets them as a complete unit.  The assembler works with five
  97. different types of tokens: identifiers, numeric literals, string literals,
  98. special characters, and end-of-file (eof).  Eof is special since it doesn't
  99. actually include any characters, and its only meaning is to stop reading
  100. from the current source.  Your input source file should consist only of
  101. characters that are printable in standard ASCII (don't be confused by this;
  102. the assembler expects its input to be in PETSCII) plus TAB and
  103. Carriage-Return.  Other characters may confuse the assembler.
  104.  
  105. Identifiers consist of a lowercase or uppercase letter or an underscore (_)
  106. followed by a sequence of such letters or decimal digits or periods (.).
  107. This is a pretty standard definition of an identifier.  Identifiers are
  108. limited to 240 characters in length and an error will be reported if you try
  109. to use one longer than that.  All of the characters of all identifiers are
  110. significant, and letters are case-sensitive.  Here are some examples of
  111. all-unique identifiers:
  112.  
  113. hello  Hello  _time4  a1_x140J  HelloThereThisIsA_LongOne
  114.  
  115. Numeric literals come in three types: decimal, hexadecimal, and binary.
  116. Decimal literals consist of an initial digit from 0 to 9 followed by any
  117. number of digits, provided that the value does not exceed 2^32-1 (approx. 4
  118. billion).  All types of literals can also have embedded underscore
  119. characters, which are ignored by the assembler.  Use them grouping digits
  120. (like the comma for big American numbers).
  121.  
  122. Hexadecimal literals consist of a dollar sign ($) followed by any number of
  123. hexadecimal digits, provided the value doesn't overflow 32 bits.  Hexadecimal
  124. digits include the decimal digits (0-9), and the first six uppercase or
  125. lowercase letters of the alphabet (either a-f or A-F).  Hexadecimal literals
  126. can also have embedded underscore characters for separators.
  127.  
  128. Binary literals consist of a percent sign (%) followed by any number of
  129. binary digits that don't overflow 32-bits values.  The binary digits are, of
  130. course, 0 and 1, and literals may include embedded underscore characters.
  131. Note that negative values are not literals.  Here are some examples of valid
  132. literals:
  133.  
  134. 0  123  0001  4_294_967_295  $aeFF  $0123_4567  %010100 %110_1010_0111_1010
  135.  
  136. String literals are sequences of characters enclosed in either single (') or
  137. double (") quotation marks.  The enclosed characters are not interpreted to
  138. be independent tokens, nomatter what they are.  One exception is that the
  139. carriage-return character cannot be enclosed in a string (this normally
  140. indicates an error anyway).  To get special non-printable characters into
  141. your strings, an "escape" character is provided: the backslash (\).  If the
  142. backslash character is encountered, then the character following it is
  143. interpreted and a special character code is put into the string in place of
  144. the backslash and the following character.  Here are the characters allowed
  145. to follow a backslash:
  146.  
  147. CHAR   CODE   MEANING
  148. ----   ----   --------
  149. \        92   backslash character (\)
  150. n        13   carriage return (newline)
  151. b        20   backspace (this is a non-destructive backspace for ACE)
  152. t         9   tab
  153. r        10   goto beginning of line (for ACE, linefeed for CBM)
  154. a         7   bell sound
  155. z         0   null character (often used as a string terminator in ACE)
  156. 0         0   null character
  157. '        39   single quote (')
  158. e        27   escape
  159. q        34   quotation mark
  160. "        34   quotation mark
  161.  
  162. So, if you really want a backslash then you have to use two of them.  If you
  163. wish to include an arbitrary character in a literal string, no facility is
  164. provided for doing that.  However, the assembler will allow you to intermix
  165. strings and numeric expressions at a higher level, so you can do it that
  166. way.  Strings are limited to include 240 (encoded) characters or less.  This
  167. is really no limitation to assembling, since you can put as many string
  168. literals contiguously into memory as you wish.  Here are some examples:
  169.  
  170. "Hello there"  "error!\a\a"  'file "output" could not be opened\n\0'
  171. "you 'dummy'!"  'you \'dummy\'!'  "Here are two backslashes: \\\\"
  172.  
  173. Special characters are single characters that cannot be interpreted as any
  174. of the other types of tokens.  These are usually "punctuation" characters,
  175. but carriage return is also a special-character token (it is a statement
  176. separator).  Some examples follow:
  177.  
  178. ,  (  #  &  )  =  /  ?  \  ~  {  
  179.  
  180. Tokens are separated by either the next character of input not being allowed
  181. to belong to the current token type, or are separated by whitespace.
  182. Whitespace characters include SPACE (" ") and TAB.  Note that carriage
  183. return is not counted as whitespace.  Comments are allowed by using a ";"
  184. character.  Everything following the semicolon up to but not including the
  185. carriage return at the end of the line will be ignored by the assembler.  (I
  186. may implement an artifical-intelligence comment parser to make sure the
  187. assembler does what you want it to, but this will be strictly an optional,
  188. time-permitting feature).
  189. ------------------------------------------------------------------------------
  190. 4. EXPRESSIONS
  191.  
  192. Numeric expressions consist of operands and operators.  If you don't know
  193. what operands and operators are, then go buy an elementary-school math
  194. book.  There are six types of operands: numeric literals, single-character
  195. string literals, identifiers, the asterisk character, one or more plus
  196. signs, and one or more minus signs.  These last three types can make parsing
  197. an expression a bit confusing, but they are necessary and useful.
  198.  
  199. Numeric literals are pretty easy to think about.  They're just 32-bit
  200. numbers and work in the usual way.  Single-character string literals are
  201. also interpreted (in the context of a numeric expression) as being a numeric
  202. literal.  The value of a single-character string is simply the PETSCII code
  203. for the character.
  204.  
  205. Identifiers or "symbols" or "labels" used in expressions refer to numeric
  206. values that have been or will be assigned to the identifiers.  Binding
  207. values to identifiers is done by assembler directives discussed in a later
  208. section.  If an identifier already has a value assigned to it by the time
  209. that the current expression is reached in assembly, then it is treated as if
  210. it were a numeric literal of the value assigned to the identifier.  If the
  211. identifier currently has no value assigned to it (i.e., it is "unresolved"),
  212. then the entire current expression will be unresolved.  In this case, the
  213. value of the expression will be recorded and will be evaluated at a later
  214. time when all of its identifiers become resolved.  A "hole" will be created
  215. where the expression should go, and the hole will be "filled in" later.
  216. Note that there are a couple of directives for which an expression must be
  217. resolved at the time it is referenced.
  218.  
  219. The asterisk character operates much like a numeric literal, except that its
  220. value is the current code address rather than a constant.  The current code
  221. address will always be for the start of an assembler instruction.  I.e., the
  222. current code address is incremented only after an instruction is assembled.
  223. This has some subtle implications, and other assemblers may implement
  224. slightly different semantics.  Directives are a little different in that the
  225. address is incremented after every value in a "commalist" is put into
  226. memory.
  227.  
  228. Relative references, i.e., operands consisting of a number of pluses or
  229. minuses, operate much like identifiers.  They are provided for convenience
  230. and work exactly how they do in the Buddy assembler.  Operands of all
  231. minuses are backward references and operands of all pluses are forward
  232. references.  Because of parsing difficulties, relative-reference operands
  233. must either be the last operand in an expression or must be followed by a
  234. ":" character.
  235.  
  236. The number of pluses or minuses tell which relative reference "point" is
  237. being referred to.  A reference point is set by the "+" and "-" assembler
  238. directives discussed later.  This gets difficult to explain with words, so
  239. here is a code example:
  240.  
  241.    ldy #5
  242. -  ldx #0
  243. -  lda name1,x
  244.    sta name2,x
  245.    beq +
  246.    cmp #"x"
  247.    beq ++
  248.    inx
  249.    bne -
  250. +  dey
  251.    bne --
  252. +  rts
  253.  
  254. This relatively bogus subroutine will copy a null-terminated character
  255. string from name1 to name2 five times, unless the string contains an "x"
  256. character, in which case the copy operation terminates immediately upon
  257. encountering the "x".  The "beq +" branches to the next "+" label to occur
  258. in the code, to the "dey" instruction.  The "beq ++" branches to the "rts",
  259. to the "+" label following the next "+" label encountered.  The "-" and "--"
  260. references work similarly, except that they refer to the previous "-" label
  261. and the previous to the previous "-" label.  You can use up to 255 pluses or
  262. minus signs in a relative-reference operand to refer to that many reference
  263. points away.
  264.  
  265. That I said relative-reference operands work much like identifiers above is
  266. no cooincidence.  For each definition of a reference point and reference to
  267. a point, an internal identifier is generated that looks like "L+123c" or
  268. "L-123c".  Note that you can't define or refer to these identifiers
  269. yourself.
  270.  
  271. There are two types of operators that can be used in expressions: monadic
  272. and diadic operators.  Monadic operators affect one operand, and dyadic
  273. operators affect two operands.  At about this point, I should spell out the
  274. actual form of an expression.  It is:
  275.  
  276. [monadic_operators] operand [ operator [monadic_operators] operand [...] ]
  277.  
  278. or:
  279.  
  280. 1 + 2
  281. -1 + -+-2 + 3
  282.  
  283. An expression may have up to 17 operands.
  284.  
  285. The monadic (one-operand) operators are: positive (+), negative (-),
  286. low-byte (<), and high-bytes (>).  You can have up to 255 of each of these
  287. monadic operators for each operand of an expression.  Positive doesn't
  288. actually do anything.  Negative will return the 32-bit 2's complement of the
  289. operand that it is attached to.  Low-byte will return the lowest eight bits
  290. of the operand it is attached to.  High-byte will return the high-order
  291. 24-bits of the 32-bit operand it is attached to.  All expressions are
  292. evaluated in full 32-bit precision.  Note that you can use the high-bytes
  293. operator more than once to extract even higher byte.  For example,
  294. "<>>value" will extract the second-highest byte of the 32-bit value.
  295.  
  296. The dyadic (two-operand) operators that are implemented are: add (+),
  297. subtract (-), multiply (*), divide (/), modulus (!), bitwise-and (&),
  298. bitwise-or (|), and bitwise-exclusive-or (^).  Yes, the plus and minus
  299. symbols are horribly overloaded, and the usual Not (modadic) operator isn't
  300. implemented, since it can be simulated with Xor, and "not, with respect to
  301. what?" becomes a problem since evaluations are performed with a full
  302. 32-bits.  We should already know what all of the implemented operators do,
  303. except maybe for Modulus.  It is like Divide, except that Modulus returns
  304. the Remainder rather than the Quotient of the division result.
  305.  
  306. Evaluation of dyadic operators is strictly left-to-right, and value
  307. overflows and underflows are ignored.  Values are always considered to be
  308. positive, but this doesn't impact 2's complement negative arithmetic for add
  309. and subtract dyadic operators.
  310.  
  311. Monadic operators take precedence over dyadic operators.  Evaluation of
  312. monadic operators is done a little differently.  All positive operators are
  313. thrown out since they don't actually do anything.  Then, if there is an even
  314. number of negative operators, they are thrown out.  If there is an odd
  315. number of negative operators, then the 2's complement negative of the
  316. operand is returned.  Then, if there are any high-bytes operators, the value
  317. is shifted that number of bytes to the right and the highest-order byte of
  318. the value is set to zero on each shift.  Note that it really doesn't make
  319. any sense to perform any more than three high-bytes operators.  Then, the
  320. low-byte operator is preformed, if asked for.  It is equivalent to taking
  321. anding the value with $000000ff.  It really doesn't make much sense to
  322. perform this operator more than once.  Also, it doesn't make any difference
  323. in which order you place the monadic operators in an expression; they are
  324. always evaluated in the static order given above.
  325.  
  326. There is one exception here.  If the first operand of an expression has
  327. high-bytes and/or low-byte monadic operators, then the rest of the
  328. expression is evaluated first and then the high/low-byte monadic operators
  329. are performed on the result.  This is done to be consistent with other
  330. assemblers and with user expectations.
  331.  
  332. Parentheses are not supported.  Here are some examples of valid expressions:
  333.  
  334. 2
  335. +2+1
  336. 2+-1
  337. 2+-------------------------------------1
  338. ++++:-+++:+---
  339. 1+"x"-"a"+"A"
  340. <>>>4_000_000_000
  341. <label+1
  342. >label+1
  343. -1
  344.  
  345. This last one ends up with a value of negative one, which is interpreted as
  346. really being 4_294_967_295.  If you were to try and do something like
  347. "lda #-1", you would get an error because the value would be interpreted as
  348. being way too big.
  349.  
  350. Expressions results and identifiers have a data type associated with them.
  351. There are four data types: Value, Address, Low-byte, High-byte. and
  352. Garbage.  The type of an expression is recorded since it will be required to
  353. provide object-module relocation features in the future.  Values are what
  354. you would expect and come from numeric and single-character-string-literal
  355. operands.  The Address type comes from the asterisk and relative reference
  356. operands and from identifier operands which are defined to be addresses.  An
  357. address is defined to be only an address in the range of the assembled
  358. code.  Addresses outside of this range are considered to be values.  The
  359. High-byte type results from applying the high-bytes (>) operator to an
  360. address operand, and the Low-byte type, from applying the low-byte (<)
  361. operator.  The Garbage type results from using an operator on two operands
  362. of types that don't make any sense (for example, from multiplying one
  363. Address by another).  The result-type rules for the operators is a bit
  364. complicated, but is intuitive.  You don't have to worry about them since the
  365. assembler takes care of them automatically.  Keeping track of expression
  366. types makes it possible to generate a list of all values in memory that must
  367. be modified in order to relocate a program to a new address without
  368. reassembling it.
  369.  
  370. String "expressions" consist of only a single string literal.  No operators
  371. are allowed.  Some assembler directives accept either numeric or string
  372. expressions and interpret them appropriately (like "byte").
  373. ------------------------------------------------------------------------------
  374. 5. PROCESSOR INSTRUCTIONS
  375.  
  376. This assembler accepts the 56 standard 6502 processor instructions.  It does
  377. not provide un-documented 6502 instructions nor 65c02 nor 65816 instructions
  378. nor custom pseudo-ops.  The latter will be provided by future macro
  379. features.  All of the assembler instructions must be in lowercase or they
  380. will not be recognized.  Here are the instructions:
  381.  
  382. NUM  INS      NUM  INS      NUM  INS      NUM  INS      NUM  INS
  383. ---  ---      12.  bvc      24.  eor      36.  pha      48.  sta
  384. 01.  adc      13.  bvs      25.  inc      37.  php      49.  stx
  385. 02.  and      14.  clc      26.  inx      38.  pla      50.  sty
  386. 03.  asl      15.  cld      27.  iny      39.  plp      51.  tax
  387. 04.  bcc      16.  cli      28.  jmp      40.  rol      52.  tay
  388. 05.  bcs      17.  clv      29.  jsr      41.  ror      53.  tsx
  389. 06.  beq      18.  cmp      30.  lda      42.  rti      54.  txa
  390. 07.  bit      19.  cpx      31.  ldx      43.  rts      55.  txs
  391. 08.  bmi      20.  cpy      32.  ldy      44.  sbc      56.  tya
  392. 09.  bne      21.  dec      33.  lsr      45.  sec
  393. 10.  bpl      22.  dex      34.  nop      46.  sed
  394. 11.  brk      23.  dey      35.  ora      47.  sei
  395.  
  396. The assembler also supports 12 addressing modes.  The "accumulator"
  397. addressing mode that can be used with the rotate and shift instructions is
  398. treated like the immediate addressing mode, so a shift-left-accumulator
  399. instruction would be just "asl" rather than "asl a".  Many other assemblers
  400. get rid of the accumulator addressing mode also.  Processor instructions
  401. (and addressing modes with "x" and "y" in them) may be given in either
  402. uppercase or lowercase, to allow for maximum compatibility with source code
  403. from other assemblers.
  404.  
  405. Here is the token syntax for the addressing modes (CR means carriage
  406. return):
  407.  
  408. num  name       gen  byt  example   tokens
  409. ---  ---------  ---  ---  -------   -------
  410. 01.  implied    00.    1            CR
  411. 02.  immediate  00.    2  #123      #     / exp8  / CR
  412. 03.  relative   00.    2  *+20      exp16 / CR
  413. 04.  zeropage   07.    2  123       exp8  / CR
  414. 05.  zp,x       08.    2  123,x     exp8  / ,     / x   / CR
  415. 06.  zp,y       09.    2  123,y     exp8  / ,     / y   / CR
  416. 07.  absolute   00.    3  12345     exp16 / CR
  417. 08.  abs,x      00.    3  12345,x   exp16 / ,     / x   / CR
  418. 09.  abs,y      00.    3  12345,y   exp16 / ,     / y   / CR
  419. 10.  indirect   00.    3  (12345)   (     / exp16 / )   / CR
  420. 11.  (ind,x)    00.    2  (123,x)   (     / exp8  / ,   / x   / )  / CR
  421. 12.  (ind),y    00.    2  (123),y   (     / exp8  / )   / ,   / y  / CR
  422.  
  423. Each instruction takes a complete line and each addressing mode must be
  424. terminated by a carriage return token (comments are skipped).  The format of
  425. an instruction line is as follows:
  426.  
  427. [prefix_directives] instruction address_mode_operand
  428.  
  429. In the case that an expression in an addressing mode is resolved at the
  430. point it is encountered and its value is less than 256, the assembler will
  431. try to use the zero-page addressing modes if possible.  On the other hand,
  432. if a zero-page addressing mode is unavailable for an instruction, then the
  433. assembler will promote or generalize the zero-page addressing mode to an
  434. absolute addressing mode, if possible.  This is what the "gen" column in the
  435. table above shows.  If after attempting to generalize the addressing mode
  436. the given addressing mode still not valid with the given instruction, then
  437. an error will be generated.
  438.  
  439. In the case that an expression in an addressing mode cannot be resolved at
  440. the point where it is encountered in the assembler's single pass, a hole is
  441. left behind, and that hole is made as "large" as possible; it is assumed
  442. that you will fill in the hole with the largest value possible.  This means,
  443. for example, if you were to assemble the following instruction:
  444.  
  445. lda var,x
  446.  
  447. then the assembler would assume this is an absolute mode, and will fill in
  448. the hole later as such, even if it turns out that "var" is assigned a value
  449. less than 256 later on.  This results in slight inefficiency in the code
  450. produced by this assembler, but it causes most two-pass assemblers to fail
  451. completely on a "phase error".  An easy way to avoid this circumstance is to
  452. make sure that all zero-page labels are defined before they are referred
  453. to.
  454.  
  455. The addressing modes that require a single byte value and that will not
  456. "generalize" to an absolute mode will have a single-byte hole created for
  457. them.  Only the branching instructions will be interpreted as having the
  458. relative addressing mode, and a single-byte hole will be left.  Two
  459. exceptions to the above rules are the "stx zp,y" and "sty zp,x", which will
  460. leave a single-byte hole on an unresolved expression, since the
  461. absolute-mode generalizations for these instructions are not supported by
  462. the processor.
  463. ------------------------------------------------------------------------------
  464. 6. DIRECTIVES
  465.  
  466. There are currently six classes of assembler directives; there will be
  467. more in the future.  For maximum compatibility, all directives can be
  468. in either uppercase or lowercase.  Also, to be more standard, most
  469. directives are required to start with the dot (.) character.
  470.  
  471. 6.1. DO-NOTHING DIRECTIVES
  472.  
  473. There are three do-nothing directives:
  474.  
  475. #                           ;does nothing
  476.                             ;blank line--does nothing
  477.  
  478. A blank line in your source code will simply be ignored.  This helps to make
  479. code much more readable.  The "#" directive is a prefix directive.  This
  480. means that it does not occupy an entire line but allows other directives and
  481. processor instructions to follow it on the same line (including other prefix
  482. directives).  (But note that you can follow any prefix directive by the
  483. blank-line directive, effectively allowing prefix directives to be regular
  484. full-line directives (powerful combining forms)).  The "#" directive is
  485. simply ignored by the assembler, but you can use it to highlight certain
  486. lines of code or other directives.
  487.  
  488. 6.2. ASSIGNMENT DIRECTIVES
  489.  
  490. There are four assignment directives.  They all assign (bind) a value to an
  491. identifier.  Here they are:
  492.  
  493. label = expression          ;assign given value to the label
  494. label:                      ;assign the current assembly address to label
  495. +                           ;generate a temporary label, assign cur address
  496. -                           ;generate a temporary label, assign cur address
  497.  
  498. The first (label=expr) is the most general.  It assigns the result of
  499. evaluating the expression to the given label.  Because this assembler is so
  500. gosh-darned awesome, the expression doesn't even have to be resolved; a
  501. "hole" will be created saying to fill in the assigned label when all of the
  502. unresolved identifiers in the expression eventually become resolved.  Most
  503. other assemblers (in fact, all that I have ever heard of) can't do this
  504. because it causes ugly implementation problems, like cascading label
  505. resolutions.  Consider the following example:
  506.  
  507. lda #a
  508. sta b,x
  509. a = b+3
  510. b = c-1
  511. c = 5
  512.  
  513. At the point where c becomes defined, there are no "memory holes" but the
  514. label hole "b" must be evaluated and filled in.  "b" gets assigned the value
  515. 4.  At this point, there are two holes: the one in the "sta" instruction and
  516. the label "a".  We fill them both in, assigning "a" the value 8, and we
  517. discover that we need to fill in a hew hole: the one in the "lda"
  518. instruction.  We do that and we are finally done.  The implementation can
  519. handle any number of these recursive label hole-fillings, limited only by
  520. the amount of near+far memory you have.
  521.  
  522. A label can only be assigned a value only once, and you will get an error if
  523. you try to redefine a label, even if it is currently unresolved.  Also, all
  524. exressions must be resolved by the end of the assembly job, or an error will
  525. be reported (but only one--naming the first unresolved label that the
  526. assembler runs across; I may fix this up in the future).
  527.  
  528. The second assignment directive is equivalent to "label = *", but it is more
  529. convenient and is also a prefix directive.  It assigns the current address
  530. (as of the start of the current line) to the given identifier.  The colon is
  531. used with this directive to make it easy and efficient to parse, and to make
  532. it easy for a human to see that a label is being defined.  Many other
  533. assemblers follow this directive with just whitespace and rely on other
  534. tricks, like putting an ugly dot before each directive, to bail them out.
  535. For maximum compatibility, you can also leave out the colon following a
  536. label definition and the assembler will figure out what you mean (though a
  537. little less efficiently).
  538.  
  539. The third and fourth set relative reference points.  They are equivalent to
  540. "rel_label = *", where "rel_label" is a specially generated internal
  541. identifier of the form "L+123c" mentioned in the expression section.  The
  542. labels defined by these directives show up in the symbol table dump, if you
  543. ask for one on the command line.  These are also prefix directives, so if
  544. you wanted to set a forward and a backward reference to the same address,
  545. then you would do something like:
  546.  
  547. +- lda #1
  548.  
  549. In fact, you could put as many or these directives on the front of a line as
  550. you want, though more than one of each will be of little use.  For source
  551. compatibility with the Buddy assembler, the ACE assembler will also accept a
  552. leading "/" on a line as being equivalent to "+-".  Note that backward
  553. relative labels will always be defined at the point that they are referenced
  554. and forward relative labels will always be undefined (unresolved) when they
  555. are referenced.  If at the end of your assembly job the assembler complains
  556. of an unresolved reference involving a label of the form "L+123c", then you
  557. refer to a forward-relative point that you don't set, and if the label is of
  558. the form "L-4000000000c", then you refer to a backward relative point that
  559. you don't define.
  560.  
  561. 6.3. ORIGIN DIRECTIVE
  562.  
  563. .org address_expression      ;set the origin of the assembly
  564.  
  565. This directive will set the code origin to the given expression.  The
  566. expression MUST be resolved at the point where it appears, since it would be
  567. very difficult to fill in the type of "hole" this would leave behind (though
  568. not impossible, hmmm...).  The origin must be set before any processor
  569. instruction or assembler directive that generates memory values or refers to
  570. the current address is encountered, and the code origin can only be set
  571. once.  This results in a contiguous code region, which is what ACE and the
  572. Commodore Kernal require.
  573.  
  574. 6.4. DEFINE-BYTES DIRECTIVES
  575.  
  576. .byte exp1, exp2, ..., expN   ;put byte values into memory
  577. .word exp1, exp2, ..., expN   ;put word values into memory
  578. .triple exp1, exp2, ..., expN ;put "triple" (3-byte) values into memory, lo->hi
  579. .long exp1, exp2, ..., expN   ;put "long" (4-byte) values into memory, lo->hi
  580.  
  581. These directives all put byte values into code memory, at the current
  582. address.  The only difference between the four of them is the size of data
  583. values they put into memory: bytes (8 bits), words (16 bits), triples (24
  584. bits), and longs (32 bits).  The code address is incremented by the
  585. appropriate number of bytes between putting each value into memory.  Any
  586. number of values can be specified by separating them by commas.  All
  587. expressions are evaluated in full 32 bits, but must fit into the size for
  588. the directive.  The expressions don't have to be resolved at the time they
  589. appear.
  590.  
  591. These directives can also be given strings for arguments, which means that
  592. each character of the string will be stored as one byte/word/etc. in memory,
  593. for example:
  594.  
  595. .byte 123, abc+xyz+%1101-"a"+$1, "hello", 0, "yo!", "keep on hackin'\0"
  596.  
  597. These directives used to be named "db", "dw", "dt", and "dw", but I changed
  598. them to be more consistent with most other 6502 assemblers out there.
  599.  
  600. 6.5. BUF DIRECTIVE
  601.  
  602. .buf size_expression       ;reserve "size" bytes of space, filled with zeroes
  603.  
  604. This directive reserves the given number of bytes of space from the current
  605. code address and fills them with zeroes.  The expression must be resolved,
  606. and can be any value from 0 up to 65535 (or the number of bytes remaining
  607. until the code address overflows the 64K code space limit).
  608.  
  609. 6.6. INCLUDE DIRECTIVE
  610.  
  611. .include "filename"       ;include the named source file at the current point
  612.  
  613. This directive will include the named source file at the current point in
  614. the current source file, as if you had typed the contents of the named
  615. file were actually typed at the current point.  Input is read from the
  616. include file until it hits EOF, and then input is resumed from the current
  617. file immediately after the include statement.  The filename must be in
  618. the form of a string literal and in the ACE syntax.
  619.  
  620. Normally, this feature is used to include standard header files into an
  621. application, such as the "acehead.s" file, but it can also be use to
  622. modularize an application into a number of different functional modules.
  623.  
  624. Include files may be nested arbitrarily deep (included files may include
  625. other files, and so on) in the assembler, but the ACE environment puts
  626. limitations on how many files can be opened at one time (although, you
  627. should never need to go more than a couple of levels deep).  The assembler
  628. doesn't check for recursive include files (although it could), but you will
  629. get an error anyway from ACE since you will exceed the number of allowed
  630. files to have opened.
  631.  
  632. Error reporting is also reported correctly in the case that an error is
  633. detected in the current source file because of a reference in a different
  634. file (both files will be named).
  635.  
  636. 6.7. PARSING AND COMPATIBILITY
  637.  
  638. Because of the way that the assembler parses the source code (it uses a
  639. one-character-peek-ahead ad-hoc parser), you can define labels that are also
  640. directive names or processor-instruction names (if you use the colon
  641. notation).  This is not a recommended practice, since you can end up with
  642. lines that look like:
  643.  
  644. x: lda: lda lda,x
  645.  
  646. The parser will know what to do, but most humans won't.  Also, because of
  647. the tokenizer, can put arbitrary spacing between tokens, except between
  648. tokens that would otherwise merge together (like two adjacent identifiers or
  649. decimal numbers).
  650.  
  651. For compatibility, the following directives are also include and are used
  652. as aliases for ACE-assembler directives.
  653.  
  654. ALIAS   ACE-as     DESCRIPTION
  655. -----   ------     -----------
  656. .asc    .byte      works since the byte directive accepts strings
  657. .byt    .byte      equivalent
  658. .seq    .include   equivalent; the filename must be a literal string
  659. .obj    ;          all tokens following this are ignored UNTIL the CR
  660. .end    <eof>      end the assembly of the current file
  661. ------------------------------------------------------------------------------
  662. 7. ERROR HANDLING
  663.  
  664. When an error is detected, the assembler will stop the whole assembly job
  665. and print out one error message (to the stderr file stream).  Here are two
  666. examples of error messages:
  667.  
  668. err ("k:":2:0) Value is too large or negative
  669.  
  670. err ("k:":3:0), ref("k:":2:0) Value is too large or negative
  671.  
  672. In both error messages, the stuff inside of the parentheses is the filename
  673. of the source file (the keyboard here), the source line where the error was
  674. detected, and the column number where the error was detected.  Currently,
  675. the column number is not implemented so it is always zero.  When it is
  676. implemented, the column numbers will start from 1, like in the Zed text
  677. editor, and it will point to the first character of the token where the
  678. error was discovered.
  679.  
  680. In the first example, the error occurred because the expression was resolved
  681. and the value was found to be too large for whatever operation was
  682. attempted.  In the second example, an expression was used but unresolved on
  683. line 2 of the source file, and when its unresolved identifier(s) was finally
  684. filled in in line 3 of the source, the "hole" to be filled in was found to
  685. be too small for the value, so an error resulted.  This is what the "ref"
  686. file position means.  Filenames are included in error messages because in
  687. the future, it will be possible to have errors crop up in included files and
  688. elsewhere.
  689.  
  690. Here is the entire list of possible error messages:
  691.  
  692. NUM  MEANING
  693. ---  -------
  694. 01.  "An identifier token exceeds 240 chars in length"
  695. 02.  "A string literal exceeds 240 chars in length"
  696. 03.  "Ran into a CR before end of string literal"
  697. 04.  "Invalid numeric literal"
  698. 05.  "Numeric literal value overflows 32-bits"
  699. 06.  "Syntax error"
  700. 07.  "Attempt to perform numeric operators on a string"
  701. 08.  "Expression has more than 17 operands"
  702. 09.  "Ran out of memory during compilation process"
  703. 10.  "Attempt to redefine a symbol"
  704. 11.  "Attempt to assemble code with code origin not set"
  705. 12.  "Internal error: You should never see this error!"
  706. 13.  "Non-numeric symbol in a numeric expression"
  707. 14.  "Expecting an operator"
  708. 15.  "Expecting an operand"
  709. 16.  "Expecting a command"
  710. 17.  "Value is too large or negative"
  711. 18.  "Branch out of range"
  712. 19.  "Feature is not (yet) implemented"
  713. 20.  "Instruction does not support given address mode"
  714. 21.  "Address wraped around 64K code address space"
  715. 22.  "Error trying to write output object file"
  716. 23.  "Directive requires resolved expression"
  717. 24.  "Code origin already set; you can't set it twice"
  718. 25.  "Unresolved symbol: "
  719. 26.  "Expecting a string-literal filename"
  720.  
  721. A "Syntax error" (#06) will be reported whenever a token other than one that
  722. was expected is found (except in the cases of the other 'Expecting'
  723. messages).  "Ran out of memory" (#09) may turn up often on an unexpanded
  724. 64.  "Expecting command" (#16) means that the assembler was expecting either
  725. a processor instruction or directive but found something else instead.  "Not
  726. implemented" (#19) means that you've tried to use a directive that isn't
  727. implemented yet.  "Unresolved symbol" (#25) will be printed with a randomly
  728. chosen unresolved symbol, with the last place in the source code where it
  729. was referenced.
  730.  
  731. There are two main reasons behind the idea of stopping at the first error
  732. encountered: simplicity and interoperability.  When ZED is implemented for
  733. ACE, it will have a feature that will allow it to invoke the assembler (as a
  734. sub-process) and have the assembler return an error location and message to
  735. ZED, which will display the error message and position the cursor to the
  736. error location (if the source file is loaded).
  737.  
  738. While on the subject of messages coming out of the assembler, here is an
  739. example of the format of the symbol table dump that you can ask for on the
  740. command line.  One line is printed for each identifier.  The "hash" value is
  741. the bucket in the hash table chosen for the identifier.  This may not have a
  742. whole lot of meaning for a user, but a good distribution of these hash
  743. buckets in the symbol table is a good thing.  Next is the 32-bit "hexvalue"
  744. of the label followed by the value in "decimal".  Then comes the type.  A
  745. type of "v" means value, "a" in-code-range address, "l" means an address
  746. low-byte, "h" means an address high-byte, and "g" means a 'garbage' type.
  747. Then comes the name of the identifier.  It comes last to give lots of space
  748. to print it.  If an identifier is ten or fewer characters long, its
  749. symbol-table-dump line will fit on a 40-column screen.  At the bottom, the
  750. number of symbols is printed.  This table is directed to the stdout file
  751. stream, so you can redirect it to a file in order to save it.
  752.  
  753. HASH  HEXVALUE    DECIMAL  T  NAME
  754. ----  -------- ----------  -  -----
  755.    8  00000f06       3846  v  aceArgv
  756.  469  00007008      28680  a  main
  757. --
  758. Number of symbols: 2
  759. ------------------------------------------------------------------------------
  760. 8. IMPLEMENTATION
  761.  
  762. In each of the ways in which it is heavy-weight and slowed-down compared to
  763. other assemblers, it is also more powerful and more flexible.
  764.  
  765. - It uses far memory for storing symbols, so there is no static or
  766.   arbitrarily small limit on the number of symbols.  Macro sizes will also
  767.   be limited by only the amount of memory available, as well as the "hole
  768.   table".
  769.  
  770. - It has to maintain a "hole table" because of its structure, but this means
  771.   that you can define labels in terms of other unresolved labels, that you
  772.   will never get a "sync error" because of incorrect assumptions made (and
  773.   not recorded) about unresolved labels, and that modular assembly can be
  774.   implemented without too much further effort (i.e., ".o" or ".obj" files),
  775.   since an unresolved external reference handling mechanism is already
  776.   implemented.
  777.  
  778. - The assembler keeps track of the "types" of labels which makes it possible
  779.   to provide code relocation information that will be needed by modular
  780.   assembly and by future multitasking operating systems.
  781.  
  782. - Because a "hole table" approach is used, the raw object code must be
  783.   stored internally until the assembly is complete and then it can be
  784.   written out to a file, but this also means that header information can be
  785.   provided in an output file since all assembly results will be known before
  786.   any output is written.
  787.  
  788. - I took the easy way out for handling errors; when an error is detected, an
  789.   error message is generated and printed and the assembler STOPs.  But the
  790.   exit mechanism provided by ACE makes it possible to integrate the
  791.   assembler with other programs, like a text editor, to move the text editor
  792.   cursor to the line and column containing the error and display a message
  793.   in the text editor.
  794.  
  795. There are two speed advantages that this assembler has over (some?) others:
  796.  
  797. - It uses a 1024-entry hash table of pointers to chains of labels, so, for a
  798.   program that has 800 or so symbols, each can be accessed in something like
  799.   1.3 tries.  For N total symbols, the required number of references is
  800.   approximately MAX( N/1024, 1 ).
  801.  
  802. - It is one-pass, so it only has to go through the overhead of reading the
  803.   source file once.  Depending on the type of device the file is stored on,
  804.   this may give a considerable savings.  This also makes it possible to
  805.   "pipe" the output of another program into the assembler, without any
  806.   "rewind" problems.
  807.  
  808. Here are some (old) performace figures, compared to the Buddy assembler for
  809. the 128.  All test cases were run on a C128 in 2-MHz mode with a RAMLink,
  810. REU, and 1571 available.
  811.  
  812. ASSEMB   TIME(sec)   FILE DEVICE   FAR STORAGE
  813. ------   ---------   -----------   -----------
  814. Buddy         45.5   RAMLink       n/a
  815. ACE-as        61.5   RAMLink       REU
  816. ACE-as        49.5   ACE ramdisk   REU
  817. ACE-as        75.6   RAMLink       RAM0+RAM1
  818. ACE-as       150.5   1571          RAM0+RAM1
  819. Buddy        240.0   1571          n/a
  820.  
  821. Part of the assembly job was loaded into memory for the Buddy assembler, but
  822. the load time is included in the figure.  As you can see, buddy performs
  823. faster with a fast file device and slower with a slow file device (because
  824. it requires two passes).  I have a couple of tricks up my sleeve to improve
  825. the ACE assembler's performance.
  826.  
  827. Here are a few data structures for your enjoyment.
  828.  
  829. Identifier descriptor:
  830.  
  831. OFF   SIZ   DESCRIPTION
  832. ---   ---   ------------
  833.   0     4   next link in hash table bucket
  834.   4     4   value of symbol, pointer to reference list, or ptr to macro defn
  835.   8     1   offset of reference in expression of reference list
  836.   9     1   type: $00=value, $01=address, $02=low-byte, $03=high-byte,
  837.                   $04=garbage, $80=unresolved, $ff=unresolved define
  838.  10     1   class: $00=normal, $01=private, $80=global (not used yet)
  839.  11     1   name length
  840.  12     n   null-terminated name string (1-240 chars)
  841. 12+n    -   SIZE
  842.  
  843. Expression/Hole descriptor:
  844.  
  845. OFF   SIZ   DESCRIPTION
  846. ---   ---   -----------
  847.   0     1   hole type: $01=byte, $02=word, $03=triple, $04=long, $40=branch,
  848.             $80=label
  849.   1     1   expression length: maximum offset+1 in bytes
  850.   2     1   number of unresolved references in expression
  851.   3     1   source column of reference
  852.   4     4   address of hole
  853.   8     4   source line of reference
  854.  12     4   source file pointer
  855.  16    14   expression operand descriptor slot #1
  856.  30    14   expression operand descriptor slot #2
  857.  44    14   expression operand descriptor slot #3
  858.  58    14   expression operand descriptor slot #4
  859.  72    14   expression operand descriptor slot #5
  860.  86    14   expression operand descriptor slot #6
  861. 100    14   expression operand descriptor slot #7
  862. 114    14   expression operand descriptor slot #8
  863. 128    14   expression operand descriptor slot #9
  864. 142    14   expression operand descriptor slot #10
  865. 156    14   expression operand descriptor slot #11
  866. 170    14   expression operand descriptor slot #12
  867. 184    14   expression operand descriptor slot #13
  868. 198    14   expression operand descriptor slot #14
  869. 212    14   expression operand descriptor slot #15
  870. 226    14   expression operand descriptor slot #16
  871. 240    14   expression operand descriptor slot #17
  872. 254     -   SIZE
  873.  
  874. Expression operand descriptor:
  875.  
  876. OFF   SIZ   DESCRIPTION
  877. ---   ---   -----------
  878.   0     1   dyadic operator: "+", "-", "*", "/", "!", "&", "|", or "^"
  879.   1     1   type of value: $00=value, $01=address, $02=low-byte, $03=high-byte,
  880.             $04=garbage type, $80=unresolved identifier
  881.   2     1   monadic-operator result sign of value: $00=positive, $80=negative
  882.   3     1   hi/lo operator counts: high_nybble=">" count, low_nybble="<" count
  883.   4     4   numeric value or unresolved-identifier pointer
  884.   8     4   next unresolved reference in chain for unresolved identifier
  885.  12     1   offset in hole structure of next unresolved reference (operand)
  886.  13     1   reserved
  887.  14     -   SIZE
  888.  
  889. File Identifier:
  890.  
  891. OFF   SIZ   DESCRIPTION
  892. ---   ---   -----------
  893.   0     4   pointer to previous file identifier on include stack
  894.   4     4   line number save
  895.   8     4   column number save
  896.  12     1   file type: $00=regular, $01=stdin, $80=macro
  897.  13     1   file descriptor save
  898.  14     1   previous character save
  899.  15     1   buffer pointer save
  900.  16     4   pointer to buffer save area (char[256])
  901.  20     4   reserved
  902.  24     1   length of entire file-identifier record
  903.  25     n   filename + '\0'
  904. 25+n    -   SIZE
  905. ------------------------------------------------------------------------------
  906. 9. THE FUTURE
  907.  
  908. This section is just random notes since I don't have the time right now to
  909. fill it in.  I will be implementing include files, conditional assembly, and
  910. macro assembly features in the future.  Modular assembly and relocatable-
  911. code generation are also in my plans.
  912.  
  913. ;todo: -implement storage classes: $00=internal, $01=rel.label, $80=exported
  914. ;      -implement source column, make line:col point to start of cur token
  915. ;      -make it so you can use a "\<CR>" to continue a line (macro)
  916. ;
  917. ; usage: as [-help] [-s] [-d] [-b] [-r] [-l] [-a addr] [file ...] [-o filename]
  918. ;
  919. ;     -help : produce this information, don't run
  920. ;        -s : produce symbol table dump at end
  921. ;        -d : provide debugging information (lots)
  922. ;        -b : produce binary module at end (default)
  923. ;        -r : produce relocatable module rather than binary module
  924. ;        -l : produce linkable ".o" module(s)
  925. ;        -a : set global code origin to given address
  926. ;        -o : put output into given filename
  927. ;
  928. ;     If -l option is not used, all files, including source and object modules,
  929. ; will be assembled together.  The output module name will be the base name of
  930. ; the first file given if it has a ".s" or ".o" extension, "a.out" if the first
  931. ; file has none of these extensions, or will be the filename given by the -o
  932. ; option if used.
  933. ;     If the -l option is used, then each given source module will be
  934. ; assembled independently into its own ".o" module.  Object modules will be
  935. ; ignored.
  936. ;     The global origin will be either that given by the -a option (if it is
  937. ; used) or by the local origin of the first source/object module.  Each
  938. ; source module that generates code must have a local code origin.
  939.  
  940. More Directives:
  941.  
  942. if <expression> <relop> <expression>
  943. elsif <expression> <relop> <expression>
  944. else
  945. endif
  946. macro macroname
  947. endmacro
  948. export label1, label2, ..., labelN
  949. bss size_expression
  950.  
  951. macro blt ;?1=addr
  952.    bcc ?1
  953. endmacro
  954.  
  955. macro add ;?1=operand
  956.    clc
  957.    adc ?1
  958. endmacro
  959.  
  960. macro ldw ;?1=dest, ?2=source
  961.  if ?# != 2
  962.    error "the ldw macro instance doesn't have two arguments"
  963.  endif
  964.  if @1 = #
  965.    argshift 2 0
  966.    lda #<?2
  967.    sta ?1+0
  968.    lda #>?2
  969.    sta ?1+1
  970.  else
  971.    lda ?2+0
  972.    sta ?1+0
  973.    lda ?2+1
  974.    sta ?1+1
  975.  endif
  976. endmacro
  977. ------------------------------------------------------------------------------
  978. So, there is finally a powerful and convenient assembler universally
  979. available for both the 64 and 128... for free.  The source code for the
  980. assembler (which can be assembled by the assembler, of course) is also
  981. available for free.  There are a few more features that need to be
  982. implemented, but I know exactly how to implement them.
  983.  
  984. Keep on Hackin'!
  985.  
  986. -Craig Bruce
  987. csbruce@ccnga.uwaterloo.ca
  988. "Give them applications and they will only want more; give them development
  989.  tools and they will give you applications, and more."
  990. ------------------------------------------------------------------------END---
  991.