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

Subversion Repositories or1k_old

[/] [or1k_old/] [tags/] [rel-0-3-0-rc3/] [or1ksim/] [tick/] [tick.c] - Diff between revs 1506 and 1540

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 1506 Rev 1540
Line 1... Line 1...
/* 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
 
 
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
Line 46... Line 47...
#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 */
int cycles_start = 0;
long long cycles_start = 0;
 
 
/* TT Count Register */
/* Indicates if the timer is actually counting.  Needed to simulate one-shot
unsigned long ttcr;
 * mode correctly */
 
int tick_count;
/* TT Mode Register */
 
unsigned long ttmr;
 
 
 
/* 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");
  mtspr(SPR_TTCR, 0);
  cpu_state.sprs[SPR_TTCR] = 0;
  mtspr(SPR_TTMR, 0);
  cpu_state.sprs[SPR_TTMR] = 0;
 
  tick_count = 0;
}
}
 
 
/* Job handler for tick timer */
/* Raises a timer exception */
void tick_job (void *param)
void tick_raise_except(void *dat)
{
{
  int mode = (ttmr & SPR_TTMR_M) >> 30;
 
  TRACE("tick_job param: %i, mode: %i at %lli (%lli)\n", (int)param, mode,
 
        runtime.sim.cycles, runtime.cpu.instructions);
 
  switch (mode) {
 
  case 1:
 
    if (!param) {
 
      cpu_state.sprs[SPR_TTCR] = ttcr = 0;
 
      cycles_start = runtime.sim.cycles - ttcr;
 
      TRACE("Scheduleing timer job for %li\n", (ttmr & SPR_TTMR_PERIOD) - ttcr);
 
      SCHED_ADD(tick_job, (void *)0, (ttmr & SPR_TTMR_PERIOD) - ttcr);
 
    }
 
  case 2:
 
    if (ttmr & SPR_TTMR_IE) {
 
      cpu_state.sprs[SPR_TTMR] |= SPR_TTMR_IP;
      cpu_state.sprs[SPR_TTMR] |= SPR_TTMR_IP;
      /* be sure not to issue timer exception if an exception occured before it */
  /* be sure not to issue a timer exception if an exception occured before it */
      if ((mfspr(SPR_SR) & SPR_SR_TEE) == SPR_SR_TEE)
  if(cpu_state.sprs[SPR_SR] & SPR_SR_TEE)
        except_handle(EXCEPT_TICK, mfspr(SPR_EEAR_BASE));
    except_handle(EXCEPT_TICK, cpu_state.sprs[SPR_EEAR_BASE]);
 
 
 
  /* Reschedule unconditionally, since we have to raise the exception until
 
   * TTMR_IP has been cleared */
 
  SCHED_ADD(tick_raise_except, NULL, 1);
 
}
 
 
 
/* Restarts the tick timer */
 
void tick_restart(void *dat)
 
{
 
  cpu_state.sprs[SPR_TTCR] = 0;
 
  cycles_start = runtime.sim.cycles;
 
  TRACE("Scheduleing timer restart job for %"PRIdREG"\n",
 
        cpu_state.sprs[SPR_TTMR] & SPR_TTMR_PERIOD);
 
  SCHED_ADD(tick_restart, NULL, cpu_state.sprs[SPR_TTMR] & SPR_TTMR_PERIOD);
 
}
 
 
 
/* Stops the timer */
 
void tick_one_shot(void *dat)
 
{
 
  TRACE("Stopping one-shot timer\n");
 
  cpu_state.sprs[SPR_TTCR] = cpu_state.sprs[SPR_TTMR] & SPR_TTMR_PERIOD;
 
  tick_count = 0;
 
}
 
 
 
/* Schedules the timer jobs */
 
static void sched_timer_job(uorreg_t prev_ttmr)
 
{
 
  uorreg_t ttmr = cpu_state.sprs[SPR_TTMR];
 
  uint32_t match_time = ttmr & SPR_TTMR_PERIOD;
 
  uint32_t ttcr_period = spr_read_ttcr() & SPR_TTCR_PERIOD;
 
 
 
  /* Remove previous jobs if they exists */
 
  if(prev_ttmr & SPR_TTMR_IE)
 
    SCHED_FIND_REMOVE(tick_raise_except, NULL);
 
 
 
  switch(prev_ttmr & SPR_TTMR_M) {
 
  case SPR_TTMR_RT:
 
    SCHED_FIND_REMOVE(tick_restart, NULL);
 
    break;
 
  case SPR_TTMR_SR:
 
    SCHED_FIND_REMOVE(tick_one_shot, NULL);
 
    break;
 
  }
 
 
 
  if(match_time >= ttcr_period)
 
    match_time -= ttcr_period;
      else
      else
        /* If TEE is currently not set we have to pend tick exception
    match_time += (0xfffffffu - ttcr_period) + 1;
           by rescheduling. */
 
        SCHED_ADD(tick_job, (void *)1, 1);
  TRACE("Cycles to go until match: %"PRIu32" (0x%"PRIx32")\n", match_time,
 
        match_time);
 
 
 
  switch(ttmr & SPR_TTMR_M) {
 
  case 0: /* Disabled timer */
 
    TRACE("Scheduleing exception when timer match (in disabled mode).\n");
 
    if(!match_time && (ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
 
      SCHED_ADD(tick_raise_except, NULL, 0);
 
    break;
 
  case SPR_TTMR_RT: /* Auto-restart timer */
 
    TRACE("Scheduleing auto-restarting timer.\n");
 
    SCHED_ADD(tick_restart, NULL, match_time);
 
    if((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
 
      SCHED_ADD(tick_raise_except, NULL, match_time);
 
    break;
 
  case SPR_TTMR_SR: /* One-shot timer */
 
    TRACE("Scheduleing one-shot timer.\n");
 
    if(tick_count) {
 
      SCHED_ADD(tick_one_shot, NULL, match_time);
 
      if((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
 
        SCHED_ADD(tick_raise_except, NULL, match_time);
    }
    }
    break;
    break;
 
  case SPR_TTMR_CR: /* Continuos timer */
 
    TRACE("Scheduleing exception when timer match (in cont. mode).\n");
 
    if((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP))
 
      SCHED_ADD(tick_raise_except, NULL, match_time);
  }
  }
}
}
 
 
/* Starts the tick timer.  This function is called by a write to ttcr spr register */
/* Handles a write to the ttcr spr */
void spr_write_ttcr (uorreg_t value)
void spr_write_ttcr (uorreg_t value)
{
{
  unsigned mode = (ttmr & SPR_TTMR_M) >> 30;
 
  TRACE("set ttcr = %"PRIxREG"\n", value);
  TRACE("set ttcr = %"PRIxREG"\n", value);
  ttcr = value;
  cycles_start = runtime.sim.cycles - value;
  /* Remove previous if it exists */
 
  TRACE("Removeing scheduled jobs\n");
  sched_timer_job(cpu_state.sprs[SPR_TTMR]);
  SCHED_FIND_REMOVE(tick_job, (void *)0);
 
  SCHED_FIND_REMOVE(tick_job, (void *)1);
 
  if (mode == 1 || mode == 2) {
 
    TRACE("Scheduleing timer job for %li\n", (ttmr & SPR_TTMR_PERIOD) - ttcr);
 
    SCHED_ADD(tick_job, (void *)0, (ttmr & SPR_TTMR_PERIOD) - ttcr);
 
    cycles_start = runtime.sim.cycles - ttcr;
 
  }
 
}
}
 
 
void spr_write_ttmr (uorreg_t value)
/* Value is the *previous* value of SPR_TTMR.  The new one can be found in
{
 * cpu_state.sprs[SPR_TTMR] */
  TRACE("set ttmr = %"PRIxREG"\n", value);
void spr_write_ttmr (uorreg_t prev_val)
  ttmr = value;
{
  /* Handle the modes properly. */
  uorreg_t value = cpu_state.sprs[SPR_TTMR];
  switch((ttmr & SPR_TTMR_M) >> 30) {
 
    case 0:    /* Timer is disabled */
  TRACE("set ttmr = %"PRIxREG" (previous: %"PRIxREG")\n", value, prev_val);
      TRACE("Removeing scheduled jobs\n");
 
      SCHED_FIND_REMOVE(tick_job, (void *)0);
  if(value & SPR_TTMR_IP) {
      SCHED_FIND_REMOVE(tick_job, (void *)1);
    if(prev_val & SPR_TTMR_IP)
      break;
      /* SPR_TTMR_IP has not been cleared, continue sending timer interrupts */
    case 1:    /* Timer should auto restart */
      SCHED_ADD(tick_raise_except, NULL, 0);
      cpu_state.sprs[SPR_TTCR] = ttcr = 0;
    else
      cycles_start = runtime.sim.cycles;
      /* Code running on or1k can't set SPR_TTMR_IP so make sure it isn't */
      TRACE("Removeing scheduled jobs\n");
      cpu_state.sprs[SPR_TTMR] &= ~SPR_TTMR_IP;
      SCHED_FIND_REMOVE(tick_job, (void *)0);
 
      SCHED_FIND_REMOVE(tick_job, (void *)1);
 
      TRACE("Scheduleing timer job for %li\n", (ttmr & SPR_TTMR_PERIOD) - ttcr);
 
      SCHED_ADD(tick_job, (void *)0, (ttmr & SPR_TTMR_PERIOD) - ttcr);
 
      break;
 
    case 2:    /* Stop the timer when match */
 
      TRACE("Removeing scheduled jobs\n");
 
      SCHED_FIND_REMOVE(tick_job, (void *)0);
 
      SCHED_FIND_REMOVE(tick_job, (void *)1);
 
      break;
 
    case 3:    /* Timer keeps running -- do nothing*/
 
      break;
 
  }
  }
 
 
 
  /* If the timer was already disabled, ttcr should not be updated */
 
  if(tick_count)
 
    cpu_state.sprs[SPR_TTCR] = runtime.sim.cycles - cycles_start;
 
 
 
  cycles_start = runtime.sim.cycles - cpu_state.sprs[SPR_TTCR];
 
 
 
  tick_count = value & SPR_TTMR_M;
 
 
 
  if((tick_count == 0xc0000000) &&
 
     (cpu_state.sprs[SPR_TTCR] == (value & SPR_TTMR_PERIOD)))
 
    tick_count = 0;
 
 
 
  sched_timer_job(prev_val);
}
}
 
 
uorreg_t spr_read_ttcr (void)
uorreg_t spr_read_ttcr (void)
{
{
  TRACE("read ttcr %lli\n", runtime.sim.cycles - cycles_start);
  uorreg_t ret;
  return runtime.sim.cycles - cycles_start;
 
 
  if(!tick_count)
 
    /* Report the time when the counter stoped (and don't carry on counting) */
 
    ret = cpu_state.sprs[SPR_TTCR];
 
  else
 
    ret = runtime.sim.cycles - cycles_start;
 
 
 
  TRACE("read ttcr %"PRIdREG" (0x%"PRIxREG")\n", ret, ret);
 
  return ret;
}
}
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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