예제 #1
0
파일: mfpemul.c 프로젝트: slippyex/OSME
/* Write Timer Data Register:

   Changing the value of the TDR change the value of the internal
   reset latch. However when the timer is stopped the reset value is
   reload into TDR in the next MFP cycle (so it seems to be the case
   according to my test on a real ST). The tricky point is that as MFP
   and CPU clock are separate (for Atari-ST) reading the value just
   after a write can occur before the next MFP cycle in which case the
   current TDR (not the one written) is returned! Fortunatly we don't
   really need to emulate this since it is more a glitch than anything
   a no one should have used it!

   Motorola Datasheet: the TDRs contain the value of their respective
   main counter. This value was captured on the last low-to-high
   transistion of the data strobe pin. The main counter is initialized
   by writting the to the TDR. If the timer is stopped the data is
   loaded simultaneously into both TDR and maincounter. If the TDR is
   written to while the timer is enabled, the value is not loaded into
   the timer until the timer counts through 01. If a write is
   performed while the timer is counting through 01 then an
   *INDETERMINATE* value is loaded into the main counter.

*/
void mfp_put_tdr(mfp_t * const mfp, int timer, int v, bogoc68_t bogoc)
{
  mfp_timer_t * const ptimer = &mfp->timers[timer&3];
  const uint68_t old_tdr = ptimer->tdr_res;

  /* Interrupt when count down to 0 so 0 is 256 */
  v  = (u8)v; v += (!v)<<8;
  ptimer->tdr_res = v;

  if (!ptimer->tcr) {
    ptimer->tdr_cur = v;
    if (mfp_feature) fprintf(stderr, "Reload timer-%c TDR @%u => %u\n",
	    ptimer->def.letter, bogoc, ptimer->tdr_res);
  } else if (ptimer->tcr && v != old_tdr) {
    uint68_t old_frq = timerfrq(old_tdr);
    if (mfp_feature) fprintf(stderr,
	    "Change timer-%c @%u cti:%u psw:%u(%u) cpp:%u"
	    " => %u(%u)->%u(%u)hz\n",
	    ptimer->def.letter, bogoc, ptimer->cti,
	    prediv_width[ptimer->tcr], ptimer->tcr,
	    cpp(ptimer->tdr_res),
	    old_frq,old_tdr,
	    timerfrq(ptimer->tdr_res), ptimer->tdr_res);
  }
}
예제 #2
0
/* Write Timer Data Register:

   Changing the value of the TDR change the value of the internal
   reset latch. However when the timer is stopped the reset value is
   reload into TDR in the next MFP cycle (so it seems to be the case
   according to my test on a real ST). The tricky point is that as MFP
   and CPU clock are separate (for Atari-ST) reading the value just
   after a write can occur before the next MFP cycle in which case the
   current TDR (not the one written) is returned! Fortunatly we don't
   really need to emulate this since it is more a glitch than anything
   and no one should have used it!

   Motorola Datasheet: the TDRs contain the value of their respective
   main counter. This value was captured on the last low-to-high
   transistion of the data strobe pin. The main counter is initialized
   by writting the to the TDR. If the timer is stopped the data is
   loaded simultaneously into both TDR and maincounter. If the TDR is
   written to while the timer is enabled, the value is not loaded into
   the timer until the timer counts through 01. If a write is
   performed while the timer is counting through 01 then an
   INDETERMINATE value is loaded into the main counter.

*/
void mfp_put_tdr(mfp_t * const mfp, int timer, int68_t v, const bogoc68_t bogoc)
{
  mfp_timer_t * const  ptimer = &mfp->timers[timer&3];
#ifndef NDEBUG
  const uint_t old_tdr = ptimer->tdr_res;
#endif

  /* Interrupt when count down to 0 so 0 is 256 */
  v  = (u8)v; v += (!v)<<8;
  ptimer->tdr_res = v;

  if (!ptimer->tcr) {
    ptimer->tdr_cur = v;
    TRACE68(mfp_cat,
          MYHD "timer-%c -- reload TDR @%u -- %u\n",
            ptimer->def.letter, (unsigned) bogoc, (unsigned) ptimer->tdr_res);
  }
#ifndef NDEBUG
  else if (ptimer->tcr && v != old_tdr) {
    uint_t old_frq = timerfrq(old_tdr);
    TRACE68(mfp_cat,
            MYHD "timer-%c -- change @%u cti:%u psw:%u(%u) cpp:%u"
            " -- %u(%u) -> %u(%u)hz\n",
            ptimer->def.letter, (unsigned) bogoc, (unsigned) ptimer->cti,
            (unsigned) prediv_width[ptimer->tcr], (unsigned) ptimer->tcr,
            (unsigned) cpp(ptimer->tdr_res),
            (unsigned) old_frq, (unsigned) old_tdr,
            (unsigned) timerfrq(ptimer->tdr_res), (unsigned) ptimer->tdr_res);
  }
#endif
}
예제 #3
0
/* Control register changes, adjust ``cti'' (cycle to next interrupt)
 *
 *    This case is a bit tricky : Changing timer prescale on the fly
 *    may have unpredictable result mostly because we dunno how
 *    prescaler works exactly. Here I assume the prescaler is
 *    resetted.
 *
 *    !!! chipmon of synergy does !!!
 *
 */
static inline
void reconf_timer(mfp_timer_t * const ptimer, int tcr, const bogoc68_t bogoc)
{
#if !defined(NDEBUG) || !defined(CPP_SUPPORTS_VA_MACROS)
  uint_t          frq = timerfrq(ptimer->tdr_res); /* old frequency       */
#endif
  const bogoc68_t cti = ptimer->cti - bogoc;       /* cycles to interrupt */
  const uint_t    psw = prediv_width[ptimer->tcr]; /* cycles count-down   */
  const uint_t    cnt = cti/psw;                   /* count-down          */
  const uint_t    psr = cti % psw;
  /* const uint68_t  psc = psw-psr; */

  /* cnt%ptimer->tdr_res+1; no MODULO since TDR may have change and anyway
     cti was calculated with 1 timer cycle !!! */
  const uint_t    tdr = cnt+1;
  const cycle68_t new_psw = prediv_width[(int)tcr];

  if (bogoc > ptimer->cti) {
    TRACE68(mfp_cat,
          MYHD "timer-%c -- reconf out of range -- @%u > cti:%u\n",
          ptimer->def.letter, (unsigned) bogoc, (unsigned) ptimer->cti);
    ptimer->cti = bogoc + psw * ptimer->tdr_res;
  } else {
    ptimer->cti = bogoc + psr + (tdr-1) * new_psw;
    ptimer->cti = bogoc + /* psr + */ (tdr/* -1 */) * new_psw;
  }

  ptimer->tcr = tcr;

  TRACE68(mfp_cat,
          MYHD "timer-%c -- reconf @%u cti:%u cpp:%u -- %u:%uhz\n",
          ptimer->def.letter, (unsigned) bogoc,
          (unsigned) ptimer->cti, (unsigned) cpp(ptimer->tdr_res),
          (unsigned) frq, (unsigned) timerfrq(ptimer->tdr_res));
}
예제 #4
0
파일: mfpemul.c 프로젝트: slippyex/OSME
/* Control register changes, adjust ``cti'' (cycle to next interrupt)
 *
 *    This case is a bit tricky : Changing timer prescale on the fly
 *    may have unpredictable result mostly because we dunno how
 *    prescaler works exactly. Here I assume the prescaler is
 *    resetted.
 *
 *    !!! chipmon of synergy does !!!
 *
 */
static __inline
void reconf_timer(mfp_timer_t * const ptimer, int tcr, const bogoc68_t bogoc)
{
  uint68_t        frq = timerfrq(ptimer->tdr_res); /* old frequency       */
  const bogoc68_t cti = ptimer->cti - bogoc;       /* cycles to interrupt */
  const uint68_t  psw = prediv_width[ptimer->tcr]; /* cycles count-down   */
  const uint68_t  cnt = cti/psw;                   /* count-down          */
  const uint68_t  psr = cti % psw;
  const uint68_t  psc = psw-psr;

  /* cnt%ptimer->tdr_res+1; no MODULO since TDR may have change and anyway
     cti was calculated with 1 timer cycle !!! */
  const uint68_t  tdr = cnt+1;
  const cycle68_t new_psw = prediv_width[(int)tcr];
  

  if (bogoc > ptimer->cti) {
    if (mfp_feature) fprintf(stderr,
	    "Reconf timer-%c @%u > cti:%u !!!CYCLE OUT OF RANGE!!!\n",
	    ptimer->def.letter, bogoc, ptimer->cti);
    ptimer->cti = bogoc + psw * ptimer->tdr_res;
  } else {

    ptimer->cti = bogoc + psr + (tdr-1) * new_psw;
    ptimer->cti = bogoc + /* psr + */ (tdr/* -1 */) * new_psw;

/*     if (ptimer->cti != cti_verif) { */
/*       if (mfp_feature) fprintf(stderr, */
/* 	      "Reconf timer-%c @%u psw:%u->%u psc:%u  cti:%u!=%u !!!\n", */
/* 	      ptimer->def.letter, bogoc, psw, new_psw, psc, */
/* 	      cti_verif, ptimer->cti); */
/*     } */
  }

  ptimer->tcr = tcr;

  if (mfp_feature) fprintf(stderr, "Reconf timer-%c @%u cti:%u cpp:%u=> %d->%dhz\n", 
	  ptimer->def.letter, bogoc,
	  ptimer->cti, cpp(ptimer->tdr_res),
	  frq,timerfrq(ptimer->tdr_res));
}
예제 #5
0
파일: mfpemul.c 프로젝트: slippyex/OSME
/* Resume a stopped timer: tcr 0->!0
 */
static __inline
void resume_timer(mfp_timer_t * const ptimer, int tcr, bogoc68_t bogoc)
{
  ptimer->tcr = tcr;
  ptimer->cti = bogoc + ptimer->tdr_cur * prediv_width[tcr] - ptimer->psc;
  
  if (mfp_feature) fprintf(stderr,
	  "Resume timer-%c @%u cti:%u cpp:%u "
	  "tdr:%u/%u psw:%u(%u) => %dhz\n", 
	  ptimer->def.letter, bogoc, ptimer->cti,
	  cpp(ptimer->tdr_res),
	  (int)ptimer->tdr_cur,(int)ptimer->tdr_res,
	  prediv_width[ptimer->tcr],ptimer->tcr,
	  timerfrq(ptimer->tdr_res));
}
예제 #6
0
/* Resume a stopped timer: tcr 0->!0
 */
static inline
void resume_timer(mfp_timer_t * const ptimer, int tcr, bogoc68_t bogoc)
{
  ptimer->tcr = tcr;
  ptimer->cti = bogoc + ptimer->tdr_cur * prediv_width[tcr] - ptimer->psc;

  TRACE68(mfp_cat,
          MYHD "timer-%c  -- resume @%u cti:%u cpp:%u "
          "tdr:%u/%u psw:%u(%u) -- %uhz\n",
          ptimer->def.letter, (unsigned) bogoc, (unsigned) ptimer->cti,
          (unsigned) cpp(ptimer->tdr_res),
          (unsigned) ptimer->tdr_cur, (unsigned) ptimer->tdr_res,
          (unsigned) prediv_width[ptimer->tcr], (unsigned) ptimer->tcr,
          (unsigned) timerfrq(ptimer->tdr_res));
}