; Simulator model support, plus misc. things associated with a cpu family. ; Copyright (C) 2000, 2002, 2003, 2006, 2009 Red Hat, Inc. ; This file is part of CGEN. (define (unit:enum u) (gen-c-symbol (string-append "UNIT_" (string-upcase (obj:str-name u)))) ) ; Return C code to define cpu implementation properties. (define (/gen-cpu-imp-properties) (string-list "\ /* The properties of this cpu's implementation. */ static const MACH_IMP_PROPERTIES @cpu@_imp_properties = { sizeof (@cpu@_cpu), #if WITH_SCACHE sizeof (SCACHE) #else 0 #endif };\n\n" ) ) ; Insn modeling support. ; Generate code to profile hardware elements. ; ??? Not currently used. (define (/gen-hw-profile-code) ; Fetch profilable input and output operands of the semantic code. (let ((in-ops (find op-profilable? (sfmt-in-ops (insn-sfmt insn)))) (out-ops (find op-profilable? (sfmt-out-ops (insn-sfmt insn))))) (string-list ; For each operand, record its being get/set. (string-list-map (lambda (op) (send op 'gen-profile-code insn #f)) in-ops) (string-list-map (lambda (op) (send op 'gen-profile-code insn #t)) out-ops) )) ) ; Return decls of hardware element profilers. ; ??? Not currently used. (define (/gen-hw-profile-decls) (string-list "/* Hardware profiling handlers. */\n\n" (string-list-map (lambda (hw) (string-append "extern void @prefix@_model_mark_get_" (gen-sym hw) " (@cpu@_cpu *" (if (hw-scalar? hw) "" ", int") ; FIXME: get index type ");\n" "extern void @prefix@_model_mark_set_" (gen-sym hw) " (@cpu@_cpu *" (if (hw-scalar? hw) "" ", int") ; FIXME: get index type ");\n")) (find hw-profilable? (current-hw-list))) "\n" ) ) ; Return the name of the class representing the given MODEL. (define (gen-model-class-name model) (string-append "@prefix@_" (gen-sym model) "_model") ) ; Return name of profiling handler for MODEL, UNIT. ; Also called by sim.scm. (define (gen-model-unit-fn-name model unit when) (string-append "model_" (gen-sym unit) "_" (symbol->string when)) ) (define (gen-model-unit-fn-decl model unit when) (let ((gen-args (lambda (args) (gen-c-args (map (lambda (arg) (string-append (mode:c-type (mode:lookup (cadr arg))) " /*" (symbol->string (car arg)) "*/")) (find (lambda (arg) ; Indices of scalars not passed. (not (null? (cdr arg)))) args))))) ) (string-append " virtual UINT " (gen-model-unit-fn-name model unit when) " (@cpu@_cpu *cpu, const struct @prefix@_idesc *idesc," " int unit_num" (if (equal? when 'after) ", unsigned long long referenced" "") (gen-args (unit:inputs unit)) (gen-args (unit:outputs unit)) ")\n")) ) ; Return decls of all insn model handlers. (define (gen-model-fn-decls model) (string-list "\n" "// Function unit handlers\n" "// To be overridden as needed.\n" (string-list-map (lambda (unit) (string-append (gen-model-unit-fn-decl model unit 'before) " {\n" " return 0;\n" " }\n" (gen-model-unit-fn-decl model unit 'after) " {\n" " return timing[idesc->sem_index].units[unit_num].done;\n" " }\n")) (model:units model)) ) ) ; Return name of profile handler for INSN, MODEL. (define (/gen-model-insn-fn-name model insn when) (string-append "model_" (gen-sym insn) "_" (symbol->string when)) ) (define (/gen-model-insn-qualified-fn-name model insn when) (string-append (gen-model-class-name model) "::" (/gen-model-insn-fn-name model insn when)) ) ; Return declaration of function to model INSN. (define (/gen-model-insn-fn-decl model insn when) (string-list "UINT " (/gen-model-insn-fn-name model insn when) " (@cpu@_cpu *current_cpu, @prefix@_scache *sem);\n" ) ) (define (/gen-model-insn-fn-decls model) (string-list " // These methods call the appropriate unit modeller(s) for each insn.\n" (string-list-map (lambda (insn) (string-list " " (/gen-model-insn-fn-decl model insn 'before) " " (/gen-model-insn-fn-decl model insn 'after))) (real-insns (current-insn-list))) ) ) ; Return function to model INSN. (define (/gen-model-insn-fn model insn when) (logit 2 "Processing modeling for " (obj:name insn) ": \"" (insn-syntax insn) "\" ...\n") (let ((sfmt (insn-sfmt insn))) (string-list "UINT\n" (/gen-model-insn-qualified-fn-name model insn when) " (@cpu@_cpu *current_cpu, @prefix@_scache *sem)\n" "{\n" (if (with-scache?) (gen-define-field-macro sfmt) "") " const @prefix@_scache* abuf = sem;\n" " const @prefix@_idesc* idesc = abuf->idesc;\n" ; or: idesc = & CPU_IDESC (current_cpu) [" ; (gen-cpu-insn-enum (mach-cpu (model:mach model)) insn) ; "];\n" " int cycles = 0;\n" (send insn 'gen-profile-locals model) (if (with-scache?) "" (string-list " PCADDR UNUSED pc = current_cpu->hardware.h_pc;\n" " @prefix@_insn_word insn = abuf->insn;\n" (gen-define-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) " " #f) (gen-sfmt-argvars-defns sfmt) (gen-extract-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) " " #f) (gen-sfmt-argvars-assigns sfmt))) ; Emit code to model the insn. Function units are handled here. (send insn 'gen-profile-code model when "cycles") " return cycles;\n" (if (with-scache?) (gen-undef-field-macro sfmt) "") "}\n\n")) ) ; Return insn modeling handlers. ; ??? Might wish to reduce the amount of output by combining identical cases. ; ??? Modelling of insns could be table driven, but that puts constraints on ; generality. (define (/gen-model-insn-fns) (string-write "/* Model handlers for each insn. */\n\n" (lambda () (string-write-map (lambda (model) (string-write ; Generate the model constructor. (gen-model-class-name model) "::" (gen-model-class-name model) " (@cpu@_cpu *cpu)\n" " : cgen_model (cpu)\n" "{\n" "}\n" "\n") (string-write-map (lambda (insn) (string-list (/gen-model-insn-fn model insn 'before) (/gen-model-insn-fn model insn 'after))) (real-insns (current-insn-list)))) (current-model-list))) ) ) (define (/gen-model-class-decls model) (string-append "\n" " " (gen-enum-decl 'unit_number "unit types" "UNIT_" (cons '(none) (append ; "apply append" squeezes out nils. (apply append (list ; create - for each unit (let ((units (model:units model))) (if (null? units) nil (map (lambda (unit) (cons (obj:name unit) (cons '- (atlist-attrs (obj-atlist model))))) units))))) '((max))))) " struct unit {\n" " unit_number unit;\n" " UINT issue;\n" " UINT done;\n" " };\n\n" ; FIXME: revisit MAX_UNITS " static const int MAX_UNITS = " (number->string (let ((insn-list (real-insns (current-insn-list)))) (if (null? insn-list) 1 (apply max (map (lambda (lengths) (apply max lengths)) (map (lambda (insn) (let ((timing (insn-timing insn))) (if (null? timing) '(1) (map (lambda (insn-timing) (if (null? (cdr insn-timing)) '1 (length (timing:units (cdr insn-timing))))) timing)))) insn-list)))))) ";\n" ) ) ; Return the C++ class representing the given model. (define (gen-model-class model) (string-list "\ class " (gen-model-class-name model) " : public cgen_model { public: " (gen-model-class-name model) " (@cpu@_cpu *cpu); // Call the proper unit modelling function for the given insn. UINT model_before (@cpu@_cpu *current_cpu, @prefix@_scache* sem) { return (this->*(timing[sem->idesc->sem_index].model_before)) (current_cpu, sem); } UINT model_after (@cpu@_cpu *current_cpu, @prefix@_scache* sem) { return (this->*(timing[sem->idesc->sem_index].model_after)) (current_cpu, sem); } " (gen-model-fn-decls model) "\ protected: " (/gen-model-insn-fn-decls model) (/gen-model-class-decls model) "\ typedef UINT (" (gen-model-class-name model) "::*model_function) (@cpu@_cpu* current_cpu, @prefix@_scache* sem); struct insn_timing { // This is an integer that identifies this insn. UINT num; // Functions to handle insn-specific profiling. model_function model_before; model_function model_after; // Array of function units used by this insn. unit units[MAX_UNITS]; }; static const insn_timing timing[]; }; " ) ) ; Return the C++ classes representing the current list of models. (define (gen-model-classes) (string-list-map (lambda (model) (string-list "\n" (gen-model-class model))) (current-model-list)) ) ; Generate timing table entry for function unit U while executing INSN. ; U is a object. ; ARGS is a list of overriding arguments from INSN. (define (/gen-insn-unit-timing model insn u args) (string-append "{ " (gen-model-class-name model) "::" (unit:enum u) ", " (number->string (unit:issue u)) ", " (let ((cycles (assq-ref args 'cycles))) (if cycles (number->string (car cycles)) (number->string (unit:done u)))) " }, " ) ) ; Generate timing table entry for MODEL for INSN. (define (/gen-insn-timing model insn) ; Instruction timing is stored as an associative list based on the model. (let ((timing (assq (obj:name model) (insn-timing insn)))) ;(display timing) (newline) (string-list " { " (gen-cpu-insn-enum (mach-cpu (model:mach model)) insn) ", " (if (obj-has-attr? insn 'VIRTUAL) "0, 0" (string-append "& " (/gen-model-insn-qualified-fn-name model insn 'before) ", " "& " (/gen-model-insn-qualified-fn-name model insn 'after))) ", { " (string-drop -2 (if (not timing) (/gen-insn-unit-timing model insn (model-default-unit model) nil) (let ((units (timing:units (cdr timing)))) (string-map (lambda (iunit) (/gen-insn-unit-timing model insn (iunit:unit iunit) (iunit:args iunit))) units)))) " } },\n" )) ) ; Generate model timing table for MODEL. (define (/gen-model-timing-table model) (string-write "/* Model timing data for `" (obj:name model) "'. */\n\n" "const " (gen-model-class-name model) "::insn_timing " (gen-model-class-name model) "::timing[] = {\n" (lambda () (string-write-map (lambda (insn) (/gen-insn-timing model insn)) (non-multi-insns (non-alias-insns (current-insn-list))))) "};\n\n" ) ) ; Return C code to define model profiling support stuff. (define (/gen-model-profile-data) (string-write "/* We assume UNIT_NONE == 0 because the tables don't always terminate\n" " entries with it. */\n\n" (lambda () (string-write-map /gen-model-timing-table (current-model-list))) ) ) ; Return C code to define the model table for MACH. (define (/gen-mach-model-table mach) (string-list "\ static const MODEL " (gen-sym mach) "_models[] =\n{\n" (string-list-map (lambda (model) (string-list " { " "\"" (obj:name model) "\", " "& " (gen-sym (model:mach model)) "_mach, " (model:enum model) ", " "TIMING_DATA (& " (gen-sym model) "_timing[0]), " (gen-sym model) "_model_init" " },\n")) (find (lambda (model) (eq? (obj:name mach) (obj:name (model:mach model)))) (current-model-list))) " { 0 }\n" "};\n\n" ) ) ; Return C code to define model init fn. (define (/gen-model-init-fn model) (string-list "\ static void\n" (gen-sym model) "_model_init (@cpu@_cpu *cpu) { cpu->model_data = new @PREFIX@_MODEL_DATA; }\n\n" ) ) ; Return C code to define model data and support fns. (define (/gen-model-defns) (string-write (lambda () (string-write-map /gen-model-init-fn (current-model-list))) "#if WITH_PROFILE_MODEL_P #define TIMING_DATA(td) td #else #define TIMING_DATA(td) 0 #endif\n\n" (lambda () (string-write-map /gen-mach-model-table (current-mach-list))) ) ) ; Return C definitions for this cpu family variant. (define (/gen-cpu-defns) "" ) ; Return C code to define the machine data. (define (/gen-mach-defns) (string-list-map (lambda (mach) (gen-obj-sanitize mach (string-list "\ static void\n" (gen-sym mach) "_init_cpu (@cpu@_cpu *cpu) { @prefix@_init_idesc_table (cpu); } const MACH " (gen-sym mach) "_mach = { \"" (obj:name mach) "\", " "\"" (mach-bfd-name mach) "\", " (number->string (cpu-word-bitsize (mach-cpu mach))) ", " ; FIXME: addr-bitsize: delete (number->string (cpu-word-bitsize (mach-cpu mach))) ", " "& " (gen-sym mach) "_models[0], " "& " (gen-sym (mach-cpu mach)) "_imp_properties, " (gen-sym mach) "_init_cpu }; "))) (current-mach-list)) ) ; Top level file generators. ; Generate model.cxx (define (cgen-model.cxx) (logit 1 "Generating " (gen-cpu-name) "-model.cxx ...\n") (assert-keep-one) ; Turn parallel execution support on if cpu needs it. (set-with-parallel?! (state-parallel-exec?)) (string-write (gen-c-copyright "Simulator model support for @prefix@." copyright-red-hat package-red-hat-simulators) "\ #if HAVE_CONFIG_H #include \"config.h\" #endif #include \"@cpu@.h\" using namespace @cpu@; // FIXME: namespace organization still wip /* The profiling data is recorded here, but is accessed via the profiling mechanism. After all, this is information for profiling. */ " /gen-model-insn-fns /gen-model-profile-data ; not adapted for sid yet ; /gen-model-defns ; /gen-cpu-imp-properties ; /gen-cpu-defns ; /gen-mach-defns ) ) (define (cgen-model.h) (logit 1 "Generating " (gen-cpu-name) "-model.h ...\n") (assert-keep-one) (string-write (gen-c-copyright "Simulator model support for @prefix@." copyright-red-hat package-red-hat-simulators) "\ #ifndef @PREFIX@_MODEL_H #define @PREFIX@_MODEL_H #include \"cgen-cpu.h\" #include \"cgen-model.h\" namespace @cpu@ { using namespace cgen; " (gen-model-classes) "\ } // namespace @cpu@ #endif // @PREFIX@_MODEL_H " ) )