1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz
3 /******************************************************************************
4 *
5 *   Sony PlayStation 2 EE timer device skeleton
6 *
7 *   To Do:
8 *     Everything
9 *
10 */
11 
12 #include "emu.h"
13 #include "ps2timer.h"
14 
15 DEFINE_DEVICE_TYPE(SONYPS2_TIMER, ps2_timer_device, "ps2timer", "PlayStation 2 EE Core Timer")
16 
ps2_timer_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)17 ps2_timer_device::ps2_timer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
18 	: device_t(mconfig, SONYPS2_TIMER, tag, owner, clock)
19 	, m_compare_timer(nullptr)
20 	, m_overflow_timer(nullptr)
21 	, m_mode(0)
22 	, m_last_enable_time(attotime::zero)
23 	, m_last_update_time(attotime::zero)
24 	, m_elapsed_time(attotime::zero)
25 	, m_enabled(false)
26 	, m_zero_return(false)
27 	, m_count(0)
28 	, m_compare(0)
29 	, m_can_hold(false)
30 	, m_hold(0)
31 	, m_clk_select(CLKS_BUSCLK1)
32 	, m_gate_enable(false)
33 	, m_gate_select(GATS_HBLNK)
34 	, m_gate_mode(GATM_LOW)
35 	, m_cmp_int_enabled(false)
36 	, m_cmp_int(false)
37 	, m_ovf_int_enabled(false)
38 	, m_ovf_int(false)
39 {
40 }
41 
device_start()42 void ps2_timer_device::device_start()
43 {
44 	if (!m_compare_timer)
45 		m_compare_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ps2_timer_device::compare), this));
46 
47 	if (!m_overflow_timer)
48 		m_overflow_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ps2_timer_device::overflow), this));
49 }
50 
device_reset()51 void ps2_timer_device::device_reset()
52 {
53 	m_mode = 0;
54 
55 	m_last_enable_time = attotime::zero;
56 	m_last_update_time = attotime::zero;
57 	m_elapsed_time = attotime::zero;
58 
59 	m_enabled = false;
60 	m_zero_return = false;
61 
62 	m_count = 0;
63 	m_compare = 0;
64 
65 	m_can_hold = false;
66 	m_hold = 0;
67 
68 	m_clk_select = CLKS_BUSCLK1;
69 
70 	m_gate_enable = false;
71 	m_gate_select = GATS_HBLNK;
72 	m_gate_mode = GATM_LOW;
73 
74 	m_cmp_int_enabled = false;
75 	m_cmp_int = false;
76 
77 	m_ovf_int_enabled = false;
78 	m_ovf_int = false;
79 
80 	m_compare_timer->adjust(attotime::never);
81 	m_overflow_timer->adjust(attotime::never);
82 }
83 
update_gate()84 void ps2_timer_device::update_gate()
85 {
86 	// TODO
87 }
88 
update_interrupts()89 void ps2_timer_device::update_interrupts()
90 {
91 	// TODO
92 }
93 
update_compare_timer()94 void ps2_timer_device::update_compare_timer()
95 {
96 	// TODO
97 }
98 
update_overflow_timer()99 void ps2_timer_device::update_overflow_timer()
100 {
101 	// TODO
102 }
103 
update_count()104 void ps2_timer_device::update_count()
105 {
106 	if (!m_enabled) return;
107 	uint32_t frequency = 0;
108 
109 	switch (m_clk_select)
110 	{
111 		case CLKS_BUSCLK1:
112 			frequency = clock();
113 			break;
114 		case CLKS_BUSCLK16:
115 			frequency = clock() / 16;
116 			break;
117 		case CLKS_BUSCLK256:
118 			frequency = clock() / 256;
119 			break;
120 		case CLKS_HBLNK:
121 			frequency = clock() / 18700;
122 			break;
123 	}
124 
125 	attotime curr_time = machine().scheduler().time();
126 	attotime time_delta = curr_time - m_last_update_time;
127 	m_last_update_time = curr_time;
128 	m_elapsed_time += time_delta;
129 	uint32_t ticks = (uint32_t)m_elapsed_time.as_ticks(frequency);
130 	if (ticks > 0)
131 	{
132 		m_elapsed_time -= attotime::from_ticks(ticks, frequency);
133 		m_count += ticks;
134 		m_count &= 0xffff;
135 	}
136 }
137 
update_hold()138 void ps2_timer_device::update_hold()
139 {
140 	// TODO
141 }
142 
set_mode(uint32_t data)143 void ps2_timer_device::set_mode(uint32_t data)
144 {
145 	static char const *const clks_names[4] = { "BUSCLK", "BUSCLK/16", "BUSCLK/256", "HBLNK" };
146 	static char const *const gatm_names[4] = { "low", "reset+rising", "reset+falling", "reset+both" };
147 	logerror("%s:          CLKS=%s, GATE=%d, GATS=%cBLNK\n", machine().describe_context(), clks_names[data & 3], BIT(data, 2), BIT(data, 3) ? 'V' : 'H');
148 	logerror("%s:          GATM=%s, ZRET=%d, CUE=%d\n", machine().describe_context(), gatm_names[(data >> 4) & 3], BIT(data, 6), BIT(data, 7));
149 	logerror("%s:          CMPE=%d, OVFE=%d, %s, %s\n", machine().describe_context(), BIT(data, 8), BIT(data, 9), BIT(data, 10) ? "Clear Equal" : "", BIT(data, 11) ? "Clear Overflow" : "");
150 
151 	if (!(data & (MODE_EQUF | MODE_OVFF)) && data == m_mode) return;
152 
153 	const uint32_t old = m_mode;
154 	m_mode = data;
155 	const uint32_t changed = old ^ data;
156 
157 	m_clk_select = (timer_clock_select)(data & 3);
158 	m_gate_enable = BIT(data, 2);
159 	m_gate_select = BIT(data, 3) ? GATS_VBLNK : GATS_HBLNK;
160 	m_gate_mode = (timer_gate_mode)((data >> 4) & 3);
161 	m_zero_return = BIT(data, 6);
162 	m_enabled = BIT(data, 7);
163 
164 	if (changed & (MODE_GATE | MODE_GATS | MODE_GATM))
165 	{
166 		update_gate();
167 	}
168 
169 	if (changed & (MODE_CUE | MODE_CLKS | MODE_ZRET))
170 	{
171 		update_compare_timer();
172 		update_overflow_timer();
173 	}
174 
175 	if (changed & (MODE_CMPE | MODE_OVFE | MODE_EQUF | MODE_OVFF))
176 	{
177 		m_cmp_int_enabled = BIT(data, 8);
178 		m_ovf_int_enabled = BIT(data, 9);
179 		m_cmp_int = BIT(data, 10) ? 0 : m_cmp_int;
180 		m_ovf_int = BIT(data, 11) ? 0 : m_ovf_int;
181 		update_interrupts();
182 	}
183 }
184 
TIMER_CALLBACK_MEMBER(ps2_timer_device::compare)185 TIMER_CALLBACK_MEMBER(ps2_timer_device::compare)
186 {
187 }
188 
TIMER_CALLBACK_MEMBER(ps2_timer_device::overflow)189 TIMER_CALLBACK_MEMBER(ps2_timer_device::overflow)
190 {
191 }
192 
read(offs_t offset,uint32_t mem_mask)193 uint32_t ps2_timer_device::read(offs_t offset, uint32_t mem_mask)
194 {
195 	uint32_t ret = 0;
196 	switch (offset)
197 	{
198 		case 0x00:
199 		{
200 			const uint32_t old = m_count;
201 			update_count();
202 			ret = m_count;
203 			if (old != m_count)
204 				logerror("%s: PS2 timer read: COUNT (%08x & %08x)\n", machine().describe_context(), ret, mem_mask);
205 			break;
206 		}
207 
208 		case 0x02:
209 			ret = m_mode;
210 			logerror("%s: PS2 timer read: MODE (%08x & %08x)\n", machine().describe_context(), ret, mem_mask);
211 			break;
212 
213 		case 0x04:
214 			ret = m_compare;
215 			logerror("%s: PS2 timer read: COMP (%08x & %08x)\n", machine().describe_context(), ret, mem_mask);
216 			break;
217 
218 		case 0x06:
219 			ret = m_hold;
220 			logerror("%s: PS2 timer read: HOLD (%08x & %08x)\n", machine().describe_context(), ret, mem_mask);
221 			break;
222 
223 		default:
224 			break;
225 	}
226 	return ret;
227 }
228 
write(offs_t offset,uint32_t data,uint32_t mem_mask)229 void ps2_timer_device::write(offs_t offset, uint32_t data, uint32_t mem_mask)
230 {
231 	switch (offset)
232 	{
233 		case 0x00:
234 			m_count = data;
235 			logerror("%s: PS2 timer write: COUNT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
236 			update_compare_timer();
237 			update_overflow_timer();
238 			break;
239 
240 		case 0x02:
241 			set_mode(data);
242 			break;
243 
244 		case 0x04:
245 		{
246 			logerror("%s: PS2 timer write: COMP = %08x & %08x\n", machine().describe_context(), data, mem_mask);
247 			if (m_compare == data)
248 				break;
249 
250 			m_compare = data;
251 			update_compare_timer();
252 			break;
253 		}
254 
255 		case 0x06:
256 		{
257 			if (!m_can_hold)
258 				break;
259 
260 			logerror("%s: PS2 timer write: HOLD = %08x & %08x\n", machine().describe_context(), data, mem_mask);
261 			if (m_hold == data)
262 				break;
263 
264 			m_hold = data;
265 			update_hold();
266 			break;
267 		}
268 
269 		default:
270 			break;
271 	}
272 }
273