xref: /netbsd/external/gpl3/gdb/dist/sim/frv/mloop.in (revision 1424dfb3)
166e63ce3Schristos# Simulator main loop for frv. -*- C -*-
2*1424dfb3Schristos# Copyright (C) 1998-2020 Free Software Foundation, Inc.
366e63ce3Schristos# Contributed by Red Hat.
466e63ce3Schristos#
566e63ce3Schristos# This file is part of the GNU Simulators.
666e63ce3Schristos#
766e63ce3Schristos# This program is free software; you can redistribute it and/or modify
866e63ce3Schristos# it under the terms of the GNU General Public License as published by
966e63ce3Schristos# the Free Software Foundation; either version 3 of the License, or
1066e63ce3Schristos# (at your option) any later version.
1166e63ce3Schristos#
1266e63ce3Schristos# This program is distributed in the hope that it will be useful,
1366e63ce3Schristos# but WITHOUT ANY WARRANTY; without even the implied warranty of
1466e63ce3Schristos# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1566e63ce3Schristos# GNU General Public License for more details.
1666e63ce3Schristos#
1766e63ce3Schristos# You should have received a copy of the GNU General Public License
1866e63ce3Schristos# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1966e63ce3Schristos
2066e63ce3Schristos# Syntax:
2166e63ce3Schristos# /bin/sh mainloop.in command
2266e63ce3Schristos#
2366e63ce3Schristos# Command is one of:
2466e63ce3Schristos#
2566e63ce3Schristos# init
2666e63ce3Schristos# support
2766e63ce3Schristos# extract-{simple,scache,pbb}
2866e63ce3Schristos# {full,fast}-exec-{simple,scache,pbb}
2966e63ce3Schristos#
3066e63ce3Schristos# A target need only provide a "full" version of one of simple,scache,pbb.
3166e63ce3Schristos# If the target wants it can also provide a fast version of same.
3266e63ce3Schristos# It can't provide more than this.
3366e63ce3Schristos
3466e63ce3Schristos# ??? After a few more ports are done, revisit.
3566e63ce3Schristos# Will eventually need to machine generate a lot of this.
3666e63ce3Schristos
3766e63ce3Schristoscase "x$1" in
3866e63ce3Schristos
3966e63ce3Schristosxsupport)
4066e63ce3Schristos
4166e63ce3Schristoscat <<EOF
4266e63ce3Schristos
4366e63ce3Schristosstatic INLINE const IDESC *
4466e63ce3Schristosextract (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, ARGBUF *abuf,
4566e63ce3Schristos         int fast_p)
4666e63ce3Schristos{
4766e63ce3Schristos  const IDESC *id = @cpu@_decode (current_cpu, pc, insn, insn, abuf);
4866e63ce3Schristos  @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
4966e63ce3Schristos  if (! fast_p)
5066e63ce3Schristos    {
5166e63ce3Schristos      int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
5266e63ce3Schristos      int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
5366e63ce3Schristos      @cpu@_fill_argbuf_tp (current_cpu, abuf, trace_p, profile_p);
5466e63ce3Schristos    }
5566e63ce3Schristos  return id;
5666e63ce3Schristos}
5766e63ce3Schristos
5866e63ce3Schristosstatic INLINE SEM_PC
5966e63ce3Schristosexecute (SIM_CPU *current_cpu, SCACHE *sc, int fast_p)
6066e63ce3Schristos{
6166e63ce3Schristos  SEM_PC vpc;
6266e63ce3Schristos
6366e63ce3Schristos  /* Force gr0 to zero before every insn.  */
6466e63ce3Schristos  @cpu@_h_gr_set (current_cpu, 0, 0);
6566e63ce3Schristos
6666e63ce3Schristos  if (fast_p)
6766e63ce3Schristos    {
6866e63ce3Schristos      vpc = (*sc->argbuf.semantic.sem_fast) (current_cpu, sc);
6966e63ce3Schristos    }
7066e63ce3Schristos  else
7166e63ce3Schristos    {
7266e63ce3Schristos      ARGBUF *abuf = &sc->argbuf;
7366e63ce3Schristos      const IDESC *idesc = abuf->idesc;
7466e63ce3Schristos#if WITH_SCACHE_PBB
7566e63ce3Schristos      int virtual_p = CGEN_ATTR_VALUE (NULL, idesc->attrs, CGEN_INSN_VIRTUAL);
7666e63ce3Schristos#else
7766e63ce3Schristos      int virtual_p = 0;
7866e63ce3Schristos#endif
7966e63ce3Schristos
8066e63ce3Schristos      if (! virtual_p)
8166e63ce3Schristos	{
8266e63ce3Schristos	  /* FIXME: call x-before */
8366e63ce3Schristos	  if (ARGBUF_PROFILE_P (abuf))
8466e63ce3Schristos	    PROFILE_COUNT_INSN (current_cpu, abuf->addr, idesc->num);
8566e63ce3Schristos	  /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}.  */
8666e63ce3Schristos	  if (FRV_COUNT_CYCLES (current_cpu, ARGBUF_PROFILE_P (abuf)))
8766e63ce3Schristos	    {
8866e63ce3Schristos	      @cpu@_model_insn_before (current_cpu, sc->first_insn_p);
8966e63ce3Schristos	      model_insn = FRV_INSN_MODEL_PASS_1;
9066e63ce3Schristos	      if (idesc->timing->model_fn != NULL)
9166e63ce3Schristos		(*idesc->timing->model_fn) (current_cpu, sc);
9266e63ce3Schristos	    }
9366e63ce3Schristos	  else
9466e63ce3Schristos	    model_insn = FRV_INSN_NO_MODELING;
95ed6a76a9Schristos	  CGEN_TRACE_INSN_INIT (current_cpu, abuf, 1);
96ed6a76a9Schristos	  CGEN_TRACE_INSN (current_cpu, idesc->idata,
9766e63ce3Schristos		      (const struct argbuf *) abuf, abuf->addr);
9866e63ce3Schristos	}
9966e63ce3Schristos#if WITH_SCACHE
10066e63ce3Schristos      vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, sc);
10166e63ce3Schristos#else
10266e63ce3Schristos      vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, abuf);
10366e63ce3Schristos#endif
10466e63ce3Schristos      if (! virtual_p)
10566e63ce3Schristos	{
10666e63ce3Schristos	  /* FIXME: call x-after */
10766e63ce3Schristos	  if (FRV_COUNT_CYCLES (current_cpu, ARGBUF_PROFILE_P (abuf)))
10866e63ce3Schristos	    {
10966e63ce3Schristos	      int cycles;
11066e63ce3Schristos	      if (idesc->timing->model_fn != NULL)
11166e63ce3Schristos		{
11266e63ce3Schristos		  model_insn = FRV_INSN_MODEL_PASS_2;
11366e63ce3Schristos		  cycles = (*idesc->timing->model_fn) (current_cpu, sc);
11466e63ce3Schristos		}
11566e63ce3Schristos	      else
11666e63ce3Schristos		cycles = 1;
11766e63ce3Schristos	      @cpu@_model_insn_after (current_cpu, sc->last_insn_p, cycles);
11866e63ce3Schristos	    }
119ed6a76a9Schristos	  CGEN_TRACE_INSN_FINI (current_cpu, abuf, 1);
12066e63ce3Schristos	}
12166e63ce3Schristos    }
12266e63ce3Schristos
12366e63ce3Schristos  return vpc;
12466e63ce3Schristos}
12566e63ce3Schristos
12666e63ce3Schristosstatic void
12766e63ce3Schristos@cpu@_parallel_write_init (SIM_CPU *current_cpu)
12866e63ce3Schristos{
12966e63ce3Schristos  CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (current_cpu);
13066e63ce3Schristos  CGEN_WRITE_QUEUE_CLEAR (q);
13166e63ce3Schristos  previous_vliw_pc = CPU_PC_GET(current_cpu);
13266e63ce3Schristos  frv_interrupt_state.f_ne_flags[0] = 0;
13366e63ce3Schristos  frv_interrupt_state.f_ne_flags[1] = 0;
13466e63ce3Schristos  frv_interrupt_state.imprecise_interrupt = NULL;
13566e63ce3Schristos}
13666e63ce3Schristos
13766e63ce3Schristosstatic void
13866e63ce3Schristos@cpu@_parallel_write_queued (SIM_CPU *current_cpu)
13966e63ce3Schristos{
14066e63ce3Schristos  int i;
14166e63ce3Schristos
14266e63ce3Schristos  FRV_VLIW *vliw = CPU_VLIW (current_cpu);
14366e63ce3Schristos  CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (current_cpu);
14466e63ce3Schristos
14566e63ce3Schristos  /* Loop over the queued writes, executing them. Set the pc to the address
14666e63ce3Schristos     of the insn which queued each write for the proper context in case an
14766e63ce3Schristos     interrupt is caused. Restore the proper pc after the writes are
14866e63ce3Schristos     completed.  */
14966e63ce3Schristos  IADDR save_pc = CPU_PC_GET (current_cpu);
15066e63ce3Schristos  IADDR new_pc  = save_pc;
15166e63ce3Schristos  int branch_taken = 0;
15266e63ce3Schristos  int limit = CGEN_WRITE_QUEUE_INDEX (q);
15366e63ce3Schristos  frv_interrupt_state.data_written.length = 0;
15466e63ce3Schristos
15566e63ce3Schristos  for (i = 0; i < limit; ++i)
15666e63ce3Schristos    {
15766e63ce3Schristos      CGEN_WRITE_QUEUE_ELEMENT *item = CGEN_WRITE_QUEUE_ELEMENT (q, i);
15866e63ce3Schristos
15966e63ce3Schristos      /* If an imprecise interrupt was generated, then, check whether the
16066e63ce3Schristos	 result should still be written.  */
16166e63ce3Schristos      if (frv_interrupt_state.imprecise_interrupt != NULL)
16266e63ce3Schristos	{
16366e63ce3Schristos	  /* Only check writes by the insn causing the exception.  */
16466e63ce3Schristos	  if (CGEN_WRITE_QUEUE_ELEMENT_IADDR (item)
16566e63ce3Schristos	      == frv_interrupt_state.imprecise_interrupt->vpc)
16666e63ce3Schristos	    {
16766e63ce3Schristos	      /* Execute writes of floating point operations resulting in
16866e63ce3Schristos		 overflow, underflow or inexact.  */
16966e63ce3Schristos	      if (frv_interrupt_state.imprecise_interrupt->kind
17066e63ce3Schristos		  == FRV_FP_EXCEPTION)
17166e63ce3Schristos		{
17266e63ce3Schristos		  if ((frv_interrupt_state.imprecise_interrupt
17366e63ce3Schristos		       ->u.fp_info.fsr_mask
17466e63ce3Schristos		       & ~(FSR_INEXACT | FSR_OVERFLOW | FSR_UNDERFLOW)))
17566e63ce3Schristos		    continue; /* Don't execute */
17666e63ce3Schristos		}
17766e63ce3Schristos	      /* Execute writes marked as 'forced'.  */
17866e63ce3Schristos	      else if (! (CGEN_WRITE_QUEUE_ELEMENT_FLAGS (item)
17966e63ce3Schristos			  & FRV_WRITE_QUEUE_FORCE_WRITE))
18066e63ce3Schristos		continue; /* Don't execute */
18166e63ce3Schristos	    }
18266e63ce3Schristos	}
18366e63ce3Schristos
18466e63ce3Schristos      /* Only execute the first branch on the queue.  */
18566e63ce3Schristos      if (CGEN_WRITE_QUEUE_ELEMENT_KIND (item) == CGEN_PC_WRITE
18666e63ce3Schristos          || CGEN_WRITE_QUEUE_ELEMENT_KIND (item) == CGEN_FN_PC_WRITE)
18766e63ce3Schristos	{
18866e63ce3Schristos	  if (branch_taken)
18966e63ce3Schristos	    continue;
19066e63ce3Schristos	  branch_taken = 1;
19166e63ce3Schristos	  if (CGEN_WRITE_QUEUE_ELEMENT_KIND (item) == CGEN_PC_WRITE)
19266e63ce3Schristos	    new_pc = item->kinds.pc_write.value;
19366e63ce3Schristos          else
19466e63ce3Schristos	    new_pc = item->kinds.fn_pc_write.value;
19566e63ce3Schristos	}
19666e63ce3Schristos
19766e63ce3Schristos      CPU_PC_SET (current_cpu, CGEN_WRITE_QUEUE_ELEMENT_IADDR (item));
19866e63ce3Schristos      frv_save_data_written_for_interrupts (current_cpu, item);
19966e63ce3Schristos      cgen_write_queue_element_execute (current_cpu, item);
20066e63ce3Schristos    }
20166e63ce3Schristos
20266e63ce3Schristos  /* Update the LR with the address of the next insn if the flag is set.
20366e63ce3Schristos     This flag gets set in frvbf_set_write_next_vliw_to_LR by the JMPL,
20466e63ce3Schristos     JMPIL and CALL insns.  */
20566e63ce3Schristos  if (frvbf_write_next_vliw_addr_to_LR)
20666e63ce3Schristos    {
20766e63ce3Schristos      frvbf_h_spr_set_handler (current_cpu, H_SPR_LR, save_pc);
20866e63ce3Schristos      frvbf_write_next_vliw_addr_to_LR = 0;
20966e63ce3Schristos    }
21066e63ce3Schristos
21166e63ce3Schristos  CPU_PC_SET (current_cpu, new_pc);
21266e63ce3Schristos  CGEN_WRITE_QUEUE_CLEAR (q);
21366e63ce3Schristos}
21466e63ce3Schristos
21566e63ce3Schristosvoid
21666e63ce3Schristos@cpu@_perform_writeback (SIM_CPU *current_cpu)
21766e63ce3Schristos{
21866e63ce3Schristos  @cpu@_parallel_write_queued (current_cpu);
21966e63ce3Schristos}
22066e63ce3Schristos
22166e63ce3Schristosstatic unsigned cache_reqno = 0x80000000; /* Start value is for debugging.  */
22266e63ce3Schristos
22366e63ce3Schristos#if 0 /* experimental */
22466e63ce3Schristos/* FR400 has single prefetch.  */
22566e63ce3Schristosstatic void
22666e63ce3Schristosfr400_simulate_insn_prefetch (SIM_CPU *current_cpu, IADDR vpc)
22766e63ce3Schristos{
22866e63ce3Schristos  int cur_ix;
22966e63ce3Schristos  FRV_CACHE *cache;
23066e63ce3Schristos
23166e63ce3Schristos/* The cpu receives 8 bytes worth of insn data for each fetch aligned
23266e63ce3Schristos   on 8 byte boundary.  */
23366e63ce3Schristos#define FR400_FETCH_SIZE 8
23466e63ce3Schristos
23566e63ce3Schristos  cur_ix = LS;
23666e63ce3Schristos  vpc &= ~(FR400_FETCH_SIZE - 1);
23766e63ce3Schristos  cache = CPU_INSN_CACHE (current_cpu);
23866e63ce3Schristos
23966e63ce3Schristos  /* Request a load of the current address buffer, if necessary.  */
24066e63ce3Schristos  if (frv_insn_fetch_buffer[cur_ix].address != vpc)
24166e63ce3Schristos    {
24266e63ce3Schristos      frv_insn_fetch_buffer[cur_ix].address = vpc;
24366e63ce3Schristos      frv_insn_fetch_buffer[cur_ix].reqno = cache_reqno++;
24466e63ce3Schristos      if (FRV_COUNT_CYCLES (current_cpu, 1))
24566e63ce3Schristos	frv_cache_request_load (cache, frv_insn_fetch_buffer[cur_ix].reqno,
24666e63ce3Schristos				frv_insn_fetch_buffer[cur_ix].address,
24766e63ce3Schristos				UNIT_I0 + cur_ix);
24866e63ce3Schristos    }
24966e63ce3Schristos
25066e63ce3Schristos  /* Wait for the current address buffer to be loaded, if necessary.  */
25166e63ce3Schristos  if (FRV_COUNT_CYCLES (current_cpu, 1))
25266e63ce3Schristos    {
25366e63ce3Schristos      FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (current_cpu);
25466e63ce3Schristos      int wait;
25566e63ce3Schristos
25666e63ce3Schristos      /* Account for any branch penalty.  */
25766e63ce3Schristos      if (ps->branch_penalty > 0 && ! ps->past_first_p)
25866e63ce3Schristos	{
25966e63ce3Schristos	  frv_model_advance_cycles (current_cpu, ps->branch_penalty);
26066e63ce3Schristos	  frv_model_trace_wait_cycles (current_cpu, ps->branch_penalty,
26166e63ce3Schristos				       "Branch penalty:");
26266e63ce3Schristos	  ps->branch_penalty = 0;
26366e63ce3Schristos	}
26466e63ce3Schristos
26566e63ce3Schristos      /* Account for insn fetch latency.  */
26666e63ce3Schristos      wait = 0;
26766e63ce3Schristos      while (frv_insn_fetch_buffer[cur_ix].reqno != NO_REQNO)
26866e63ce3Schristos	{
26966e63ce3Schristos	  frv_model_advance_cycles (current_cpu, 1);
27066e63ce3Schristos	  ++wait;
27166e63ce3Schristos	}
27266e63ce3Schristos      frv_model_trace_wait_cycles (current_cpu, wait, "Insn fetch:");
27366e63ce3Schristos      return;
27466e63ce3Schristos    }
27566e63ce3Schristos
27666e63ce3Schristos  /* Otherwise just load the insns directly from the cache.
27766e63ce3Schristos   */
27866e63ce3Schristos  if (frv_insn_fetch_buffer[cur_ix].reqno != NO_REQNO)
27966e63ce3Schristos    {
28066e63ce3Schristos      frv_cache_read (cache, cur_ix, vpc);
28166e63ce3Schristos      frv_insn_fetch_buffer[cur_ix].reqno = NO_REQNO;
28266e63ce3Schristos    }
28366e63ce3Schristos}
28466e63ce3Schristos#endif /* experimental */
28566e63ce3Schristos
28666e63ce3Schristos/* FR500 has dual prefetch.  */
28766e63ce3Schristosstatic void
28866e63ce3Schristossimulate_dual_insn_prefetch (SIM_CPU *current_cpu, IADDR vpc, int fetch_size)
28966e63ce3Schristos{
29066e63ce3Schristos  int i;
29166e63ce3Schristos  int cur_ix, pre_ix;
29266e63ce3Schristos  SI pre_address;
29366e63ce3Schristos  FRV_CACHE *cache;
29466e63ce3Schristos
29566e63ce3Schristos  /* See if the pc is within the addresses specified by either of the
29666e63ce3Schristos     fetch buffers.  If so, that will be the current buffer. Otherwise,
29766e63ce3Schristos     arbitrarily select the LD buffer as the current one since it gets
29866e63ce3Schristos     priority in the case of interfering load requests.  */
29966e63ce3Schristos  cur_ix = LD;
30066e63ce3Schristos  vpc &= ~(fetch_size - 1);
30166e63ce3Schristos  for (i = LS; i < FRV_CACHE_PIPELINES; ++i)
30266e63ce3Schristos    {
30366e63ce3Schristos      if (frv_insn_fetch_buffer[i].address == vpc)
30466e63ce3Schristos	{
30566e63ce3Schristos	  cur_ix = i;
30666e63ce3Schristos	  break;
30766e63ce3Schristos	}
30866e63ce3Schristos    }
30966e63ce3Schristos  cache = CPU_INSN_CACHE (current_cpu);
31066e63ce3Schristos
31166e63ce3Schristos  /* Request a load of the current address buffer, if necessary.  */
31266e63ce3Schristos  if (frv_insn_fetch_buffer[cur_ix].address != vpc)
31366e63ce3Schristos    {
31466e63ce3Schristos      frv_insn_fetch_buffer[cur_ix].address = vpc;
31566e63ce3Schristos      frv_insn_fetch_buffer[cur_ix].reqno = cache_reqno++;
31666e63ce3Schristos      if (FRV_COUNT_CYCLES (current_cpu, 1))
31766e63ce3Schristos	frv_cache_request_load (cache, frv_insn_fetch_buffer[cur_ix].reqno,
31866e63ce3Schristos				frv_insn_fetch_buffer[cur_ix].address,
31966e63ce3Schristos				UNIT_I0 + cur_ix);
32066e63ce3Schristos    }
32166e63ce3Schristos
32266e63ce3Schristos  /* If the prefetch buffer does not represent the next sequential address, then
32366e63ce3Schristos     request a load of the next sequential address.  */
32466e63ce3Schristos  pre_ix = (cur_ix + 1) % FRV_CACHE_PIPELINES;
32566e63ce3Schristos  pre_address = vpc + fetch_size;
32666e63ce3Schristos  if (frv_insn_fetch_buffer[pre_ix].address != pre_address)
32766e63ce3Schristos    {
32866e63ce3Schristos      frv_insn_fetch_buffer[pre_ix].address = pre_address;
32966e63ce3Schristos      frv_insn_fetch_buffer[pre_ix].reqno = cache_reqno++;
33066e63ce3Schristos      if (FRV_COUNT_CYCLES (current_cpu, 1))
33166e63ce3Schristos	frv_cache_request_load (cache, frv_insn_fetch_buffer[pre_ix].reqno,
33266e63ce3Schristos				frv_insn_fetch_buffer[pre_ix].address,
33366e63ce3Schristos				UNIT_I0 + pre_ix);
33466e63ce3Schristos    }
33566e63ce3Schristos
33666e63ce3Schristos  /* If counting cycles, account for any branch penalty and/or insn fetch
33766e63ce3Schristos     latency here.  */
33866e63ce3Schristos  if (FRV_COUNT_CYCLES (current_cpu, 1))
33966e63ce3Schristos    {
34066e63ce3Schristos      FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (current_cpu);
34166e63ce3Schristos      int wait;
34266e63ce3Schristos
34366e63ce3Schristos      /* Account for any branch penalty.  */
34466e63ce3Schristos      if (ps->branch_penalty > 0 && ! ps->past_first_p)
34566e63ce3Schristos	{
34666e63ce3Schristos	  frv_model_advance_cycles (current_cpu, ps->branch_penalty);
34766e63ce3Schristos	  frv_model_trace_wait_cycles (current_cpu, ps->branch_penalty,
34866e63ce3Schristos				       "Branch penalty:");
34966e63ce3Schristos	  ps->branch_penalty = 0;
35066e63ce3Schristos	}
35166e63ce3Schristos
35266e63ce3Schristos      /* Account for insn fetch latency.  */
35366e63ce3Schristos      wait = 0;
35466e63ce3Schristos      while (frv_insn_fetch_buffer[cur_ix].reqno != NO_REQNO)
35566e63ce3Schristos	{
35666e63ce3Schristos	  frv_model_advance_cycles (current_cpu, 1);
35766e63ce3Schristos	  ++wait;
35866e63ce3Schristos	}
35966e63ce3Schristos      frv_model_trace_wait_cycles (current_cpu, wait, "Insn fetch:");
36066e63ce3Schristos      return;
36166e63ce3Schristos    }
36266e63ce3Schristos
36366e63ce3Schristos  /* Otherwise just load the insns directly from the cache.
36466e63ce3Schristos   */
36566e63ce3Schristos  if (frv_insn_fetch_buffer[cur_ix].reqno != NO_REQNO)
36666e63ce3Schristos    {
36766e63ce3Schristos      frv_cache_read (cache, cur_ix, vpc);
36866e63ce3Schristos      frv_insn_fetch_buffer[cur_ix].reqno = NO_REQNO;
36966e63ce3Schristos    }
37066e63ce3Schristos  if (frv_insn_fetch_buffer[pre_ix].reqno != NO_REQNO)
37166e63ce3Schristos    {
37266e63ce3Schristos      frv_cache_read (cache, pre_ix, pre_address);
37366e63ce3Schristos      frv_insn_fetch_buffer[pre_ix].reqno = NO_REQNO;
37466e63ce3Schristos    }
37566e63ce3Schristos}
37666e63ce3Schristos
37766e63ce3Schristosstatic void
37866e63ce3Schristos@cpu@_simulate_insn_prefetch (SIM_CPU *current_cpu, IADDR vpc)
37966e63ce3Schristos{
38066e63ce3Schristos  SI hsr0;
38166e63ce3Schristos  SIM_DESC sd;
38266e63ce3Schristos
38366e63ce3Schristos  /* Nothing to do if not counting cycles and the cache is not enabled.  */
38466e63ce3Schristos  hsr0 = GET_HSR0 ();
38566e63ce3Schristos  if (! GET_HSR0_ICE (hsr0) && ! FRV_COUNT_CYCLES (current_cpu, 1))
38666e63ce3Schristos    return;
38766e63ce3Schristos
38866e63ce3Schristos  /* Different machines handle prefetch defferently.  */
38966e63ce3Schristos  sd = CPU_STATE (current_cpu);
39066e63ce3Schristos  switch (STATE_ARCHITECTURE (sd)->mach)
39166e63ce3Schristos    {
39266e63ce3Schristos    case bfd_mach_fr400:
39366e63ce3Schristos    case bfd_mach_fr450:
39466e63ce3Schristos      simulate_dual_insn_prefetch (current_cpu, vpc, 8);
39566e63ce3Schristos      break;
39666e63ce3Schristos    case bfd_mach_frvtomcat:
39766e63ce3Schristos    case bfd_mach_fr500:
39866e63ce3Schristos    case bfd_mach_fr550:
39966e63ce3Schristos    case bfd_mach_frv:
40066e63ce3Schristos      simulate_dual_insn_prefetch (current_cpu, vpc, 16);
40166e63ce3Schristos      break;
40266e63ce3Schristos    default:
40366e63ce3Schristos      break;
40466e63ce3Schristos    }
40566e63ce3Schristos}
40666e63ce3Schristos
40766e63ce3Schristosint frv_save_profile_model_p;
40866e63ce3SchristosEOF
40966e63ce3Schristos
41066e63ce3Schristos;;
41166e63ce3Schristos
41266e63ce3Schristosxinit)
41366e63ce3Schristos
41466e63ce3Schristoscat <<EOF
41566e63ce3Schristos/*xxxinit*/
41666e63ce3Schristos  /* If the timer is enabled, then we will enable model profiling during
41766e63ce3Schristos     execution.  This is because the timer needs accurate cycles counts to
41866e63ce3Schristos     work properly.  Save the original setting of model profiling.  */
41966e63ce3Schristos  if (frv_interrupt_state.timer.enabled)
42066e63ce3Schristos    frv_save_profile_model_p = PROFILE_MODEL_P (current_cpu);
42166e63ce3SchristosEOF
42266e63ce3Schristos
42366e63ce3Schristos;;
42466e63ce3Schristos
42566e63ce3Schristosxextract-simple | xextract-scache)
42666e63ce3Schristos
42766e63ce3Schristos# Inputs:  current_cpu, vpc, sc, FAST_P
42866e63ce3Schristos# Outputs: sc filled in
42966e63ce3Schristos# SET_LAST_INSN_P(last_p) called to indicate whether insn is last one
43066e63ce3Schristos
43166e63ce3Schristoscat <<EOF
43266e63ce3Schristos{
43366e63ce3Schristos  CGEN_INSN_INT insn = frvbf_read_imem_USI (current_cpu, vpc);
43466e63ce3Schristos  extract (current_cpu, vpc, insn, SEM_ARGBUF (sc), FAST_P);
43566e63ce3Schristos  SET_LAST_INSN_P ((insn & 0x80000000) != 0);
43666e63ce3Schristos}
43766e63ce3SchristosEOF
43866e63ce3Schristos
43966e63ce3Schristos;;
44066e63ce3Schristos
44166e63ce3Schristosxfull-exec-* | xfast-exec-*)
44266e63ce3Schristos
44366e63ce3Schristos# Inputs: current_cpu, vpc, FAST_P
44466e63ce3Schristos# Outputs:
44566e63ce3Schristos#   vpc contains the address of the next insn to execute
44666e63ce3Schristos#   pc of current_cpu must be up to date (=vpc) upon exit
44766e63ce3Schristos#   CPU_INSN_COUNT (current_cpu) must be updated by number of insns executed
44866e63ce3Schristos#
44966e63ce3Schristos# Unlike the non-parallel case, this version is responsible for doing the
45066e63ce3Schristos# scache lookup.
45166e63ce3Schristos
45266e63ce3Schristoscat <<EOF
45366e63ce3Schristos{
45466e63ce3Schristos  FRV_VLIW *vliw;
45566e63ce3Schristos  int first_insn_p = 1;
45666e63ce3Schristos  int last_insn_p = 0;
45766e63ce3Schristos  int ninsns;
45866e63ce3Schristos  CGEN_ATTR_VALUE_ENUM_TYPE slot;
45966e63ce3Schristos
46066e63ce3Schristos  /* If the timer is enabled, then enable model profiling.  This is because
46166e63ce3Schristos     the timer needs accurate cycles counts to work properly.  */
46266e63ce3Schristos  if (frv_interrupt_state.timer.enabled && ! frv_save_profile_model_p)
46366e63ce3Schristos    sim_profile_set_option (current_state, "-model", PROFILE_MODEL_IDX, "1");
46466e63ce3Schristos
46566e63ce3Schristos  /* Init parallel-write queue and vliw.  */
46666e63ce3Schristos  @cpu@_parallel_write_init (current_cpu);
46766e63ce3Schristos  vliw = CPU_VLIW (current_cpu);
46866e63ce3Schristos  frv_vliw_reset (vliw, STATE_ARCHITECTURE (CPU_STATE (current_cpu))->mach,
46966e63ce3Schristos                  CPU_ELF_FLAGS (current_cpu));
47066e63ce3Schristos  frv_current_fm_slot = UNIT_NIL;
47166e63ce3Schristos
47266e63ce3Schristos  for (ninsns = 0; ! last_insn_p && ninsns < FRV_VLIW_SIZE; ++ninsns)
47366e63ce3Schristos    {
47466e63ce3Schristos      SCACHE *sc;
47566e63ce3Schristos      const CGEN_INSN *insn;
47666e63ce3Schristos      int error;
47766e63ce3Schristos      /* Go through the motions of finding the insns in the cache.  */
47866e63ce3Schristos      @cpu@_simulate_insn_prefetch (current_cpu, vpc);
47966e63ce3Schristos
48066e63ce3Schristos      sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P);
48166e63ce3Schristos      sc->first_insn_p = first_insn_p;
48266e63ce3Schristos      last_insn_p = sc->last_insn_p;
48366e63ce3Schristos
48466e63ce3Schristos      /* Add the insn to the vliw and set up the interrupt state.  */
48566e63ce3Schristos      insn = sc->argbuf.idesc->idata;
48666e63ce3Schristos      error = frv_vliw_add_insn (vliw, insn);
48766e63ce3Schristos      if (! error)
48866e63ce3Schristos        frv_vliw_setup_insn (current_cpu, insn);
48966e63ce3Schristos      frv_detect_insn_access_interrupts (current_cpu, sc);
49066e63ce3Schristos      slot = (*vliw->current_vliw)[vliw->next_slot - 1];
49166e63ce3Schristos      if (slot >= UNIT_FM0 && slot <= UNIT_FM3)
49266e63ce3Schristos        frv_current_fm_slot = slot;
49366e63ce3Schristos
49466e63ce3Schristos      vpc = execute (current_cpu, sc, FAST_P);
49566e63ce3Schristos
49666e63ce3Schristos      SET_H_PC (vpc); /* needed for interrupt handling */
49766e63ce3Schristos      first_insn_p = 0;
49866e63ce3Schristos    }
49966e63ce3Schristos
50066e63ce3Schristos  /* If the timer is enabled, and model profiling was not originally enabled,
50166e63ce3Schristos     then turn it off again.  This is the only place we can currently gain
50266e63ce3Schristos     control to do this.  */
50366e63ce3Schristos  if (frv_interrupt_state.timer.enabled && ! frv_save_profile_model_p)
50466e63ce3Schristos    sim_profile_set_option (current_state, "-model", PROFILE_MODEL_IDX, "0");
50566e63ce3Schristos
50666e63ce3Schristos  /* Check for interrupts.  Also handles writeback if necessary.  */
50766e63ce3Schristos  frv_process_interrupts (current_cpu);
50866e63ce3Schristos
50966e63ce3Schristos  CPU_INSN_COUNT (current_cpu) += ninsns;
51066e63ce3Schristos}
51166e63ce3SchristosEOF
51266e63ce3Schristos
51366e63ce3Schristos;;
51466e63ce3Schristos
51566e63ce3Schristos*)
51666e63ce3Schristos  echo "Invalid argument to mainloop.in: $1" >&2
51766e63ce3Schristos  exit 1
51866e63ce3Schristos  ;;
51966e63ce3Schristos
52066e63ce3Schristosesac
521