OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [stable_0_2_0_rc3/] [or1ksim/] [tick/] [tick.c] - Diff between revs 1648 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 1648 Rev 1765
/* tick.c -- Simulation of OpenRISC 1000 tick timer
/* tick.c -- Simulation of OpenRISC 1000 tick timer
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
   Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org
   Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org
 
 
This file is part of OpenRISC 1000 Architectural Simulator.
This file is part of OpenRISC 1000 Architectural Simulator.
 
 
This program is free software; you can redistribute it and/or modify
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
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
(at your option) any later version.
 
 
This program is distributed in the hope that it will be useful,
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
 
/* This is functional simulation of OpenRISC 1000 architectural
/* This is functional simulation of OpenRISC 1000 architectural
   tick timer.
   tick timer.
*/
*/
 
 
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
 
 
#include "config.h"
#include "config.h"
 
 
#ifdef HAVE_INTTYPES_H
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#include <inttypes.h>
#endif
#endif
 
 
#include "port.h"
#include "port.h"
#include "arch.h"
#include "arch.h"
#include "abstract.h"
#include "abstract.h"
#include "except.h"
#include "except.h"
#include "tick.h"
#include "tick.h"
#include "opcode/or32.h"
#include "opcode/or32.h"
#include "spr_defs.h"
#include "spr_defs.h"
#include "execute.h"
#include "execute.h"
#include "pic.h"
#include "pic.h"
#include "sprs.h"
#include "sprs.h"
#include "sim-config.h"
#include "sim-config.h"
#include "sched.h"
#include "sched.h"
#include "debug.h"
#include "debug.h"
 
 
DEFAULT_DEBUG_CHANNEL(tick);
DEFAULT_DEBUG_CHANNEL(tick);
 
 
/* When did the timer start to count */
/* When did the timer start to count */
long long cycles_start = 0;
long long cycles_start = 0;
 
 
/* Indicates if the timer is actually counting.  Needed to simulate one-shot
/* Indicates if the timer is actually counting.  Needed to simulate one-shot
 * mode correctly */
 * mode correctly */
int tick_count;
int tick_count;
 
 
/* Reset. It initializes TTCR register. */
/* Reset. It initializes TTCR register. */
void tick_reset(void)
void tick_reset(void)
{
{
  if (config.sim.verbose)
  if (config.sim.verbose)
    PRINTF("Resetting Tick Timer.\n");
    PRINTF("Resetting Tick Timer.\n");
  cpu_state.sprs[SPR_TTCR] = 0;
  cpu_state.sprs[SPR_TTCR] = 0;
  cpu_state.sprs[SPR_TTMR] = 0;
  cpu_state.sprs[SPR_TTMR] = 0;
  tick_count = 0;
  tick_count = 0;
}
}
 
 
/* Raises a timer exception */
/* Raises a timer exception */
void tick_raise_except(void *dat)
void tick_raise_except(void *dat)
{
{
  cpu_state.sprs[SPR_TTMR] |= SPR_TTMR_IP;
  cpu_state.sprs[SPR_TTMR] |= SPR_TTMR_IP;
 
 
  /* Reschedule unconditionally, since we have to raise the exception until
  /* Reschedule unconditionally, since we have to raise the exception until
   * TTMR_IP has been cleared */
   * TTMR_IP has been cleared */
  sched_next_insn(tick_raise_except, NULL);
  sched_next_insn(tick_raise_except, NULL);
 
 
  /* be sure not to issue a timer exception if an exception occured before it */
  /* be sure not to issue a timer exception if an exception occured before it */
  if(cpu_state.sprs[SPR_SR] & SPR_SR_TEE)
  if(cpu_state.sprs[SPR_SR] & SPR_SR_TEE)
    except_handle(EXCEPT_TICK, cpu_state.sprs[SPR_EEAR_BASE]);
    except_handle(EXCEPT_TICK, cpu_state.sprs[SPR_EEAR_BASE]);
}
}
 
 
/* Restarts the tick timer */
/* Restarts the tick timer */
void tick_restart(void *dat)
void tick_restart(void *dat)
{
{
  cpu_state.sprs[SPR_TTCR] = 0;
  cpu_state.sprs[SPR_TTCR] = 0;
  cycles_start = runtime.sim.cycles;
  cycles_start = runtime.sim.cycles;
  TRACE("Scheduleing timer restart job for %"PRIdREG"\n",
  TRACE("Scheduleing timer restart job for %"PRIdREG"\n",
        cpu_state.sprs[SPR_TTMR] & SPR_TTMR_PERIOD);
        cpu_state.sprs[SPR_TTMR] & SPR_TTMR_PERIOD);
  SCHED_ADD(tick_restart, NULL, cpu_state.sprs[SPR_TTMR] & SPR_TTMR_PERIOD);
  SCHED_ADD(tick_restart, NULL, cpu_state.sprs[SPR_TTMR] & SPR_TTMR_PERIOD);
}
}
 
 
/* Stops the timer */
/* Stops the timer */
void tick_one_shot(void *dat)
void tick_one_shot(void *dat)
{
{
  TRACE("Stopping one-shot timer\n");
  TRACE("Stopping one-shot timer\n");
  cpu_state.sprs[SPR_TTCR] = cpu_state.sprs[SPR_TTMR] & SPR_TTMR_PERIOD;
  cpu_state.sprs[SPR_TTCR] = cpu_state.sprs[SPR_TTMR] & SPR_TTMR_PERIOD;
  tick_count = 0;
  tick_count = 0;
}
}
 
 
/* Schedules the timer jobs */
/* Schedules the timer jobs */
static void sched_timer_job(uorreg_t prev_ttmr)
static void sched_timer_job(uorreg_t prev_ttmr)
{
{
  uorreg_t ttmr = cpu_state.sprs[SPR_TTMR];
  uorreg_t ttmr = cpu_state.sprs[SPR_TTMR];
  uint32_t match_time = ttmr & SPR_TTMR_PERIOD;
  uint32_t match_time = ttmr & SPR_TTMR_PERIOD;
  uint32_t ttcr_period = spr_read_ttcr() & SPR_TTCR_PERIOD;
  uint32_t ttcr_period = spr_read_ttcr() & SPR_TTCR_PERIOD;
 
 
  /* Remove previous jobs if they exists */
  /* Remove previous jobs if they exists */
  if((prev_ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
  if((prev_ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
    SCHED_FIND_REMOVE(tick_raise_except, NULL);
    SCHED_FIND_REMOVE(tick_raise_except, NULL);
 
 
  switch(prev_ttmr & SPR_TTMR_M) {
  switch(prev_ttmr & SPR_TTMR_M) {
  case SPR_TTMR_RT:
  case SPR_TTMR_RT:
    SCHED_FIND_REMOVE(tick_restart, NULL);
    SCHED_FIND_REMOVE(tick_restart, NULL);
    break;
    break;
  case SPR_TTMR_SR:
  case SPR_TTMR_SR:
    SCHED_FIND_REMOVE(tick_one_shot, NULL);
    SCHED_FIND_REMOVE(tick_one_shot, NULL);
    break;
    break;
  }
  }
 
 
  if(match_time >= ttcr_period)
  if(match_time >= ttcr_period)
    match_time -= ttcr_period;
    match_time -= ttcr_period;
  else
  else
    match_time += (0xfffffffu - ttcr_period) + 1;
    match_time += (0xfffffffu - ttcr_period) + 1;
 
 
  TRACE("Cycles to go until match: %"PRIu32" (0x%"PRIx32")\n", match_time,
  TRACE("Cycles to go until match: %"PRIu32" (0x%"PRIx32")\n", match_time,
        match_time);
        match_time);
 
 
  switch(ttmr & SPR_TTMR_M) {
  switch(ttmr & SPR_TTMR_M) {
  case 0: /* Disabled timer */
  case 0: /* Disabled timer */
    TRACE("Scheduleing exception when timer match (in disabled mode).\n");
    TRACE("Scheduleing exception when timer match (in disabled mode).\n");
    if(!match_time && (ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
    if(!match_time && (ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
      SCHED_ADD(tick_raise_except, NULL, 0);
      SCHED_ADD(tick_raise_except, NULL, 0);
    break;
    break;
  case SPR_TTMR_RT: /* Auto-restart timer */
  case SPR_TTMR_RT: /* Auto-restart timer */
    TRACE("Scheduleing auto-restarting timer.\n");
    TRACE("Scheduleing auto-restarting timer.\n");
    SCHED_ADD(tick_restart, NULL, match_time);
    SCHED_ADD(tick_restart, NULL, match_time);
    if((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
    if((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
      SCHED_ADD(tick_raise_except, NULL, match_time);
      SCHED_ADD(tick_raise_except, NULL, match_time);
    break;
    break;
  case SPR_TTMR_SR: /* One-shot timer */
  case SPR_TTMR_SR: /* One-shot timer */
    TRACE("Scheduleing one-shot timer.\n");
    TRACE("Scheduleing one-shot timer.\n");
    if(tick_count) {
    if(tick_count) {
      SCHED_ADD(tick_one_shot, NULL, match_time);
      SCHED_ADD(tick_one_shot, NULL, match_time);
      if((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
      if((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
        SCHED_ADD(tick_raise_except, NULL, match_time);
        SCHED_ADD(tick_raise_except, NULL, match_time);
    }
    }
    break;
    break;
  case SPR_TTMR_CR: /* Continuos timer */
  case SPR_TTMR_CR: /* Continuos timer */
    TRACE("Scheduleing exception when timer match (in cont. mode).\n");
    TRACE("Scheduleing exception when timer match (in cont. mode).\n");
    if((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
    if((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
      SCHED_ADD(tick_raise_except, NULL, match_time);
      SCHED_ADD(tick_raise_except, NULL, match_time);
  }
  }
}
}
 
 
/* Handles a write to the ttcr spr */
/* Handles a write to the ttcr spr */
void spr_write_ttcr (uorreg_t value)
void spr_write_ttcr (uorreg_t value)
{
{
  TRACE("set ttcr = %"PRIxREG"\n", value);
  TRACE("set ttcr = %"PRIxREG"\n", value);
  cycles_start = runtime.sim.cycles - value;
  cycles_start = runtime.sim.cycles - value;
 
 
  sched_timer_job(cpu_state.sprs[SPR_TTMR]);
  sched_timer_job(cpu_state.sprs[SPR_TTMR]);
}
}
 
 
/* Value is the *previous* value of SPR_TTMR.  The new one can be found in
/* Value is the *previous* value of SPR_TTMR.  The new one can be found in
 * cpu_state.sprs[SPR_TTMR] */
 * cpu_state.sprs[SPR_TTMR] */
void spr_write_ttmr (uorreg_t prev_val)
void spr_write_ttmr (uorreg_t prev_val)
{
{
  uorreg_t value = cpu_state.sprs[SPR_TTMR];
  uorreg_t value = cpu_state.sprs[SPR_TTMR];
 
 
  TRACE("set ttmr = %"PRIxREG" (previous: %"PRIxREG")\n", value, prev_val);
  TRACE("set ttmr = %"PRIxREG" (previous: %"PRIxREG")\n", value, prev_val);
 
 
  /* Code running on or1k can't set SPR_TTMR_IP so make sure it isn't */
  /* Code running on or1k can't set SPR_TTMR_IP so make sure it isn't */
  cpu_state.sprs[SPR_TTMR] &= ~SPR_TTMR_IP;
  cpu_state.sprs[SPR_TTMR] &= ~SPR_TTMR_IP;
 
 
  /* If the timer was already disabled, ttcr should not be updated */
  /* If the timer was already disabled, ttcr should not be updated */
  if(tick_count)
  if(tick_count)
    cpu_state.sprs[SPR_TTCR] = runtime.sim.cycles - cycles_start;
    cpu_state.sprs[SPR_TTCR] = runtime.sim.cycles - cycles_start;
 
 
  cycles_start = runtime.sim.cycles - cpu_state.sprs[SPR_TTCR];
  cycles_start = runtime.sim.cycles - cpu_state.sprs[SPR_TTCR];
 
 
  tick_count = value & SPR_TTMR_M;
  tick_count = value & SPR_TTMR_M;
 
 
  if((tick_count == 0xc0000000) &&
  if((tick_count == 0xc0000000) &&
     (cpu_state.sprs[SPR_TTCR] == (value & SPR_TTMR_PERIOD)))
     (cpu_state.sprs[SPR_TTCR] == (value & SPR_TTMR_PERIOD)))
    tick_count = 0;
    tick_count = 0;
 
 
  sched_timer_job(prev_val);
  sched_timer_job(prev_val);
}
}
 
 
uorreg_t spr_read_ttcr (void)
uorreg_t spr_read_ttcr (void)
{
{
  uorreg_t ret;
  uorreg_t ret;
 
 
  if(!tick_count)
  if(!tick_count)
    /* Report the time when the counter stoped (and don't carry on counting) */
    /* Report the time when the counter stoped (and don't carry on counting) */
    ret = cpu_state.sprs[SPR_TTCR];
    ret = cpu_state.sprs[SPR_TTCR];
  else
  else
    ret = runtime.sim.cycles - cycles_start;
    ret = runtime.sim.cycles - cycles_start;
 
 
  TRACE("read ttcr %"PRIdREG" (0x%"PRIxREG")\n", ret, ret);
  TRACE("read ttcr %"PRIdREG" (0x%"PRIxREG")\n", ret, ret);
  return ret;
  return ret;
}
}
 
 

powered by: WebSVN 2.1.0

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