OpenCores
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
"

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.