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