home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 357_01 / cstar1.exe / PL68K.DOC < prev    next >
Text File  |  1991-06-20  |  34KB  |  718 lines

  1. PL/68K.DOC:  The Dr. Dobb's Journal Article
  2.  
  3. June 25, 1991
  4.  
  5. The following is a slight revision of an article that appeared in the 
  6. January, 1986 issue of Dr. Dobb's Journal.  Alas, the figures are no 
  7. longer available.
  8.  
  9. This article gives the original vision behind the language.  It does *not* 
  10. describe the current language, which is CSTAR.  (The PL/68K language 
  11. evolved in the years 1986 and 1987 to become the CSTAR language.)  
  12. See the files CSTAR.DOC and DESIGN.DOC for a discussion of how 
  13. PL/68K became CSTAR.  
  14.  
  15.  
  16. C BECOMES 68000 ASSEMBLY LANGUAGE
  17.  
  18. One day not long ago, I became embroiled in an old debate with another 
  19. programmer named Charlie...
  20.  
  21. "The programming team I manage is about to start a big project,"  I said, 
  22. "and I must decide which language to use."  
  23.  
  24. "Really?  Which languages are you considering?"
  25.  
  26. "C and 68000 assembly language.  The product will have strong 
  27. competition, and great performance is crucial, so it's reasonable to 
  28. consider assembly language.  On the other hand , C is so much easier to 
  29. use.
  30.  
  31. "Why don't you program in C and recode in assembly language as 
  32. needed?"  Charlie asked.
  33.  
  34. "Of course I've considered that.  It might work as far as execution speed 
  35. is concerned, although I'm not sure.  C doesn't let you allocate registers 
  36. globally, and that's a big handicap.  Speed is not the only problem, 
  37. though.  The code must be compact, but our C compiler produces code 
  38. that is 50 percent larger than assembly language.  No, there's no doubt 
  39. about it--eventually the program will have to be written in assembly."
  40.  
  41. "Do the initial prototyping in C.  That's the right way," Charlie persisted.  
  42. "When the program is finished recoding in assembly language will be 
  43. much easier."
  44.  
  45. "Hmmm.  I'm not convinced.  Recoding is going to be expensive; we'll 
  46. end up debugging the whole program twice.  There might even be 
  47. pressure from higher management not to recode and come out with an 
  48. inferior product."
  49.  
  50. Charlie just snorted and walked away, muttering something about 
  51. assembly language being a throw back to the dark ages.
  52.  
  53.  
  54. WRITING IN BOTH C AND ASSEMBLY LANGUAGE
  55.  
  56. Fortunately, my friend John overheard this conversation.  John and I have 
  57. worked together for 15 years, and we enjoy discussing problems that 
  58. come up on the job.  John laughed, "Charlie is more interested in being 
  59. right about C than in solving your problem."
  60.  
  61. "You sound more sympathetic."
  62.  
  63. "Well, your choice is crucial.  Which language you use determines, to a 
  64. large extent, how your project will turn out."
  65.  
  66. "Yes.  What bothers me most is that I've got to choose now, but I won't 
  67. know until the project is almost over whether the choice was correct."
  68.  
  69. "I think I know a way around this dilemma--it's a language I invented 
  70. called PL/68K."
  71.  
  72. "John, my only options are C and 68000 assembly language."
  73.  
  74. "Don't be fooled by the name.  PL/68K isn't really an independent 
  75. language but a way of using C to do assembly-language programming."
  76.  
  77. "John, you are not making sense!"
  78.  
  79. "Let me explain.  You can think of PL/68K as being either C or assembly 
  80. language--either/or.  But in fact, you can run a program written in 
  81. PL/68K through both the PL/68K assembler and any standard C 
  82. compiler.  PL/68K is both C and assembly language at the same time."
  83.  
  84. "Wait a minute.  You are going much too fast," I said.  "First of all, you 
  85. can't possibly compile an assembly-language program with a C compiler!  
  86. Assembly language doesn't look anything like C--the C compiler will 
  87. spit out a thousand error messages!"
  88.  
  89. "PL/68K doesn't resemble 'traditional' assembly language.  Forget what 
  90. assembly language usually looks like and ask yourself, 'What are the 
  91. characteristics of assembly language?' "
  92.  
  93. "Go on," I replied.  "You tell me."
  94.  
  95. "First, assembly language allows full access to all machine resources--all 
  96. registers, all locations in memory (including the run-time stack), all I/O 
  97. ports, all privilege modes, and all machine instructions.  Second, there is 
  98. a one-for-one correspondence between the source code you write and and 
  99. the object code produced by the assembler.  You always know what code 
  100. a particular assembly-language construct generates; assemblers neither 
  101. rearrange code nor 'optimize' code away nor add anything extraneous.  
  102. Assemblers are very literal-minded.  Thus, assembly language ensures 
  103. zero time and space overhead."
  104.  
  105. "You're saying that assembly language gives you complete control over 
  106. the machine, without a compiler getting in the way."
  107.  
  108. "Exactly.  Now, suppose we say assembly language is any language that 
  109. (1) allows complete access to all machine resources, (2) provides a clear 
  110. correspondence between source code and object code, and (3) imposes 
  111. zero time or space overhead."
  112.  
  113.  
  114. SEMANTIC IDENTITY
  115.  
  116. "Hmmm," I mused.  "This definition doesn't say what assembly language 
  117. looks like.  It could even look like C.  But I still don't understand.  If you 
  118. run a PL/68K program through an assembler, you will get one program.  
  119. If you run the same source through a C compiler, you will get a second 
  120. program.  The two programs are not going to do the same things--similar 
  121. things, maybe, but not the same things.  The fact that the source code is 
  122. the same doesn't matter.  To put it another way, given a result desired 
  123. from a specific PL/68K program, we would still have to choose between 
  124. assembling the program with the PL/68K assembler or compiling it with a 
  125. C compiler."
  126.  
  127. "You've stated the problem very well," John said, "but I have discovered 
  128. that it's possible to design PL/68K so that the program produced by the 
  129. PL/68K assembler will work in the same way as the program produced 
  130. by the C compiler."
  131.  
  132. "That sounds impossible!"
  133.  
  134. "I don't think so.  Let's turn the problem around.  Suppose we design 
  135. PL/68K according to what might be called 'the principle of semantic 
  136. equivalence.'  This principle states that a program, when assembled by 
  137. the PL/68K assembler, must work in the same way as when it is compiled 
  138. by a standard C compiler.  Now let's ask ourselves, 'What needs to be 
  139. eliminated from PL/68K to guarantee semantic equivalence?' " (See 
  140. Figure 1.)
  141.  
  142. "Tell me," I said, "how much of C is left after the principle of semantic 
  143. equivalence takes its toll?"
  144.  
  145. "Just about all of it. The preprocessor is identical to the C preprocessor.  
  146. All declarations and structure statements are present.  Function are 
  147. unchanged, as are Boolean and relational operators and expressions.  
  148. PL/68K is a little more fussy about types and type conversions than C is 
  149. and there are some slight restrictions are placed on how complicated 
  150. arithmetic expressions can be.
  151.  
  152. "You keep talking about PL/68K being assembly language," I said.  
  153. "How is it possible to produce code the quality of assembly language 
  154. from a language that is a subset of C?"
  155.  
  156. "I haven't shown you the whole language yet.  Two other rules guide the 
  157. design of PL/68K.  These rules, together with the principle of semantic 
  158. equivalence, determine the form and content of PL/68K.  The two rules 
  159. are 'the code selection rule'--the assembler for PL/68K does no code 
  160. selection, and all arithmetic operations in PL/68K correspond to unique 
  161. 68000 machine instructions; and 'the register allocation rule'--the 
  162. assembler for PL/68K does no register allocation.  The programmer must 
  163. specify how registers will be allocated.
  164.  
  165. "In short, these rules say that an assembler for PL/68K never has to make 
  166. any significant decisions.  Because the PL/68K assembler knows how to 
  167. select code and allocate register, it will never need any of the fancy 
  168. techniques used by optimizing compilers, but it will be able to produce 
  169. code that is just as good as assembly language.
  170.  
  171. "I like to think of the assembler for PL/68K as a simple compiler, 
  172. consisting of a parser, a straightforward code generator and  a peephole 
  173. optimizer.  The whole job should take about a year to complete rather than 
  174. the 10 to 20 programmer years for a typical optimizing compiler.  Using 
  175. compiler technology to write an assembler was the initial idea that started 
  176. me thinking about PL/68K."
  177.  
  178. Now that I've presented the general ideas behind PL/68K, I'll drop this 
  179. dialogue format and these fictional characters and look at the details of the 
  180. language.
  181.  
  182.  
  183. SPECIFYING REGISTERS
  184.  
  185. Because PL/68K is both assembly language and C, some way must be 
  186. found to deal with assembly-language constructs such as registers, 
  187. address modes, and individual machine instructions, while at the same 
  188. time remaining compatible with C.  These assembly-language constructs 
  189. are represented by reserved words, shown in Table 1.
  190.  
  191. As for the registers of the 68000, d0 through d7 stand for the data 
  192. registers, a0 through a7 for the address registers, pc for the program 
  193. counter, ssr for the status register, and ccr for the condition code register, 
  194. which is the lower byte of the ssr.
  195.  
  196. Standard aliases are also defined.  Register a7 can also be called sp, ssp, 
  197. or usp to denote the stack pointer (or system stack pointer or user stack 
  198. pointer).  The reserved words r0 through r7 are synonyms for d0 through 
  199. d7, and the names r8 through r15 are synonyms for registers a0 through 
  200. a7.
  201.  
  202. All registers on the 68000 are 32 bits long (except the status registers), 
  203. but not every instruction uses all 32 bits of a register.  Besides long (32-
  204. bit) operations, byte-length (8-bit) and word-length (16-bit) operations are 
  205. permitted on data registers, and word-length operations are permitted on  
  206. address registers.  To represent the length of an operation, the name of 
  207. any data register can be followed by a 'b' to denote to denote byte length 
  208. or w to denote word length.  Thus, d0 stands for the long register d0, 
  209. d0w stands for the word-length register d0, and d0b stands for the byte-
  210. length register d0.  Address registers are treated in a similar manner, 
  211. except that byte-length operations are not permitted.
  212.  
  213.  
  214. ADDRESS MODES
  215.  
  216. The 68000 has 12 different address modes, or means of accessing 
  217. operands. (See Table 2)  The address modes are represented in PL/68K 
  218. by five of C's operators, namely &, *, ++, P P, and P>.
  219.  
  220. Let's look, for example, at the Address Register Indirect with 
  221. Postincrement address mode.  (It's a lot easier to use than to say.)  This 
  222. mode uses the contents of an address register as the address of an 
  223. operand.  After the operation is performed, the address register is 
  224. incremented by 1, 2, or 4, depending on the size of the operation.  In 
  225. traditional assembly language, that mode applied to address register a0  
  226. would be written as (a0)+.  In PL/68K, that address modes is represented 
  227. by *a0++.  for example, you would write d0b = *a0++; in PL/68K 
  228. instead of MOVE.B (a0)+, d0b.  
  229.  
  230. The word primitive  denotes what is called an effective address in 
  231. machine-language terms.  A primitive describes an operand, which may 
  232. be in a register, on the run-time stack, or in static memory.  In PL/68K, 
  233. the valid forms of primitives are determined by the address modes I've 
  234. just discussed.
  235.  
  236.  
  237. DECLARATIONS
  238.  
  239. In effect, declarations produce DC (define constant) and DS (define 
  240. storage) pseudo-operations.  (See Table 3)  Although declarations produce 
  241. no executable code they determine what code gets produced by arithmetic 
  242. operators.  For instance, if a is an integer, the assignment statement a *= 
  243. b, which multiplies a by b, generates a MULS (signed multiply) machine 
  244. instruction, but if a is an unsigned integer or pointer, the assignment 
  245. statement generates a MULU (unsigned multiply) instruction.
  246.  
  247. As another example, the assignment a += b. which adds b to a, generates 
  248. and ADD.B (byte length add) instruction if a is a char, but it generates an 
  249. ADD.W (word length add) instruction if a is a long word or pointer.
  250.  
  251.  
  252. ASSEMBLY-LANGUAGE INSTRUCTIONS AND PSEUDO-OPERATIONS
  253.  
  254. Reserved identifiers also stand for 68000 machine-language instructions 
  255. and pseudo-operations.  A library of pseudofunctions must be linked with 
  256. a PL/68K program when it is translated with a C compiler.  This library, 
  257. called the ops library, contains declarations and functions that allow C 
  258. programs to simulate the effect of 68000 machine instructions and 
  259. pseudo-operations.  (See Table 4)
  260.  
  261. The pseudofunction btst ( ), for example, simulates the BTST (bit test) 
  262. machine instruction.  In PL/68K, you would write btst(1,d0b); in those 
  263. places where you would write btst.b#11,d0 in traditional 68000 assembly 
  264. language.
  265.  
  266. Other pseudofunctions allow PL/68K programs to refer to assembly-
  267. language pseudo-operations.  The PL/68K assembler translates the org( ), 
  268. even( ), bss( ), text(), and data( ) pseudofunctions to the ORG, EVEN 
  269. BSS, TEXT, and DATA pseudo-operations.  Similarly, the PL/68K 
  270. assembler translates the dcb( ), dcw( ), dcl( ), dsb( ), dsw( ), and dsl( )  
  271. pseudofunctions to the DC.B, DC.W, DC.L, DS.B, DS.W, and DS.L 
  272. pseudo-operations.  None of these pseudofunctions has any effect when a 
  273. C compiler translates a PL/68K program.  In other words, the 
  274. corresponding pseudofunctions in the ops library do nothing.
  275.  
  276. You may be wondering why I keep calling these routines 
  277. pseudofunctions.  After all, they are perfectly good functions when 
  278. compiling a PL/68K program with C compiler.  When you turn the 
  279. program through the PL/68K assembler, though, it translates 
  280. pseudofunctions directly in 68000 machine instructions or pseudo-
  281. operations.
  282.  
  283.  
  284. EXPRESSIONS AND ASSIGNMENT STATEMENTS
  285.  
  286. I've covered the components of low-level assembly language--register, 
  287. address modes and effective addresses, machine instructions, and 
  288. pseudo-ops.  Now let's see how you put these components together to 
  289. make expressions and assignment statements.
  290.  
  291. Expressions are just like C expressions, but they may not be arbitrarily 
  292. complex.  As the code selection rule requires, PL/68K defines what code 
  293. arithmetic expressions will generate.
  294.  
  295. (See Table 5.)  The += and + operators generate the ADD instruction, the 
  296. P=  and P operators generate the SUB instruction, and so on.  Many 
  297. machine instructions on the 68000 have several variants--for example, 
  298. ADDA adds address registers, ADDI adds literal data, and plain ADD 
  299. adds to data registers and memory locations.  The assembler has to do 
  300. some code selection, but the choice is easy; even traditional assemblers do 
  301. that much.
  302.  
  303.  
  304. BOOLEAN EXPRESSIONS
  305.  
  306. Boolean expressions in PL/68K are similar to Boolean expressions in C.  
  307. All the boolean operators !, | |, and && and all the relational operators ==, 
  308. !=, <, <=, >, and >= are allowed.
  309.  
  310. Boolean expressions can only appear in the appropriate part of if, do, 
  311. while, and for statements.  The code fragment a ==b; is not valid in 
  312. PL/68K outside a structure statement.  This restriction eliminates a whole 
  313. class of hard-to-find errors (the programmer almost certainly meant to say
  314. a = b).
  315.  
  316. Because Boolean expressions appear in limited contexts,  less work is 
  317. required to evaluate them.  (See Tables 6 and 7)  Boolean expressions 
  318. generate the TST (test operand) or CMP (compare) instructions followed 
  319. by some form of the Bxx (conditional branch) instruction.  The Bxx 
  320. instruction chosen depends on the relop and the declared type of the 
  321. operand being tested.  The NOT (!) operator generates no code at all but 
  322. instead simply reverses the "polarity" of one or more BXX instructions.  
  323. For example, the statement
  324.  
  325.     if(a == 0)
  326.  
  327. generates
  328.  
  329.     TST A
  330.      BNE
  331.  
  332. while the statement
  333.  
  334.     if(!(a == 0))
  335.  
  336. generates
  337.  
  338.     TST A
  339.      BEQ
  340.     
  341. Similarly, the  |  | and && operator generate no extra code.  Incidentally, 
  342. you can use parentheses in Boolean expressions to affect the order of 
  343. binding of Boolean operators.  For instance,  the Boolean expression 
  344.  
  345.     if(a && !(b<5 | |b>20))
  346.  
  347. is valid and generates    
  348.  
  349.     TST    A
  350.     BEQ
  351.     CMPI    5, B
  352.     BLT
  353.     CMPI    20, B
  354.     BGT
  355.  
  356. You can specify condition code values directly.  (See Table 8)  For 
  357. instance, the statement
  358.  
  359.     if (ccr=Z)
  360.  
  361. tests the  current value of the zero bit in the condition code 
  362. register and generates the BNZ (branch not zero) instruction.  Z is a 
  363. macro in C, defined in the ops library, which expands to a call to the 
  364. pseudofunction cc_z( ).
  365.  
  366.  
  367. STRUCTURE STATEMENTS
  368.  
  369. I said earlier that PL/68K has all C's structure statements--if, do, while, 
  370. for, and switch.  They look exactly like C code, but curly braces are 
  371. required surrounding statement lists in structure statements.  In other 
  372. words, structure statements have the form
  373.  
  374.    if(...) {statement list}
  375.    if(...) {statement list} else {statement list}
  376.    while(...) {statement list}
  377.    do {statement list} while(...);
  378.    for(...) {statement list}
  379.    switch(...) {statement list}
  380.  
  381. In my opinion, allowing curly braces to be optional is a big flaw in C.  In 
  382. this example:
  383.  
  384.     if(abc<5)
  385.            xyz=5;
  386.          if(abc<6)
  387.                 xyz=6;
  388.  
  389. the indentation is misleading and will probably cause a bug.  This kind of 
  390. error can be extremely difficult to find.
  391.  
  392. Let's see what code PL/68K's structure statements produce.  In the 
  393. accompanying tables, the dollar sign denotes code that corresponds to 
  394. some language construct.  for example,
  395.  
  396.     $ statement list $
  397.  
  398. stands for whatever code is generated for the statement list.  The statement 
  399. list could be arbitrarily complicated--for instance, it could contain nested 
  400. structure statements.  the notation
  401.  
  402.     $ Evaluate boolean. If false, jump to label1 $
  403.  
  404. indicates that code is generated for the Boolean expression such that a 
  405. jump to label1 is taken if the Boolean expression is false,  Otherwise, 
  406. control falls through to the following code.  Labels are indicated in the 
  407. usual way, by identifiers followed by colons.  All generated labels are, of 
  408. course, unique, even though they may have identical names in the tables.
  409.  
  410. Table 9 shows the if statement.  When an if statement contains no else 
  411. clause, the Boolean expression is evaluated, and control either falls 
  412. through to the then clause or jump is make to the end of the statement.
  413.  
  414. Similar code is generated when the if statement contains an else clause.  
  415. the Boolean expression is evaluated, and control either falls through to the 
  416. then clause or a jump is made to the  else clause.  A BRA (branch always) 
  417. instruction following the then clause skips around the else clause.
  418.  
  419. The code generated for the while statement, shown in Table 10 might be a 
  420. little controversial.  the first instruction is  a branch to the end of the loop 
  421. so that the loop test occurs at the bottom.  This produces the fastest code 
  422. unless the while loop is  executed less than once on average.  In the rare 
  423. cases in which this jump is unwanted, the programmer must simulate the 
  424. loop in some way.
  425.  
  426. Notice the labels called continue_label and break_label.  These are used as 
  427. target labels for the break and continue statements.  In other words, 
  428. within a while, do, or for statement, the effect of a continue instruction is 
  429. to generate a branch to the continue_label defined for that statement.  
  430. Similarly, a break statement generates a jump to the appropriate 
  431. break_label.  As in C, you can also use the break statement inside a 
  432. switch statement.
  433.  
  434. The while statement generates different code if the Boolean expression is 
  435. a nonzero constant.  this is a common idiom in C, and the definition of 
  436. PL/68K ensures that there is no time penalty for using it.
  437.  
  438. The code for the do statement, shown in Table 11 is similar to the code 
  439. produced by the while statement.  The code for the for statement (See 
  440. Table 12) is more interesting.  If the loop test in a for statement is 
  441. nontrivial, the code for it appears at the bottom of the loop.  Note also that 
  442. the syntax of the for statement is more restricted than in C.
  443.  
  444. The switch statement, shown in Table 13 generates a jump table--i.e., a 
  445. table of addresses.  code is generated that jumps through that table to the 
  446. proper case statement, based on the contents of a register.  Note that the 
  447. switch statement destroys this register.
  448.  
  449. It is sometimes better to generate a sequence of tests rather than a table 
  450. jump, but the case statement always generates a table jump.  Remember, 
  451. each language construct in PL/68K stands for a particular sequence of 
  452. code--if you want a sequence of tests, use a sequence of if statements; if 
  453. you want a table jump, use a switch statement.
  454.  
  455. Many compilers generate jumps to jumps when they translate structure 
  456. statement, but the definition of PL/68K requires that all jumps to jumps 
  457. (and jumps to return statements) be eliminated.  The assembler can do this 
  458. in several ways.  For instance, if the assembler creates a parse tree for an 
  459. entire function before any code is generated, it's easy for the code 
  460. generator to look at the target of any jump to see if it is another jump or a 
  461. return instruction.  Alternatively, the assembler can use a standard 
  462. peephole optimizer.
  463.  
  464.  
  465. FUNCTION CALLS
  466.  
  467. Functions in PL/68K can have formal parameters and local arguments, 
  468. just as in C.  The code shown in Table 14 is generated by function calls.  
  469. Code is generated to push all arguments on the stack, a JSR (jump to 
  470. subroutine) instruction is generated to pop arguments off the stack.  One 
  471. long word is always reserved on the stack for the first argument, which 
  472. shortens the calling sequence when there are less than two arguments.
  473.  
  474. The ADD instruction can be eliminated by having the called program, 
  475. instead of the calling program, pop the arguments off the stack, but the 
  476. sequence shown in Table 14 is the fastest.  If you eliminated the ADD 
  477. instruction and pushed the arguments in the same way (that is, above the 
  478. return address), the called program would need to do much more work to 
  479. pop off its arguments.  You could also push the actual arguments below 
  480. the return address, but that way actually increases the length of the calling 
  481. sequence.  In order to push arguments below the return address, you 
  482. would have to use an instruction such as move arg,m(sp), which is 2 
  483. bytes longer than move arg,P(sp).
  484.  
  485. Unlike standard C, PL/68K does specify the order in which arguments 
  486. are pushed, namely in reverse order.  thus, a function that takes a variable 
  487. number of arguments--printf( ) for instance--will find its first argument 
  488. on the top of the stack.
  489.  
  490. Of course, it is often best to pass arguments in registers, but PL/68K 
  491. doesn't need a separate mechanism to do this.  Suppose you have a 
  492. function called g( ) whose two arguments are passed on the stack.  to 
  493. change g( ) so that it will take its arguments in registers, you must define 
  494. the  following macro
  495.  
  496.     #define g(a,b) d0=a; d1=b; g1()
  497.  
  498. and change g's name to g1.  Notice that a statement such as
  499.  
  500.     if(...) g(x,y);
  501.  
  502. cannot cause problems in PL/68K because you must write
  503.  
  504.     if(...) {g(x,y);}
  505.  
  506. instead.  (If braces were omitted, after macro expansion, the code would 
  507. be
  508.  
  509.     if(...)d0=a; d1=b;g1();
  510.  
  511. and only the assignment d0=a would be part of the if statement.)
  512.  
  513. This macro might generate redundant code.  Suppose it were called with 
  514. d0 as the first argument, for instance.  The macro would expand to d0=d0 
  515. and generate the instruction move d0,d0.  to handle that problem, the 
  516. PL/68K assembler eliminates redundant moves.  If you must generate 
  517. such a redundant move for some reason, use a pseudofunction.  
  518. Pseudofunctions are never second-guessed by the assembler.
  519.  
  520.  
  521. ACCESSING VARIABLES WITHIN FUNCTIONS
  522.  
  523. Now that I've covered the passing of arguments to a function,  I'll explain 
  524. how the function gets hold of those arguments.  This is a complicated 
  525. subject, so before getting involved in some messy details, let's handle the 
  526. easy cases.
  527.  
  528. First, PL/68K keeps its hands off all registers declared outside any 
  529. function.  These global registers can be accessed from within functions, 
  530. but PL/68K never generates code to save or restore them.  Consequently, 
  531. you can prevent PL/68K from interfering with any register simply by 
  532. declaring that register outside a function.  By the way, the register 
  533. keyword is not valid outside functions, but that does not prevent you 
  534. from declaring register variables anywhere you wish, either in C or in 
  535. PL/68K.  For instance, you can declare a0 to be global simply by saying 
  536.  
  537.     char *a0;
  538.  
  539. outside any function.
  540.  
  541. Second, except for these global registers, all registers used in a function 
  542. are saved on entry and restored on exit from the function.  the assembler 
  543. uses the MOVEM.L (move multiply register. long) instruction for this 
  544. purpose.  Accessing register variables declared in a function is, of course, 
  545. easy.
  546.  
  547. Third, if a local variable is declared to be static, memory is allocated to 
  548. that variable in static memory, not on the stack.  No extra code is needed 
  549. to access that variable, either on function entry or exit.
  550.  
  551. Static internal variables are not very useful; because the values of static 
  552. internals are retained between invocations of a function, static internals are 
  553. destroyed by recursive function calls.  Also, on many machines 
  554. (including the 68000) accessing a variable in static memory is more 
  555. expensive than accessing a "local auto" variable--that is, a local stack 
  556. variable.  At any rate, generating code for static internal variables is 
  557. straightforward and is not affected by the following complications.
  558.  
  559. Functions need to access two kinds of nonregister variables:  formal 
  560. parameters and local auto variables.  Both types are allocated on the stack.  
  561. You have three choices for how PL/68K generates code for these stack 
  562. variables.  You make your choice using one of three pseudofunctions:  
  563. base(An), base(sp), or nobase( ).  if none of these appears in a function, 
  564. the default is base(sp).
  565.  
  566. First, you can have PL/68K access stack variables via an address register 
  567. that is different from the stack pointer, as shown in Table 15.  If the 
  568. base(An) pseudofunction appears anywhere in the function (where An is 
  569. any address register except the stack pointer, a7), PL/68K generates a 
  570. LINK (link and allocate) instruction on function entry and UNLK  
  571. instruction on function exit.  All stack variables are accessed via the 
  572. address register named in the base(An) pseudofunction.
  573.  
  574. Second, you can have PL/68K access stack variables via the stack 
  575. pointer, as shown in Table 16.  The assembler generates this kind of code 
  576. if the base(a7) or base(sp) pseudofunction appears anywhere in the 
  577. function.  The code generated for sp-based functions is more complicated, 
  578. but more efficient, than that for An-based functions.  If an sp-based 
  579. function contains no function calls, the stack pointer is not incremented on 
  580. function entry and local auto variables are accessed using positive offsets 
  581. from the stack pointer.  If the function does contain other function call, 
  582. however, space is reserved for local auto variables by incrementing the 
  583. stack pointer on function entry, and local auto variables are accessed using 
  584. negative offsets from the stack pointer.
  585.  
  586. Third, you can access stack variables by hand.  If the no_base( ) 
  587. pseudofunction occurs anywhere in the function, no code is generated on 
  588. function entry or exit, declarations of stack variables are ignored, and no 
  589. explicit references to stack variables are permitted.  the no_base( ) 
  590. pseudofunction is useful when you must play some kind of game with the 
  591. stack.
  592.  
  593. Sp-based functions are somewhat dangerous.  If the stack pointer is 
  594. changed using a pseudofunction, the offsets used to access stack variables 
  595. are going to get out of sync.  to handle this problem, several 
  596. pseudofunctions, shown in Table 17 allow you to indicate that the offsets 
  597. should be changed.
  598.  
  599. The push(arg) and pop(arg) pseudofunctions are equivalent to the 
  600. move(arg,*P Psp) and move(*sp++,arg) pseudofunctions, but in 
  601. addition, they tell the PL/68K assembler to adjust the offsets used to 
  602. access stack variables in sp-based functions.  The addsp(n) and subsp(n) 
  603. pseudofunctions are equivalent to the addi(n,sp) and subi(n,sp) 
  604. pseudofunctions, but again they tell the assembler to adjust offsets.  
  605. Finally, the adjsp(n) pseudofunction generates no code but tells the 
  606. assembler to adjust the offsets.  These pseudofunctions have no effect on 
  607. An-based functions.
  608.  
  609.  
  610. SUMMARY
  611.  
  612. To summarize the strengths and weaknesses of PL/68K, the syntactical 
  613. restrictions that make PL/68K a strict subset of C are listed as follows:
  614.  
  615. o All operand/operator combinations correspond to an instruction in the 
  616. 68000 instruction set.
  617.  
  618. o Assignment statements are slightly restricted.
  619.  
  620. o Statement lists must be surrounded by curly brackets.
  621.  
  622. o There are no floating point or double constants or operators.
  623.  
  624. There are no additions or changes to C syntax.  PL/68K and assembly 
  625. language are semantically identical; the advantages of PL/68K over 
  626. assembly language are all syntactical:
  627.  
  628. o C syntax makes programs easier to read.
  629.  
  630. o C syntax eliminates many common coding errors.
  631.  
  632. o Far fewer visible labels are required.
  633.  
  634. PL/68K is not the successor to C nor is it superior to C for most 
  635. programming projects.  The advantages of PL/68K over C apply only in 
  636. limited circumstances, but when performance is paramount, PL/68K 
  637. stands out:
  638.  
  639. o All  machine resources and instructions are available.
  640.  
  641. o Global allocation of registers is possible.
  642.  
  643. o Total control over generated code is possible.
  644.  
  645. o Generated code is smaller and faster.
  646.  
  647. Figure 2 shows the relationship between PL/68K and its two parent 
  648. languages.  PL/68K is only a subset of C; not all of C is included.  On the 
  649. other hand, C must be augmented by the ops library in order to simulate 
  650. all the machine resources of assembly language.
  651.  
  652. Listing One shows an example of a PL/68K function.  This function finds 
  653. a name in a symbol table and returns information about that name in 
  654. registers.  Listing Two shows the code generated by the PL/68K 
  655. assembler for that function.
  656.  
  657.  
  658. CONCLUSION
  659.  
  660. PL/68K started life as a C-like assembly language for the 68000 chip.  
  661. High-level assemblers are not new--a paper by Niklaus Wirth (Journal 
  662. ACM 15, January 1, 1968) described a high-level assembly language for 
  663. IBM 360 machines.
  664.  
  665. My early thinking about PL/68K was influenced by Wirth's paper and by 
  666. the register allocation and code selection principles.  At that stage, I was 
  667. interested in using compiler technology to create better assemblers.  I saw 
  668. no particular reason to make PL/68K a subset of C.
  669.  
  670. I felt dissatisfied with the initial version of PL/68K; it was doomed to be 
  671. "just another computer language."  Not wanting to add another minor 
  672. dialect to the Babel of computer languages, I decided to make PL/68K's 
  673. syntax identical to C's.  This was a lucky decision.
  674.  
  675. From the first, PL/68K had to be able to name all machine resources, 
  676. including machine instructions and assembly-language pseudo-ops.  Early 
  677. versions of the language allowed "raw" lines of assembly code to be 
  678. interspersed with C-like lines of code.  Although this approach had some  
  679. merit, my decision to make PL/68K's syntax compatible with C 
  680. convinced me to use functional notation to represent assembly-language 
  681. features.  This change was also fortunate.
  682.  
  683. I began to speculate about what would happen if a PL/68K program were 
  684. compiled with a C compiler.  I asked myself, suppose the program 
  685. produced by the C compiler and the program produced by the PL/68K 
  686. assembler were semantically equivalent?  Suddenly, PL/68K became not 
  687. just another assembly language but a new way of using C.
  688.  
  689. The principle of semantic equivalence guided a redesign of the language; 
  690. any construct that violated this principle had to go.  In addition, I invented 
  691. the ops library so that C programs could simulate 68000 machine 
  692. instructions.  Along with the ops library, the concept of pseudofunctions 
  693. was born, and the language was complete.
  694.  
  695. PL/68K allows me to sidestep a question that has been haunting me ever 
  696. since I started programming--whether to program in assembly language 
  697. and accept the resulting inconveniences or to program in a high-level 
  698. language and accept a final product that is larger and slower than it could 
  699. be.  PL/68K solves that dilemma.
  700.  
  701. You can design and write a program in C, keeping in mind the possibility 
  702. that you will convert it to PL/68K eventually.  You can write difficult parts 
  703. of the program, or parts of the program, you can produce a PL/68K 
  704. version of the program, if desired, by rewriting or excluding those parts 
  705. of the program that use full C.  You then test the PL/68K version and 
  706. improve its performance as much as you require.
  707.  
  708. PL/68K hits precisely the right level of abstraction for systems 
  709. programming.  All the features of C allow you to design and code 
  710. programs easily, but when you need to do low-level work, nothing stands 
  711. in your way.
  712.  
  713. A final thought--you could transfer most of the syntax and all the design 
  714. rules of PL/68K to a similar language for other machines.  In this limited 
  715. sense, PL/68K is a machine-independent assembly language--PL/68K 
  716. programs are much more portable than programs written in traditional 
  717. assembly language.
  718.