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

Subversion Repositories eco32

[/] [eco32/] [trunk/] [sim/] [timer.c] - Diff between revs 8 and 25

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

Rev 8 Rev 25
/*
/*
 * timer.c -- timer simulation
 * timer.c -- timer simulation
 */
 */
 
 
 
 
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <setjmp.h>
#include <setjmp.h>
 
 
#include "common.h"
#include "common.h"
#include "console.h"
#include "console.h"
#include "error.h"
#include "error.h"
#include "except.h"
#include "except.h"
#include "cpu.h"
#include "cpu.h"
#include "timer.h"
#include "timer.h"
 
 
 
 
#define TIME_WRAP       1000000         /* avoid overflow of current time */
#define TIME_WRAP       1000000         /* avoid overflow of current time */
 
 
 
 
 
/*
 
 * data structure for simulation timer
 
 */
typedef struct timer {
typedef struct timer {
  struct timer *next;
  struct timer *next;
  int alarm;
  int alarm;
  void (*callback)(int param);
  void (*callback)(int param);
  int param;
  int param;
} Timer;
} Timer;
 
 
 
 
 
/*
 
 * data structure for timer/counter device
 
 */
 
typedef struct {
 
  Word ctrl;
 
  Word divisor;
 
  Word counter;
 
  int irq;
 
} TimerCounter;
 
 
 
 
static Bool debug = false;
static Bool debug = false;
 
 
static Timer *activeTimers = NULL;
static Timer *activeTimers = NULL;
static Timer *freeTimers = NULL;
static Timer *freeTimers = NULL;
 
static int currentTime = 0;              /* measured in clock cycles */
 
 
static int currentTime = 0;
static TimerCounter timerCounters[NUMBER_TMRCNT];
 
 
static Word timerCtrl = 0x00000000;
 
static Word timerDivisor = 0xFFFFFFFF;
 
static Word timerCounter = 0xFFFFFFFF;
 
 
 
 
 
Word timerRead(Word addr) {
Word timerRead(Word addr) {
 
  int dev, reg;
  Word data;
  Word data;
 
 
  if (debug) {
  if (debug) {
    cPrintf("\n**** TIMER READ from 0x%08X", addr);
    cPrintf("\n**** TIMER READ from 0x%08X", addr);
  }
  }
  if (addr == TIMER_CTRL) {
  dev = addr >> 12;
    data = timerCtrl;
  if (dev >= NUMBER_TMRCNT) {
 
    /* illegal device */
 
    throwException(EXC_BUS_TIMEOUT);
 
  }
 
  reg = addr & 0x0FFF;
 
  if (reg == TIMER_CTRL) {
 
    data = timerCounters[dev].ctrl;
 
  } else
 
  if (reg == TIMER_DIVISOR) {
 
    data = timerCounters[dev].divisor;
  } else
  } else
  if (addr == TIMER_DIVISOR) {
  if (reg == TIMER_COUNTER) {
    data = timerDivisor;
    data = timerCounters[dev].counter;
  } else {
  } else {
    /* illegal register */
    /* illegal register */
    throwException(EXC_BUS_TIMEOUT);
    throwException(EXC_BUS_TIMEOUT);
  }
  }
  if (debug) {
  if (debug) {
    cPrintf(", data = 0x%08X ****\n", data);
    cPrintf(", data = 0x%08X ****\n", data);
  }
  }
  return data;
  return data;
}
}
 
 
 
 
void timerWrite(Word addr, Word data) {
void timerWrite(Word addr, Word data) {
 
  int dev, reg;
 
 
  if (debug) {
  if (debug) {
    cPrintf("\n**** TIMER WRITE to 0x%08X, data = 0x%08X ****\n",
    cPrintf("\n**** TIMER WRITE to 0x%08X, data = 0x%08X ****\n",
            addr, data);
            addr, data);
  }
  }
  if (addr == TIMER_CTRL) {
  dev = addr >> 12;
 
  if (dev >= NUMBER_TMRCNT) {
 
    /* illegal device */
 
    throwException(EXC_BUS_TIMEOUT);
 
  }
 
  reg = addr & 0x0FFF;
 
  if (reg == TIMER_CTRL) {
    if (data & TIMER_IEN) {
    if (data & TIMER_IEN) {
      timerCtrl |= TIMER_IEN;
      timerCounters[dev].ctrl |= TIMER_IEN;
    } else {
    } else {
      timerCtrl &= ~TIMER_IEN;
      timerCounters[dev].ctrl &= ~TIMER_IEN;
    }
    }
    if (data & TIMER_EXP) {
    if (data & TIMER_EXP) {
      timerCtrl |= TIMER_EXP;
      timerCounters[dev].ctrl |= TIMER_EXP;
    } else {
    } else {
      timerCtrl &= ~TIMER_EXP;
      timerCounters[dev].ctrl &= ~TIMER_EXP;
    }
    }
    if ((timerCtrl & TIMER_IEN) != 0 &&
    if ((timerCounters[dev].ctrl & TIMER_IEN) != 0 &&
        (timerCtrl & TIMER_EXP) != 0) {
        (timerCounters[dev].ctrl & TIMER_EXP) != 0) {
      /* raise timer interrupt */
      /* raise timer interrupt */
      cpuSetInterrupt(IRQ_TIMER);
      cpuSetInterrupt(timerCounters[dev].irq);
    } else {
    } else {
      /* lower timer interrupt */
      /* lower timer interrupt */
      cpuResetInterrupt(IRQ_TIMER);
      cpuResetInterrupt(timerCounters[dev].irq);
    }
    }
  } else
  } else
  if (addr == TIMER_DIVISOR) {
  if (reg == TIMER_DIVISOR) {
    timerDivisor = data;
    timerCounters[dev].divisor = data;
    timerCounter = data;
    timerCounters[dev].counter = data;
  } else {
  } else {
    /* illegal register */
    /* illegal register */
    throwException(EXC_BUS_TIMEOUT);
    throwException(EXC_BUS_TIMEOUT);
  }
  }
}
}
 
 
 
 
void timerTick(void) {
void timerTick(void) {
  Timer *timer;
  Timer *timer;
  void (*callback)(int param);
  void (*callback)(int param);
  int param;
  int param;
 
  int i;
 
 
  /* increment current time, avoid overflow */
  /* increment current time */
  if (++currentTime == TIME_WRAP) {
  currentTime += CC_PER_INSTR;
 
  /* avoid overflow */
 
  if (currentTime >= TIME_WRAP) {
    currentTime -= TIME_WRAP;
    currentTime -= TIME_WRAP;
    timer = activeTimers;
    timer = activeTimers;
    while (timer != NULL) {
    while (timer != NULL) {
      timer->alarm -= TIME_WRAP;
      timer->alarm -= TIME_WRAP;
      timer = timer->next;
      timer = timer->next;
    }
    }
  }
  }
  /* check whether any simulation timer expired */
  /* check whether any simulation timer expired */
  while (activeTimers != NULL &&
  while (activeTimers != NULL &&
         currentTime >= activeTimers->alarm) {
         currentTime >= activeTimers->alarm) {
    timer = activeTimers;
    timer = activeTimers;
    activeTimers = timer->next;
    activeTimers = timer->next;
    callback = timer->callback;
    callback = timer->callback;
    param = timer->param;
    param = timer->param;
    timer->next = freeTimers;
    timer->next = freeTimers;
    freeTimers = timer;
    freeTimers = timer;
    (*callback)(param);
    (*callback)(param);
  }
  }
  /* decrement counter and check if an interrupt must be raised */
  /* decrement counters and check if an interrupt must be raised */
  if (--timerCounter == 0) {
  for (i = 0; i < NUMBER_TMRCNT; i++) {
    timerCounter = timerDivisor;
    if (timerCounters[i].counter <= CC_PER_INSTR) {
    timerCtrl |= TIMER_EXP;
      timerCounters[i].counter += timerCounters[i].divisor - CC_PER_INSTR;
    if (timerCtrl & TIMER_IEN) {
      timerCounters[i].ctrl |= TIMER_EXP;
 
      if (timerCounters[i].ctrl & TIMER_IEN) {
      /* raise timer interrupt */
      /* raise timer interrupt */
      cpuSetInterrupt(IRQ_TIMER);
        cpuSetInterrupt(timerCounters[i].irq);
 
      }
 
    } else {
 
      timerCounters[i].counter -= CC_PER_INSTR;
    }
    }
  }
  }
}
}
 
 
 
 
void timerStart(int msec, void (*callback)(int param), int param) {
void timerStart(int usec, void (*callback)(int param), int param) {
  Timer *timer;
  Timer *timer;
  Timer *p;
  Timer *p;
 
 
  if (freeTimers == NULL) {
  if (freeTimers == NULL) {
    error("out of timers");
    error("out of timers");
  }
  }
  timer = freeTimers;
  timer = freeTimers;
  freeTimers = timer->next;
  freeTimers = timer->next;
  timer->alarm = currentTime + msec;
  timer->alarm = currentTime + usec * CC_PER_USEC;
  timer->callback = callback;
  timer->callback = callback;
  timer->param = param;
  timer->param = param;
  if (activeTimers == NULL ||
  if (activeTimers == NULL ||
      timer->alarm < activeTimers->alarm) {
      timer->alarm < activeTimers->alarm) {
    /* link into front of active timers queue */
    /* link into front of active timers queue */
    timer->next = activeTimers;
    timer->next = activeTimers;
    activeTimers = timer;
    activeTimers = timer;
  } else {
  } else {
    /* link elsewhere into active timers queue */
    /* link elsewhere into active timers queue */
    p = activeTimers;
    p = activeTimers;
    while (p->next != NULL &&
    while (p->next != NULL &&
           p->next->alarm <= timer->alarm) {
           p->next->alarm <= timer->alarm) {
      p = p->next;
      p = p->next;
    }
    }
    timer->next = p->next;
    timer->next = p->next;
    p->next = timer;
    p->next = timer;
  }
  }
}
}
 
 
 
 
void timerReset(void) {
void timerReset(void) {
  Timer *timer;
  Timer *timer;
 
  int i;
 
 
  cPrintf("Resetting Timer...\n");
  cPrintf("Resetting Timer...\n");
  while (activeTimers != NULL) {
  while (activeTimers != NULL) {
    timer = activeTimers;
    timer = activeTimers;
    activeTimers = timer->next;
    activeTimers = timer->next;
    timer->next = freeTimers;
    timer->next = freeTimers;
    freeTimers = timer;
    freeTimers = timer;
  }
  }
 
  for (i = 0; i < NUMBER_TMRCNT; i++) {
 
    timerCounters[i].ctrl = 0x00000000;
 
    timerCounters[i].divisor = 0xFFFFFFFF;
 
    timerCounters[i].counter = 0xFFFFFFFF;
 
    timerCounters[i].irq = IRQ_TIMER_0 + i;
 
  }
}
}
 
 
 
 
void timerInit(void) {
void timerInit(void) {
  Timer *timer;
  Timer *timer;
  int i;
  int i;
 
 
  for (i = 0; i < NUMBER_TIMERS; i++) {
  for (i = 0; i < NUMBER_TIMERS; i++) {
    timer = malloc(sizeof(Timer));
    timer = malloc(sizeof(Timer));
    if (timer == NULL) {
    if (timer == NULL) {
      error("cannot allocate simulation timers");
      error("cannot allocate simulation timers");
    }
    }
    timer->next = freeTimers;
    timer->next = freeTimers;
    freeTimers = timer;
    freeTimers = timer;
  }
  }
  timerReset();
  timerReset();
}
}
 
 
 
 
void timerExit(void) {
void timerExit(void) {
  Timer *timer;
  Timer *timer;
 
 
  timerReset();
  while (activeTimers != NULL) {
 
    timer = activeTimers;
 
    activeTimers = timer->next;
 
    timer->next = freeTimers;
 
    freeTimers = timer;
 
  }
  while (freeTimers != NULL) {
  while (freeTimers != NULL) {
    timer = freeTimers;
    timer = freeTimers;
    freeTimers = timer->next;
    freeTimers = timer->next;
    free(timer);
    free(timer);
  }
  }
}
}
 
 

powered by: WebSVN 2.1.0

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