/* frv simulator machine independent profiling code.
- Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1998-2017 Free Software Foundation, Inc.
Contributed by Red Hat
This file is part of the GNU simulators.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define WANT_CPU
#include "profile.h"
#include "profile-fr400.h"
#include "profile-fr500.h"
+#include "profile-fr550.h"
static void
reset_gr_flags (SIM_CPU *cpu, INT gr)
{
SIM_DESC sd = CPU_STATE (cpu);
- if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400)
+ if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400
+ || STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr450)
fr400_reset_gr_flags (cpu, gr);
/* Other machines have no gr flags right now. */
}
reset_fr_flags (SIM_CPU *cpu, INT fr)
{
SIM_DESC sd = CPU_STATE (cpu);
- if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400)
+ if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400
+ || STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr450)
fr400_reset_fr_flags (cpu, fr);
else if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr500)
fr500_reset_fr_flags (cpu, fr);
reset_acc_flags (SIM_CPU *cpu, INT acc)
{
SIM_DESC sd = CPU_STATE (cpu);
- if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400)
+ if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400
+ || STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr450)
fr400_reset_acc_flags (cpu, acc);
/* Other machines have no acc flags right now. */
}
int *fdiv;
int *fsqrt;
int *idiv;
+ int *flt;
+ int *media;
int *ccr;
int *gr = ps->gr_busy;
int *fr = ps->fr_busy;
int *acc = ps->acc_busy;
+ int *spr;
/* This loop handles GR, FR and ACC registers. */
for (i = 0; i < 64; ++i)
{
*ccr -= cycles;
++ccr;
}
+ /* This loop handles SPR registers. */
+ spr = ps->spr_busy;
+ for (i = 0; i < 4096; ++i)
+ {
+ if (*spr <= cycles)
+ *spr = 0;
+ else
+ *spr -= cycles;
+ ++spr;
+ }
/* This loop handles resources. */
idiv = ps->idiv_busy;
fdiv = ps->fdiv_busy;
++fdiv;
++fsqrt;
}
+ /* Float and media units can occur in 4 slots on some machines. */
+ flt = ps->float_busy;
+ media = ps->media_busy;
+ for (i = 0; i < 4; ++i)
+ {
+ *flt = (*flt <= cycles) ? 0 : (*flt - cycles);
+ *media = (*media <= cycles) ? 0 : (*media - cycles);
+ ++flt;
+ ++media;
+ }
}
/* Print information about the wait for the given number of cycles. */
int *gr_lat = ps->gr_latency;
int *fr_lat = ps->fr_latency;
int *acc_lat = ps->acc_latency;
+ int *spr_lat;
int *ccr;
int *gr = ps->gr_busy;
int *fr = ps->fr_busy;
int *acc = ps->acc_busy;
+ int *spr;
/* This loop handles GR, FR and ACC registers. */
for (i = 0; i < 64; ++i)
{
}
++ccr; ++ccr_lat;
}
+ /* This loop handles SPR registers. */
+ spr = ps->spr_busy;
+ spr_lat = ps->spr_latency;
+ for (i = 0; i < 4096; ++i)
+ {
+ if (*spr_lat)
+ {
+ *spr = *spr_lat;
+ *spr_lat = 0;
+ }
+ ++spr; ++spr_lat;
+ }
}
/* Run the caches until all pending cache flushes are complete. */
switch (STATE_ARCHITECTURE (sd)->mach)
{
case bfd_mach_fr400:
+ case bfd_mach_fr450:
fr400_model_insn_before (cpu, first_p);
break;
case bfd_mach_fr500:
fr500_model_insn_before (cpu, first_p);
break;
+ case bfd_mach_fr550:
+ fr550_model_insn_before (cpu, first_p);
+ break;
default:
break;
}
switch (STATE_ARCHITECTURE (sd)->mach)
{
case bfd_mach_fr400:
+ case bfd_mach_fr450:
fr400_model_insn_after (cpu, last_p, cycles);
break;
case bfd_mach_fr500:
fr500_model_insn_after (cpu, last_p, cycles);
break;
+ case bfd_mach_fr550:
+ fr550_model_insn_after (cpu, last_p, cycles);
+ break;
default:
break;
}
/* Top up the post-processing time of the given FR by the given number of
cycles. */
void
+update_FR_ptime (SIM_CPU *cpu, INT out_FR, int cycles)
+{
+ if (out_FR >= 0)
+ {
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ /* If a load is pending on this register, then add the cycles to
+ the post processing time for this register. Otherwise apply it
+ directly to the latency of the register. */
+ if (! load_pending_for_register (cpu, out_FR, 1, REGTYPE_FR))
+ {
+ int *fr = ps->fr_latency;
+ fr[out_FR] += cycles;
+ }
+ else
+ ps->fr_ptime[out_FR] += cycles;
+ }
+}
+
+void
+update_FRdouble_ptime (SIM_CPU *cpu, INT out_FR, int cycles)
+{
+ if (out_FR >= 0)
+ {
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ /* If a load is pending on this register, then add the cycles to
+ the post processing time for this register. Otherwise apply it
+ directly to the latency of the register. */
+ if (! load_pending_for_register (cpu, out_FR, 2, REGTYPE_FR))
+ {
+ int *fr = ps->fr_latency;
+ fr[out_FR] += cycles;
+ if (out_FR < 63)
+ fr[out_FR + 1] += cycles;
+ }
+ else
+ {
+ ps->fr_ptime[out_FR] += cycles;
+ if (out_FR < 63)
+ ps->fr_ptime[out_FR + 1] += cycles;
+ }
+ }
+}
+
+/* Top up the post-processing time of the given ACC by the given number of
+ cycles. */
+void
update_ACC_ptime (SIM_CPU *cpu, INT out_ACC, int cycles)
{
if (out_ACC >= 0)
}
}
+/* Top up the post-processing time of the given SPR by the given number of
+ cycles. */
+void
+update_SPR_ptime (SIM_CPU *cpu, INT out_SPR, int cycles)
+{
+ if (out_SPR >= 0)
+ {
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ /* No load can be pending on this register. Apply the cycles
+ directly to the latency of the register. */
+ int *spr = ps->spr_latency;
+ spr[out_SPR] += cycles;
+ }
+}
+
void
decrease_ACC_busy (SIM_CPU *cpu, INT out_ACC, int cycles)
{
}
}
+void
+increase_ACC_busy (SIM_CPU *cpu, INT out_ACC, int cycles)
+{
+ if (out_ACC >= 0)
+ {
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ int *acc = ps->acc_busy;
+ acc[out_ACC] += cycles;
+ }
+}
+
+void
+enforce_full_acc_latency (SIM_CPU *cpu, INT in_ACC)
+{
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ ps->acc_busy_adjust [in_ACC] = -1;
+}
+
void
decrease_FR_busy (SIM_CPU *cpu, INT out_FR, int cycles)
{
}
}
+/* Top up the latency of the given SPR by the given number of cycles. */
+void
+update_SPR_latency (SIM_CPU *cpu, INT out_SPR, int cycles)
+{
+ if (out_SPR >= 0)
+ {
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ int *spr = ps->spr_latency;
+ if (spr[out_SPR] < cycles)
+ spr[out_SPR] = cycles;
+ }
+}
+
/* Top up the latency of the given integer division resource by the given
number of cycles. */
void
r[in_resource] = cycles;
}
+/* Set the latency of the given resource to the given number of cycles. */
+void
+update_float_resource_latency (SIM_CPU *cpu, INT in_resource, int cycles)
+{
+ /* operate directly on the busy cycles since each resource can only
+ be used once in a VLIW insn. */
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ int *r = ps->float_busy;
+ r[in_resource] = cycles;
+}
+
+void
+update_media_resource_latency (SIM_CPU *cpu, INT in_resource, int cycles)
+{
+ /* operate directly on the busy cycles since each resource can only
+ be used once in a VLIW insn. */
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ int *r = ps->media_busy;
+ r[in_resource] = cycles;
+}
+
/* Set the branch penalty to the given number of cycles. */
void
update_branch_penalty (SIM_CPU *cpu, int cycles)
}
}
+/* Check the availability of the given SPR register and update the number
+ of cycles the current VLIW insn must wait until it is available. */
+void
+vliw_wait_for_SPR (SIM_CPU *cpu, INT in_SPR)
+{
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ int *spr = ps->spr_busy;
+ /* If the latency of the register is greater than the current wait
+ then update the current wait. */
+ if (in_SPR >= 0 && spr[in_SPR] > ps->vliw_wait)
+ {
+ if (TRACE_INSN_P (cpu))
+ sprintf (hazard_name, "Data hazard for spr %d:", in_SPR);
+ ps->vliw_wait = spr[in_SPR];
+ }
+}
+
/* Check the availability of the given integer division resource and update
the number of cycles the current VLIW insn must wait until it is available.
*/
{
if (TRACE_INSN_P (cpu))
{
- sprintf (hazard_name, "Resource hazard for integer division in slot I%d:", in_resource);
+ sprintf (hazard_name, "Resource hazard for floating point division in slot F%d:", in_resource);
}
ps->vliw_wait = r[in_resource];
}
{
if (TRACE_INSN_P (cpu))
{
- sprintf (hazard_name, "Resource hazard for integer division in slot I%d:", in_resource);
+ sprintf (hazard_name, "Resource hazard for square root in slot F%d:", in_resource);
+ }
+ ps->vliw_wait = r[in_resource];
+ }
+}
+
+/* Check the availability of the given float unit resource and update
+ the number of cycles the current VLIW insn must wait until it is available.
+*/
+void
+vliw_wait_for_float_resource (SIM_CPU *cpu, INT in_resource)
+{
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ int *r = ps->float_busy;
+ /* If the latency of the resource is greater than the current wait
+ then update the current wait. */
+ if (r[in_resource] > ps->vliw_wait)
+ {
+ if (TRACE_INSN_P (cpu))
+ {
+ sprintf (hazard_name, "Resource hazard for floating point unit in slot F%d:", in_resource);
+ }
+ ps->vliw_wait = r[in_resource];
+ }
+}
+
+/* Check the availability of the given media unit resource and update
+ the number of cycles the current VLIW insn must wait until it is available.
+*/
+void
+vliw_wait_for_media_resource (SIM_CPU *cpu, INT in_resource)
+{
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ int *r = ps->media_busy;
+ /* If the latency of the resource is greater than the current wait
+ then update the current wait. */
+ if (r[in_resource] > ps->vliw_wait)
+ {
+ if (TRACE_INSN_P (cpu))
+ {
+ sprintf (hazard_name, "Resource hazard for media unit in slot M%d:", in_resource);
}
ps->vliw_wait = r[in_resource];
}
}
}
+int
+post_wait_for_SPR (SIM_CPU *cpu, INT in_SPR)
+{
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ int *spr = ps->spr_busy;
+
+ if (in_SPR >= 0 && spr[in_SPR] > ps->post_wait)
+ {
+ ps->post_wait = spr[in_SPR];
+ if (TRACE_INSN_P (cpu))
+ sprintf (hazard_name, "Data hazard for spr[%d]:", in_SPR);
+ }
+}
+
int
post_wait_for_fdiv (SIM_CPU *cpu, INT slot)
{
}
}
+int
+post_wait_for_float (SIM_CPU *cpu, INT slot)
+{
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ int *flt = ps->float_busy;
+
+ /* Multiple floating point square roots in the same slot need only wait 1
+ extra cycle. */
+ if (flt[slot] > ps->post_wait)
+ {
+ ps->post_wait = flt[slot];
+ if (TRACE_INSN_P (cpu))
+ {
+ sprintf (hazard_name, "Resource hazard for floating point unit in slot F%d:", slot);
+ }
+ }
+}
+
+int
+post_wait_for_media (SIM_CPU *cpu, INT slot)
+{
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu);
+ int *media = ps->media_busy;
+
+ /* Multiple floating point square roots in the same slot need only wait 1
+ extra cycle. */
+ if (media[slot] > ps->post_wait)
+ {
+ ps->post_wait = media[slot];
+ if (TRACE_INSN_P (cpu))
+ {
+ sprintf (hazard_name, "Resource hazard for media unit in slot M%d:", slot);
+ }
+ }
+}
+
/* Print cpu-specific profile information. */
#define COMMAS(n) sim_add_commas (comma_buf, sizeof (comma_buf), (n))
slot_names[] =
{
"none",
- "I0", "I1", "I01", "IALL",
- "FM0", "FM1", "FM01", "FMALL", "FMLOW",
+ "I0", "I1", "I01", "I2", "I3", "IALL",
+ "FM0", "FM1", "FM01", "FM2", "FM3", "FMALL", "FMLOW",
"B0", "B1", "B01",
"C"
};
max_name_len, slot_names[i],
max_val < 10000 ? 5 : 10,
COMMAS (INSNS_IN_SLOT (i)));
- sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH,
+ sim_profile_print_bar (sd, cpu, PROFILE_HISTOGRAM_WIDTH,
INSNS_IN_SLOT (i),
max_val);
sim_io_printf (sd, "\n");