1 ; Generic simulator application utilities.
2 ; Copyright (C) 2000 Red Hat, Inc.
3 ; This file is part of CGEN.
4 ; See file COPYING.CGEN for details.
6 ; The cache-addr? method.
7 ; Return #t if the hardware element's address is stored in the scache buffer.
8 ; This saves doing the index calculation during semantic processing.
11 <hardware-base> 'cache-addr?
14 (has-attr? self 'CACHE-ADDR)))
17 (define (hw-cache-addr? hw) (send hw 'cache-addr?))
19 ; The needed-iflds method.
20 ; Return list of ifields needed during semantic execution by hardware element
21 ; SELF referenced by <operand> OP in <sformat> SFMT.
24 <hardware-base> 'needed-iflds
25 (lambda (self op sfmt)
26 (list (op-ifield op)))
30 <hw-register> 'needed-iflds
31 (lambda (self op sfmt)
32 (list (op-ifield op)))
33 ; Instead of the following, we now arrange to store the ifield in the
34 ; argbuf, even for CACHE-ADDR operands. This way, the ifield values
35 ; (register numbers, etc.) remain available during semantics tracing.
36 ; (if (hw-cache-addr? self)
38 ; (list (op-ifield op))))
41 ; For addresses this is none because we make our own copy of the ifield
42 ; [because we want to use a special type].
45 <hw-address> 'needed-iflds
46 (lambda (self op sfmt)
50 (define (hw-needed-iflds hw op sfmt) (send hw 'needed-iflds op sfmt))
52 ; Return a list of ifields of <operand> OP that must be recorded in ARGBUF
54 ; ??? At the moment there can only be at most one, but callers must not
57 (define (op-needed-iflds op sfmt)
58 (let ((indx (op:index op)))
59 (logit 4 "op-needed-iflds op=" (obj:name op) " indx=" (obj:name indx)
60 " indx-type=" (hw-index:type indx) " sfmt=" (obj:name sfmt) "\n")
63 (eq? (hw-index:type indx) 'ifield)
64 (not (= (ifld-length (hw-index:value indx)) 0)))
65 (hw-needed-iflds (op:type op) op sfmt))
66 ((eq? (hw-index:type indx) 'derived-ifield)
67 (ifld-needed-iflds indx))
71 ; Operand extraction (ARGBUF) support code.
73 ; Any operand that uses a non-empty ifield needs extraction support.
74 ; Normally we just record the ifield's value. However, in cases where
75 ; hardware elements have CACHE-ADDR specified or where the mode of the
76 ; hardware index isn't compatible with the mode of the decoded ifield
77 ; (this can happen for pc-relative instruction address), we need to record
80 ; Return a boolean indicating if <operand> OP needs any extraction processing.
82 (define (op-extract? op)
83 (let* ((indx (op:index op))
85 (if (derived-operand? op)
86 (any-true? (map op-extract? (derived-args op)))
87 (and (eq? (hw-index:type indx) 'ifield)
88 (not (= (ifld-length (hw-index:value indx)) 0))))))
89 (logit 4 "op-extract? op=" (obj:name op) " =>" extract? "\n")
93 ; Return a list of operands that need special extraction processing.
94 ; SFMT is an <sformat> object.
96 (define (sfmt-extracted-operands sfmt)
97 (let ((in-ops (sfmt-in-ops sfmt))
98 (out-ops (sfmt-out-ops sfmt)))
99 (let ((ops (append (find op-extract? in-ops)
100 (find op-extract? out-ops))))
104 ; Return a list of ifields that are needed by the semantic code.
105 ; SFMT is an <sformat> object.
106 ; ??? This redoes a lot of the calculation that sfmt-extracted-operands does.
108 (define (sfmt-needed-iflds sfmt)
109 (let ((in-ops (sfmt-in-ops sfmt))
110 (out-ops (sfmt-out-ops sfmt)))
111 (let ((ops (append (find op-extract? in-ops)
112 (find op-extract? out-ops))))
113 (nub (apply append (map (lambda (op)
114 (op-needed-iflds op sfmt))
119 ; Sformat argument buffer.
121 ; This contains the details needed to create an argument buffer `fields' union
122 ; entry for the containing sformats.
124 (define <sformat-argbuf>
125 (class-make '<sformat-argbuf>
128 ; - NAME is derived from one of the containing sformats.
130 ; List of structure elements.
131 ; Each element is ("var name" "C type" bitsize).
132 ; The list is sorted by decreasing size, then C type,
139 (define-getters <sformat-argbuf> sbuf (sfmts elms))
141 ; Subroutine of -sfmt-contents to return an ifield element.
142 ; The result is ("var-name" "C-type" bitsize).
144 (define (-sfmt-ifld-elm f sfmt)
145 (let ((real-mode (mode-real-mode (ifld-decode-mode f))))
147 (mode:c-type real-mode)
148 (mode:bits real-mode)))
152 ; The result is ("var-name" "C-type" approx-bitsize) or #f if unneeded.
153 ; For the default case we use the ifield as is, which is computed elsewhere.
156 <hardware-base> 'sbuf-elm
157 (lambda (self op ifmt)
162 <hw-register> 'sbuf-elm
163 (lambda (self op ifmt)
164 (if (hw-cache-addr? self)
165 (list (gen-sym (op:index op))
166 (string-append (gen-type self) "*")
167 ; Use 64 bits for size. Doesn't really matter, just put them
173 ; We want to use ADDR/IADDR in ARGBUF for addresses
176 <hw-address> 'sbuf-elm
177 (lambda (self op ifmt)
178 (list (gen-sym (op:index op))
180 ; Use 64 bits for size. Doesn't really matter, just put them
186 <hw-iaddress> 'sbuf-elm
187 (lambda (self op ifmt)
188 (list (gen-sym (op:index op))
190 ; Use 64 bits for size. Doesn't really matter, just put them
195 ; Subroutine of -sfmt-contents to return an operand element.
196 ; These are in addition (or instead of) the actual ifields.
197 ; This is also used to compute definitions of local vars needed in the
199 ; The result is ("var-name" "C-type" approx-bitsize) or #f if unneeded.
201 (define (sfmt-op-sbuf-elm op sfmt)
202 (send (op:type op) 'sbuf-elm op sfmt)
205 ; Subroutine of compute-sformat-bufs! to compute list of structure elements
206 ; needed by <sformat> SFMT.
208 ; (SFMT ("var-name1" "C-type1" size1) ("var-name2" "C-type2" size2) ...)
209 ; and is sorted by decreasing size, then C type, then variable name
210 ; (as <sformat-argbuf> wants it).
212 (define (-sfmt-contents sfmt)
213 (let ((needed-iflds (sfmt-needed-iflds sfmt))
214 (extracted-ops (sfmt-extracted-operands sfmt))
215 (in-ops (sfmt-in-ops sfmt))
216 (out-ops (sfmt-out-ops sfmt))
217 (sort-elms (lambda (a b)
218 ; Sort by descending size, then ascending C type name,
219 ; then ascending name.
220 (cond ((> (caddr a) (caddr b))
222 ((= (caddr a) (caddr b))
223 (cond ((string<? (cadr a) (cadr b))
225 ((string=? (cadr a) (cadr b))
226 (string<? (car a) (car b)))
233 "-sfmt-contents sfmt=" (obj:name sfmt)
234 " needed-iflds=" (string-map obj:str-name needed-iflds)
235 " extracted-ops=" (string-map obj:str-name extracted-ops)
236 " in-ops=" (string-map obj:str-name in-ops)
237 " out-ops=" (string-map obj:str-name out-ops)
241 ; Compute list of all things we need to record at extraction time.
243 ; Discard #f entries, they indicate "unneeded".
247 (-sfmt-ifld-elm f sfmt))
250 (sfmt-op-sbuf-elm op sfmt))
252 (cond ((with-any-profile?)
254 ; Profiling support. ??? This stuff is in flux.
256 (sfmt-op-profile-elm op sfmt #f))
257 (find op-profilable? in-ops))
259 (sfmt-op-profile-elm op sfmt #t))
260 (find op-profilable? out-ops))))
266 ; Return #t if ELM-LIST is a subset of SBUF.
267 ; SBUF is an <sformat-argbuf> object.
269 (define (-sbuf-subset? elm-list sbuf)
270 ; We take advantage of the fact that elements in each are already sorted.
271 ; FIXME: Can speed up.
272 (let loop ((elm-list elm-list) (sbuf-elm-list (sbuf-elms sbuf)))
273 (cond ((null? elm-list)
275 ((null? sbuf-elm-list)
277 ((equal? (car elm-list) (car sbuf-elm-list))
278 (loop (cdr elm-list) (cdr sbuf-elm-list)))
280 (loop elm-list (cdr sbuf-elm-list)))))
283 ; Subroutine of compute-sformat-bufs!.
284 ; Lookup ELM-LIST in SBUF-LIST. A match is found if ELM-LIST
285 ; is a subset of one in SBUF-LIST.
286 ; Return the containing <sformat-argbuf> object if found, otherwise return #f.
287 ; SBUF-LIST is a list of <sformat-argbuf> objects.
288 ; ELM-LIST is (elm1 elm2 ...).
290 (define (-sbuf-lookup elm-list sbuf-list)
291 (let loop ((sbuf-list sbuf-list))
292 (cond ((null? sbuf-list)
294 ((-sbuf-subset? elm-list (car sbuf-list))
297 (loop (cdr sbuf-list)))))
300 ; Compute and record the set of <sformat-argbuf> objects needed for SFMT-LIST,
301 ; a list of all sformats.
302 ; The result is the computed list of <sformat-argbuf> objects.
304 ; This is used to further reduce the number of entries in the argument buffer's
305 ; `fields' union. Some sformats have structs with the same contents or one is
306 ; a subset of another's, thus there is no need to distinguish them as far as
307 ; the struct is concerned (there may be other reasons to distinguish them of
309 ; The consequence of this is fewer semantic fragments created in with-sem-frags
312 (define (compute-sformat-argbufs! sfmt-list)
313 (logit 1 "Computing sformat argument buffers ...\n")
316 ; Sort by descending length. This helps building the result: while
317 ; iterating over each element, its sbuf is either a subset of a
318 ; previous entry or requires a new entry.
319 (sort (map -sfmt-contents sfmt-list)
321 (> (length a) (length b)))))
322 ; Build an <sformat-argbuf> object.
323 (build-sbuf (lambda (sfmt-data)
324 (make <sformat-argbuf>
325 (obj:name (car sfmt-data))
330 ; Start off with the first sfmt.
331 ; Also build an empty sbuf. Which sbuf to use for an empty argument list
332 ; is rather arbitrary. Rather than pick one, keep the empty sbuf unto
334 (let ((nub-sbufs (list (build-sbuf (car sfmt-contents))))
335 (empty-sbuf (make <sformat-argbuf>
336 'fmt-empty "no operands" atlist-empty
339 (sfmt-set-sbuf! (caar sfmt-contents) (car nub-sbufs))
341 ; Now loop over the remaining sfmts.
342 (let loop ((sfmt-contents (cdr sfmt-contents)))
343 (if (not (null? sfmt-contents))
344 (let ((sfmt-data (car sfmt-contents)))
345 (if (null? (cdr sfmt-data))
346 (sfmt-set-sbuf! (car sfmt-data) empty-sbuf)
347 (let ((sbuf (-sbuf-lookup (cdr sfmt-data) nub-sbufs)))
350 (set! sbuf (build-sbuf sfmt-data))
351 (set! nub-sbufs (cons sbuf nub-sbufs))))
352 (sfmt-set-sbuf! (car sfmt-data) sbuf)))
353 (loop (cdr sfmt-contents)))))
356 ; Note that the result will be sorted by ascending number of elements
357 ; (because the search list was sorted by descending length and the result
358 ; is built up in reverse order of that).
359 ; Not that it matters, but that's kinda nice.
360 (cons empty-sbuf nub-sbufs)))
365 ; By default hardware elements are not profilable.
367 (method-make! <hardware-base> 'profilable? (lambda (self) #f))
370 <hw-register> 'profilable?
371 (lambda (self) (has-attr? self 'PROFILE))
374 ; Return boolean indicating if HW is profilable.
376 (define (hw-profilable? hw) (send hw 'profilable?))
378 ; Return a boolean indicating if OP is profilable.
380 (define (op-profilable? op)
381 (hw-profilable? (op:type op))
384 ; sbuf-profile-data method.
385 ; Return a list of C type and size to use in an sformat's argument buffer.
388 <hardware-base> 'sbuf-profile-data
390 (error "sbuf-profile-elm not supported for this hw type"))
394 <hw-register> 'sbuf-profile-data
396 ; Don't unnecessarily bloat size of argument buffer.
397 (if (<= (hw-num-elms self) 255)
398 (list "unsigned char" 8)
399 (list "unsigned short" 16)))
402 ; Utility to return name of variable/structure-member to use to record
403 ; profiling data for SYM.
405 (define (gen-profile-sym sym out?)
406 (string-append (if out? "out_" "in_")
407 (if (symbol? sym) (symbol->string sym) sym))
410 ; Return name of variable/structure-member to use to record data needed for
411 ; profiling operand SELF.
414 <operand> 'sbuf-profile-sym
416 (gen-profile-sym (gen-sym self) out?))
419 ; sbuf-profile-elm method.
420 ; Return the ARGBUF member needed for profiling SELF in <sformat> SFMT.
421 ; The result is (var-name "C-type" approx-bitsize) or #f if unneeded.
424 <operand> 'sbuf-profile-elm
425 (lambda (self sfmt out?)
426 (if (hw-scalar? (op:type self))
428 (cons (send self 'sbuf-profile-sym out?)
429 (send (op:type self) 'sbuf-profile-data))))
432 ; Subroutine of -sfmt-contents to return an operand's profile element.
433 ; The result is (var-name "C-type" approx-bitsize) or #f if unneeded.
435 (define (sfmt-op-profile-elm op sfmt out?)
436 (send op 'sbuf-profile-elm sfmt out?)
439 ; ARGBUF accessor support.
441 ; Define and undefine C macros to tuck away details of instruction format used
442 ; in the extraction and semantic code. Instruction format names can
443 ; change frequently and this can result in unnecessarily large diffs from one
444 ; generated version of the file to the next. Secondly, tucking away details of
445 ; the extracted argument structure from the extraction code is a good thing.
447 ; Name of macro to access fields in ARGBUF.
448 (define c-argbuf-macro "FLD")
450 ; NB: If sfmt is #f, then define the macro to pass through the argument
451 ; symbol. This is appropriate for "simple" (non-scache) simulators
452 ; that have no abuf/scache in the sem.c routines, but rather plain
454 (define (gen-define-argbuf-macro sfmt)
455 (string-append "#define " c-argbuf-macro "(f) "
459 (gen-sym (sfmt-sbuf sfmt))
464 (define (gen-undef-argbuf-macro sfmt)
465 (string-append "#undef " c-argbuf-macro "\n")
468 ; For old code. Delete in time.
469 (define gen-define-field-macro gen-define-argbuf-macro)
470 (define gen-undef-field-macro gen-undef-argbuf-macro)
472 ; Return a C reference to an ARGBUF field value.
474 (define (gen-argbuf-ref name)
475 (string-append c-argbuf-macro " (" name ")")
478 ; Return name of ARGBUF member for extracted <field> F.
480 (define (gen-ifld-argbuf-name f)
484 ; Return the C reference to a cached ifield.
486 (define (gen-ifld-argbuf-ref f)
487 (gen-argbuf-ref (gen-ifld-argbuf-name f))
490 ; Return name of ARGBUF member holding processed from of extracted
491 ; ifield value for <hw-index> index.
493 (define (gen-hw-index-argbuf-name index)
497 ; Return C reference to a processed <hw-index> in ARGBUF.
499 (define (gen-hw-index-argbuf-ref index)
500 (gen-argbuf-ref (gen-hw-index-argbuf-name index))
505 ; Main procedure call tree:
506 ; cgen-decode.{c,cxx}
508 ; gen-decoder [our entry point]
510 ; -gen-decoder-switch
511 ; -gen-decoder-switch
513 ; decode-build-table is called to construct a tree of "table-guts" elements
514 ; (??? Need better name obviously),
515 ; and then gen-decoder is recursively called on each of these elements.
517 ; Return C/C++ code that fetches the desired decode bits from C value VAL.
518 ; SIZE is the size in bits of val (the MSB is 1 << (size - 1)) which we
520 ; BITNUMS must be monotonically increasing.
521 ; LSB0? is non-#f if bit number 0 is the least significant bit.
522 ; FIXME: START may not be handled right in words beyond first.
524 ; e.g. (-gen-decode-bits '(0 1 2 3 8 9 10 11) 0 16 "insn" #f)
525 ; --> "(((insn >> 8) & 0xf0) | ((insn >> 4) & 0xf))"
526 ; FIXME: The generated code has some inefficiencies in edge cases. Later.
528 (define (-gen-decode-bits bitnums start size val lsb0?)
530 ; Compute a list of lists of three numbers:
531 ; (first bitnum in group, position in result (0=LSB), bits in result)
534 ; POS = starting bit position of current group.
535 ; COUNT = number of bits in group.
536 ; Work from least to most significant bit so reverse bitnums.
537 (let loop ((result nil) (pos 0) (count 0) (bitnums (reverse bitnums)))
538 ;(display (list result pos count bitnums)) (newline)
541 (if (or (= (length bitnums) 1)
542 ; Are numbers not next to each other?
543 (not (= (- (car bitnums) (if lsb0? -1 1))
545 (loop (cons (list (car bitnums) pos (+ 1 count))
553 ; While we could just always emit "(0" to handle the case of an empty set,
554 ; keeping the code more readable for the normal case is important.
555 (if (< (length groups) 1)
561 (let* ((first (car group))
564 ; Difference between where value is and where
566 ; FIXME: Need to handle left (-ve) shift.
569 (- (+ start size) (+ first bits)))
572 " | ((" val " >> " (number->string shift)
574 (number->string (- (integer-expt 2 bits) 1))
575 " << " (number->string pos) "))")))
580 ; Convert decoder table into C code.
582 ; Return code for one insn entry.
583 ; REST is the remaining entries.
585 (define (-gen-decode-insn-entry entry rest indent fn?)
586 (assert (eq? 'insn (dtable-entry-type entry)))
587 (logit 3 "Generating decode insn entry for " (obj:name (dtable-entry-value entry)) " ...\n")
589 (let* ((insn (dtable-entry-value entry))
590 (fmt-name (gen-sym (insn-sfmt insn))))
594 ; Leave invalids to the default case.
595 ((eq? (obj:name insn) 'x-invalid)
598 ; If same contents as next case, fall through.
599 ; FIXME: Can reduce more by sorting cases. Much later.
600 ((and (not (null? rest))
602 (eq? 'insn (dtable-entry-type (car rest)))
605 (obj:name (dtable-entry-value (car rest)))))
606 (string-append indent " case "
607 (number->string (dtable-entry-index entry))
608 " : /* fall through */\n"))
611 (string-append indent " case "
612 (number->string (dtable-entry-index entry)) " : "
613 "itype = " (gen-cpu-insn-enum (current-cpu) insn) ";"
614 ; Compensate for base-insn-size > current-insn-size by adjusting entire_insn.
615 ; Activate this logic only for sid simulators; they are consistent in
616 ; interpreting base-insn-bitsize this way.
617 (if (and (equal? APPLICATION 'SID-SIMULATOR)
618 (> (state-base-insn-bitsize) (insn-length insn)))
620 " entire_insn = base_insn >> "
621 (number->string (- (state-base-insn-bitsize) (insn-length insn)))
626 (string-append " @prefix@_extract_" fmt-name " (this, current_cpu, pc, base_insn, entire_insn); goto done;\n")
627 (string-append " goto extract_" fmt-name ";\n"))
631 ; Subroutine of -decode-expr-ifield-tracking.
632 ; Return a list of all possible values for ifield IFLD-NAME.
633 ; FIXME: Quick-n-dirty implementation. Should use bit arrays.
635 (define (-decode-expr-ifield-values ifld-name)
636 (let* ((ifld (current-ifld-lookup ifld-name))
637 (bits (ifld-length ifld)))
638 (if (mode-unsigned? (ifld-mode ifld))
639 (iota (logsll 1 bits))
640 (iota (logsll 1 bits) (- (logsll 1 (- bits 1))))))
643 ; Subroutine of -decode-expr-ifield-tracking,-decode-expr-ifield-mark-used.
644 ; Create the search key for tracking table lookup.
646 (define (-decode-expr-ifield-tracking-key insn ifld-name)
647 (symbol-append (obj:name (insn-ifmt insn)) '-x- ifld-name)
650 ; Subroutine of -gen-decode-expr-entry.
651 ; Return a table to track used ifield values.
652 ; The table is an associative list of (key . value-list).
653 ; KEY is "iformat-name-x-ifield-name".
654 ; VALUE-LIST is a list of the unused values.
656 (define (-decode-expr-ifield-tracking expr-list)
660 (map (lambda (ifld-name)
661 (cons (exprtable-entry-insn entry)
663 (-decode-expr-ifield-values ifld-name))))
664 (exprtable-entry-iflds entry)))
666 ; TABLE1 is a list of (insn ifld-name value1 value2 ...).
667 (nub (map (lambda (elm)
669 (-decode-expr-ifield-tracking-key (car elm) (cadr elm))
675 ; Subroutine of -decode-expr-ifield-mark-used!.
676 ; Return list of values completely used for ifield IFLD-NAME in EXPR.
677 ; "completely used" here means the value won't appear elsewhere.
678 ; e.g. in (andif (eq f-rd 15) (eq f-rx 14)) we don't know what happens
679 ; for the (ne f-rx 14) case.
681 (define (-decode-expr-ifield-values-used ifld-name expr)
682 (case (rtx-name expr)
684 (if (and (rtx-kind? 'ifield (rtx-cmp-op-arg expr 0))
685 (rtx-constant? (rtx-cmp-op-arg expr 1)))
686 (list (rtx-constant-value (rtx-cmp-op-arg expr 1)))
689 (if (rtx-kind? 'ifield (rtx-member-value expr))
690 (rtx-member-set expr)
696 ; Subroutine of -gen-decode-expr-entry.
697 ; Mark ifield values used by EXPR-ENTRY in TRACKING-TABLE.
699 (define (-decode-expr-ifield-mark-used! tracking-table expr-entry)
700 (let ((insn (exprtable-entry-insn expr-entry))
701 (expr (exprtable-entry-expr expr-entry))
702 (ifld-names (exprtable-entry-iflds expr-entry)))
703 (for-each (lambda (ifld-name)
705 (assq (-decode-expr-ifield-tracking-key insn ifld-name)
707 (used (-decode-expr-ifield-values-used ifld-name expr)))
708 (for-each (lambda (value)
709 (delq! value table-entry))
716 ; Subroutine of -gen-decode-expr-entry.
717 ; Return code to set `itype' and branch to the extraction phase.
719 (define (-gen-decode-expr-set-itype indent insn-enum fmt-name fn?)
727 (string-append "@prefix@_extract_" fmt-name " (this, current_cpu, pc, base_insn, entire_insn); goto done;")
728 (string-append "goto extract_" fmt-name ";"))
734 ; Generate code to decode the expression table in ENTRY.
735 ; INVALID-INSN is the <insn> object of the pseudo insn to handle invalid ones.
737 (define (-gen-decode-expr-entry entry indent invalid-insn fn?)
738 (assert (eq? 'expr (dtable-entry-type entry)))
739 (logit 3 "Generating decode expr entry for " (exprtable-name (dtable-entry-value entry)) " ...\n")
741 (let ((expr-list (exprtable-insns (dtable-entry-value entry))))
744 (number->string (dtable-entry-index entry))
747 (let ((iflds-tracking (-decode-expr-ifield-tracking expr-list))
748 (indent (string-append indent " ")))
750 (let loop ((expr-list expr-list) (code nil))
752 (if (null? expr-list)
754 ; All done. If we used up all field values we don't need to
755 ; "fall through" and select the invalid insn marker.
757 (if (all-true? (map null? (map cdr iflds-tracking)))
761 (-gen-decode-expr-set-itype
763 (gen-cpu-insn-enum (current-cpu) invalid-insn)
767 ; Not all done, process next expr.
769 (let ((insn (exprtable-entry-insn (car expr-list)))
770 (expr (exprtable-entry-expr (car expr-list)))
771 (ifld-names (exprtable-entry-iflds (car expr-list))))
773 ; Mark of those ifield values we use first.
774 ; If there are none left afterwards, we can unconditionally
776 (-decode-expr-ifield-mark-used! iflds-tracking (car expr-list))
779 ; If this is the last expression, and it uses up all
780 ; remaining ifield values, there's no need to perform any
782 (if (and (null? (cdr expr-list))
783 (all-true? (map null? (map cdr iflds-tracking))))
785 ; Need this in a list for a later append!.
787 (-gen-decode-expr-set-itype
789 (gen-cpu-insn-enum (current-cpu) insn)
790 (gen-sym (insn-sfmt insn))
793 ; We don't use up all ifield values, so emit a test.
794 (let ((iflds (map current-ifld-lookup ifld-names)))
797 (gen-define-ifields iflds
799 (string-append indent " ")
801 (gen-extract-ifields iflds
803 (string-append indent " ")
806 (rtl-c 'BI expr nil #:ifield-var? #t)
808 (-gen-decode-expr-set-itype
809 (string-append indent " ")
810 (gen-cpu-insn-enum (current-cpu) insn)
811 (gen-sym (insn-sfmt insn))
815 (loop (cdr expr-list)
816 (append! code next-code)))))))
820 ; Generate code to decode TABLE.
821 ; REST is the remaining entries.
822 ; SWITCH-NUM, STARTBIT, DECODE-BITSIZE, INDENT, LSB0?, INVALID-INSN are same
823 ; as for -gen-decoder-switch.
825 (define (-gen-decode-table-entry table rest switch-num startbit decode-bitsize indent lsb0? invalid-insn fn?)
826 (assert (eq? 'table (dtable-entry-type table)))
827 (logit 3 "Generating decode table entry for case " (dtable-entry-index table) " ...\n")
831 (number->string (dtable-entry-index table))
833 ; If table is same as next, just emit a "fall through" to cut down on
835 (if (and (not (null? rest))
836 ; Ensure both tables.
837 (eq? 'table (dtable-entry-type (car rest)))
839 (eqv? (subdtable-key (dtable-entry-value table))
840 (subdtable-key (dtable-entry-value (car rest)))))
841 " /* fall through */\n"
844 (-gen-decoder-switch switch-num
847 (subdtable-table (dtable-entry-value table))
848 (string-append indent " ")
854 ; Subroutine of -decode-sort-entries.
855 ; Return a boolean indicating if A,B are equivalent entries.
857 (define (-decode-equiv-entries? a b)
858 (let ((a-type (dtable-entry-type a))
859 (b-type (dtable-entry-type b)))
860 (if (eq? a-type b-type)
863 (let ((a-name (obj:name (dtable-entry-value a)))
864 (b-name (obj:name (dtable-entry-value b))))
865 (eq? a-name b-name)))
867 ; Ignore expr entries for now.
870 (let ((a-name (subdtable-key (dtable-entry-value a)))
871 (b-name (subdtable-key (dtable-entry-value b))))
872 (eq? a-name b-name))))
873 ; A and B are not the same type.
877 ; Subroutine of -gen-decoder-switch, sort ENTRIES according to desired
878 ; print order (maximizes amount of fall-throughs, but maintains numerical
879 ; order as much as possible).
880 ; ??? This is an O(n^2) algorithm. An O(n Log(n)) algorithm can be done
881 ; but it seemed more complicated than necessary for now.
883 (define (-decode-sort-entries entries)
885 ; Return list of entries in non-empty list L that have the same decode
886 ; entry as the first entry. Entries found are marked with #f so
887 ; they're not processed again.
889 ; Start off the result with the first entry, then see if the
890 ; remaining ones match it.
891 (let ((first (car l)))
892 (let loop ((l (cdr l)) (result (cons first nil)))
895 (if (and (car l) (-decode-equiv-entries? first (car l)))
896 (let ((lval (car l)))
898 (loop (cdr l) (cons lval result)))
899 (loop (cdr l) result)))))))
901 (let loop ((entries (list-copy entries)) (result nil))
903 (apply append (reverse! result))
906 (cons (find-equiv! entries)
908 (loop (cdr entries) result)))))
911 ; Generate switch statement to decode TABLE-GUTS.
912 ; SWITCH-NUM is for compatibility with the computed goto decoder and
914 ; STARTBIT is the bit offset of the instruction value that C variable `insn'
915 ; holds (note that this is independent of LSB0?).
916 ; DECODE-BITSIZE is the number of bits of the insn that `insn' holds.
917 ; LSB0? is non-#f if bit number 0 is the least significant bit.
918 ; INVALID-INSN is the <insn> object of the pseudo insn to handle invalid ones.
920 ; FIXME: for the few-alternative case (say, 2), generating
922 ; else if (val == 0) { ... }
923 ; else if (val == 1) { ... }
925 ; may well be less stressful on the compiler to optimize than small switch() stmts.
927 (define (-gen-decoder-switch switch-num startbit decode-bitsize table-guts indent lsb0? invalid-insn fn?)
928 ; For entries that are a single insn, we're done, otherwise recurse.
932 ; Are we at the next word?
933 (if (not (= startbit (dtable-guts-startbit table-guts)))
935 (set! startbit (dtable-guts-startbit table-guts))
936 (set! decode-bitsize (dtable-guts-bitsize table-guts))
937 ; FIXME: Bits may get fetched again during extraction.
938 (string-append indent " unsigned int val;\n"
939 indent " /* Must fetch more bits. */\n"
941 (gen-ifetch "pc" startbit decode-bitsize)
944 (string-append indent " unsigned int val = "))
945 (-gen-decode-bits (dtable-guts-bitnums table-guts)
946 (dtable-guts-startbit table-guts)
947 (dtable-guts-bitsize table-guts) "insn" lsb0?)
949 indent " switch (val)\n"
952 ; The code is more readable, and icache use is improved, if we collapse
953 ; common code into one case and use "fall throughs" for all but the last of
954 ; a set of common cases.
955 ; FIXME: We currently rely on -gen-decode-foo-entry to recognize the fall
956 ; through. We should take care of it ourselves.
958 (let loop ((entries (-decode-sort-entries (dtable-guts-entries table-guts)))
964 (cons (case (dtable-entry-type (car entries))
966 (-gen-decode-insn-entry (car entries) (cdr entries) indent fn?))
968 (-gen-decode-expr-entry (car entries) indent invalid-insn fn?))
970 (-gen-decode-table-entry (car entries) (cdr entries)
971 switch-num startbit decode-bitsize
972 indent lsb0? invalid-insn fn?))
976 ; ??? Can delete if all cases are present.
977 indent " default : itype = "
978 (gen-cpu-insn-enum (current-cpu) invalid-insn)
982 " @prefix@_extract_sfmt_empty (this, current_cpu, pc, base_insn, entire_insn); goto done;\n"
983 " goto extract_sfmt_empty;\n")
990 ; Decoder generation entry point.
991 ; Generate code to decode INSN-LIST.
992 ; BITNUMS is the set of bits to initially key off of.
993 ; DECODE-BITSIZE is the number of bits of the instruction that `insn' holds.
994 ; LSB0? is non-#f if bit number 0 is the least significant bit.
995 ; INVALID-INSN is the <insn> object of the pseudo insn to handle invalid ones.
996 ; FN? is non-#f if the extractors are functions rather than inline code
998 (define (gen-decoder insn-list bitnums decode-bitsize indent lsb0? invalid-insn fn?)
999 (logit 3 "Building decode tree.\n"
1000 "bitnums = " (stringize bitnums " ") "\n"
1001 "decode-bitsize = " (number->string decode-bitsize) "\n"
1002 "lsb0? = " (if lsb0? "#t" "#f") "\n"
1003 "fn? = " (if fn? "#t" "#f") "\n"
1006 ; First build a table that decodes the instruction set.
1008 (let ((table-guts (decode-build-table insn-list bitnums
1009 decode-bitsize lsb0?
1014 (-gen-decoder-switch "0" 0 decode-bitsize table-guts indent lsb0?