; CPU architecture description. ; Copyright (C) 2000, 2003, 2009 Red Hat, Inc. ; This file is part of CGEN. ; See file COPYING.CGEN for details. ; Top level class that records everything about a cpu. ; FIXME: Rename this to something else and rename to ; for consistency with other classes (define-foo -> object). (define (class-make ' nil '( ; An object of type . data ;; ??? All should really be assumed to be a black-box table. (attr-list . (() . ())) (enum-list . ()) (kw-list . ()) (isa-list . ()) (cpu-list . ()) (mach-list . ()) (model-list . ()) (ifld-table . ()) (hw-list . ()) (op-table . ()) (ifmt-list . ()) (sfmt-list . ()) (insn-table . ()) (minsn-table . ()) (subr-list . ()) (insn-extract . #f) ; FIXME: wip (and move elsewhere) (insn-execute . #f) ; FIXME: wip (and move elsewhere) ; standard values derived from the input data derived ; #t if multi-insns have been instantiated (multi-insns-instantiated? . #f) ; #t if instructions have been analyzed (insns-analyzed? . #f) ; #t if semantics were included in the analysis (semantics-analyzed? . #f) ; #t if alias insns were included in the analysis (aliases-analyzed? . #f) ; ordinal of next object that needs one (next-ordinal . 0) ) nil) ) ; Accessors. ; Each getter is arch-foo. ; Each setter is arch-set-foo!. (define-getters arch (data attr-list enum-list kw-list isa-list cpu-list mach-list model-list ifld-table hw-list op-table ifmt-list sfmt-list insn-table minsn-table subr-list derived multi-insns-instantiated? insns-analyzed? semantics-analyzed? aliases-analyzed? next-ordinal ) ) (define-setters arch (data attr-list enum-list kw-list isa-list cpu-list mach-list model-list ifld-table hw-list op-table ifmt-list sfmt-list insn-table minsn-table subr-list derived multi-insns-instantiated? insns-analyzed? semantics-analyzed? aliases-analyzed? next-ordinal ) ) ; For elements recorded as a table, return a sorted list. ; ??? All elements should really be assumed to be a black-box table. (define (arch-ifld-list arch) (/ident-object-table->list (arch-ifld-table arch)) ) (define (arch-op-list arch) (/ident-object-table->list (arch-op-table arch)) ) (define (arch-insn-list arch) (/ident-object-table->list (arch-insn-table arch)) ) (define (arch-minsn-list arch) (/ident-object-table->list (arch-minsn-table arch)) ) ;; Get the next ordinal and increment it for the next time. (define (/get-next-ordinal! arch) (let ((ordinal (arch-next-ordinal arch))) (arch-set-next-ordinal! arch (+ ordinal 1)) ordinal) ) ;; FIXME: temp hack for current-ifld-lookup, current-op-lookup. ;; Return the element of list L with the lowest ordinal. (define (/get-lowest-ordinal l) (let ((lowest-obj #f) (lowest-ord (/get-next-ordinal! CURRENT-ARCH))) (for-each (lambda (elm) (if (< (obj-ordinal elm) lowest-ord) (begin (set! lowest-obj elm) (set! lowest-ord (obj-ordinal elm))))) l) lowest-obj) ) ;; Table of objects with two access styles: ;; hash lookup, ordered list. ;; The main table is the hash table, the list is lazily created and cached. ;; The table is recorded as (hash-table . list). ;; The list is #f if it needs to be computed. ;; Each entry in the hash table is a list, multiple objects can have the same ;; key (e.g. insns from different isas can have the same name). ;; ;; This relies on the ordinal element of objects to build the ;; ordered list. (define (/make-ident-object-table hash-size) (cons (make-hash-table hash-size) #f) ) ;; Return ordered list. ;; ;; To allow splicing in new objects we recognize two kinds of ordinal numbers: ;; integer and (integer . integer) where the latter is a pair of ;; major-ordinal-number and minor-ordinal-number. (define (/ident-object-table->list iot) (if (cdr iot) (cdr iot) (let ((unsorted (hash-fold (lambda (key value prior) ;; NOTE: {value} usually contains just ;; one element. (append value prior)) '() (car iot)))) (set-cdr! iot (sort unsorted (lambda (a b) ;; Ordinals are either an integer or ;; (major . minor). (let ((oa (obj-ordinal a)) (ob (obj-ordinal b))) ;; Quick test for common case. (if (and (number? oa) (number? ob)) (< oa ob) (let ((maj-a (if (pair? oa) (car oa) oa)) (maj-b (if (pair? ob) (car ob) ob)) (min-a (if (pair? oa) (cdr oa) 0)) (min-b (if (pair? ob) (cdr ob) 0))) (cond ((< maj-a maj-b) #t) ((= maj-a maj-b) (< min-a min-b)) (else #f)))))))) (cdr iot))) ) ;; Add an entry to an ident-object-table. (define (/ident-object-table-add! arch iot key object) ;; Give OBJECT an ordinal if it doesn't have one already. (if (not (obj-ordinal object)) (obj-set-ordinal! object (/get-next-ordinal! arch))) ;; Remember: Elements in the hash table are lists of objects, this is because ;; multiple objects can have the same key if they come from different isas. (let ((elm (hashq-ref (car iot) key))) (if elm (hashq-set! (car iot) key (cons object elm)) (hashq-set! (car iot) key (cons object nil)))) ;; Need to recompute the sorted list. (set-cdr! iot #f) *UNSPECIFIED* ) ;; Look up KEY in an ident-object-table. (define (/ident-object-table-lookup iot key) (hashq-ref iot key) ) ; Class for recording things specified in `define-arch'. ; This simplifies define-arch as the global arch object CURRENT-ARCH ; must exist before loading the .cpu file. (define (class-make ' '() '( ; Default alignment of memory operations. ; One of aligned, unaligned, forced. default-alignment ; Orientation of insn bit numbering (#f->msb=0, #t->lsb=0). insn-lsb0? ; List of all machs. ; Each element is pair of (mach-name . sanitize-key) ; where sanitize-key is #f if there is none. ; blah blah blah ... ooohhh, evil sanitize key, blah blah blah machs ; List of all isas (instruction set architecture). ; Each element is a pair of (isa-name . sanitize-key) ; where sanitize-key is #f if there is none. ; There is usually just one. ARM has two (arm, thumb). ; blah blah blah ... ooohhh, evil sanitize key, blah blah blah isas ; ??? Defaults for other things should be here. ) nil) ) (define-getters adata (default-alignment insn-lsb0? machs isas) ) ; Add, list, lookup accessors for . ; ; For the lookup routines, the result is the object or #f if not found. ; For some, if X is already an object, return that. (define (current-arch-name) (obj:name (arch-data CURRENT-ARCH))) (define (current-arch-comment) (obj:comment (arch-data CURRENT-ARCH))) (define (current-arch-atlist) (obj-atlist (arch-data CURRENT-ARCH))) (define (current-arch-default-alignment) (adata-default-alignment (arch-data CURRENT-ARCH))) (define (current-arch-insn-lsb0?) (adata-insn-lsb0? (arch-data CURRENT-ARCH))) (define (current-arch-mach-name-list) (map car (adata-machs (arch-data CURRENT-ARCH))) ) (define (current-arch-isa-name-list) (map car (adata-isas (arch-data CURRENT-ARCH))) ) ; Attributes. ; Recorded as a pair of lists. ; The car is a list of objects. ; The cdr is an associative list of (name . ) elements, for lookup. ; Could use a hash table except that there currently aren't that many. (define (current-attr-list) (car (arch-attr-list CURRENT-ARCH))) (define (current-attr-add! a) ; NOTE: While putting this test in define-attr feels better, having it here ; is more robust, internal calls get checked too. Thus it's here. ; Ditto for all the other such tests in this file. (if (current-attr-lookup (obj:name a)) (parse-error (make-current-context "define-attr") "attribute already defined" (obj:name a))) (let ((adata (arch-attr-list CURRENT-ARCH))) ; Build list in normal order so we don't have to reverse it at the end ; (since our format is non-trivial). (if (null? (car adata)) (arch-set-attr-list! CURRENT-ARCH (cons (cons a nil) (acons (obj:name a) a nil))) (begin (append! (car adata) (cons a nil)) (append! (cdr adata) (acons (obj:name a) a nil))))) *UNSPECIFIED* ) (define (current-attr-lookup attr-name) (assq-ref (cdr (arch-attr-list CURRENT-ARCH)) attr-name) ) ; Enums. (define (current-enum-list) (arch-enum-list CURRENT-ARCH)) (define (current-enum-add! e) (if (current-enum-lookup (obj:name e)) (parse-error (make-current-context "define-enum") "enum already defined" (obj:name e))) (arch-set-enum-list! CURRENT-ARCH (cons e (arch-enum-list CURRENT-ARCH))) *UNSPECIFIED* ) (define (current-enum-lookup enum-name) (object-assq enum-name (current-enum-list)) ) ; Keywords. (define (current-kw-list) (arch-kw-list CURRENT-ARCH)) (define (current-kw-add! kw) (if (current-kw-lookup (obj:name kw)) (parse-error (make-current-context "define-keyword") "keyword already defined" (obj:name kw))) (arch-set-kw-list! CURRENT-ARCH (cons kw (arch-kw-list CURRENT-ARCH))) *UNSPECIFIED* ) (define (current-kw-lookup kw-name) (object-assq kw-name (current-kw-list)) ) ; Instruction sets. (define (current-isa-list) (arch-isa-list CURRENT-ARCH)) (define (current-isa-add! i) (if (current-isa-lookup (obj:name i)) (parse-error (make-current-context "define-isa") "isa already defined" (obj:name i))) (arch-set-isa-list! CURRENT-ARCH (cons i (arch-isa-list CURRENT-ARCH))) *UNSPECIFIED* ) (define (current-isa-lookup isa-name) (object-assq isa-name (current-isa-list)) ) ;; Given a list of objects OBJ-LIST, return those objects that are from the ;; ISA(s) in ISA-NAME-LIST. ;; ISA-NAME-LIST may be (all) or #f (which also means (all)). (define (obj-filter-by-isa obj-list isa-name-list) (if (or (eq? isa-name-list #f) (memq 'all isa-name-list)) obj-list (find (lambda (obj) (let ((obj-isas (obj-attr-value obj 'ISA))) (non-null-intersection? obj-isas isa-name-list))) obj-list)) ) ; Cpu families. (define (current-cpu-list) (arch-cpu-list CURRENT-ARCH)) (define (current-cpu-add! c) (if (current-cpu-lookup (obj:name c)) (parse-error (make-current-context "define-cpu") "cpu already defined" (obj:name c))) (arch-set-cpu-list! CURRENT-ARCH (cons c (arch-cpu-list CURRENT-ARCH))) *UNSPECIFIED* ) (define (current-cpu-lookup cpu-name) (object-assq cpu-name (current-cpu-list)) ) ; Machines. (define (current-mach-list) (arch-mach-list CURRENT-ARCH)) (define (current-mach-add! m) (if (current-mach-lookup (obj:name m)) (parse-error (make-current-context "define-mach") "mach already defined" (obj:name m))) (arch-set-mach-list! CURRENT-ARCH (cons m (arch-mach-list CURRENT-ARCH))) *UNSPECIFIED* ) (define (current-mach-lookup mach-name) (object-assq mach-name (current-mach-list)) ) ; Models. (define (current-model-list) (arch-model-list CURRENT-ARCH)) (define (current-model-add! m) (if (current-model-lookup (obj:name m)) (parse-error (make-current-context "define-model") "model already defined" (obj:name m))) (arch-set-model-list! CURRENT-ARCH (cons m (arch-model-list CURRENT-ARCH))) *UNSPECIFIED* ) (define (current-model-lookup model-name) (object-assq model-name (current-model-list)) ) ;; Hardware elements. ;; ;; NOTE: Hardware elements must be uniquely named across all machs and isas. (define (current-hw-list) (arch-hw-list CURRENT-ARCH)) (define (current-hw-add! hw) (if (current-hw-lookup (obj:name hw)) (parse-error (make-current-context "define-hardware") "hardware already defined" (obj:name hw))) (arch-set-hw-list! CURRENT-ARCH (cons hw (arch-hw-list CURRENT-ARCH))) *UNSPECIFIED* ) (define (current-hw-lookup hw) (if (object? hw) hw ; This doesn't use object-assq on purpose. Hardware objects handle ; get-name specially. (find-first (lambda (hw-obj) (eq? (send hw-obj 'get-name) hw)) (current-hw-list))) ) ;; Instruction fields. ;; ;; NOTE: Instruction fields must be uniquely named across all machs, ;; but isas may share ifields with the same name. (define (current-ifld-list) (/ident-object-table->list (arch-ifld-table CURRENT-ARCH)) ) (define (current-ifld-add! f) (if (/ifld-already-defined? f) (parse-error (make-obj-context f "define-ifield") "ifield already defined" (obj:name f))) (/ident-object-table-add! CURRENT-ARCH (arch-ifld-table CURRENT-ARCH) (obj:name f) f) *UNSPECIFIED* ) ;; Look up ifield X in the current architecture. ;; Returns the object or #f if not found. ;; If there is an ambiguity (i.e. the ifield is in multiple ISAs and ;; MAYBE-ISA-NAME-LIST doesn't disambiguate the choice) an error is signalled. ;; ;; If X is an object, just return it. ;; This is to handle ??? ;; Otherwise X is the name of the ifield to look up. ;; If MAYBE-ISA-NAME-LIST is provided, the car is a list of ISAs to look in. ;; If the specified isa list is #f, look in all ISAs. (define (current-ifld-lookup x . maybe-isa-name-list) (if (ifield? x) x (let ((f-list (/ident-object-table-lookup (car (arch-ifld-table CURRENT-ARCH)) x))) (if f-list (let* ((isas (if (not (null? maybe-isa-name-list)) (car maybe-isa-name-list) #f)) (filtered-f-list (obj-filter-by-isa f-list isas))) (case (length filtered-f-list) ((0) (error "Ifield not in specified ISA:" x)) ((1) (car filtered-f-list)) (else (error "Ambiguous ifield lookup:" x)))) #f))) ) ; Return a boolean indicating if F is currently defined. ; This is slightly complicated because multiple isas can have different ; ifields with the same name. (define (/ifld-already-defined? f) (let ((iflds (/ident-object-table-lookup (car (arch-ifld-table CURRENT-ARCH)) (obj:name f)))) ; We've got all the ifields with the same name, ; now see if any have the same ISA as F. (if iflds (let ((result #f) (f-isas (obj-isa-list f))) (for-each (lambda (ff) (if (non-null-intersection? f-isas (obj-isa-list ff)) (set! result #t))) iflds) result) #f)) ) ;; Operands. ;; ;; NOTE: Operands must be uniquely named across all machs, ;; but isas may share operands with the same name. (define (current-op-list) (/ident-object-table->list (arch-op-table CURRENT-ARCH)) ) (define (current-op-add! op) (if (/op-already-defined? op) (parse-error (make-obj-context op "define-operand") "operand already defined" (obj:name op))) (/ident-object-table-add! CURRENT-ARCH (arch-op-table CURRENT-ARCH) (obj:name op) op) *UNSPECIFIED* ) ;; Look up operand NAME in the current architecture. ;; Returns the object or #f if not found. ;; If there is an ambiguity (i.e. the operand is in multiple ISAs and ;; MAYBE-ISA-NAME-LIST doesn't disambiguate the choice) an error is signalled. ;; ;; If MAYBE-ISA-NAME-LIST is provided, the car is a list of ISAs to look in. ;; If the specified isa list is #f, look in all ISAs. (define (current-op-lookup name . maybe-isa-name-list) (let ((op-list (/ident-object-table-lookup (car (arch-op-table CURRENT-ARCH)) name))) (if op-list (let* ((isas (if (not (null? maybe-isa-name-list)) (car maybe-isa-name-list) #f)) (filtered-o-list (obj-filter-by-isa op-list isas))) (case (length filtered-o-list) ((0) (error "Operand not in specified ISA:" name)) ((1) (car filtered-o-list)) (else (error "Ambiguous operand lookup:" name)))) #f)) ) ; Return a boolean indicating if OP is currently defined. ; This is slightly complicated because multiple isas can have different ; operands with the same name. (define (/op-already-defined? op) (let ((ops (/ident-object-table-lookup (car (arch-op-table CURRENT-ARCH)) (obj:name op)))) ; We've got all the operands with the same name, ; now see if any have the same ISA as OP. (if ops (let ((result #f) (op-isas (obj-isa-list op))) (for-each (lambda (o) (if (non-null-intersection? op-isas (obj-isa-list o)) (set! result #t))) ops) result) #f)) ) ; Instruction field formats. (define (current-ifmt-list) (arch-ifmt-list CURRENT-ARCH)) ; Semantic formats (akin to ifmt's, except includes semantics to distinguish ; insns). (define (current-sfmt-list) (arch-sfmt-list CURRENT-ARCH)) ;; Instructions. ;; ;; NOTE: Instructions must be uniquely named across all machs, ;; but isas may share instructions with the same name. (define (current-insn-list) (/ident-object-table->list (arch-insn-table CURRENT-ARCH)) ) (define (current-insn-add! i) (if (/insn-already-defined? i) (parse-error (make-obj-context i "define-insn") "insn already defined" (obj:name i))) (/ident-object-table-add! CURRENT-ARCH (arch-insn-table CURRENT-ARCH) (obj:name i) i) *UNSPECIFIED* ) ;; Look up insn NAME in the current architecture. ;; Returns the object or #f if not found. ;; If there is an ambiguity (i.e. the insn is in multiple ISAs and ;; ISA-NAME-LIST doesn't disambiguate the choice) an error is signalled. ;; If the specified isa list is #f, look in all ISAs. (define (current-insn-lookup name isa-name-list) (let ((i-list (/ident-object-table-lookup (car (arch-insn-table CURRENT-ARCH)) name))) (if i-list (let ((filtered-i-list (obj-filter-by-isa i-list isa-name-list))) (case (length filtered-i-list) ((0) (error "Insn not in specified ISA:" name)) ((1) (car filtered-i-list)) (else (error "Ambiguous insn lookup:" name)))) #f)) ) ; Return a boolean indicating if INSN is currently defined. ; This is slightly complicated because multiple isas can have different ; insns with the same name. (define (/insn-already-defined? insn) (let ((insns (/ident-object-table-lookup (car (arch-insn-table CURRENT-ARCH)) (obj:name insn)))) ; We've got all the insns with the same name, ; now see if any have the same ISA as INSN. (if insns (let ((result #f) (insn-isas (obj-isa-list insn))) (for-each (lambda (i) (if (non-null-intersection? insn-isas (obj-isa-list i)) (set! result #t))) insns) result) #f)) ) ;; Macro instructions. ;; ;; NOTE: Instructions must be uniquely named across all machs, ;; but isas may share instructions with the same name. (define (current-minsn-list) (/ident-object-table->list (arch-minsn-table CURRENT-ARCH)) ) (define (current-minsn-add! m) (if (/minsn-already-defined? m) (parse-error (make-obj-context m "define-minsn") "macro-insn already defined" (obj:name m))) (/ident-object-table-add! CURRENT-ARCH (arch-minsn-table CURRENT-ARCH) (obj:name m) m) *UNSPECIFIED* ) ;; Look up minsn NAME in the current architecture. ;; Returns the object or #f if not found. ;; If there is an ambiguity (i.e. the minsn is in multiple ISAs and ;; ISA-NAME-LIST doesn't disambiguate the choice) an error is signalled. ;; If the specified isa list is #f, look in all ISAs. (define (current-minsn-lookup name isa-name-list) (let ((m-list (/ident-object-table-lookup (car (arch-minsn-table CURRENT-ARCH)) name))) (if m-list (let ((filtered-m-list (obj-filter-by-isa m-list isa-name-list))) (case (length filtered-m-list) ((0) (error "Macro-insn not in specified ISA:" name)) ((1) (car filtered-m-list)) (else (error "Ambiguous macro-insn lookup:" name)))) #f)) ) ; Return a boolean indicating if MINSN is currently defined. ; This is slightly complicated because multiple isas can have different ; macro-insns with the same name. (define (/minsn-already-defined? m) (let ((minsns (/ident-object-table-lookup (car (arch-minsn-table CURRENT-ARCH)) (obj:name m)))) ; We've got all the macro-insns with the same name, ; now see if any have the same ISA as M. (if minsns (let ((result #f) (m-isas (obj-isa-list m))) (for-each (lambda (mm) (if (non-null-intersection? m-isas (obj-isa-list mm)) (set! result #t))) minsns) result) #f)) ) ; rtx subroutines. (define (current-subr-list) (map cdr (arch-subr-list CURRENT-ARCH))) (define (current-subr-add! s) (if (current-subr-lookup (obj:name s)) (parse-error (make-current-context "define-subr") "subroutine already defined" (obj:name s))) (arch-set-subr-list! CURRENT-ARCH (acons (obj:name s) s (arch-subr-list CURRENT-ARCH))) *UNSPECIFIED* ) (define (current-subr-lookup name) (assq-ref (arch-subr-list CURRENT-ARCH) name) ) ; Arch parsing support. ; Parse an alignment spec. (define (/arch-parse-alignment context alignment) (if (memq alignment '(aligned unaligned forced)) alignment (parse-error context "invalid alignment" alignment)) ) ; Parse an arch mach spec. ; The value is a list of mach names or (mach-name sanitize-key) elements. ; The result is a list of (mach-name . sanitize-key) elements. (define (/arch-parse-machs context machs) (for-each (lambda (m) (if (or (symbol? m) (and (list? m) (= (length m) 2) (symbol? (car m)) (symbol? (cadr m)))) #t ; ok (parse-error context "bad arch mach spec" m))) machs) (map (lambda (m) (if (symbol? m) (cons m #f) (cons (car m) (cadr m)))) machs) ) ; Parse an arch isa spec. ; The value is a list of isa names or (isa-name sanitize-key) elements. ; The result is a list of (isa-name . sanitize-key) elements. (define (/arch-parse-isas context isas) (for-each (lambda (m) (if (or (symbol? m) (and (list? m) (= (length m) 2) (symbol? (car m)) (symbol? (cadr m)))) #t ; ok (parse-error context "bad arch isa spec" m))) isas) (map (lambda (m) (if (symbol? m) (cons m #f) (cons (car m) (cadr m)))) isas) ) ; Parse an architecture description ; This is the main routine for building an arch object from a cpu ; description in the .cpu file. ; All arguments are in raw (non-evaluated) form. (define (/arch-parse context name comment attrs default-alignment insn-lsb0? machs isas) (logit 2 "Processing arch " name " ...\n") (make (parse-name context name) (parse-comment context comment) (atlist-parse context attrs "arch") (/arch-parse-alignment context default-alignment) (parse-boolean context insn-lsb0?) (/arch-parse-machs context machs) (/arch-parse-isas context isas)) ) ; Read an architecture description. ; This is the main routine for analyzing an arch description in the .cpu file. ; ARG-LIST is an associative list of field name and field value. ; parse-arch is invoked to create the `arch' object. (define /arch-read (lambda arg-list (let ((context "arch-read") ; object members and default values (name "unknown") (comment "") (attrs nil) (default-alignment 'aligned) (insn-lsb0? #f) (machs #f) (isas #f) ) ; Loop over each element in ARG-LIST, recording what's found. (let loop ((arg-list arg-list)) (if (null? arg-list) nil (let ((arg (car arg-list)) (elm-name (caar arg-list))) (case elm-name ((name) (set! name (cadr arg))) ((comment) (set! comment (cadr arg))) ((attrs) (set! attrs (cdr arg))) ((default-alignment) (set! default-alignment (cadr arg))) ((insn-lsb0?) (set! insn-lsb0? (cadr arg))) ((machs) (set! machs (cdr arg))) ((isas) (set! isas (cdr arg))) (else (parse-error context "invalid arch arg" arg))) (loop (cdr arg-list))))) ; Ensure required fields are present. (if (not machs) (parse-error context "missing machs spec")) (if (not isas) (parse-error context "missing isas spec")) ; Now that we've identified the elements, build the object. (/arch-parse context name comment attrs default-alignment insn-lsb0? machs isas) ) ) ) ; Define an arch object, name/value pair list version. (define define-arch (lambda arg-list (let ((a (apply /arch-read arg-list))) (arch-set-data! CURRENT-ARCH a) (def-mach-attr! (adata-machs a)) (keep-mach-validate!) (def-isa-attr! (adata-isas a)) (keep-isa-validate!) ; Install the builtin objects now that we have an arch, and now that ; attributes MACH and ISA exist. (reader-install-builtin!) a)) ) ; Mach/isa processing. ; Create the MACH attribute. ; MACHS is the canonicalized machs spec to define-arch: (name . sanitize-key). (define (def-mach-attr! machs) (let ((mach-enums (append '((base)) (map (lambda (mach) (cons (car mach) (cons '- (if (cdr mach) (list (cons 'sanitize (cdr mach))) nil)))) machs) '((max))))) (define-attr '(type bitset) '(name MACH) '(comment "machine type selection") '(default base) (cons 'values mach-enums)) ) *UNSPECIFIED* ) ; Return #t if MACH is supported by OBJ. ; This is done by looking for the MACH attribute in OBJ. ; By definition, objects that support the default (base) mach support ; all machs. (define (mach-supports? mach obj) (let ((machs (obj-attr-value obj 'MACH)) (name (obj:name mach))) (or (memq name machs) (memq 'base machs))) ;(let ((deflt (attr-lookup-default 'MACH obj))) ; (any-true? (map (lambda (m) (memq m deflt)) machs))))) ) ; Create the ISA attribute. ; ISAS is the canonicalized isas spec to define-arch: (name . sanitize-key). ; ISAS is a list of isa names. (define (def-isa-attr! isas) (let ((isa-enums (append (map (lambda (isa) (cons (car isa) (cons '- (if (cdr isa) (list (cons 'sanitize (cdr isa))) nil)))) isas) '((max))))) (define-attr '(type bitset) '(name ISA) '(comment "instruction set selection") ; If there's only one isa, don't (yet) pollute the tables with a value ; for it. (if (= (length isas) 1) '(for) '(for ifield operand insn hardware)) (cons 'default (list (caar isa-enums))) (cons 'values isa-enums)) ) *UNSPECIFIED* ) ; Return the bitset attr value for all isas. (define (all-isas-attr-value) (current-arch-isa-name-list) ) ; Return an ISA attribute of all isas. ; This is useful for things like f-nil which exist across all isas. (define (all-isas-attr) (bitset-attr-make 'ISA (all-isas-attr-value)) ) ; Return list of ISA names specified by attribute object ATLIST. (define (attr-isa-list atlist) (atlist-attr-value atlist 'ISA #f) ) ; Return list of ISA names specified by OBJ. (define (obj-isa-list obj) (obj-attr-value obj 'ISA) ) ; Return #t if ISA is supported by OBJ. ; This is done by looking for the ISA attribute in OBJ. (define (isa-supports? isa obj) (let ((isas (obj-isa-list obj)) (name (obj:name isa))) (->bool (memq name isas))) ) ; The fetch/decode/execute process. ; "extract" is a fancy word for fetch/decode. ; FIXME: wip, not currently used. ; FIXME: move to inside define-isa, and maybe elsewhere. ; ;(defmacro ; define-extract (code) ; ;(arch-set-insn-extract! CURRENT-ARCH code) ; *UNSPECIFIED* ;) ; ;(defmacro ; define-execute (code) ; ;(arch-set-insn-execute! CURRENT-ARCH code) ; *UNSPECIFIED* ;) ; ISA specification. ; Each architecture is generally one isa, but in the case of ARM (and a few ; others) there is more than one. ; ; ??? "ISA" has a very well defined meaning, and our usage of it one might ; want to quibble over. A better name would be welcome. ; Associated with an instruction set is its framing. ; This refers to how instructions are laid out at the liw level (where several ; insns are framed together and executed sequentially or in parallel). ; ??? If one defines the term "format" as being how an individual instruction ; is laid out then formatting can be thought of as being different from ; framing. However, it's possible for a particular ISA to intertwine the two. ; Thus this will need to evolve. ; ??? Not used yet, wip. (define