1 /* Mednafen - Multi-system Emulator
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 /*
18  TODO: Determine if the interrupt request bit can be manually set even if timer enable and/or timer int enable bits are 0.
19 */
20 
21 #include "pcfx.h"
22 #include "interrupt.h"
23 #include "timer.h"
24 
25 static uint16 control;
26 static uint16 period;
27 static int32 counter;
28 
29 static int32 lastts;
30 
CalcNextEventTS(const v810_timestamp_t timestamp)31 static INLINE v810_timestamp_t CalcNextEventTS(const v810_timestamp_t timestamp)
32 {
33    return((control & 0x2) ? (timestamp + counter) : PCFX_EVENT_NONONO);
34 }
35 
36 #define EFF_PERIOD ((period ? period : 0x10000) * 15)
37 
FXTIMER_Update(const v810_timestamp_t timestamp)38 v810_timestamp_t FXTIMER_Update(const v810_timestamp_t timestamp)
39 {
40    if(control & 0x2)
41    {
42       int32 cycles = timestamp - lastts;
43       counter -= cycles;
44       while(counter <= 0)
45       {
46          counter += EFF_PERIOD;
47          if(control & 0x1)
48          {
49             control |= 0x4;
50             PCFXIRQ_Assert(PCFXIRQ_SOURCE_TIMER, TRUE);
51          }
52       }
53    }
54 
55    lastts = timestamp;
56 
57    return(CalcNextEventTS(timestamp));
58 }
59 
FXTIMER_ResetTS(int32 ts_base)60 void FXTIMER_ResetTS(int32 ts_base)
61 {
62    lastts = ts_base;
63 }
64 
FXTIMER_Read16(uint32 A,const v810_timestamp_t timestamp)65 uint16 FXTIMER_Read16(uint32 A, const v810_timestamp_t timestamp)
66 {
67    FXTIMER_Update(timestamp);
68 
69    switch(A & 0xFC0)
70    {
71       default:
72          break;
73       case 0xF00:
74          return(control);
75       case 0xF80:
76          return(period);
77       case 0xFC0:
78          return((counter + 14) / 15);
79    }
80 
81    return 0;
82 }
83 
FXTIMER_Read8(uint32 A,const v810_timestamp_t timestamp)84 uint8 FXTIMER_Read8(uint32 A, const v810_timestamp_t timestamp)
85 {
86    FXTIMER_Update(timestamp);
87    return(FXTIMER_Read16(A&~1, timestamp) >> ((A & 1) * 8));
88 }
89 
FXTIMER_Write16(uint32 A,uint16 V,const v810_timestamp_t timestamp)90 void FXTIMER_Write16(uint32 A, uint16 V, const v810_timestamp_t timestamp)
91 {
92    FXTIMER_Update(timestamp);
93 
94    switch(A & 0xFC0)
95    {
96       default:
97          break;
98       case 0xF00:
99          if(!(control & 0x2) && (V & 0x2))
100             counter = EFF_PERIOD;
101          control = V & 0x7;
102 
103          if(V & 0x4)
104             FXDBG("Timer control write with D2 set?");
105 
106          PCFXIRQ_Assert(PCFXIRQ_SOURCE_TIMER, (bool)(control & 0x4));
107          PCFX_SetEvent(PCFX_EVENT_TIMER, CalcNextEventTS(timestamp));
108          break;
109 
110       case 0xF80:
111          period = V;
112          PCFX_SetEvent(PCFX_EVENT_TIMER, CalcNextEventTS(timestamp));
113          break;
114    }
115 }
116 
FXTIMER_StateAction(StateMem * sm,int load,int data_only)117 int FXTIMER_StateAction(StateMem *sm, int load, int data_only)
118 {
119    SFORMAT StateRegs[] =
120    {
121       SFVAR(counter),
122       SFVAR(period),
123       SFVAR(control),
124       SFEND
125    };
126 
127    int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "TIMR", false);
128 
129    if(load)
130    {
131 
132    }
133    return(ret);
134 }
135 
136 
137 
FXTIMER_GetRegister(const std::string & name,uint32 & value,std::string * special)138 bool FXTIMER_GetRegister(const std::string &name, uint32 &value, std::string *special)
139 {
140    if(name == "TCTRL")
141    {
142       value = control;
143       if(special)
144       {
145          char buf[256];
146          snprintf(buf, 256, "Counting Enabled: %d, IRQ Enabled: %d, IRQ Asserted: %d", (int)(bool)(control & 2), (int)(bool)(control & 1), (int)(bool)(control & 4));
147          *special = std::string(buf);
148       }
149       return(TRUE);
150    }
151    else if(name == "TPRD")
152    {
153       value = period;
154       if(special)
155       {
156          char buf[256];
157          snprintf(buf, 256, "Effective Period: %d; 21477272 / %d = %fHz", EFF_PERIOD, EFF_PERIOD, (double)21477272 / (EFF_PERIOD));
158          *special = std::string(buf);
159       }
160       return(TRUE);
161    }
162    else if(name == "TCNTR")
163    {
164       value = counter;
165       if(special)
166       {
167          //char buf[256];
168          //snprintf(buf, 256, "Pad: %d, ??: %d, Timer: %d, Reset: %d",
169          //*special = std::string(buf);
170       }
171       return(TRUE);
172    }
173    else
174       return(FALSE);
175 }
176 
FXTIMER_Reset(void)177 void FXTIMER_Reset(void)
178 {
179    control = 0;
180    period = 0;
181    counter = 0;
182 }
183 
FXTIMER_Init(void)184 void FXTIMER_Init(void)
185 {
186    lastts = 0;
187    FXTIMER_Reset();
188 }
189