URL
https://opencores.org/ocsvn/scarts/scarts/trunk
Subversion Repositories scarts
[/] [scarts/] [trunk/] [toolchain/] [scarts-binutils/] [binutils-2.19.1/] [cgen/] [sim-cpu.scm] - Rev 6
Compare with Previous | Blame | View Log
; CPU family related simulator generator, excluding decoding and model support. ; Copyright (C) 2000, 2001, 2009 Red Hat, Inc. ; This file is part of CGEN. ; Notes: ; - Add support to generate copies of semantic code and perform constant ; folding based on selected mach. This would collapse out untaken branches ; of tests on (current-mach). ; Utilities of cgen-cpu.h. ; Print various parameters of the cpu family. ; A "cpu family" here is a collection of variants of a particular architecture ; that share sufficient commonality that they can be handled together. "\ /* Maximum number of instructions that are fetched at a time. This is for LIW type instructions sets (e.g. m32r). */ #define MAX_LIW_INSNS ""\n\ /* Maximum number of instructions that can be executed in parallel. */ #define MAX_PARALLEL_INSNS ""\n\n"; (gen-enum-decl '@cpu@_virtual ; "@cpu@ virtual insns" ; "@ARCH@_INSN_" ; not @CPU@ to match CGEN_INSN_TYPE in opc.h ; '((x-invalid 0) ; (x-before -1) (x-after -2) ; (x-begin -3) (x-chain -4) (x-cti-chain -5))) ; Return a boolean indicating if hardware element HW needs storage allocated ; for it in the SIM_CPU struct. ; Subroutine of -gen-hardware-types to generate the struct containing ; hardware elements of one isa. ; If struct is empty, leave it out to simplify generated code. ""; Return C type declarations of all of the hardware elements. ; The name of the type is prepended with the cpu family name. "/* CPU state information. */\n""typedef struct {\n"" /* Hardware elements. */\n"" struct {\n"" } hardware;\n""#define CPU_CGEN_HW(cpu) (& (cpu)->cpu_data.hardware)\n";" /* CPU profiling state information. */\n" ;" struct {\n" ;(string-list-map (lambda (hw) (send hw 'gen-profile-decl)) ; (find hw-profilable? (current-hw-list))) ;" } profile;\n" ;"#define CPU_CGEN_PROFILE(cpu) (& (cpu)->cpu_data.profile)\n" "} @CPU@_CPU_DATA;\n\n"; If there are any virtual regs, output get/set macros for them. """/* Virtual regs. */\n\n""Generating get/set for "" ...\n""\n"; Return the declaration of register access functions. "/* Cover fns for register access. */\n""@cpu@""\n""/* These must be hand-written. */\n""extern CPUREG_FETCH_FN @cpu@_fetch_register;\n""extern CPUREG_STORE_FN @cpu@_store_register;\n""\n"; Generate type of struct holding model state while executing. "Generating model decls ...\n""typedef struct {\n"" int empty;\n"; ensure struct isn't empty so it compiles " "" "";\n""} MODEL_""_DATA;\n\n"; Utility of -gen-extract-macros to generate a macro to define the local ; vars to contain extracted field values and the code to assign them ; for <iformat> IFMT. "Processing format "" ...\n"""""; We don't need an extra blank line here as gen-extract-ifields adds one. ; Generate macros to extract instruction fields. "Generating extraction macros ...\n""\ /* Macros to simplify extraction, reading and semantic code. These define and assign the local vars that contain the insn's fields. */ \n"; Utility of -gen-parallel-exec-type to generate the definition of one ; structure in PAREXEC. ; SFMT is an <sformat> object. " struct { /* "" */\n"" int empty;\n"; ensure struct isn't empty so it compiles "Processing operand "" of format "" ...\n"" "" "";\n"" "" ""_idx;\n"""" "" "";\n"" } "";\n"; Generate the definition of the structure that holds register values, etc. ; for use during parallel execution. When instructions are executed parallelly ; either ; - their inputs are read before their outputs are written. Thus we have to ; fetch the input values of several instructions before executing any of them. ; - or their outputs are queued here first and then written out after all insns ; have executed. ; The fetched/queued values are stored in an array of PAREXEC structs, one ; element per instruction. "Generating PAREXEC type ...\n""/* Queued output values of an instruction. */\n""/* Fetched input values of an instruction. */\n""\ struct parexec { union {\n""\ } operands; /* For conditionally written operands, bitmask of which ones were. */ int written; };\n\n"; Generate the TRACE_RECORD struct definition. ; This struct will hold all necessary data for doing tracing and profiling ; (e.g. register numbers). The goal is to remove all tracing code from the ; semantic code. Then the fast/full distinction needn't use conditionals to ; discard/include the tracing/profiling code. "\ /* Collection of various things for the trace handler to use. */ typedef struct trace_record { IADDR pc; /* FIXME:wip */ } TRACE_RECORD; \n"; Utilities of cgen-cpu.c ; Get/set fns for every register. "@cpu@"" return GET_"" (""""regno"");\n"" return CPU (""""[regno]"");\n"" SET_"" (""""regno, ""newval);\n"" CPU (""""[regno]"") = newval;\n"; Generate a function to record trace results in a trace record. "\ /* Record trace results for INSN. */ void @cpu@_record_trace_results (SIM_CPU *current_cpu, CGEN_INSN *insn, int *indices, TRACE_RECORD *tr) {\n""}\n"; Utilities of cgen-read.c. ; Parallel-read support is not currently used by any port and this code ; has been left to bitrot. Don't delete it just yet. ; Return C code to fetch and save all input operands to instructions with ; <sformat> SFMT. ; Utility of -gen-read-switch to generate a switch case for <sformat> SFMT. "Processing read switch case for \"""\" ...\n"" CASE (read, READ_"") : ""/* "" */\n"" {\n"" "" "" }\n"" BREAK (read);\n\n"; Generate the guts of a C switch statement to read insn operands. ; The switch is based on instruction formats. "Processing readers ...\n"; Utilities of cgen-write.c. ; This is the other way of implementing parallel execution support. ; Instead of fetching all the input operands first, write all the output ; operands and their addresses to holding variables, and then run a ; post-processing pass to update the cpu state. ; ; There are separate implementations for semantics as functions and semantics ; as one big switch. For the function case we create a function that is a ; switch on each semantic format and loops writing each insn's results back. ; For the switch case we add cases to the switch to handle the write back, ; and it is up to the pbb compiler to include them in the generated "code". ; Return C code to fetch and save all output operands to instructions with ; <sformat> SFMT. ; Utility of gen-write-switch to generate a switch case for <sformat> SFMT. ; If INSN is non-#f, it is the <insn> object of the insn in which case ; the case is named after the insn not the format. This is done because ; current sem-switch support emits one handler per insn instead of per sfmt. "Processing write switch case for \"""\" ...\n""CASE (sem, INSN_WRITE_"") : ""case @CPU@_"" : ""/* "" */\n"" {\n"" SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);\n"" const ARGBUF *abuf = SEM_ARGBUF (sem_arg)->fields.write.abuf;\n"""" int UNUSED written = abuf->written;\n";(gen-define-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) " " #f) - used by cgen-read.c ;(gen-extract-ifields (sfmt-iflds sfmt) (sfmt-length sfmt) " " #f) - used by cgen-read.c " IADDR UNUSED pc = abuf->addr;\n"""" SEM_BRANCH_INIT\n"; no trailing `;' on purpose """ vpc = SEM_NEXT_VPC (sem_arg, pc, 0);\n""""\n""\n"" SEM_BRANCH_FINI (vpc);\n"""" }\n"" NEXT (vpc);\n"" break;\n""\n"; Generate the guts of a C switch statement to write insn operands. ; The switch is based on instruction formats. ; ??? This will generate cases for formats that don't need it. ; E.g. on the m32r all 32 bit insns can't be executed in parallel. ; It's easier to generate the code anyway so we do. "Processing writers ...\n"; Utilities of cgen-semantics.c. ; Return name of semantic fn for INSN. ;(string-append "sem_" (gen-sym insn)) ; Return semantic fn table entry for INSN. " { ""@PREFIX@_INSN_"", ""SEM_FN_NAME (@prefix@,"")"" },\n"; Return C code to define a table of all semantic fns and a function to ; add the info to the insn descriptor table. "\ /* Table of all semantic fns. */ static const struct sem_fn_desc sem_fns[] = {\n""\ { 0, 0 } }; /* Add the semantic fns to IDESC_TABLE. */ void SEM_FN_NAME (@prefix@,init_idesc_table) (SIM_CPU *current_cpu) { IDESC *idesc_table = CPU_IDESC (current_cpu); const struct sem_fn_desc *sf; int mach_num = MACH_NUM (CPU_MACH (current_cpu)); for (sf = &sem_fns[0]; sf->fn != 0; ++sf) { const CGEN_INSN *insn = idesc_table[sf->index].idata; int valid_p = (CGEN_INSN_VIRTUAL_P (insn) || CGEN_INSN_MACH_HAS_P (insn, mach_num)); #if FAST_P if (valid_p) idesc_table[sf->index].sem_fast = sf->fn; else idesc_table[sf->index].sem_fast = SEM_FN_NAME (@prefix@,x_invalid); #else if (valid_p) idesc_table[sf->index].sem_full = sf->fn; else idesc_table[sf->index].sem_full = SEM_FN_NAME (@prefix@,x_invalid); #endif } } \n"; Return C code to perform the semantics of INSN. " ""\n"""; Indicate generating code for INSN. ; Use the compiled form if available. ; The case when they're not available is for virtual insns. ; Return definition of C function to perform INSN. ; This version handles the with-scache case. "Processing semantics for "": \"""\" ...\n""/* "": "" */\n\n""static SEM_PC\n""SEM_FN_NAME (@prefix@,"")"" (SIM_CPU *current_cpu, SEM_ARG sem_arg, PAREXEC *par_exec)\n"" (SIM_CPU *current_cpu, SEM_ARG sem_arg)\n""{\n"""" ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"; Unconditionally written operands are not recorded here. " int UNUSED written = 0;\n"; The address of this insn, needed by extraction and semantic code. ; Note that the address recorded in the cpu state struct is not used. ; For faster engines that copy will be out of date. " IADDR UNUSED pc = abuf->addr;\n"" SEM_BRANCH_INIT\n"; no trailing `;' on purpose """ SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, "");\n""\n""\n"; Only update what's been written if some are conditionally written. ; Otherwise we know they're all written so there's no point in ; keeping track. " abuf->written = written;\n"""" SEM_BRANCH_FINI (vpc);\n"""" return vpc;\n""""}\n\n"; Return definition of C function to perform INSN. ; This version handles the without-scache case. ; ??? TODO: multiword insns. "Processing semantics for "": \"""\" ...\n""/* "": "" */\n\n""static SEM_STATUS\n""SEM_FN_NAME (@prefix@,"")"" (SIM_CPU *current_cpu, SEM_ARG sem_arg, PAREXEC *par_exec, CGEN_INSN_INT insn)\n"" (SIM_CPU *current_cpu, SEM_ARG sem_arg, CGEN_INSN_INT insn)\n""{\n"""" SEM_STATUS status = 0;\n"; ??? wip " ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"; Unconditionally written operands are not recorded here. " int UNUSED written = 0;\n"" IADDR UNUSED pc = GET_H_PC ();\n"" SEM_BRANCH_INIT\n"; no trailing `;' on purpose """ SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, "");\n"" "" ""\n""\n"; Only update what's been written if some are conditionally written. ; Otherwise we know they're all written so there's no point in ; keeping track. " abuf->written = written;\n"""; SEM_{,N}BRANCH_FINI are user-supplied macros. " SEM_BRANCH_FINI (vpc, "" SEM_NBRANCH_FINI (vpc, "");\n"""" return status;\n""""}\n\n""Processing semantics ...\n"; Utility of -gen-sem-case to return the mask of operands always written ; to in <sformat> SFMT. ; ??? Not currently used. ; Utility of -gen-sem-case to return #t if any operand in <sformat> SFMT is ; conditionally written to. ; Generate a switch case to perform INSN. "Processing ""parallel """"semantic switch case for \"""\" ...\n"; INSN_ is prepended here and not elsewhere to avoid name collisions ; with symbols like AND, etc. " CASE (sem, ""INSN_""PAR_"""") : ""/* "" */\n""{\n"" SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);\n"" ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n"""; Unconditionally written operands are not recorded here. " int UNUSED written = 0;\n"; The address of this insn, needed by extraction and semantic code. ; Note that the address recorded in the cpu state struct is not used. " IADDR UNUSED pc = abuf->addr;\n"" SEM_BRANCH_INIT\n"; no trailing `;' on purpose """"" "" ""\n"" vpc = SEM_NEXT_VPC (sem_arg, pc, "");\n""\n""\n"; Only update what's been written if some are conditionally written. ; Otherwise we know they're all written so there's no point in ; keeping track. " abuf->written = written;\n"""" SEM_BRANCH_FINI (vpc);\n""""""}\n"" NEXT (vpc);\n\n""Processing semantic switch ...\n"; Turn parallel execution support off. ; Generate the guts of a C switch statement to execute parallel instructions. ; This switch is included after the non-parallel instructions in the semantic ; switch. ; ; ??? We duplicate the writeback case for each insn, even though we only need ; one case per insn format. The former keeps the code for each insn ; together and might improve cache usage. On the other hand the latter ; reduces the amount of code, though it is believed that in this particular ; instance the win isn't big enough. "Processing parallel insn semantic switch ...\n"; Turn parallel execution support on. ; Top level file generators. ; Generate cpu-<cpu>.h "Generating ""'s cpu.h ...\n"; Turn parallel execution support on if cpu needs it. ; Tell the rtl->c translator we're not the simulator. ; ??? Minimizes changes in generated code until this is changed. ; RTL->C happens for field decoding. "CPU family header for @cpu@.""\ #ifndef CPU_@CPU@_H #define CPU_@CPU@_H """"""#endif /* CPU_@CPU@_H */\n"; Generate defs-<isa>.h. "Generating ""'s defs.h ...\n"; Tell the rtl->c translator we're not the simulator. ; ??? Minimizes changes in generated code until this is changed. ; RTL->C happens for field decoding. "ISA definitions header for "".""\ #ifndef DEFS_@PREFIX@_H #define DEFS_@PREFIX@_H ""#endif /* DEFS_@PREFIX@_H */\n"; Generate cpu-<cpu>.c "Generating ""'s cpu.c ...\n"; Turn parallel execution support on if cpu needs it. ; Initialize rtl generation. "Misc. support for CPU family @cpu@.""\ #define WANT_CPU @cpu@ #define WANT_CPU_@CPU@ #include \"sim-main.h\" #include \"cgen-ops.h\" "; Generate read.c "Generating ""'s read.c ...\n"; Turn parallel execution support off. ; Tell the rtx->c translator we are the simulator. "Simulator instruction operand reader for "".""\ #ifdef DEFINE_LABELS /* The labels have the case they have because the enum of insn types is all uppercase and in the non-stdc case the fmt symbol is built into the enum name. */ static struct { int index; void *label; } labels[] = {\n"" { ""@PREFIX@_INSN_"", && case_read_READ_"" },\n"" { 0, 0 } }; int i; for (i = 0; labels[i].label != 0; ++i) CPU_IDESC (current_cpu) [labels[i].index].read = labels[i].label; #undef DEFINE_LABELS #endif /* DEFINE_LABELS */ #ifdef DEFINE_SWITCH {\n""\ SEM_ARG sem_arg = sc; ARGBUF *abuf = SEM_ARGBUF (sem_arg); SWITCH (read, sem_arg->read)\n""\ SWITCH (read, decode->read)\n""\ { ""\ } ENDSWITCH (read) /* End of read switch. */ } #undef DEFINE_SWITCH #endif /* DEFINE_SWITCH */ "; Generate write.c "Generating ""'s write.c ...\n"; Turn parallel execution support off. ; Tell the rtx->c translator we are the simulator. "Simulator instruction operand writer for "".""\ /* Write cached results of 1 or more insns executed in parallel. */ void @cpu@_parallel_write (SIM_CPU *cpu, SCACHE *sbufs, PAREXEC *pbufs, int ninsns) {\n""\ SEM_ARG sem_arg = sc; ARGBUF *abuf = SEM_ARGBUF (sem_arg);\n""""\ do { ARGBUF *abuf = SEM_ARGBUF (sbufs); switch (abuf->idesc->write) { \n";(/indent-add 8) ;(/indent-add -8) "\ } } while (--ninsns > 0); } "; Generate semantics.c ; Each instruction is implemented in its own function. "Generating ""'s semantics.c ...\n"; Turn parallel execution support on if cpu needs it. ; Tell the rtx->c translator we are the simulator. "Simulator instruction semantics for @cpu@.""\ #define WANT_CPU @cpu@ #define WANT_CPU_@CPU@ #include \"sim-main.h\" #include \"cgen-mem.h\" #include \"cgen-ops.h\" #undef GET_ATTR ""GET_ATTR(cpu, num, attr) \ CGEN_ATTR_VALUE (NULL, abuf->idesc->attrs, CGEN_INSN_""attr)"" /* This is used so that we can compile two copies of the semantic code, one with full feature support and one without that runs fast(er). FAST_P, when desired, is defined on the command line, -DFAST_P=1. */ #if FAST_P #define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_semf_,fn) #undef TRACE_RESULT #define TRACE_RESULT(cpu, abuf, name, type, val) #else #define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_sem_,fn) #endif \n"; Put the table at the end so we don't have to declare all the sem fns. ; Generate sem-switch.c. ; Each instruction is a case in a switch(). ; This file consists of just the switch(). It is included by mainloop.c. "Generating ""'s sem-switch.c ...\n"; Turn parallel execution support off. ; It is later turned on/off when generating the actual semantic code. ; Tell the rtx->c translator we are the simulator. "Simulator instruction semantics for @cpu@.""\ #ifdef DEFINE_LABELS /* The labels have the case they have because the enum of insn types is all uppercase and in the non-stdc case the insn symbol is built into the enum name. */ static struct { int index; void *label; } labels[] = {\n"" { ""@PREFIX@_INSN_"", && case_sem_INSN_"" },\n"" { ""@CPU@_INSN_PAR_"", && case_sem_INSN_PAR_"" },\n"" { ""@CPU@_INSN_WRITE_"", && case_sem_INSN_WRITE_"" },\n"""" { 0, 0 } }; int i; for (i = 0; labels[i].label != 0; ++i) { #if FAST_P CPU_IDESC (current_cpu) [labels[i].index].sem_fast_lab = labels[i].label; #else CPU_IDESC (current_cpu) [labels[i].index].sem_full_lab = labels[i].label; #endif } #undef DEFINE_LABELS #endif /* DEFINE_LABELS */ #ifdef DEFINE_SWITCH /* If hyper-fast [well not unnecessarily slow] execution is selected, turn off frills like tracing and profiling. */ /* FIXME: A better way would be to have TRACE_RESULT check for something that can cause it to be optimized out. Another way would be to emit special handlers into the instruction \"stream\". */ #if FAST_P #undef TRACE_RESULT #define TRACE_RESULT(cpu, abuf, name, type, val) #endif #undef GET_ATTR ""GET_ATTR(cpu, num, attr) \ CGEN_ATTR_VALUE (NULL, abuf->idesc->attrs, CGEN_INSN_""attr)"" { #if WITH_SCACHE_PBB /* Branch to next handler without going around main loop. */ #define NEXT(vpc) goto * SEM_ARGBUF (vpc) -> semantic.sem_case SWITCH (sem, SEM_ARGBUF (vpc) -> semantic.sem_case) #else /* ! WITH_SCACHE_PBB */ #define NEXT(vpc) BREAK (sem) #ifdef __GNUC__ #if FAST_P SWITCH (sem, SEM_ARGBUF (sc) -> idesc->sem_fast_lab) #else SWITCH (sem, SEM_ARGBUF (sc) -> idesc->sem_full_lab) #endif #else SWITCH (sem, SEM_ARGBUF (sc) -> idesc->num) #endif #endif /* ! WITH_SCACHE_PBB */ { """" } ENDSWITCH (sem) /* End of semantic switch. */ /* At this point `vpc' contains the next insn to execute. */ } #undef DEFINE_SWITCH #endif /* DEFINE_SWITCH */ "; Generate mainloop.in. ; ??? Not currently used. "Generating mainloop.in ...\n""cat <<EOF >/dev/null\n""Simulator main loop for @arch@.""EOF\n""\ # Syntax: # /bin/sh mainloop.in init|support|{full,fast}-{extract,exec}-{scache,nocache} # ??? There's lots of conditional compilation here. # After a few more ports are done, revisit. case \"x$1\" in xsupport) cat <<EOF /*xsupport*/ EOF ;; xinit) cat <<EOF /*xinit*/ EOF ;; xfull-extract-* | xfast-extract-*) cat <<EOF { ""} EOF ;; xfull-exec-* | xfast-exec-*) cat <<EOF { ""} EOF ;; *) echo \"Invalid argument to mainloop.in: $1\" >&2 exit 1 ;; esac "