📄 mloop.in
字号:
# Simulator main loop for frv. -*- C -*-# Copyright (C) 1998, 1999, 2000, 2001, 2003 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.## 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.# Syntax:# /bin/sh mainloop.in command## Command is one of:## init# support# extract-{simple,scache,pbb}# {full,fast}-exec-{simple,scache,pbb}## A target need only provide a "full" version of one of simple,scache,pbb.# If the target wants it can also provide a fast version of same.# It can't provide more than this.# ??? After a few more ports are done, revisit.# Will eventually need to machine generate a lot of this.case "x$1" inxsupport)cat <<EOFstatic INLINE const IDESC *extract (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, ARGBUF *abuf, int fast_p){ const IDESC *id = @cpu@_decode (current_cpu, pc, insn, insn, abuf); @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p); if (! fast_p) { int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc); int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc); @cpu@_fill_argbuf_tp (current_cpu, abuf, trace_p, profile_p); } return id;}static INLINE SEM_PCexecute (SIM_CPU *current_cpu, SCACHE *sc, int fast_p){ SEM_PC vpc; /* Force gr0 to zero before every insn. */ @cpu@_h_gr_set (current_cpu, 0, 0); if (fast_p) { vpc = (*sc->argbuf.semantic.sem_fast) (current_cpu, sc); } else { ARGBUF *abuf = &sc->argbuf; const IDESC *idesc = abuf->idesc;#if WITH_SCACHE_PBB int virtual_p = CGEN_ATTR_VALUE (NULL, idesc->attrs, CGEN_INSN_VIRTUAL);#else int virtual_p = 0;#endif if (! virtual_p) { /* FIXME: call x-before */ if (ARGBUF_PROFILE_P (abuf)) PROFILE_COUNT_INSN (current_cpu, abuf->addr, idesc->num); /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */ if (FRV_COUNT_CYCLES (current_cpu, ARGBUF_PROFILE_P (abuf))) { @cpu@_model_insn_before (current_cpu, sc->first_insn_p); model_insn = FRV_INSN_MODEL_PASS_1; if (idesc->timing->model_fn != NULL) (*idesc->timing->model_fn) (current_cpu, sc); } else model_insn = FRV_INSN_NO_MODELING; TRACE_INSN_INIT (current_cpu, abuf, 1); TRACE_INSN (current_cpu, idesc->idata, (const struct argbuf *) abuf, abuf->addr); }#if WITH_SCACHE vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, sc);#else vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, abuf);#endif if (! virtual_p) { /* FIXME: call x-after */ if (FRV_COUNT_CYCLES (current_cpu, ARGBUF_PROFILE_P (abuf))) { int cycles; if (idesc->timing->model_fn != NULL) { model_insn = FRV_INSN_MODEL_PASS_2; cycles = (*idesc->timing->model_fn) (current_cpu, sc); } else cycles = 1; @cpu@_model_insn_after (current_cpu, sc->last_insn_p, cycles); } TRACE_INSN_FINI (current_cpu, abuf, 1); } } return vpc;}static void@cpu@_parallel_write_init (SIM_CPU *current_cpu){ CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (current_cpu); CGEN_WRITE_QUEUE_CLEAR (q); previous_vliw_pc = CPU_PC_GET(current_cpu); frv_interrupt_state.f_ne_flags[0] = 0; frv_interrupt_state.f_ne_flags[1] = 0; frv_interrupt_state.imprecise_interrupt = NULL;}static void@cpu@_parallel_write_queued (SIM_CPU *current_cpu){ int i; FRV_VLIW *vliw = CPU_VLIW (current_cpu); CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (current_cpu); /* Loop over the queued writes, executing them. Set the pc to the address of the insn which queued each write for the proper context in case an interrupt is caused. Restore the proper pc after the writes are completed. */ IADDR save_pc = CPU_PC_GET (current_cpu); IADDR new_pc = save_pc; int branch_taken = 0; int limit = CGEN_WRITE_QUEUE_INDEX (q); frv_interrupt_state.data_written.length = 0; for (i = 0; i < limit; ++i) { CGEN_WRITE_QUEUE_ELEMENT *item = CGEN_WRITE_QUEUE_ELEMENT (q, i); /* If an imprecise interrupt was generated, then, check whether the result should still be written. */ if (frv_interrupt_state.imprecise_interrupt != NULL) { /* Only check writes by the insn causing the exception. */ if (CGEN_WRITE_QUEUE_ELEMENT_IADDR (item) == frv_interrupt_state.imprecise_interrupt->vpc) { /* Execute writes of floating point operations resulting in overflow, underflow or inexact. */ if (frv_interrupt_state.imprecise_interrupt->kind == FRV_FP_EXCEPTION) { if ((frv_interrupt_state.imprecise_interrupt ->u.fp_info.fsr_mask & ~(FSR_INEXACT | FSR_OVERFLOW | FSR_UNDERFLOW))) continue; /* Don't execute */ } /* Execute writes marked as 'forced'. */ else if (! (CGEN_WRITE_QUEUE_ELEMENT_FLAGS (item) & FRV_WRITE_QUEUE_FORCE_WRITE)) continue; /* Don't execute */ } } /* Only execute the first branch on the queue. */ if (CGEN_WRITE_QUEUE_ELEMENT_KIND (item) == CGEN_PC_WRITE || CGEN_WRITE_QUEUE_ELEMENT_KIND (item) == CGEN_FN_PC_WRITE) { if (branch_taken) continue; branch_taken = 1; if (CGEN_WRITE_QUEUE_ELEMENT_KIND (item) == CGEN_PC_WRITE) new_pc = item->kinds.pc_write.value; else new_pc = item->kinds.fn_pc_write.value; } CPU_PC_SET (current_cpu, CGEN_WRITE_QUEUE_ELEMENT_IADDR (item)); frv_save_data_written_for_interrupts (current_cpu, item); cgen_write_queue_element_execute (current_cpu, item); } /* Update the LR with the address of the next insn if the flag is set. This flag gets set in frvbf_set_write_next_vliw_to_LR by the JMPL, JMPIL and CALL insns. */ if (frvbf_write_next_vliw_addr_to_LR) { frvbf_h_spr_set_handler (current_cpu, H_SPR_LR, save_pc); frvbf_write_next_vliw_addr_to_LR = 0; } CPU_PC_SET (current_cpu, new_pc); CGEN_WRITE_QUEUE_CLEAR (q);}void@cpu@_perform_writeback (SIM_CPU *current_cpu){ @cpu@_parallel_write_queued (current_cpu);}static unsigned cache_reqno = 0x80000000; /* Start value is for debugging. */#if 0 /* experimental *//* FR400 has single prefetch. */static voidfr400_simulate_insn_prefetch (SIM_CPU *current_cpu, IADDR vpc){ int cur_ix; FRV_CACHE *cache;/* The cpu receives 8 bytes worth of insn data for each fetch aligned on 8 byte boundary. */#define FR400_FETCH_SIZE 8 cur_ix = LS; vpc &= ~(FR400_FETCH_SIZE - 1); cache = CPU_INSN_CACHE (current_cpu); /* Request a load of the current address buffer, if necessary. */ if (frv_insn_fetch_buffer[cur_ix].address != vpc) { frv_insn_fetch_buffer[cur_ix].address = vpc; frv_insn_fetch_buffer[cur_ix].reqno = cache_reqno++; if (FRV_COUNT_CYCLES (current_cpu, 1)) frv_cache_request_load (cache, frv_insn_fetch_buffer[cur_ix].reqno, frv_insn_fetch_buffer[cur_ix].address, UNIT_I0 + cur_ix); } /* Wait for the current address buffer to be loaded, if necessary. */ if (FRV_COUNT_CYCLES (current_cpu, 1)) { FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (current_cpu); int wait; /* Account for any branch penalty. */ if (ps->branch_penalty > 0 && ! ps->past_first_p) { frv_model_advance_cycles (current_cpu, ps->branch_penalty); frv_model_trace_wait_cycles (current_cpu, ps->branch_penalty,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -