📄 profile.c
字号:
/* frv simulator machine independent profiling code. Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. Contributed by Red HatThis file is part of the GNU simulators.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public License alongwith this program; if not, write to the Free Software Foundation, Inc.,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#define WANT_CPU#define WANT_CPU_FRVBF#include "sim-main.h"#include "bfd.h"#if WITH_PROFILE_MODEL_P#include "profile.h"#include "profile-fr400.h"#include "profile-fr500.h"#include "profile-fr550.h"static voidreset_gr_flags (SIM_CPU *cpu, INT gr){ SIM_DESC sd = CPU_STATE (cpu); 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. */}static voidreset_fr_flags (SIM_CPU *cpu, INT fr){ SIM_DESC sd = CPU_STATE (cpu); 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);}static voidreset_acc_flags (SIM_CPU *cpu, INT acc){ SIM_DESC sd = CPU_STATE (cpu); 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. */}static voidreset_cc_flags (SIM_CPU *cpu, INT cc){ SIM_DESC sd = CPU_STATE (cpu); if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr500) fr500_reset_cc_flags (cpu, cc); /* Other machines have no cc flags. */}voidset_use_is_gr_complex (SIM_CPU *cpu, INT gr){ if (gr != -1) { FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu); reset_gr_flags (cpu, gr); ps->cur_gr_complex |= (((DI)1) << gr); }}voidset_use_not_gr_complex (SIM_CPU *cpu, INT gr){ if (gr != -1) { FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu); ps->cur_gr_complex &= ~(((DI)1) << gr); }}intuse_is_gr_complex (SIM_CPU *cpu, INT gr){ if (gr != -1) { FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu); return ps->cur_gr_complex & (((DI)1) << gr); } return 0;}/* Globals flag indicates whether this insn is being modeled. */enum FRV_INSN_MODELING model_insn = FRV_INSN_NO_MODELING;/* static buffer for the name of the currently most restrictive hazard. */static char hazard_name[100] = "";/* Print information about the wait applied to an entire VLIW insn. */FRV_INSN_FETCH_BUFFER frv_insn_fetch_buffer[]= { {1, NO_REQNO}, {1, NO_REQNO} /* init with impossible address. */};enum cache_request{ cache_load, cache_invalidate, cache_flush, cache_preload, cache_unlock};/* A queue of load requests from the data cache. Use to keep track of loads which are still pending. *//* TODO -- some of these are mutually exclusive and can use a union. */typedef struct{ FRV_CACHE *cache; unsigned reqno; SI address; int length; int is_signed; int regnum; int cycles; int regtype; int lock; int all; int slot; int active; enum cache_request request;} CACHE_QUEUE_ELEMENT;#define CACHE_QUEUE_SIZE 64 /* TODO -- make queue dynamic */struct{ unsigned reqno; int ix; CACHE_QUEUE_ELEMENT q[CACHE_QUEUE_SIZE];} cache_queue = {0, 0};/* Queue a request for a load from the cache. The load will be queued as 'inactive' and will be requested after the given number of cycles have passed from the point the load is activated. */voidrequest_cache_load (SIM_CPU *cpu, INT regnum, int regtype, int cycles){ CACHE_QUEUE_ELEMENT *q; FRV_VLIW *vliw; int slot; /* For a conditional load which was not executed, CPU_LOAD_LENGTH will be zero. */ if (CPU_LOAD_LENGTH (cpu) == 0) return; if (cache_queue.ix >= CACHE_QUEUE_SIZE) abort (); /* TODO: Make the queue dynamic */ q = & cache_queue.q[cache_queue.ix]; ++cache_queue.ix; q->reqno = cache_queue.reqno++; q->request = cache_load; q->cache = CPU_DATA_CACHE (cpu); q->address = CPU_LOAD_ADDRESS (cpu); q->length = CPU_LOAD_LENGTH (cpu); q->is_signed = CPU_LOAD_SIGNED (cpu); q->regnum = regnum; q->regtype = regtype; q->cycles = cycles; q->active = 0; vliw = CPU_VLIW (cpu); slot = vliw->next_slot - 1; q->slot = (*vliw->current_vliw)[slot]; CPU_LOAD_LENGTH (cpu) = 0;}/* Queue a request to flush the cache. The request will be queued as 'inactive' and will be requested after the given number of cycles have passed from the point the request is activated. */voidrequest_cache_flush (SIM_CPU *cpu, FRV_CACHE *cache, int cycles){ CACHE_QUEUE_ELEMENT *q; FRV_VLIW *vliw; int slot; if (cache_queue.ix >= CACHE_QUEUE_SIZE) abort (); /* TODO: Make the queue dynamic */ q = & cache_queue.q[cache_queue.ix]; ++cache_queue.ix; q->reqno = cache_queue.reqno++; q->request = cache_flush; q->cache = cache; q->address = CPU_LOAD_ADDRESS (cpu); q->all = CPU_PROFILE_STATE (cpu)->all_cache_entries; q->cycles = cycles; q->active = 0; vliw = CPU_VLIW (cpu); slot = vliw->next_slot - 1; q->slot = (*vliw->current_vliw)[slot];}/* Queue a request to invalidate the cache. The request will be queued as 'inactive' and will be requested after the given number of cycles have passed from the point the request is activated. */voidrequest_cache_invalidate (SIM_CPU *cpu, FRV_CACHE *cache, int cycles){ CACHE_QUEUE_ELEMENT *q; FRV_VLIW *vliw; int slot; if (cache_queue.ix >= CACHE_QUEUE_SIZE) abort (); /* TODO: Make the queue dynamic */ q = & cache_queue.q[cache_queue.ix]; ++cache_queue.ix; q->reqno = cache_queue.reqno++; q->request = cache_invalidate; q->cache = cache; q->address = CPU_LOAD_ADDRESS (cpu); q->all = CPU_PROFILE_STATE (cpu)->all_cache_entries; q->cycles = cycles; q->active = 0; vliw = CPU_VLIW (cpu); slot = vliw->next_slot - 1; q->slot = (*vliw->current_vliw)[slot];}/* Queue a request to preload the cache. The request will be queued as 'inactive' and will be requested after the given number of cycles have passed from the point the request is activated. */voidrequest_cache_preload (SIM_CPU *cpu, FRV_CACHE *cache, int cycles){ CACHE_QUEUE_ELEMENT *q; FRV_VLIW *vliw; int slot; if (cache_queue.ix >= CACHE_QUEUE_SIZE) abort (); /* TODO: Make the queue dynamic */ q = & cache_queue.q[cache_queue.ix]; ++cache_queue.ix; q->reqno = cache_queue.reqno++; q->request = cache_preload; q->cache = cache; q->address = CPU_LOAD_ADDRESS (cpu); q->length = CPU_LOAD_LENGTH (cpu); q->lock = CPU_LOAD_LOCK (cpu); q->cycles = cycles; q->active = 0; vliw = CPU_VLIW (cpu); slot = vliw->next_slot - 1; q->slot = (*vliw->current_vliw)[slot]; CPU_LOAD_LENGTH (cpu) = 0;}/* Queue a request to unlock the cache. The request will be queued as 'inactive' and will be requested after the given number of cycles have passed from the point the request is activated. */voidrequest_cache_unlock (SIM_CPU *cpu, FRV_CACHE *cache, int cycles){ CACHE_QUEUE_ELEMENT *q; FRV_VLIW *vliw; int slot; if (cache_queue.ix >= CACHE_QUEUE_SIZE) abort (); /* TODO: Make the queue dynamic */ q = & cache_queue.q[cache_queue.ix]; ++cache_queue.ix; q->reqno = cache_queue.reqno++; q->request = cache_unlock; q->cache = cache; q->address = CPU_LOAD_ADDRESS (cpu); q->cycles = cycles; q->active = 0; vliw = CPU_VLIW (cpu); slot = vliw->next_slot - 1; q->slot = (*vliw->current_vliw)[slot];}static voidsubmit_cache_request (CACHE_QUEUE_ELEMENT *q){ switch (q->request) { case cache_load: frv_cache_request_load (q->cache, q->reqno, q->address, q->slot); break; case cache_flush: frv_cache_request_invalidate (q->cache, q->reqno, q->address, q->slot, q->all, 1/*flush*/); break; case cache_invalidate: frv_cache_request_invalidate (q->cache, q->reqno, q->address, q->slot, q->all, 0/*flush*/); break; case cache_preload: frv_cache_request_preload (q->cache, q->address, q->slot, q->length, q->lock); break; case cache_unlock: frv_cache_request_unlock (q->cache, q->address, q->slot); break; default: abort (); }}/* Activate all inactive load requests. */static voidactivate_cache_requests (SIM_CPU *cpu){ int i; for (i = 0; i < cache_queue.ix; ++i) { CACHE_QUEUE_ELEMENT *q = & cache_queue.q[i]; if (! q->active) { q->active = 1; /* Submit the request now if the cycle count is zero. */ if (q->cycles == 0) submit_cache_request (q); } }}/* Check to see if a load is pending which affects the given register(s). */intload_pending_for_register (SIM_CPU *cpu, int regnum, int words, int regtype){ int i; for (i = 0; i < cache_queue.ix; ++i) { CACHE_QUEUE_ELEMENT *q = & cache_queue.q[i]; /* Must be the same kind of register. */ if (! q->active || q->request != cache_load || q->regtype != regtype) continue; /* If the registers numbers are equal, then we have a match. */ if (q->regnum == regnum) return 1; /* load pending */ /* Check for overlap of a load with a multi-word register. */ if (regnum < q->regnum) { if (regnum + words > q->regnum) return 1; } /* Check for overlap of a multi-word load with the register. */ else { int data_words = (q->length + sizeof (SI) - 1) / sizeof (SI); if (q->regnum + data_words > regnum) return 1; } } return 0; /* no load pending */}/* Check to see if a cache flush pending which affects the given address. */static intflush_pending_for_address (SIM_CPU *cpu, SI address){ int line_mask = ~(CPU_DATA_CACHE (cpu)->line_size - 1); int i; for (i = 0; i < cache_queue.ix; ++i) { CACHE_QUEUE_ELEMENT *q = & cache_queue.q[i]; /* Must be the same kind of request and active. */ if (! q->active || q->request != cache_flush) continue; /* If the addresses are equal, then we have a match. */ if ((q->address & line_mask) == (address & line_mask)) return 1; /* flush pending */ } return 0; /* no flush pending */}static voidremove_cache_queue_element (SIM_CPU *cpu, int i){ /* If we are removing the load of a FR register, then remember which one(s). */ CACHE_QUEUE_ELEMENT q = cache_queue.q[i]; for (--cache_queue.ix; i < cache_queue.ix; ++i) cache_queue.q[i] = cache_queue.q[i + 1]; /* If we removed a load of a FR register, check to see if any other loads of that register is still queued. If not, then apply the queued post processing time of that register to its latency. Also apply 1 extra cycle of latency to the register since it was a floating point load. */ if (q.request == cache_load && q.regtype != REGTYPE_NONE) { FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (cpu); int data_words = (q.length + sizeof (SI) - 1) / sizeof (SI); int j; for (j = 0; j < data_words; ++j) { int regnum = q.regnum + j; if (! load_pending_for_register (cpu, regnum, 1, q.regtype)) { if (q.regtype == REGTYPE_FR) { int *fr = ps->fr_busy; fr[regnum] += 1 + ps->fr_ptime[regnum]; ps->fr_ptime[regnum] = 0; } } } }}/* Copy data from the cache buffer to the target register(s). */static voidcopy_load_data (SIM_CPU *current_cpu, FRV_CACHE *cache, int slot, CACHE_QUEUE_ELEMENT *q){ switch (q->length) { case 1: if (q->regtype == REGTYPE_FR) { if (q->is_signed) { QI value = CACHE_RETURN_DATA (cache, slot, q->address, QI, 1); SET_H_FR (q->regnum, value); } else { UQI value = CACHE_RETURN_DATA (cache, slot, q->address, UQI, 1); SET_H_FR (q->regnum, value); } } else { if (q->is_signed) { QI value = CACHE_RETURN_DATA (cache, slot, q->address, QI, 1); SET_H_GR (q->regnum, value); } else { UQI value = CACHE_RETURN_DATA (cache, slot, q->address, UQI, 1); SET_H_GR (q->regnum, value); } } break; case 2: if (q->regtype == REGTYPE_FR) { if (q->is_signed) { HI value = CACHE_RETURN_DATA (cache, slot, q->address, HI, 2); SET_H_FR (q->regnum, value); } else { UHI value = CACHE_RETURN_DATA (cache, slot, q->address, UHI, 2); SET_H_FR (q->regnum, value); } } else { if (q->is_signed) { HI value = CACHE_RETURN_DATA (cache, slot, q->address, HI, 2); SET_H_GR (q->regnum, value); } else { UHI value = CACHE_RETURN_DATA (cache, slot, q->address, UHI, 2); SET_H_GR (q->regnum, value); } } break; case 4: if (q->regtype == REGTYPE_FR) { SET_H_FR (q->regnum, CACHE_RETURN_DATA (cache, slot, q->address, SF, 4));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -