1 ; Opcode table support.
2 ; Copyright (C) 2000 Red Hat, Inc.
3 ; This file is part of CGEN.
5 ; Append code here to be run before insn parsing/etc.
6 ; These are for internal use and aren't intended to appear in .cpu files.
7 ; ??? Nothing currently uses them but that might change.
9 (define parse-init-code "")
10 (define insert-init-code "")
11 (define extract-init-code "")
12 (define print-init-code "")
14 ; Define CGEN_INIT_{PARSE,INSERT,EXTRACT,PRINT} macros.
15 ; ??? These were early escape hatches. Not currently used.
17 (define (-gen-init-macros)
18 (logit 2 "Generating init macros ...\n")
20 "#define CGEN_INIT_PARSE(od) \\
24 "#define CGEN_INIT_INSERT(od) \\
28 "#define CGEN_INIT_EXTRACT(od) \\
32 "#define CGEN_INIT_PRINT(od) \\
39 ; Instruction field support.
41 ; Return C code to declare various ifield types,decls.
43 (define (-gen-ifield-decls)
44 (logit 2 "Generating instruction field decls ...\n")
46 "/* This struct records data prior to insertion or after extraction. */\n"
47 "struct cgen_fields\n{\n"
48 ; A special member `length' is used to record the length.
50 (string-map gen-ifield-value-decl (non-derived-ifields (current-ifld-list)))
55 ; Instruction syntax support.
57 ; Extract the operand fields in SYNTAX-STRING.
58 ; The result is a list of operand names.
59 ; ??? Not currently used, but keep awhile.
61 (define (extract-syntax-operands syntax)
62 (let loop ((syn syntax) (result nil))
64 (cond ((= (string-length syn) 0)
67 ((char=? #\\ (string-ref syn 0))
68 (if (= (string-length syn) 1)
69 (error "missing char after '\\'" syntax))
70 (loop (string-drop 2 syn) result))
72 ((char=? #\$ (string-ref syn 0))
73 ; Extract the symbol from the string, which will be the name of
74 ; an operand. Append it to the result.
75 (if (= (string-length syn) 1)
76 (error "missing operand name" syntax))
77 (if (char=? (string-ref syn 1) #\{)
78 (let ((n (chars-until-delimiter syn #\})))
79 ; Note that 'n' includes the leading ${.
81 ((0) (error "empty operand name" syntax))
82 ((#f) (error "missing '}'" syntax))
83 (else (loop (string-drop (+ n 1) syn)
84 (cons (string->symbol (substring syn 2 n))
86 (let ((n (id-len (string-drop1 syn))))
88 (error "empty or invalid operand name" syntax))
89 (loop (string-drop (1+ n) syn)
90 (cons (string->symbol (substring syn 1 (1+ n)))
93 (else (loop (string-drop1 syn) result))))
96 ; Strip the mnemonic part from SYNTAX.
97 ; (ie: everything up to but not including the first space or '$')
98 ; If STRIP-MNEM-OPERANDS?, strip them too.
100 (define (strip-mnemonic strip-mnem-operands? syntax)
101 (let ((space (string-index syntax #\space)))
102 (if strip-mnem-operands?
104 (string-drop space syntax)
106 (let loop ((syn syntax))
107 (if (= (string-length syn) 0)
109 (case (string-ref syn 0)
111 ((#\\) (loop (string-drop 2 syn)))
113 (else (loop (string-drop1 syn))))))))
116 ; Compute the sequence of syntax bytes for SYNTAX.
117 ; STRIP-MNEMONIC? is #t if the mnemonic part is to be stripped off.
118 ; STRIP-MNEM-OPERANDS? is #t if any mnemonic operands are to be stripped off.
119 ; SYNTAX is a string of text and operands.
120 ; OP-MACRO is the macro to call that computes an operand's value.
121 ; The resulting syntax is expressed as a sequence of bytes.
122 ; Values < 128 are characters that must be matched.
123 ; Values >= 128 are 128 + the index into the operand table.
125 (define (compute-syntax strip-mnemonic? strip-mnem-operands? syntax op-macro)
126 (let ((context "syntax computation")
127 (syntax (if strip-mnemonic?
128 (strip-mnemonic strip-mnem-operands? syntax)
131 (let loop ((syn syntax) (result ""))
133 (cond ((= (string-length syn) 0)
134 (string-append result "0"))
136 ((char=? #\\ (string-ref syn 0))
137 (if (= (string-length syn) 1)
138 (parse-error context "missing char after '\\'" syntax))
139 (let ((escaped-char (string-ref syn 1))
140 (remainder (string-drop 2 syn)))
141 (if (char=? #\\ escaped-char)
142 (loop remainder (string-append result "'\\\\', "))
143 (loop remainder (string-append result "'" (string escaped-char) "', ")))))
145 ((char=? #\$ (string-ref syn 0))
146 ; Extract the symbol from the string, which will be the name of
147 ; an operand. Append it to the result.
148 (if (= (string-length syn) 1)
149 (parse-error context "missing operand name" syntax))
150 ; Is it $foo or ${foo}?
151 (if (char=? (string-ref syn 1) #\{)
152 (let ((n (chars-until-delimiter syn #\})))
153 ; Note that 'n' includes the leading ${.
154 ; FIXME: \} not implemented yet.
156 ((0) (parse-error context "empty operand name" syntax))
157 ((#f) (parse-error context "missing '}'" syntax))
158 (else (loop (string-drop (+ n 1) syn)
159 (string-append result op-macro " ("
162 (substring syn 2 n)))
164 (let ((n (id-len (string-drop1 syn))))
166 (parse-error context "empty or invalid operand name" syntax))
167 (let ((operand (string->symbol (substring syn 1 (1+ n)))))
168 (if (not (current-op-lookup operand))
169 (parse-error context "undefined operand " operand syntax)))
170 (loop (string-drop (1+ n) syn)
171 (string-append result op-macro " ("
174 (substring syn 1 (1+ n))))
177 ; Append the character to the result.
178 (else (loop (string-drop1 syn)
179 (string-append result
180 "'" (string-take1 syn) "', "))))))
183 ; Return C code to define the syntax string for SYNTAX
184 ; MNEM is the C value to use to represent the instruction's mnemonic.
185 ; OP is the C macro to use to compute an operand's syntax value.
187 (define (gen-syntax-entry mnem op syntax)
191 ; `mnem' is used to represent the mnemonic, so we always want to strip it
192 ; from the syntax string, regardless of the setting of `strip-mnemonic?'.
193 (compute-syntax #t #f syntax op)
197 ; Instruction format table support.
199 ; Return the table for IFMT, an <iformat> object.
201 (define (-gen-ifmt-table-1 ifmt)
203 (ifmt-eg-insn ifmt) ; sanitize based on the example insn
205 "static const CGEN_IFMT " (gen-sym ifmt) " ATTRIBUTE_UNUSED = {\n"
207 (number->string (ifmt-mask-length ifmt)) ", "
208 (number->string (ifmt-length ifmt)) ", "
209 "0x" (number->string (ifmt-mask ifmt) 16) ", "
211 (string-list-map (lambda (ifld)
212 (string-list "{ F (" (ifld-enum ifld #f) ") }, "))
217 ; Generate the insn format table.
219 (define (-gen-ifmt-table)
221 "/* Instruction formats. */\n\n"
222 (gen-define-with-symcat "F(f) & @arch@_cgen_ifld_table[@ARCH@_" "f]")
223 (string-list-map -gen-ifmt-table-1 (current-ifmt-list))
228 ; Parse/insert/extract/print handlers.
229 ; Each handler type is recorded in the assembler/disassembler as an array of
230 ; pointers to functions. The value recorded in the operand table is the index
231 ; into this array. The first element in the array is reserved as index 0 is
232 ; special (the "default").
234 ; The handlers are recorded here as associative lists in case we ever want
235 ; to record more than just the name.
237 ; Adding a new handler involves
238 ; - specifying its name in the .cpu file
239 ; - getting its name appended to these tables
240 ; - writing the C code
242 ; ??? It might be useful to define the handler in Scheme. Later.
244 (define opc-parse-handlers '((insn-normal)))
245 (define opc-insert-handlers '((insn-normal)))
246 (define opc-extract-handlers '((insn-normal)))
247 (define opc-print-handlers '((insn-normal)))
249 ; FIXME: There currently isn't a spot for specifying special handlers for
250 ; each instruction. For now assume we always use the same ones.
252 (define (insn-handlers insn)
254 (number->string (assq-lookup-index 'insn-normal opc-parse-handlers 0))
256 (number->string (assq-lookup-index 'insn-normal opc-insert-handlers 0))
258 (number->string (assq-lookup-index 'insn-normal opc-extract-handlers 0))
260 (number->string (assq-lookup-index 'insn-normal opc-print-handlers 0))
264 ; Return C code to define the cgen_opcode_handler struct for INSN.
265 ; This is intended to be the ultimate escape hatch for the parse/insert/
266 ; extract/print handlers. Each entry is an index into a table of handlers.
267 ; The escape hatch isn't used yet.
269 (define (gen-insn-handlers insn)
277 ; Handler table support.
278 ; There are tables for each of parse/insert/extract/print.
280 ; Return C code to define the handler table for NAME with values VALUES.
282 (define (gen-handler-table name values)
284 "cgen_" name "_fn * const @arch@_cgen_" name "_handlers[] = \n{\n"
285 (string-map (lambda (elm)
286 (string-append " " name "_"
287 (gen-c-symbol (car elm))
294 ; Instruction table support.
296 ; Return a declaration of an enum for all insns.
298 (define (-gen-insn-enum)
299 (logit 2 "Generating instruction enum ...\n")
300 (let ((insns (gen-obj-list-enums (non-multi-insns (current-insn-list)))))
302 (gen-enum-decl 'cgen_insn_type "@arch@ instruction types"
304 (cons '(invalid) insns))
305 "/* Index of `invalid' insn place holder. */\n"
306 "#define CGEN_INSN_INVALID @ARCH@_INSN_INVALID\n\n"
307 "/* Total number of insns in table. */\n"
308 "#define MAX_INSNS ((int) @ARCH@_INSN_"
309 (string-upcase (gen-c-symbol (caar (list-take -1 insns)))) " + 1)\n\n"
314 ; Return a reference to the format table entry of INSN.
316 (define (gen-ifmt-entry insn)
317 (string-append "& " (gen-sym (insn-ifmt insn)))
320 ; Return the definition of an instruction value entry.
322 (define (gen-ivalue-entry insn)
324 "0x" (number->string (insn-value insn) 16)
325 (if #f ; (ifmt-opcodes-beyond-base? (insn-ifmt insn))
327 ; ??? wip: opcode values beyond the base insn
333 ; Generate an insn opcode entry for INSN.
334 ; ALL-ATTRS is a list of all instruction attributes.
335 ; NUM-NON-BOOLS is the number of non-boolean insn attributes.
337 (define (-gen-insn-opcode-entry insn all-attrs num-non-bools)
341 "/* " (insn-syntax insn) " */\n"
343 " " (gen-insn-handlers insn) ",\n"
344 " " (gen-syntax-entry "MNEM" "OP" (insn-syntax insn)) ",\n"
345 ; ??? 'twould save space to put a pointer here and record format separately
346 " " (gen-ifmt-entry insn) ", "
347 ;"0x" (number->string (insn-value insn) 16) ",\n"
348 (gen-ivalue-entry insn) "\n"
352 ; Generate insn table.
354 (define (-gen-insn-opcode-table)
355 (logit 2 "Generating instruction opcode table ...\n")
356 (let* ((all-attrs (current-insn-attr-list))
357 (num-non-bools (attr-count-non-bools all-attrs)))
359 (gen-define-with-symcat "A(a) (1 << CGEN_INSN_" "a)")
360 (gen-define-with-symcat "OPERAND(op) @ARCH@_OPERAND_" "op")
362 #define MNEM CGEN_SYNTAX_MNEMONIC /* syntax value for mnemonic */
363 #define OP(field) CGEN_SYNTAX_MAKE_FIELD (OPERAND (field))
365 /* The instruction table. */
367 static const CGEN_OPCODE @arch@_cgen_insn_opcode_table[MAX_INSNS] =
369 /* Special null first entry.
370 A `num' value of zero is thus invalid.
371 Also, the special `invalid' insn resides here. */
372 { { 0, 0, 0, 0 }, {{0}}, 0, {0}},\n"
375 (string-write-map (lambda (insn)
376 (logit 3 "Generating insn opcode entry for " (obj:name insn) " ...\n")
377 (-gen-insn-opcode-entry insn all-attrs
379 (non-multi-insns (current-insn-list))))
394 ; Return assembly/disassembly hashing support.
396 (define (-gen-hash-fns)
399 #ifndef CGEN_ASM_HASH_P
400 #define CGEN_ASM_HASH_P(insn) 1
403 #ifndef CGEN_DIS_HASH_P
404 #define CGEN_DIS_HASH_P(insn) 1
407 /* Return non-zero if INSN is to be added to the hash table.
408 Targets are free to override CGEN_{ASM,DIS}_HASH_P in the .opc file. */
411 asm_hash_insn_p (insn)
412 const CGEN_INSN *insn ATTRIBUTE_UNUSED;
414 return CGEN_ASM_HASH_P (insn);
418 dis_hash_insn_p (insn)
419 const CGEN_INSN *insn;
421 /* If building the hash table and the NO-DIS attribute is present,
423 if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_NO_DIS))
425 return CGEN_DIS_HASH_P (insn);
428 #ifndef CGEN_ASM_HASH
429 #define CGEN_ASM_HASH_SIZE 127
430 #ifdef CGEN_MNEMONIC_OPERANDS
431 #define CGEN_ASM_HASH(mnem) (*(unsigned char *) (mnem) % CGEN_ASM_HASH_SIZE)
433 #define CGEN_ASM_HASH(mnem) (*(unsigned char *) (mnem) % CGEN_ASM_HASH_SIZE) /*FIXME*/
437 /* It doesn't make much sense to provide a default here,
438 but while this is under development we do.
439 BUFFER is a pointer to the bytes of the insn, target order.
440 VALUE is the first base_insn_bitsize bits as an int in host order. */
442 #ifndef CGEN_DIS_HASH
443 #define CGEN_DIS_HASH_SIZE 256
444 #define CGEN_DIS_HASH(buf, value) (*(unsigned char *) (buf))
447 /* The result is the hash value of the insn.
448 Targets are free to override CGEN_{ASM,DIS}_HASH in the .opc file. */
454 return CGEN_ASM_HASH (mnem);
457 /* BUF is a pointer to the bytes of the insn, target order.
458 VALUE is the first base_insn_bitsize bits as an int in host order. */
461 dis_hash_insn (buf, value)
462 const char * buf ATTRIBUTE_UNUSED;
463 CGEN_INSN_INT value ATTRIBUTE_UNUSED;
465 return CGEN_DIS_HASH (buf, value);
471 ; Hash support decls.
473 (define (-gen-hash-decls)
476 /* The hash functions are recorded here to help keep assembler code out of
477 the disassembler and vice versa. */
479 static int asm_hash_insn_p PARAMS ((const CGEN_INSN *));
480 static unsigned int asm_hash_insn PARAMS ((const char *));
481 static int dis_hash_insn_p PARAMS ((const CGEN_INSN *));
482 static unsigned int dis_hash_insn PARAMS ((const char *, CGEN_INSN_INT));
487 ; Macro insn support.
489 ; Return a macro-insn expansion entry.
491 (define (-gen-miexpn-entry entry)
496 ; Return a macro-insn table entry.
497 ; ??? wip, not currently used.
499 (define (-gen-minsn-table-entry minsn all-attrs num-non-bools)
503 " /* " (minsn-syntax minsn) " */\n"
506 "-1, " ; macro-insns are not currently enumerated, no current need to
507 "\"" (obj:str-name minsn) "\", "
508 "\"" (minsn-mnemonic minsn) "\",\n"
509 " " (gen-syntax-entry "MNEM" "OP" (minsn-syntax minsn)) ",\n"
510 " (PTR) & macro_" (gen-sym minsn) "_expansions[0],\n"
512 (gen-obj-attr-defn 'minsn minsn all-attrs num-non-bools gen-insn-attr-mask)
517 ; Return a macro-insn opcode table entry.
518 ; ??? wip, not currently used.
520 (define (-gen-minsn-opcode-entry minsn all-attrs num-non-bools)
524 " /* " (minsn-syntax minsn) " */\n"
527 "-1, " ; macro-insns are not currently enumerated, no current need to
528 "\"" (obj:str-name minsn) "\", "
529 "\"" (minsn-mnemonic minsn) "\",\n"
530 " " (gen-syntax-entry "MNEM" "OP" (minsn-syntax minsn)) ",\n"
531 " (PTR) & macro_" (gen-sym minsn) "_expansions[0],\n"
533 (gen-obj-attr-defn 'minsn minsn all-attrs num-non-bools gen-insn-attr-mask)
538 ; Macro insn expansion has one basic form, but we optimize the common case
539 ; of unconditionally expanding the input text to one instruction.
540 ; The general form is a Scheme expression that is interpreted at runtime to
541 ; decide how to perform the expansion. Yes, that means having a (perhaps
542 ; minimal) Scheme interpreter in the assembler.
543 ; Another thing to do is have a builder for each real insn so instead of
544 ; expanding to text, the macro-expansion could invoke the builder for each
547 (define (-gen-macro-insn-table)
548 (logit 2 "Generating macro-instruction table ...\n")
549 (let* ((minsn-list (map (lambda (minsn)
550 (if (has-attr? minsn 'ALIAS)
551 (minsn-make-alias "gen-macro-insn-table" minsn)
553 (current-minsn-list)))
554 (all-attrs (current-insn-attr-list))
555 (num-non-bools (attr-count-non-bools all-attrs)))
557 "/* Formats for ALIAS macro-insns. */\n\n"
558 (gen-define-with-symcat "F(f) & @arch@_cgen_ifld_table[@ARCH@_" "f]")
560 (string-write-map -gen-ifmt-table-1
561 (map insn-ifmt (find (lambda (minsn)
562 (has-attr? minsn 'ALIAS))
565 "/* Each non-simple macro entry points to an array of expansion possibilities. */\n\n"
567 (string-write-map (lambda (minsn)
568 (if (has-attr? minsn 'ALIAS)
571 "static const CGEN_MINSN_EXPANSION macro_" (gen-sym minsn) "_expansions[] =\n"
573 (string-map -gen-miexpn-entry
574 (minsn-expansions minsn))
575 " { 0, 0 }\n};\n\n")))
577 (gen-define-with-symcat "A(a) (1 << CGEN_INSN_" "a)")
578 (gen-define-with-symcat "OPERAND(op) @ARCH@_OPERAND_" "op")
580 #define MNEM CGEN_SYNTAX_MNEMONIC /* syntax value for mnemonic */
581 #define OP(field) CGEN_SYNTAX_MAKE_FIELD (OPERAND (field))
583 /* The macro instruction table. */
585 static const CGEN_IBASE @arch@_cgen_macro_insn_table[] =
589 (string-write-map (lambda (minsn)
590 (logit 3 "Generating macro-insn table entry for " (obj:name minsn) " ...\n")
591 ; Simple macro-insns are emitted as aliases of real insns.
592 (if (has-attr? minsn 'ALIAS)
593 (gen-insn-table-entry minsn all-attrs num-non-bools)
594 (-gen-minsn-table-entry minsn all-attrs num-non-bools)))
599 /* The macro instruction opcode table. */
601 static const CGEN_OPCODE @arch@_cgen_macro_insn_opcode_table[] =
604 (string-write-map (lambda (minsn)
605 (logit 3 "Generating macro-insn table entry for " (obj:name minsn) " ...\n")
606 ; Simple macro-insns are emitted as aliases of real insns.
607 (if (has-attr? minsn 'ALIAS)
608 (-gen-insn-opcode-entry minsn all-attrs num-non-bools)
609 (-gen-minsn-opcode-entry minsn all-attrs num-non-bools)))
622 ; Emit a function to call to initialize the opcode table.
624 (define (-gen-opcode-init-fn)
627 static void set_fields_bitsize PARAMS ((CGEN_FIELDS *, int));
629 /* Set the recorded length of the insn in the CGEN_FIELDS struct. */
632 set_fields_bitsize (fields, size)
636 CGEN_FIELDS_BITSIZE (fields) = size;
639 /* Function to call before using the operand instance table.
640 This plugs the opcode entries and macro instructions into the cpu table. */
643 @arch@_cgen_init_opcode_table (cd)
647 int num_macros = (sizeof (@arch@_cgen_macro_insn_table) /
648 sizeof (@arch@_cgen_macro_insn_table[0]));
649 const CGEN_IBASE *ib = & @arch@_cgen_macro_insn_table[0];
650 const CGEN_OPCODE *oc = & @arch@_cgen_macro_insn_opcode_table[0];
651 CGEN_INSN *insns = (CGEN_INSN *) xmalloc (num_macros * sizeof (CGEN_INSN));
652 memset (insns, 0, num_macros * sizeof (CGEN_INSN));
653 for (i = 0; i < num_macros; ++i)
655 insns[i].base = &ib[i];
656 insns[i].opcode = &oc[i];
657 @arch@_cgen_build_insn_regex (& insns[i]);
659 cd->macro_insn_table.init_entries = insns;
660 cd->macro_insn_table.entry_size = sizeof (CGEN_IBASE);
661 cd->macro_insn_table.num_init_entries = num_macros;
663 oc = & @arch@_cgen_insn_opcode_table[0];
664 insns = (CGEN_INSN *) cd->insn_table.init_entries;
665 for (i = 0; i < MAX_INSNS; ++i)
667 insns[i].opcode = &oc[i];
668 @arch@_cgen_build_insn_regex (& insns[i]);
671 cd->sizeof_fields = sizeof (CGEN_FIELDS);
672 cd->set_fields_bitsize = set_fields_bitsize;
674 cd->asm_hash_p = asm_hash_insn_p;
675 cd->asm_hash = asm_hash_insn;
676 cd->asm_hash_size = CGEN_ASM_HASH_SIZE;
678 cd->dis_hash_p = dis_hash_insn_p;
679 cd->dis_hash = dis_hash_insn;
680 cd->dis_hash_size = CGEN_DIS_HASH_SIZE;
686 ; Top level C code generators
688 ; FIXME: Create enum objects for all the enums we explicitly declare here.
689 ; Then they'd be usable and we wouldn't have to special case them here.
692 (logit 1 "Generating " (current-arch-name) "-opc.h ...\n")
694 (gen-c-copyright "Instruction opcode header for @arch@."
695 CURRENT-COPYRIGHT CURRENT-PACKAGE)
701 (lambda () (gen-extra-opc.h (opc-file-path) (current-arch-name)))
707 #endif /* @ARCH@_OPC_H */
712 ; This file contains the instruction opcode table.
715 (logit 1 "Generating " (current-arch-name) "-opc.c ...\n")
717 (gen-c-copyright "Instruction opcode table for @arch@."
718 CURRENT-COPYRIGHT CURRENT-PACKAGE)
720 #include \"sysdep.h\"
721 #include \"ansidecl.h\"
723 #include \"symcat.h\"
724 #include \"@prefix@-desc.h\"
725 #include \"@prefix@-opc.h\"
726 #include \"libiberty.h\"
728 (lambda () (gen-extra-opc.c (opc-file-path) (current-arch-name)))
731 -gen-insn-opcode-table
732 -gen-macro-insn-table