1 ; Opcode table support.
2 ; Copyright (C) 2000, 2005, 2009 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
127 (let ((context (make-prefix-context "syntax computation"))
128 (syntax (if strip-mnemonic?
129 (strip-mnemonic strip-mnem-operands? syntax)
132 (let loop ((syn syntax) (result ""))
134 (cond ((= (string-length syn) 0)
135 (string-append result "0"))
137 ((char=? #\\ (string-ref syn 0))
138 (if (= (string-length syn) 1)
139 (parse-error context "missing char after '\\'" syntax))
140 (let ((escaped-char (string-ref syn 1))
141 (remainder (string-drop 2 syn)))
142 (if (char=? #\\ escaped-char)
143 (loop remainder (string-append result "'\\\\', "))
144 (loop remainder (string-append result "'" (string escaped-char) "', ")))))
146 ((char=? #\$ (string-ref syn 0))
147 ; Extract the symbol from the string, which will be the name of
148 ; an operand. Append it to the result.
149 (if (= (string-length syn) 1)
150 (parse-error context "missing operand name" syntax))
151 ; Is it $foo or ${foo}?
152 (if (char=? (string-ref syn 1) #\{)
153 (let ((n (chars-until-delimiter syn #\})))
154 ; Note that 'n' includes the leading ${.
155 ; FIXME: \} not implemented yet.
157 ((0) (parse-error context "empty operand name" syntax))
158 ((#f) (parse-error context "missing '}'" syntax))
159 (else (loop (string-drop (+ n 1) syn)
160 (string-append result op-macro " ("
163 (substring syn 2 n)))
165 (let ((n (id-len (string-drop1 syn))))
167 (parse-error context "empty or invalid operand name" syntax))
168 (let ((operand (string->symbol (substring syn 1 (1+ n)))))
169 (if (not (current-op-lookup operand isa-name-list))
170 (parse-error context "undefined operand " operand syntax)))
171 (loop (string-drop (1+ n) syn)
172 (string-append result op-macro " ("
175 (substring syn 1 (1+ n))))
178 ; Append the character to the result.
179 (else (loop (string-drop1 syn)
180 (string-append result
181 "'" (string-take1 syn) "', "))))))
184 ; Return C code to define the syntax string for SYNTAX
185 ; MNEM is the C value to use to represent the instruction's mnemonic.
186 ; OP is the C macro to use to compute an operand's syntax value.
187 ; ISA-NAME-LIST is the list of ISA names in which the owning insn lives.
189 (define (gen-syntax-entry mnem op syntax isa-name-list)
193 ; `mnem' is used to represent the mnemonic, so we always want to strip it
194 ; from the syntax string, regardless of the setting of `strip-mnemonic?'.
195 (compute-syntax #t #f syntax op isa-name-list)
199 ; Instruction format table support.
201 ; Return the table for IFMT, an <iformat> object.
203 (define (/gen-ifmt-table-1 ifmt)
205 (ifmt-eg-insn ifmt) ; sanitize based on the example insn
207 "static const CGEN_IFMT " (gen-sym ifmt) " ATTRIBUTE_UNUSED = {\n"
209 (number->string (ifmt-mask-length ifmt)) ", "
210 (number->string (ifmt-length ifmt)) ", "
211 "0x" (number->string (ifmt-mask ifmt) 16) ", "
213 (string-list-map (lambda (ifld)
214 (string-list "{ F (" (ifld-enum ifld #f) ") }, "))
219 ; Generate the insn format table.
221 (define (/gen-ifmt-table)
223 "/* Instruction formats. */\n\n"
224 (gen-define-with-symcat "F(f) & @arch@_cgen_ifld_table[@ARCH@_" "f]")
225 (string-list-map /gen-ifmt-table-1 (current-ifmt-list))
230 ; Parse/insert/extract/print handlers.
231 ; Each handler type is recorded in the assembler/disassembler as an array of
232 ; pointers to functions. The value recorded in the operand table is the index
233 ; into this array. The first element in the array is reserved as index 0 is
234 ; special (the "default").
236 ; The handlers are recorded here as associative lists in case we ever want
237 ; to record more than just the name.
239 ; Adding a new handler involves
240 ; - specifying its name in the .cpu file
241 ; - getting its name appended to these tables
242 ; - writing the C code
244 ; ??? It might be useful to define the handler in Scheme. Later.
246 (define opc-parse-handlers '((insn-normal)))
247 (define opc-insert-handlers '((insn-normal)))
248 (define opc-extract-handlers '((insn-normal)))
249 (define opc-print-handlers '((insn-normal)))
251 ; FIXME: There currently isn't a spot for specifying special handlers for
252 ; each instruction. For now assume we always use the same ones.
254 (define (insn-handlers insn)
256 (number->string (assq-lookup-index 'insn-normal opc-parse-handlers 0))
258 (number->string (assq-lookup-index 'insn-normal opc-insert-handlers 0))
260 (number->string (assq-lookup-index 'insn-normal opc-extract-handlers 0))
262 (number->string (assq-lookup-index 'insn-normal opc-print-handlers 0))
266 ; Return C code to define the cgen_opcode_handler struct for INSN.
267 ; This is intended to be the ultimate escape hatch for the parse/insert/
268 ; extract/print handlers. Each entry is an index into a table of handlers.
269 ; The escape hatch isn't used yet.
271 (define (gen-insn-handlers insn)
279 ; Handler table support.
280 ; There are tables for each of parse/insert/extract/print.
282 ; Return C code to define the handler table for NAME with values VALUES.
284 (define (gen-handler-table name values)
286 "cgen_" name "_fn * const @arch@_cgen_" name "_handlers[] = \n{\n"
287 (string-map (lambda (elm)
288 (string-append " " name "_"
289 (gen-c-symbol (car elm))
296 ; Instruction table support.
298 ; Return a declaration of an enum for all insns.
300 (define (/gen-insn-enum)
301 (logit 2 "Generating instruction enum ...\n")
302 (let ((insns (gen-obj-list-enums (non-multi-insns (current-insn-list)))))
304 (gen-enum-decl 'cgen_insn_type "@arch@ instruction types"
306 (cons '(invalid) insns))
307 "/* Index of `invalid' insn place holder. */\n"
308 "#define CGEN_INSN_INVALID @ARCH@_INSN_INVALID\n\n"
309 "/* Total number of insns in table. */\n"
310 "#define MAX_INSNS ((int) @ARCH@_INSN_"
311 (string-upcase (gen-c-symbol (caar (list-take -1 insns)))) " + 1)\n\n"
316 ; Return a reference to the format table entry of INSN.
318 (define (gen-ifmt-entry insn)
319 (string-append "& " (gen-sym (insn-ifmt insn)))
322 ; Return the definition of an instruction value entry.
324 (define (gen-ivalue-entry insn)
326 "0x" (number->string (insn-value insn) 16)
327 (if #f ; (ifmt-opcodes-beyond-base? (insn-ifmt insn))
329 ; ??? wip: opcode values beyond the base insn
335 ; Generate an insn opcode entry for INSN.
336 ; ALL-ATTRS is a list of all instruction attributes.
337 ; NUM-NON-BOOLS is the number of non-boolean insn attributes.
339 (define (/gen-insn-opcode-entry insn all-attrs num-non-bools)
343 "/* " (insn-syntax insn) " */\n"
345 " " (gen-insn-handlers insn) ",\n"
347 (gen-syntax-entry "MNEM" "OP" (insn-syntax insn) (obj-isa-list insn))
349 ; ??? 'twould save space to put a pointer here and record format separately
350 " " (gen-ifmt-entry insn) ", "
351 ;"0x" (number->string (insn-value insn) 16) ",\n"
352 (gen-ivalue-entry insn) "\n"
356 ; Generate insn table.
358 (define (/gen-insn-opcode-table)
359 (logit 2 "Generating instruction opcode table ...\n")
360 (let* ((all-attrs (current-insn-attr-list))
361 (num-non-bools (attr-count-non-bools all-attrs)))
363 (gen-define-with-symcat "A(a) (1 << CGEN_INSN_" "a)")
364 (gen-define-with-symcat "OPERAND(op) @ARCH@_OPERAND_" "op")
366 #define MNEM CGEN_SYNTAX_MNEMONIC /* syntax value for mnemonic */
367 #define OP(field) CGEN_SYNTAX_MAKE_FIELD (OPERAND (field))
369 /* The instruction table. */
371 static const CGEN_OPCODE @arch@_cgen_insn_opcode_table[MAX_INSNS] =
373 /* Special null first entry.
374 A `num' value of zero is thus invalid.
375 Also, the special `invalid' insn resides here. */
376 { { 0, 0, 0, 0 }, {{0}}, 0, {0}},\n"
379 (string-write-map (lambda (insn)
380 (logit 3 "Generating insn opcode entry for " (obj:name insn) " ...\n")
381 (/gen-insn-opcode-entry insn all-attrs
383 (non-multi-insns (current-insn-list))))
398 ; Return assembly/disassembly hashing support.
400 (define (/gen-hash-fns)
403 #ifndef CGEN_ASM_HASH_P
404 #define CGEN_ASM_HASH_P(insn) 1
407 #ifndef CGEN_DIS_HASH_P
408 #define CGEN_DIS_HASH_P(insn) 1
411 /* Return non-zero if INSN is to be added to the hash table.
412 Targets are free to override CGEN_{ASM,DIS}_HASH_P in the .opc file. */
415 asm_hash_insn_p (insn)
416 const CGEN_INSN *insn ATTRIBUTE_UNUSED;
418 return CGEN_ASM_HASH_P (insn);
422 dis_hash_insn_p (insn)
423 const CGEN_INSN *insn;
425 /* If building the hash table and the NO-DIS attribute is present,
427 if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_NO_DIS))
429 return CGEN_DIS_HASH_P (insn);
432 #ifndef CGEN_ASM_HASH
433 #define CGEN_ASM_HASH_SIZE 127
434 #ifdef CGEN_MNEMONIC_OPERANDS
435 #define CGEN_ASM_HASH(mnem) (*(unsigned char *) (mnem) % CGEN_ASM_HASH_SIZE)
437 #define CGEN_ASM_HASH(mnem) (*(unsigned char *) (mnem) % CGEN_ASM_HASH_SIZE) /*FIXME*/
441 /* It doesn't make much sense to provide a default here,
442 but while this is under development we do.
443 BUFFER is a pointer to the bytes of the insn, target order.
444 VALUE is the first base_insn_bitsize bits as an int in host order. */
446 #ifndef CGEN_DIS_HASH
447 #define CGEN_DIS_HASH_SIZE 256
448 #define CGEN_DIS_HASH(buf, value) (*(unsigned char *) (buf))
451 /* The result is the hash value of the insn.
452 Targets are free to override CGEN_{ASM,DIS}_HASH in the .opc file. */
458 return CGEN_ASM_HASH (mnem);
461 /* BUF is a pointer to the bytes of the insn, target order.
462 VALUE is the first base_insn_bitsize bits as an int in host order. */
465 dis_hash_insn (buf, value)
466 const char * buf ATTRIBUTE_UNUSED;
467 CGEN_INSN_INT value ATTRIBUTE_UNUSED;
469 return CGEN_DIS_HASH (buf, value);
475 ; Hash support decls.
477 (define (/gen-hash-decls)
480 /* The hash functions are recorded here to help keep assembler code out of
481 the disassembler and vice versa. */
483 static int asm_hash_insn_p (const CGEN_INSN *);
484 static unsigned int asm_hash_insn (const char *);
485 static int dis_hash_insn_p (const CGEN_INSN *);
486 static unsigned int dis_hash_insn (const char *, CGEN_INSN_INT);
491 ; Macro insn support.
493 ; Return a macro-insn expansion entry.
495 (define (/gen-miexpn-entry entry)
500 ; Return a macro-insn table entry.
501 ; ??? wip, not currently used.
503 (define (/gen-minsn-table-entry minsn all-attrs num-non-bools)
507 " /* " (minsn-syntax minsn) " */\n"
510 "-1, " ; macro-insns are not currently enumerated, no current need to
511 "\"" (obj:str-name minsn) "\", "
512 "\"" (minsn-mnemonic minsn) "\",\n"
514 (gen-syntax-entry "MNEM" "OP" (minsn-syntax minsn) (obj-isa-list minsn))
516 " (PTR) & macro_" (gen-sym minsn) "_expansions[0],\n"
518 (gen-obj-attr-defn 'minsn minsn all-attrs num-non-bools gen-insn-attr-mask)
523 ; Return a macro-insn opcode table entry.
524 ; ??? wip, not currently used.
526 (define (/gen-minsn-opcode-entry minsn all-attrs num-non-bools)
530 " /* " (minsn-syntax minsn) " */\n"
533 "-1, " ; macro-insns are not currently enumerated, no current need to
534 "\"" (obj:str-name minsn) "\", "
535 "\"" (minsn-mnemonic minsn) "\",\n"
537 (gen-syntax-entry "MNEM" "OP" (minsn-syntax minsn) (obj-isa-list minsn))
539 " (PTR) & macro_" (gen-sym minsn) "_expansions[0],\n"
541 (gen-obj-attr-defn 'minsn minsn all-attrs num-non-bools gen-insn-attr-mask)
546 ; Macro insn expansion has one basic form, but we optimize the common case
547 ; of unconditionally expanding the input text to one instruction.
548 ; The general form is a Scheme expression that is interpreted at runtime to
549 ; decide how to perform the expansion. Yes, that means having a (perhaps
550 ; minimal) Scheme interpreter in the assembler.
551 ; Another thing to do is have a builder for each real insn so instead of
552 ; expanding to text, the macro-expansion could invoke the builder for each
555 (define (/gen-macro-insn-table)
556 (logit 2 "Generating macro-instruction table ...\n")
557 (let* ((minsn-list (map (lambda (minsn)
558 (if (has-attr? minsn 'ALIAS)
559 (minsn-make-alias (make-prefix-context "gen-macro-insn-table")
562 (current-minsn-list)))
563 (all-attrs (current-insn-attr-list))
564 (num-non-bools (attr-count-non-bools all-attrs)))
566 "/* Formats for ALIAS macro-insns. */\n\n"
567 (gen-define-with-symcat "F(f) & @arch@_cgen_ifld_table[@ARCH@_" "f]")
569 (string-write-map /gen-ifmt-table-1
570 (map insn-ifmt (find (lambda (minsn)
571 (has-attr? minsn 'ALIAS))
574 "/* Each non-simple macro entry points to an array of expansion possibilities. */\n\n"
576 (string-write-map (lambda (minsn)
577 (if (has-attr? minsn 'ALIAS)
580 "static const CGEN_MINSN_EXPANSION macro_" (gen-sym minsn) "_expansions[] =\n"
582 (string-map /gen-miexpn-entry
583 (minsn-expansions minsn))
584 " { 0, 0 }\n};\n\n")))
586 (gen-define-with-symcat "A(a) (1 << CGEN_INSN_" "a)")
587 (gen-define-with-symcat "OPERAND(op) @ARCH@_OPERAND_" "op")
589 #define MNEM CGEN_SYNTAX_MNEMONIC /* syntax value for mnemonic */
590 #define OP(field) CGEN_SYNTAX_MAKE_FIELD (OPERAND (field))
592 /* The macro instruction table. */
594 static const CGEN_IBASE @arch@_cgen_macro_insn_table[] =
598 (string-write-map (lambda (minsn)
599 (logit 3 "Generating macro-insn table entry for " (obj:name minsn) " ...\n")
600 ; Simple macro-insns are emitted as aliases of real insns.
601 (if (has-attr? minsn 'ALIAS)
602 (gen-insn-table-entry minsn all-attrs num-non-bools)
603 (/gen-minsn-table-entry minsn all-attrs num-non-bools)))
608 /* The macro instruction opcode table. */
610 static const CGEN_OPCODE @arch@_cgen_macro_insn_opcode_table[] =
613 (string-write-map (lambda (minsn)
614 (logit 3 "Generating macro-insn table entry for " (obj:name minsn) " ...\n")
615 ; Simple macro-insns are emitted as aliases of real insns.
616 (if (has-attr? minsn 'ALIAS)
617 (/gen-insn-opcode-entry minsn all-attrs num-non-bools)
618 (/gen-minsn-opcode-entry minsn all-attrs num-non-bools)))
631 ; Emit a function to call to initialize the opcode table.
633 (define (/gen-opcode-init-fn)
636 /* Set the recorded length of the insn in the CGEN_FIELDS struct. */
639 set_fields_bitsize (CGEN_FIELDS *fields, int size)
641 CGEN_FIELDS_BITSIZE (fields) = size;
644 /* Function to call before using the operand instance table.
645 This plugs the opcode entries and macro instructions into the cpu table. */
648 @arch@_cgen_init_opcode_table (CGEN_CPU_DESC cd)
651 int num_macros = (sizeof (@arch@_cgen_macro_insn_table) /
652 sizeof (@arch@_cgen_macro_insn_table[0]));
653 const CGEN_IBASE *ib = & @arch@_cgen_macro_insn_table[0];
654 const CGEN_OPCODE *oc = & @arch@_cgen_macro_insn_opcode_table[0];
655 CGEN_INSN *insns = xmalloc (num_macros * sizeof (CGEN_INSN));
657 /* This test has been added to avoid a warning generated
658 if memset is called with a third argument of value zero. */
660 memset (insns, 0, num_macros * sizeof (CGEN_INSN));
661 for (i = 0; i < num_macros; ++i)
663 insns[i].base = &ib[i];
664 insns[i].opcode = &oc[i];
665 @arch@_cgen_build_insn_regex (& insns[i]);
667 cd->macro_insn_table.init_entries = insns;
668 cd->macro_insn_table.entry_size = sizeof (CGEN_IBASE);
669 cd->macro_insn_table.num_init_entries = num_macros;
671 oc = & @arch@_cgen_insn_opcode_table[0];
672 insns = (CGEN_INSN *) cd->insn_table.init_entries;
673 for (i = 0; i < MAX_INSNS; ++i)
675 insns[i].opcode = &oc[i];
676 @arch@_cgen_build_insn_regex (& insns[i]);
679 cd->sizeof_fields = sizeof (CGEN_FIELDS);
680 cd->set_fields_bitsize = set_fields_bitsize;
682 cd->asm_hash_p = asm_hash_insn_p;
683 cd->asm_hash = asm_hash_insn;
684 cd->asm_hash_size = CGEN_ASM_HASH_SIZE;
686 cd->dis_hash_p = dis_hash_insn_p;
687 cd->dis_hash = dis_hash_insn;
688 cd->dis_hash_size = CGEN_DIS_HASH_SIZE;
694 ; Top level C code generators
696 ; FIXME: Create enum objects for all the enums we explicitly declare here.
697 ; Then they'd be usable and we wouldn't have to special case them here.
700 (logit 1 "Generating " (current-arch-name) "-opc.h ...\n")
702 (gen-c-copyright "Instruction opcode header for @arch@."
703 CURRENT-COPYRIGHT CURRENT-PACKAGE)
709 (lambda () (gen-extra-opc.h (opc-file-path) (current-arch-name)))
715 #endif /* @ARCH@_OPC_H */
720 ; This file contains the instruction opcode table.
723 (logit 1 "Generating " (current-arch-name) "-opc.c ...\n")
725 (gen-c-copyright "Instruction opcode table for @arch@."
726 CURRENT-COPYRIGHT CURRENT-PACKAGE)
728 #include \"sysdep.h\"
729 #include \"ansidecl.h\"
731 #include \"symcat.h\"
732 #include \"@prefix@-desc.h\"
733 #include \"@prefix@-opc.h\"
734 #include \"libiberty.h\"
736 (lambda () (gen-extra-opc.c (opc-file-path) (current-arch-name)))
739 /gen-insn-opcode-table
740 /gen-macro-insn-table