Advertisement
xiahanlu

设备定时器和分频器

Oct 13th, 2018
246
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.14 KB | None | 0 0
  1. /* timer about TIMA, TMA, TAC
  2.  *
  3.  * Copyright (C) 2018 moecmks
  4.  * This file is part of KS3578.
  5.  *
  6.  * do What The Fuck you want to Public License
  7.  *
  8.  * Version 1.0, March 2000
  9.  * Copyright (C) 2000 Banlu Kemiyatorn (]d).
  10.  * 136 Nives 7 Jangwattana 14 Laksi Bangkok
  11.  * Everyone is permitted to copy and distribute verbatim copies
  12.  * of this license document, but changing it is not allowed.
  13.  *
  14.  * Ok, the purpose of this license is simple
  15.  * and you just
  16.  *
  17.  * DO WHAT THE FUCK YOU WANT TO.
  18.  */
  19.  
  20. #include "gameboy.h"
  21. #include "internal.h"
  22.  
  23. void timer_write (struct timer *timer, ks_uint16 addr, ks_uint8 value) {
  24.  
  25.   switch (addr) {
  26.   case 0xFF05: /* TIMA */
  27.     timer->reg05_TIMA = value;
  28.     break;
  29.   case 0xFF06: /* TMA */
  30.     timer->reg06_TMA = value;
  31.     break;
  32.   case 0xFF07: /* TAC */
  33.     if ( (value & 0x04) && !(timer->reg07_TAC & 0x04)) {
  34.       timer->timestamp = timer->gb->cpu_clks_timer; /* low to high, open pulse, init timestamp. */
  35.       timer->reg05_TIMA = timer->reg06_TMA;
  36.     }
  37.     timer->reg07_TAC = value;
  38.     break;
  39.   default:
  40.     assert(0);
  41.   }
  42. #ifdef TIMER_RESET_IN_RESET_FREQ_MOD_
  43.   timer->timestamp = timer->gb->cpu_clks_timer;
  44. #endif
  45. }
  46.  
  47. ks_uint8 timer_read (struct timer *timer, ks_uint16 addr) {
  48.  
  49.   switch (addr) {
  50.   case 0xFF05: /* TIMA */
  51.     return timer->reg05_TIMA;
  52.   case 0xFF06: /* TMA */
  53.     return timer->reg06_TMA;
  54.   case 0xFF07: /* TAC */
  55.     return timer->reg07_TAC;
  56.   default:
  57.     assert(0);
  58.   }
  59.   return 0;
  60. }
  61.  
  62. /*XXX: this function looks bad. */
  63. static
  64. void timer_update (struct timer *timer) {
  65.   /* !must update gameboy's context about timer before this call */
  66.   /*   double cpu_clks_timer;
  67.   double cpu_clks_el */
  68.   ks_double elap;
  69.   ks_int32 coub;
  70.   ks_double calc_cac;
  71.   assert (timer != ks_null);
  72.   /* enable timing???*/
  73.   if ( !(timer->reg07_TAC & 0x04))
  74.     return  ;
  75.   else ;
  76.   /* get elapsed cpu time */
  77.   elap = timer->gb->cpu_clks_timer - timer->timestamp;
  78.   /* convert to basic frequency of timer */
  79.   calc_cac = timer->freq_tab[timer->reg07_TAC & 3];
  80.   coub = 0;
  81.   while (elap > calc_cac) {
  82.     /* update timer */
  83.     if (timer->reg05_TIMA == 0xFF) {
  84.       /* overflow, IRQ_3 interrupt will requested */
  85.       timer->reg05_TIMA = timer->reg06_TMA;
  86.       timer->gb->reg0F_IF |= IRQ_3;  
  87.     } else {
  88.       timer->reg05_TIMA ++;
  89.     }
  90.     elap -= calc_cac;
  91.     coub = 1;
  92.   }
  93.   /* update timestamp */
  94.   if (coub != 0) {
  95.     timer->gb->cpu_clks_timer = elap;
  96.     timer->timestamp = 0.0;
  97.   }
  98. }
  99.  
  100. int timer_init (struct timer **timer) {
  101.   struct timer *timer_ =ks_null;
  102.   assert (timer != ks_null);
  103.  
  104.   timer_ = (struct timer *)
  105.      calloc (sizeof (struct timer), 1);
  106.   timer_->clks = timer_update;
  107.   assert (timer_ != ks_null);
  108.   * timer = timer_;
  109.   return 0;
  110. }
  111.  
  112. void timer_cgb_mode (struct timer *timer) {
  113. #ifdef TIMER_DIVIDER_SAME_FREQ_BOTH_CBG_DMG_BASE_DMG
  114.   timer->freq_tab[0] = 2047.998;
  115.   timer->freq_tab[1] = 31.998;
  116.   timer->freq_tab[2] = 127.998;
  117.   timer->freq_tab[3] = 511.998;
  118. #else
  119.   timer->freq_tab[0] = 1023.998;
  120.   timer->freq_tab[1] = 15.998;
  121.   timer->freq_tab[2] = 63.998;
  122.   timer->freq_tab[3] = 255.998;
  123. #endif
  124. }
  125.  
  126. void timer_dmg_mode (struct timer *timer) {
  127.   timer->freq_tab[0] = 1023.998;
  128.   timer->freq_tab[1] = 15.998;
  129.   timer->freq_tab[2] = 63.998;
  130.   timer->freq_tab[3] = 255.998;
  131. }
  132.  
  133. void timer_uninit (struct timer **timer) {
  134.   struct timer *timer_;
  135.   assert (timer != ks_null);
  136.   timer_ = *timer;
  137.   *timer = ks_null;
  138.   if (timer_ != ks_null)
  139.     free (timer_);
  140.   else ;
  141. }
  142. void divider_write (struct divider *divider, ks_uint8 value) {
  143.  
  144.   divider->reg04_DIV = value;
  145. }
  146.  
  147. ks_uint8 divider_read (struct divider *divider) {
  148.  
  149.   return divider->reg04_DIV;
  150. }
  151.  
  152. void divider_cgb_mode (struct divider *divider) {
  153. #ifdef TIMER_DIVIDER_SAME_FREQ_BOTH_CBG_DMG_BASE_DMG
  154.   divider->freq = 512.0;
  155. #else
  156.   divider->freq = 256.0;
  157. #endif
  158. }
  159.  
  160. void divider_dmg_mode (struct divider *divider) {
  161.   divider->freq = 256.0;
  162. }
  163.  
  164. /*XXX: this function looks bad. */
  165. static
  166. void divider_update (struct divider *divider) {
  167.   /* !must update gameboy's context about divider before this call */
  168.   /*   double cpu_clks_divider;
  169.   double cpu_clks_el */
  170.   ks_double elap;
  171.   ks_int32 coub;
  172.   assert (divider != ks_null);
  173.   /* get elapsed cpu time */
  174.   elap = divider->gb->cpu_clks_divider - divider->timestamp;
  175.   coub = 0;
  176.   while (elap > divider->freq) {
  177.     /* update divider */
  178.     divider->reg04_DIV++;
  179.     elap -= divider->freq;
  180.     coub = 1;
  181.   }
  182.   /* update timestamp */
  183.   if (coub != 0) {
  184.     divider->gb->cpu_clks_divider = elap;
  185.     divider->timestamp = 0.0;
  186.   }
  187. }
  188.  
  189. int divider_init (struct divider **divider) {
  190.   struct divider *divider_ =ks_null;
  191.   assert (divider != ks_null);
  192.  
  193.   divider_ = (struct divider *)
  194.      calloc (sizeof (struct divider), 1);
  195.   divider_->clks = divider_update;
  196.   assert (divider_ != ks_null);
  197.   * divider = divider_;
  198.   divider_dmg_mode (divider_);
  199.   return 0;
  200. }
  201.  
  202. void divider_uninit (struct divider **divider) {
  203.   struct divider *divider_;
  204.   assert (divider != ks_null);
  205.   divider_ = *divider;
  206.   *divider = ks_null;
  207.   if (divider_ != ks_null)
  208.     free (divider_);
  209.   else ;
  210. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement