proposal.tr 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. .TL
  2. Code Expander
  3. .br
  4. (proposal)
  5. .SH
  6. Introduction
  7. .LP
  8. The \fBcode expander\fR, \fBce\fR, is a program that translates EM-code to
  9. objectcode. The main goal is to translate very fast. \fBce\fR is an instance
  10. of the EM_CODE(3L)-interface. During execution of \fBce\fR, \fBce\fR will build
  11. in core a machine independent objectfile ( NEW A.OUT(5L)). With \fBcv\fR or
  12. with routines supplied by the user the machine independent objectcode will
  13. be converted to a machine dependent object code. \fBce\fR needs
  14. information about the targetmachine (e.g. the opcode's). We divide the
  15. information into two parts:
  16. .IP
  17. - The description in assembly instructions of EM-code instructions.
  18. .IP
  19. - The description in objectcode of assembly instructions.
  20. .LP
  21. With these two tables we can make a \fBcode expander generator\fR which
  22. generates a \fBce\fR. It is possible to put the information in one table
  23. but that will probably introduce (propable) more bugs in the table. So we
  24. divide and conquer. With this approach it is also possible to generate
  25. assembly code ( rather yhan objectcode), wich is useful for debugging.
  26. There is of course a link between the two tables, the link
  27. consist of a restriction on the assembly format. Every assembly
  28. instruction must have the following format:
  29. .sp
  30. INSTR ::= LABEL : MNEMONIC [ OPERAND ( "," OPERAND)* ]
  31. .sp
  32. .LP
  33. \fBCeg\fR uses the following algorithm:
  34. .IP \0\0a)
  35. The assembly table will be converted to a (C-)routine assemble().
  36. assemble() gets as argument a string, the assembler instruction,
  37. and can use the MNEMONIC to execute the corresponding action in the
  38. assembly table.
  39. .IP \0\0b)
  40. The routine assemble() can now be used to convert the EM-code table to
  41. a set of C-routines, wich together form an instance of the
  42. EM_CODE(3L).
  43. .SH
  44. The EM-instruction table
  45. .LP
  46. We use the following grammar:
  47. .sp
  48. .TS
  49. center box ;
  50. l.
  51. TABLE ::= (ROW)*
  52. ROW ::= C_instr ( SPECIAL | SIMPLE)
  53. SPECIAL ::= ( CONDITION SIMPLE)+ 'default' SIMPLE
  54. SIMPLE ::= '==>' ACTIONLIST | '::=' ACTIONLIST
  55. ACTIONLIST ::= [ ACTION ( ';' ACTION)* ] '.'
  56. ACTION ::= function-call | assembly-instruction
  57. .TE
  58. .LP
  59. An example for the 8086:
  60. .LP
  61. .DS
  62. C_lxl
  63. $arg1 == 0 ==> "push bp".
  64. $arg1 == 1 ==> "push EM_BSIZE(bp)".
  65. default ==> "mov cx, $arg1";
  66. "mov si, bp";
  67. "1: mov si, EM_BSIZE(si);
  68. "loop 1b"
  69. "push si".
  70. .DE
  71. .sp
  72. Some remarks:
  73. .sp
  74. * The C_instr is a function indentifier in the EM_CODE(3L)-interface.
  75. .LP
  76. * CONDITION is a "boolean" C-expression.
  77. .LP
  78. * The arguments of an EM-instruction can be used in CONDITION and in assembly
  79. instructions. They are referred by $arg\fIi\fR. \fBceg\fR modifies the
  80. arguments as follows:
  81. .IP \0\0-
  82. For local variables at positive offsets it increases this offset by EM_BSIZE
  83. .IP \0\0-
  84. It makes names en labels unique. The user must supply the formats (see mach.h).
  85. .LP
  86. * function-call is allowed to implement e.g. push/pop optimization.
  87. For example:
  88. .LP
  89. .DS
  90. C_adi
  91. $arg1 == 2 ==> combine( "pop ax");
  92. combine( "pop bx");
  93. "add ax, bx";
  94. save( "push ax").
  95. default ==> arg_error( "C_adi", $arg1).
  96. .DE
  97. .LP
  98. * The C-functions called in the EM-instructions table have to use the routine
  99. assemble()/gen?(). "assembler-instr" is in fact assemble( "assembler-instr").
  100. .LP
  101. * \fBceg\fR takes care not only about the conversions of arguments but also
  102. about
  103. changes between segments. There are situation when one doesn't want
  104. conversion of arguments. This can be done by using ::= in stead of ==>.
  105. This is usefull when two C_instr are equivalent. For example:
  106. .IP
  107. C_slu ::= C_sli( $arg1)
  108. .LP
  109. * There are EM-CODE instructions wich are machine independent (e.g. C_open()).
  110. For these EM_CODE instructions \fBceg\fR will generate \fIdefault\fR-
  111. instructions. There is one exception: in the case of C_pro() the tablewriter
  112. has to supply a function prolog().
  113. .LP
  114. * Also the EM-pseudoinstructions C_bss_\fIcstp\fR(), C_hol_\fIcstp\fR(),
  115. C_con_\fIcstp\fR() and C_rom_\fIcstp\fR can be translated automaticly.
  116. \fBceg\fR only has to know how to interpretate string-constants:
  117. .DS
  118. \&..icon $arg2 == 1 ==> gen1( (char) atoi( $arg1))
  119. $arg2 == 2 ==> gen2( atoi( $arg1))
  120. $arg2 == 4 ==> gen4( atol( $arg1))
  121. \&..ucon $arg2 == 1 ==> gen1( (char) atoi( $arg1))
  122. $arg2 == 2 ==> gen2( atoi( $arg1))
  123. $arg2 == 4 ==> gen4( atol( $arg1))
  124. \&..fcon ::= not_implemented( "..fcon")
  125. .DE
  126. .LP
  127. * Still, life can be made easier for the tablewriter; For the routines wich
  128. he/she didn't implement \fBceg\fR will generate a default instruction wich
  129. generates an error-message. \fBceg\fR seems to generate :
  130. .IP
  131. C_xxx ::= not_implemented( "C_xxx")
  132. .SH
  133. The assembly table
  134. .LP
  135. How to map assembly on objectcode.
  136. .LP
  137. Each row in the table consists of two fields, one field for the assembly
  138. instruction, the other field for the corresponding objectcode. The tablewriter
  139. can use the following primitives to generate code for the machine
  140. instructions :
  141. .IP "\0\0gen1( b)\0\0:" 17
  142. generates one byte in de machine independent objectfile.
  143. .IP "\0\0gen2( w)\0\0:" 17
  144. generates one word ( = two bytes), the table writer can change the byte
  145. order by setting the flag BYTES_REVERSED.
  146. .IP "\0\0gen4( l)\0\0:" 17
  147. generates two words ( = four bytes), the table writer can change the word
  148. order by setting the flag WORDS_REVERSED.
  149. .IP "\0\0reloc( n, o, r)\0\0:" 17
  150. generates relocation information for a label ( = name + offset +
  151. relocationtype).
  152. .LP
  153. Besides these primitives the table writer may use his self written
  154. C-functions. This allows the table writer e.g. to write functions to set
  155. bitfields within a byte.
  156. .LP
  157. There are more or less two methods to encode the assembly instructions:
  158. .IP \0\0a)
  159. MNEMONIC and OPERAND('s) are encoded independently of each other. This can be
  160. done when the target machine has an orthogonal instruction set (e.g. pdp-11).
  161. .IP \0\0b)
  162. MNEMONIC and OPERAND('s) together determine the opcode. In this case the
  163. assembler often uses overloading: one MNEMONIC is used for several
  164. different machine-instructions. For example : (8086)
  165. .br
  166. mov ax, bx
  167. .br
  168. mov ax, variable
  169. .br
  170. These instructions have different opcodes.
  171. .LP
  172. As the transformation MNEMONIC-OPCODE is not one to
  173. one the table writer must be allowed to put restrictions on the operands.
  174. This can be done with type declarations. For example:
  175. .LP
  176. .DS
  177. mov dst:REG, src:MEM ==>
  178. gen1( 0x8b);
  179. modRM( op2.reg, op1);
  180. .DE
  181. .DS
  182. mov dst:REG, src:REG ==>
  183. gen1( 0x89);
  184. modRM( op2.reg, op1);
  185. .DE
  186. .LP
  187. modRM() is a function written by the tablewriter and is used to encode
  188. the operands. This frees the table writer of endless typing.
  189. .LP
  190. The table writer has to do the "typechecking" by himself. But typechecking
  191. is almost the same as operand decoding. So it's more efficient to do this
  192. in one function. We now have all the tools to describe the function
  193. assemble().
  194. .IP
  195. assemble() first calls the function
  196. decode_operand() ( by the table writer written), with two arguments: a
  197. string ( the operand) and a
  198. pointer to a struct. The struct is declared by the table writer and must
  199. consist of at least a field called type. ( the other fields in the struct can
  200. be used to remember information about the decoded operand.) Now assemble()
  201. fires a row wich is selected by mapping the MNEMONIC and the type of the
  202. operands.
  203. .br
  204. In the second field of a row there may be references to other
  205. fields in the struct (e.g. op2.reg in the example above).
  206. .LP
  207. We ignored one problem. It's possible when the operands are encoded, that
  208. not everything is known. For example $arg\fIi\fR arguments in the
  209. EM-instruction table get their value at runtime. This problem is solved by
  210. introducing a function eval(). eval() has a string as argument and returns
  211. an arith. The string consists of constants and/or $arg\fIi\fR's and the value
  212. returned by eval() is the value of the string. To encode the $arg\fIi\fR's
  213. in as few bytes as possible the table writer can use the statements %if,
  214. %else and %endif. They can be used in the same manner as #if, #else and
  215. #endif in C and result in a runtime test. An example :
  216. .LP
  217. .DS
  218. -- Some rows of the assembly table
  219. mov dst:REG, src:DATA ==>
  220. %if sfit( eval( src), 8) /* does the immediate-data fit in 1 byte? */
  221. R53( 0x16 , op1.reg);
  222. gen1( eval( src));
  223. %else
  224. R53( 0x17 , op1.reg);
  225. gen2( eval( src));
  226. %endif
  227. .LD
  228. mov dst:REG, src:REG ==>
  229. gen1( 0x8b);
  230. modRM( op1.reg, op2);
  231. .DE
  232. .DS
  233. -- The corresponding part in the function assemble() :
  234. case MNEM_mov :
  235. decode_operand( arg1, &op1);
  236. decode_operand( arg2, &op2);
  237. if ( REG( op1.type) && DATA( op2.type)) {
  238. printf( "if ( sfit( %s, 8)) {\\\\n", eval( src));
  239. R53( 0x16 , op1.reg);
  240. printf( "gen1( %s)\\\\n", eval( arg2));
  241. printf( "}\\\\nelse {\\\\n");
  242. R53( 0x17 , op1.reg);
  243. printf( "gen2( %s)\\\\n", eval( arg2));
  244. printf( "}\\\\n");
  245. }
  246. else if ( REG( op1.type) && REG( op2.type)) {
  247. gen1( 0x8b);
  248. modRM( op1.reg, op2);
  249. }
  250. .DE
  251. .DS
  252. -- Some rows of the right part of the EM-instruction table are translated
  253. -- in the following C-functions.
  254. "mov ax, $arg1" ==>
  255. if ( sfit( w, 8)) { /* w is the actual argument of C_xxx( w) */
  256. gen1( 176); /* R53() */
  257. gen1( w);
  258. }
  259. else {
  260. gen1( 184);
  261. gen2( w);
  262. }
  263. .LD
  264. "mov ax, bx" ==>
  265. gen1( 138);
  266. gen1( 99); /* modRM() */
  267. .DE
  268. .SH
  269. Restrictions
  270. .LP
  271. .IP \0\01)
  272. The EM-instructions C_exc() is not implemented.
  273. .IP \0\03)
  274. All messages are ignored.