1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz
3 /***************************************************************************
4 
5     Sony PocketStation
6 
7     PocketStation games were dowloaded from PS1 games into flash RAM after
8     the unit had been inserted in the memory card slot, and so this should
9     be emulated alongside the PS1.  However, as many flash dumps exist, it
10     is possible to emulate the PocketStation in the meantime.
11 
12     CPU: ARM7T (32 bit RISC Processor)
13     Memory: 2Kbytes of SRAM, 128Kbytes of FlashROM
14     Graphics: 32x32 monochrome LCD
15     Sound: 1 12-bit PCM channel
16     Input: 5 input buttons, 1 reset button
17     Infrared communication: Bi-directional and uni-directional comms
18     Other: 1 LED indicator
19 
20     Currently, a handful of games run, but some die due to odd hardware
21     issues.
22 
23     To start a game:
24     - Wait for the set-date screen to appear
25     - Press Down
26     - Set date with directional controls (optional)
27     - Press Button 1, wait, press Button 1, press Right, game starts
28 
29     If you do nothing for about 20 secs, it turns itself off (screen goes white).
30 
31 ****************************************************************************/
32 
33 #include "emu.h"
34 #include "bus/generic/carts.h"
35 #include "bus/generic/slot.h"
36 #include "cpu/arm7/arm7.h"
37 #include "cpu/arm7/arm7core.h"
38 #include "sound/dac.h"
39 #include "emupal.h"
40 #include "screen.h"
41 #include "speaker.h"
42 
43 #define LOG_UNKNOWN (1 << 0)
44 #define LOG_FTLB    (1 << 1)
45 #define LOG_IRQS    (1 << 2)
46 #define LOG_INTC    (1 << 3)
47 #define LOG_TIMER   (1 << 4)
48 #define LOG_CLOCK   (1 << 5)
49 #define LOG_RTC     (1 << 6)
50 #define LOG_LCD     (1 << 7)
51 #define LOG_AUDIO   (1 << 8)
52 #define LOG_ALL     (LOG_UNKNOWN | LOG_FTLB | LOG_IRQS | LOG_INTC | LOG_TIMER | LOG_CLOCK | LOG_RTC | LOG_LCD | LOG_AUDIO)
53 #define LOG_DEFAULT LOG_ALL
54 
55 #define VERBOSE     (0)
56 #include "logmacro.h"
57 
58 class pockstat_state : public driver_device
59 {
60 public:
pockstat_state(const machine_config & mconfig,device_type type,const char * tag)61 	pockstat_state(const machine_config &mconfig, device_type type, const char *tag) :
62 		driver_device(mconfig, type, tag),
63 		m_lcd_buffer(*this, "lcd_buffer"),
64 		m_maincpu(*this, "maincpu"),
65 		m_cart(*this, "cartslot")
66 	{ }
67 
68 	void pockstat(machine_config &config);
69 
70 	DECLARE_INPUT_CHANGED_MEMBER(input_update);
71 
72 private:
73 	virtual void machine_start() override;
74 	virtual void machine_reset() override;
75 
76 	void mem_map(address_map &map);
77 
78 	uint32_t screen_update_pockstat(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
79 
80 	void set_interrupt_line(uint32_t line, int state);
81 	uint32_t get_interrupt_line(uint32_t line);
82 
83 	void timer_start(int index);
84 
85 	required_shared_ptr<uint32_t> m_lcd_buffer;
86 	required_device<cpu_device> m_maincpu;
87 	required_device<generic_slot_device> m_cart;
88 	memory_region *m_cart_rom;
89 
90 	static constexpr uint32_t TIMER_COUNT = 3;
91 
92 	enum : uint32_t
93 	{
94 		CLOCK_STEADY = 0x10
95 	};
96 
97 	enum
98 	{
99 		INT_BTN_ACTION     = 0x00000001, // "Action button"
100 		INT_BTN_RIGHT      = 0x00000002, // "Right button"
101 		INT_BTN_LEFT       = 0x00000004, // "Left button"
102 		INT_BTN_DOWN       = 0x00000008, // "Down button"
103 		INT_BTN_UP         = 0x00000010, // "Up button"
104 		INT_UNKNOWN        = 0x00000020, // "Unknown"
105 		INT_COM            = 0x00000040, // "COM" ???
106 		INT_TIMER0         = 0x00000080, // "Timer 0"
107 		INT_TIMER1         = 0x00000100, // "Timer 1"
108 		INT_RTC            = 0x00000200, // "RTC"
109 		INT_BATTERY        = 0x00000400, // "Battery Monitor"
110 		INT_IOP            = 0x00000800, // "IOP"
111 		INT_IRDA           = 0x00001000, // "IrDA"
112 		INT_TIMER2         = 0x00002000, // "Timer 2"
113 		INT_IRQ_MASK       = 0x00001fbf,
114 		INT_FIQ_MASK       = 0x00002040,
115 		INT_STATUS_MASK    = 0x0000021f
116 	};
117 
118 	struct ftlb_regs_t
119 	{
120 		uint32_t control;
121 		uint32_t stat;
122 		uint32_t valid;
123 		uint32_t wait1;
124 		uint32_t wait2;
125 		uint32_t entry[16];
126 		uint32_t serial;
127 	} m_ftlb_regs;
128 
129 	struct intc_regs_t
130 	{
131 		uint32_t hold;
132 		uint32_t status;
133 		uint32_t enable;
134 		uint32_t mask;
135 	} m_intc_regs;
136 
137 	struct timer_t
138 	{
139 		uint32_t period;
140 		uint32_t count;
141 		uint32_t control;
142 		emu_timer *timer;
143 	} m_timers[TIMER_COUNT];
144 
145 	struct clock_regs_t
146 	{
147 		uint32_t mode;
148 		uint32_t control;
149 	} m_clock_regs;
150 
151 	struct rtc_regs_t
152 	{
153 		uint32_t mode;
154 		uint32_t control;
155 		uint32_t time;
156 		uint32_t date;
157 		emu_timer *timer;
158 	} m_rtc_regs;
159 
160 	uint32_t m_lcd_control;
161 	int32_t m_flash_write_enable_count;
162 	int32_t m_flash_write_count;
163 
164 	uint32_t ftlb_r(offs_t offset, uint32_t mem_mask = ~0);
165 	void ftlb_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
166 	uint32_t intc_r(offs_t offset, uint32_t mem_mask = ~0);
167 	void intc_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
168 	uint32_t timer_r(offs_t offset, uint32_t mem_mask = ~0);
169 	void timer_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
170 	uint32_t clock_r(offs_t offset, uint32_t mem_mask = ~0);
171 	void clock_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
172 	uint32_t rtc_r(offs_t offset, uint32_t mem_mask = ~0);
173 	void rtc_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
174 	uint32_t lcd_r(offs_t offset, uint32_t mem_mask = ~0);
175 	void lcd_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
176 	uint32_t rombank_r(offs_t offset, uint32_t mem_mask = ~0);
177 	uint32_t flash_r(offs_t offset, uint32_t mem_mask = ~0);
178 	void flash_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
179 	uint32_t audio_r(offs_t offset, uint32_t mem_mask = ~0);
180 	void audio_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
181 	TIMER_CALLBACK_MEMBER(timer_tick);
182 	TIMER_CALLBACK_MEMBER(rtc_tick);
183 	DECLARE_DEVICE_IMAGE_LOAD_MEMBER(flash_load);
184 
185 	static const int CPU_FREQ[16];
186 };
187 
188 const int pockstat_state::CPU_FREQ[16] =
189 {
190 	0x00f800,
191 	0x01f000,
192 	0x03e000,
193 	0x07c000,
194 	0x0f8000,
195 	0x1e8000,
196 	0x3d0000,
197 	0x7a0000,
198 	0x7a0000,
199 	0x7a0000,
200 	0x7a0000,
201 	0x7a0000,
202 	0x7a0000,
203 	0x7a0000,
204 	0x7a0000,
205 	0x7a0000
206 };
207 
ftlb_r(offs_t offset,uint32_t mem_mask)208 uint32_t pockstat_state::ftlb_r(offs_t offset, uint32_t mem_mask)
209 {
210 	switch(offset)
211 	{
212 	case 0x0000/4:
213 		LOGMASKED(LOG_FTLB, "%s: FlashROM TLB Control = %08x & %08x\n", machine().describe_context(), m_ftlb_regs.control, mem_mask);
214 		return m_ftlb_regs.control | 1; // ???
215 	case 0x0004/4:
216 		LOGMASKED(LOG_FTLB, "%s: Unknown (F_STAT) = %08x & %08x\n", machine().describe_context(), m_ftlb_regs.stat, mem_mask);
217 		return m_ftlb_regs.stat;
218 	case 0x0008/4:
219 		LOGMASKED(LOG_FTLB, "%s: FlashROM TLB Valid Tag = %08x & %08x\n", machine().describe_context(), m_ftlb_regs.valid, mem_mask);
220 		return m_ftlb_regs.valid;
221 	case 0x000c/4:
222 		LOGMASKED(LOG_FTLB, "%s: Unknown (F_WAIT1) = %08x & %08x\n", machine().describe_context(), m_ftlb_regs.wait1, mem_mask);
223 		return m_ftlb_regs.wait1;
224 	case 0x0010/4:
225 		LOGMASKED(LOG_FTLB, "%s: Unknown (F_WAIT2) = %08x & %08x\n", machine().describe_context(), m_ftlb_regs.wait2 | 0x04, mem_mask);
226 		return m_ftlb_regs.wait2 | 0x04;
227 	case 0x0100/4:
228 	case 0x0104/4:
229 	case 0x0108/4:
230 	case 0x010c/4:
231 	case 0x0110/4:
232 	case 0x0114/4:
233 	case 0x0118/4:
234 	case 0x011c/4:
235 	case 0x0120/4:
236 	case 0x0124/4:
237 	case 0x0128/4:
238 	case 0x012c/4:
239 	case 0x0130/4:
240 	case 0x0134/4:
241 	case 0x0138/4:
242 	case 0x013c/4:
243 		LOGMASKED(LOG_FTLB, "%s: FlashROM TLB Entry %d = %08x & %08x\n", machine().describe_context(), offset - 0x100/4, m_ftlb_regs.entry[offset - 0x100/4],
244 			mem_mask);
245 		return m_ftlb_regs.entry[offset - 0x100/4];
246 	case 0x0300/4:
247 		LOGMASKED(LOG_FTLB, "%s: Unknown (F_SN) = %08x & %08x\n", machine().describe_context(), m_ftlb_regs.serial, mem_mask);
248 		return m_ftlb_regs.serial;
249 	default:
250 		LOGMASKED(LOG_FTLB | LOG_UNKNOWN, "%s: Unknown Register %08x & %08x\n", machine().describe_context(), 0x06000000 + (offset << 2), mem_mask);
251 		break;
252 	}
253 	return 0;
254 }
255 
ftlb_w(offs_t offset,uint32_t data,uint32_t mem_mask)256 void pockstat_state::ftlb_w(offs_t offset, uint32_t data, uint32_t mem_mask)
257 {
258 	switch(offset)
259 	{
260 	case 0x0000/4:
261 		LOGMASKED(LOG_FTLB, "%s: FlashROM TLB Control = %08x & %08x\n", machine().describe_context(), data, mem_mask);
262 		COMBINE_DATA(&m_ftlb_regs.control);
263 		break;
264 	case 0x0004/4:
265 		LOGMASKED(LOG_FTLB, "%s: Unknown (F_STAT) = %08x & %08x\n", machine().describe_context(), data, mem_mask);
266 		COMBINE_DATA(&m_ftlb_regs.stat);
267 		break;
268 	case 0x0008/4:
269 		LOGMASKED(LOG_FTLB, "%s: FlashROM TLB Valid Tag = %08x & %08x\n", machine().describe_context(), data, mem_mask);
270 		COMBINE_DATA(&m_ftlb_regs.valid);
271 		break;
272 	case 0x000c/4:
273 		LOGMASKED(LOG_FTLB, "%s: Unknown (F_WAIT1) = %08x & %08x\n", machine().describe_context(), data, mem_mask);
274 		COMBINE_DATA(&m_ftlb_regs.wait1);
275 		break;
276 	case 0x0010/4:
277 		LOGMASKED(LOG_FTLB, "%s: Unknown (F_WAIT2) = %08x & %08x\n", machine().describe_context(), data, mem_mask);
278 		COMBINE_DATA(&m_ftlb_regs.wait2);
279 		break;
280 	case 0x0100/4:
281 	case 0x0104/4:
282 	case 0x0108/4:
283 	case 0x010c/4:
284 	case 0x0110/4:
285 	case 0x0114/4:
286 	case 0x0118/4:
287 	case 0x011c/4:
288 	case 0x0120/4:
289 	case 0x0124/4:
290 	case 0x0128/4:
291 	case 0x012c/4:
292 	case 0x0130/4:
293 	case 0x0134/4:
294 	case 0x0138/4:
295 	case 0x013c/4:
296 		LOGMASKED(LOG_FTLB, "%s: FlashROM TLB Entry %d = %08x & %08x\n", machine().describe_context(), offset - 0x100/4, data, mem_mask);
297 		COMBINE_DATA(&m_ftlb_regs.entry[offset - 0x100/4]);
298 		break;
299 	case 0x0300/4:
300 		LOGMASKED(LOG_FTLB, "%s: Unknown (F_SN) = %08x & %08x\n", machine().describe_context(), data, mem_mask);
301 		COMBINE_DATA(&m_ftlb_regs.serial);
302 		break;
303 	default:
304 		LOGMASKED(LOG_FTLB | LOG_UNKNOWN, "%s: Unknown Register %08x = %08x & %08x\n", machine().describe_context(), 0x06000000 + (offset << 2), data, mem_mask);
305 		break;
306 	}
307 }
308 
get_interrupt_line(uint32_t line)309 uint32_t pockstat_state::get_interrupt_line(uint32_t line)
310 {
311 	return m_intc_regs.status & line;
312 }
313 
set_interrupt_line(uint32_t line,int state)314 void pockstat_state::set_interrupt_line(uint32_t line, int state)
315 {
316 	if (line)
317 	{
318 		if (state)
319 		{
320 			m_intc_regs.status |= line & INT_STATUS_MASK;
321 			m_intc_regs.hold |= line &~ INT_STATUS_MASK;
322 			LOGMASKED(LOG_IRQS, "Setting IRQ line %08x, status = %08x, hold = %08x\n", line, m_intc_regs.status, m_intc_regs.hold);
323 		}
324 		else
325 		{
326 			m_intc_regs.status &= ~line;
327 			m_intc_regs.hold &= ~line;
328 			LOGMASKED(LOG_IRQS, "Clearing IRQ line %08x, status = %08x, hold = %08x\n", line, m_intc_regs.status, m_intc_regs.hold);
329 		}
330 	}
331 
332 	const uint32_t new_irq = m_intc_regs.hold & m_intc_regs.enable & INT_IRQ_MASK;
333 	if (new_irq)
334 	{
335 		m_maincpu->set_input_line(ARM7_IRQ_LINE, ASSERT_LINE);
336 	}
337 	else
338 	{
339 		m_maincpu->set_input_line(ARM7_IRQ_LINE, CLEAR_LINE);
340 	}
341 
342 	const uint32_t new_fiq = m_intc_regs.hold & m_intc_regs.enable & INT_FIQ_MASK;
343 	if (new_fiq)
344 	{
345 		m_maincpu->set_input_line(ARM7_FIRQ_LINE, ASSERT_LINE);
346 	}
347 	else
348 	{
349 		m_maincpu->set_input_line(ARM7_FIRQ_LINE, CLEAR_LINE);
350 	}
351 }
352 
intc_r(offs_t offset,uint32_t mem_mask)353 uint32_t pockstat_state::intc_r(offs_t offset, uint32_t mem_mask)
354 {
355 	switch(offset)
356 	{
357 	case 0x0000/4:
358 		LOGMASKED(LOG_INTC, "%s: Held Interrupt Read: %08x & %08x\n", machine().describe_context(), m_intc_regs.hold, mem_mask);
359 		return m_intc_regs.hold;
360 	case 0x0004/4:
361 		LOGMASKED(LOG_INTC, "%s: Interrupt Status Read: %08x & %08x\n", machine().describe_context(), m_intc_regs.status, mem_mask);
362 		return m_intc_regs.status;
363 	case 0x0008/4:
364 		LOGMASKED(LOG_INTC, "%s: Interrupt Enable Read: %08x & %08x\n", machine().describe_context(), m_intc_regs.enable, mem_mask);
365 		return m_intc_regs.enable;
366 	case 0x000c/4:
367 		LOGMASKED(LOG_INTC, "%s: Interrupt Mask Read (Invalid): %08x & %08x\n", machine().describe_context(), 0, mem_mask);
368 		return 0;
369 	case 0x0010/4:
370 		LOGMASKED(LOG_INTC, "%s: Interrupt Acknowledge Read (Invalid): %08x & %08x\n", machine().describe_context(), 0, mem_mask);
371 		return 0;
372 	default:
373 		LOGMASKED(LOG_INTC | LOG_UNKNOWN, "%s: Unknown Register Read: %08x & %08x\n", machine().describe_context(), 0x0a000000 + (offset << 2), mem_mask);
374 		break;
375 	}
376 	return 0;
377 }
378 
intc_w(offs_t offset,uint32_t data,uint32_t mem_mask)379 void pockstat_state::intc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
380 {
381 	switch(offset)
382 	{
383 	case 0x0000/4:
384 		LOGMASKED(LOG_INTC, "%s: Held Interrupt (Invalid Write) = %08x & %08x\n", machine().describe_context(), data, mem_mask);
385 		break;
386 	case 0x0004/4:
387 		LOGMASKED(LOG_INTC, "%s: Interrupt Status (Invalid Write) = %08x & %08x\n", machine().describe_context(), data, mem_mask);
388 		break;
389 	case 0x0008/4:
390 		LOGMASKED(LOG_INTC, "%s: Interrupt Enable = %08x & %08x\n", machine().describe_context(), data, mem_mask);
391 		m_intc_regs.enable |= data;
392 		//COMBINE_DATA(&m_intc_regs.enable);
393 		//m_intc_regs.status &= m_intc_regs.enable;
394 		//m_intc_regs.hold &= m_intc_regs.enable;
395 		set_interrupt_line(0, 0);
396 		break;
397 	case 0x000c/4:
398 		LOGMASKED(LOG_INTC, "%s: Interrupt Mask = %08x & %08x\n", machine().describe_context(), data, mem_mask);
399 		m_intc_regs.enable &= ~data;
400 		COMBINE_DATA(&m_intc_regs.mask);
401 		//m_intc_regs.status &= m_intc_regs.enable;
402 		//m_intc_regs.hold &= m_intc_regs.enable;
403 		set_interrupt_line(0, 0);
404 		break;
405 	case 0x0010/4:
406 		LOGMASKED(LOG_INTC, "%s: Interrupt Acknowledge = %08x & %08x\n", machine().describe_context(), data, mem_mask);
407 		m_intc_regs.hold &= ~data;
408 		m_intc_regs.status &= ~data;
409 		set_interrupt_line(0, 0);
410 		//COMBINE_DATA(&m_intc_regs.acknowledge);
411 		break;
412 	default:
413 		LOGMASKED(LOG_INTC | LOG_UNKNOWN, "%s: Unknown Register %08x = %08x & %08x\n", machine().describe_context(), 0x0a000000 + (offset << 2), data, mem_mask);
414 		break;
415 	}
416 }
417 
TIMER_CALLBACK_MEMBER(pockstat_state::timer_tick)418 TIMER_CALLBACK_MEMBER(pockstat_state::timer_tick)
419 {
420 	set_interrupt_line(param == 2 ? INT_TIMER2 : (param == 1 ? INT_TIMER1 : INT_TIMER0), 1);
421 	m_timers[param].count = m_timers[param].period;
422 	timer_start(param);
423 }
424 
timer_start(int index)425 void pockstat_state::timer_start(int index)
426 {
427 	int divisor = 1;
428 	attotime period;
429 	switch (m_timers[index].control & 3)
430 	{
431 	case 0:
432 	case 3:
433 		divisor = 1;
434 		break;
435 	case 1:
436 		divisor = 16;
437 		break;
438 	case 2:
439 		divisor = 256;
440 		break;
441 	}
442 	period = attotime::from_hz(CPU_FREQ[m_clock_regs.mode & 0x0f] / 2) * divisor * m_timers[index].count;
443 	m_timers[index].timer->adjust(period, index);
444 }
445 
timer_r(offs_t offset,uint32_t mem_mask)446 uint32_t pockstat_state::timer_r(offs_t offset, uint32_t mem_mask)
447 {
448 	switch (offset)
449 	{
450 	case 0x0000/4:
451 	case 0x0010/4:
452 	case 0x0020/4:
453 	{
454 		const uint32_t index = offset / (0x10/4);
455 		LOGMASKED(LOG_TIMER, "%s: Timer %d Period Read: %08x & %08x\n", machine().describe_context(), index, m_timers[index].period, mem_mask);
456 		return m_timers[index].period;
457 	}
458 	case 0x0004/4:
459 	case 0x0014/4:
460 	case 0x0024/4:
461 	{
462 		const uint32_t index = offset / (0x10/4);
463 		LOGMASKED(LOG_TIMER, "%s: Timer %d Count Read: %08x & %08x\n", machine().describe_context(), index, m_timers[index].count, mem_mask);
464 		if(m_timers[index].control & 4)
465 		{
466 			m_timers[index].count--;
467 			if (m_timers[index].count > m_timers[index].period)
468 			{
469 				m_timers[index].count = m_timers[index].period;
470 			}
471 			return --m_timers[index].count;
472 		}
473 		return m_timers[index].count;
474 	}
475 	case 0x0008/4:
476 	case 0x0018/4:
477 	case 0x0028/4:
478 	{
479 		const uint32_t index = offset / (0x10/4);
480 		LOGMASKED(LOG_TIMER, "%s: Timer %d Control = %08x & %08x\n", machine().describe_context(), index, m_timers[index].control, mem_mask);
481 		return m_timers[index].control;
482 	}
483 	default:
484 		LOGMASKED(LOG_TIMER | LOG_UNKNOWN, "%s: Unknown Register %08x & %08x\n", machine().describe_context(), 0x0a800000 + (offset << 2), mem_mask);
485 		break;
486 	}
487 	return 0;
488 }
489 
timer_w(offs_t offset,uint32_t data,uint32_t mem_mask)490 void pockstat_state::timer_w(offs_t offset, uint32_t data, uint32_t mem_mask)
491 {
492 	switch (offset)
493 	{
494 	case 0x0000/4:
495 	case 0x0010/4:
496 	case 0x0020/4:
497 	{
498 		const uint32_t index = offset / (0x10/4);
499 		LOGMASKED(LOG_TIMER, "%s: Timer %d Period = %08x & %08x\n", machine().describe_context(), index, data, mem_mask);
500 		COMBINE_DATA(&m_timers[index].period);
501 		break;
502 	}
503 	case 0x0004/4:
504 	case 0x0014/4:
505 	case 0x0024/4:
506 	{
507 		const uint32_t index = offset / (0x10/4);
508 		LOGMASKED(LOG_TIMER, "%s: Timer %d Count = %08x & %08x\n", machine().describe_context(), index, data, mem_mask);
509 		COMBINE_DATA(&m_timers[index].count);
510 		break;
511 	}
512 	case 0x0008/4:
513 	case 0x0018/4:
514 	case 0x0028/4:
515 	{
516 		const uint32_t index = offset / (0x10/4);
517 		LOGMASKED(LOG_TIMER, "%s: Timer %d Control = %08x & %08x\n", machine().describe_context(), index, data, mem_mask);
518 		COMBINE_DATA(&m_timers[index].control);
519 		if(m_timers[index].control & 4)
520 		{
521 			timer_start(index);
522 		}
523 		else
524 		{
525 			m_timers[index].timer->adjust(attotime::never, index);
526 		}
527 		break;
528 	}
529 	default:
530 		LOGMASKED(LOG_TIMER | LOG_UNKNOWN, "%s: Unknown Register %08x = %08x & %08x\n", machine().describe_context(), 0x0a800000 + (offset << 2), data, mem_mask);
531 		break;
532 	}
533 }
534 
clock_r(offs_t offset,uint32_t mem_mask)535 uint32_t pockstat_state::clock_r(offs_t offset, uint32_t mem_mask)
536 {
537 	switch(offset)
538 	{
539 		case 0x0000/4:
540 			LOGMASKED(LOG_CLOCK, "%s: Clock Mode Read: %08x & %08x\n", machine().describe_context(), m_clock_regs.mode | 0x10, mem_mask);
541 			return m_clock_regs.mode | CLOCK_STEADY;
542 		case 0x0004/4:
543 			LOGMASKED(LOG_CLOCK, "%s: Clock Control Read: %08x & %08x\n", machine().describe_context(), m_clock_regs.control, mem_mask);
544 			return m_clock_regs.control;
545 		default:
546 			LOGMASKED(LOG_CLOCK | LOG_UNKNOWN, "%s: Unknown Register %08x & %08x\n", machine().describe_context(), 0x0b000000 + (offset << 2), mem_mask);
547 			break;
548 	}
549 	return 0;
550 }
551 
clock_w(offs_t offset,uint32_t data,uint32_t mem_mask)552 void pockstat_state::clock_w(offs_t offset, uint32_t data, uint32_t mem_mask)
553 {
554 	switch(offset)
555 	{
556 		case 0x0000/4:
557 			LOGMASKED(LOG_CLOCK, "%s: Clock Mode = %08x & %08x\n", machine().describe_context(), data, mem_mask);
558 			COMBINE_DATA(&m_clock_regs.mode);
559 			m_maincpu->set_unscaled_clock(CPU_FREQ[m_clock_regs.mode & 0x0f]);
560 			break;
561 		case 0x0004/4:
562 			LOGMASKED(LOG_CLOCK, "%s: Clock Control = %08x & %08x\n", machine().describe_context(), data, mem_mask);
563 			COMBINE_DATA(&m_clock_regs.control);
564 			break;
565 		default:
566 			LOGMASKED(LOG_CLOCK | LOG_UNKNOWN, "%s: Unknown Register %08x = %08x & %08x\n", machine().describe_context(), 0x0b000000 + (offset << 2), data, mem_mask);
567 			break;
568 	}
569 }
570 
TIMER_CALLBACK_MEMBER(pockstat_state::rtc_tick)571 TIMER_CALLBACK_MEMBER(pockstat_state::rtc_tick)
572 {
573 	set_interrupt_line(INT_RTC, get_interrupt_line(INT_RTC) ? 0 : 1);
574 	if (!(m_rtc_regs.mode & 1))
575 	{
576 		m_rtc_regs.time++;
577 		if ((m_rtc_regs.time & 0x0000000f) == 0x0000000a)
578 		{
579 			m_rtc_regs.time &= 0xfffffff0;
580 			m_rtc_regs.time += 0x00000010;
581 			if ((m_rtc_regs.time & 0x000000ff) == 0x00000060)
582 			{
583 				m_rtc_regs.time &= 0xffffff00;
584 				m_rtc_regs.time += 0x00000100;
585 				if ((m_rtc_regs.time & 0x00000f00) == 0x00000a00)
586 				{
587 					m_rtc_regs.time &= 0xfffff0ff;
588 					m_rtc_regs.time += 0x00001000;
589 					if ((m_rtc_regs.time & 0x0000ff00) == 0x00006000)
590 					{
591 						m_rtc_regs.time &= 0xffff00ff;
592 						m_rtc_regs.time += 0x00010000;
593 						if ((m_rtc_regs.time & 0x00ff0000) == 0x00240000)
594 						{
595 							m_rtc_regs.time &= 0xff00ffff;
596 							m_rtc_regs.time += 0x01000000;
597 							if ((m_rtc_regs.time & 0x0f000000) == 0x08000000)
598 							{
599 								m_rtc_regs.time &= 0xf0ffffff;
600 								m_rtc_regs.time |= 0x01000000;
601 							}
602 						}
603 						else if ((m_rtc_regs.time & 0x000f0000) == 0x000a0000)
604 						{
605 							m_rtc_regs.time &= 0xfff0ffff;
606 							m_rtc_regs.time += 0x00100000;
607 						}
608 					}
609 				}
610 			}
611 		}
612 	}
613 	m_rtc_regs.timer->adjust(attotime::from_hz(1));
614 }
615 
rtc_r(offs_t offset,uint32_t mem_mask)616 uint32_t pockstat_state::rtc_r(offs_t offset, uint32_t mem_mask)
617 {
618 	switch(offset)
619 	{
620 	case 0x0000/4:
621 		LOGMASKED(LOG_RTC, "%s: RTC Mode Read: %08x & %08x\n", machine().describe_context(), m_rtc_regs.mode, mem_mask);
622 		return m_rtc_regs.mode;
623 	case 0x0004/4:
624 		LOGMASKED(LOG_RTC, "%s: RTC Control Read: %08x & %08x\n", machine().describe_context(), m_rtc_regs.control, mem_mask);
625 		return m_rtc_regs.control;
626 	case 0x0008/4:
627 		LOGMASKED(LOG_RTC, "%s: RTC Time Read: %08x & %08x\n", machine().describe_context(), m_rtc_regs.time, mem_mask);
628 		return m_rtc_regs.time;
629 	case 0x000c/4:
630 		LOGMASKED(LOG_RTC, "%s: RTC Date Read: %08x & %08x\n", machine().describe_context(), m_rtc_regs.date, mem_mask);
631 		return m_rtc_regs.date;
632 	default:
633 		LOGMASKED(LOG_RTC | LOG_UNKNOWN, "%s: Unknown Register %08x & %08x\n", machine().describe_context(), 0x0b800000 + (offset << 2), mem_mask);
634 		break;
635 	}
636 	return 0;
637 }
638 
rtc_w(offs_t offset,uint32_t data,uint32_t mem_mask)639 void pockstat_state::rtc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
640 {
641 	switch (offset)
642 	{
643 	case 0x0000/4:
644 		LOGMASKED(LOG_RTC, "%s: RTC Mode = %08x & %08x\n", machine().describe_context(), data, mem_mask);
645 		COMBINE_DATA(&m_rtc_regs.mode);
646 		break;
647 	case 0x0004/4:
648 		LOGMASKED(LOG_RTC, "%s: RTC Control = %08x & %08x\n", machine().describe_context(), data, mem_mask);
649 		if (m_rtc_regs.control == 1 && data == 1)
650 		{
651 			switch (m_rtc_regs.mode >> 1)
652 			{
653 			case 0: // Seconds
654 				m_rtc_regs.time += 0x00000001;
655 				if ((m_rtc_regs.time & 0x0000000f) == 0x0000000a)
656 				{
657 					m_rtc_regs.time &= 0xfffffff0;
658 					m_rtc_regs.time += 0x00000010;
659 					if ((m_rtc_regs.time & 0x000000ff) == 0x00000060)
660 					{
661 						m_rtc_regs.time &= 0xffffff00;
662 					}
663 				}
664 				break;
665 			case 1: // Minutes
666 				m_rtc_regs.time += 0x00000100;
667 				if ((m_rtc_regs.time & 0x00000f00) == 0x00000a00)
668 				{
669 					m_rtc_regs.time &= 0xfffff0ff;
670 					m_rtc_regs.time += 0x00001000;
671 					if ((m_rtc_regs.time & 0x0000ff00) == 0x00006000)
672 					{
673 						m_rtc_regs.time &= 0xffff00ff;
674 					}
675 				}
676 				break;
677 			case 2: // Hours
678 				m_rtc_regs.time += 0x00010000;
679 				if ((m_rtc_regs.time & 0x00ff0000) == 0x00240000)
680 				{
681 					m_rtc_regs.time &= 0xff00ffff;
682 				}
683 				else if ((m_rtc_regs.time & 0x000f0000) == 0x000a0000)
684 				{
685 					m_rtc_regs.time &= 0xfff0ffff;
686 					m_rtc_regs.time += 0x00100000;
687 				}
688 				break;
689 			case 3: // Day of the week
690 				m_rtc_regs.time += 0x01000000;
691 				if ((m_rtc_regs.time & 0x0f000000) == 0x08000000)
692 				{
693 					m_rtc_regs.time &= 0xf0ffffff;
694 					m_rtc_regs.time |= 0x01000000;
695 				}
696 				break;
697 			case 4: // Day
698 				m_rtc_regs.date += 0x00000001;
699 				if ((m_rtc_regs.date & 0x000000ff) == 0x00000032)
700 				{
701 					m_rtc_regs.date &= 0xffffff00;
702 				}
703 				else if ((m_rtc_regs.date & 0x0000000f) == 0x0000000a)
704 				{
705 					m_rtc_regs.date &= 0xfffffff0;
706 					m_rtc_regs.date += 0x00000010;
707 				}
708 				break;
709 			case 5: // Month
710 				m_rtc_regs.date += 0x00000100;
711 				if ((m_rtc_regs.date & 0x0000ff00) == 0x00001300)
712 				{
713 					m_rtc_regs.date &= 0xffffff00;
714 					m_rtc_regs.date |= 0x00000001;
715 				}
716 				else if ((m_rtc_regs.date & 0x00000f00) == 0x00000a00)
717 				{
718 					m_rtc_regs.date &= 0xfffff0ff;
719 					m_rtc_regs.date += 0x00001000;
720 				}
721 				break;
722 			case 6: // Year (LSB)
723 				m_rtc_regs.date += 0x00010000;
724 				if ((m_rtc_regs.date & 0x000f0000) == 0x000a0000)
725 				{
726 					m_rtc_regs.date &= 0xfff0ffff;
727 					m_rtc_regs.date += 0x00100000;
728 					if ((m_rtc_regs.date & 0x00f00000) == 0x00a00000)
729 					{
730 						m_rtc_regs.date &= 0xff00ffff;
731 					}
732 				}
733 				break;
734 			case 7: // Year (MSB)
735 				break;
736 			}
737 			m_rtc_regs.control = 0;
738 		}
739 		else if(m_rtc_regs.control == 0)
740 		{
741 			COMBINE_DATA(&m_rtc_regs.control);
742 		}
743 		break;
744 	default:
745 		LOGMASKED(LOG_RTC | LOG_UNKNOWN, "%s: Unknown Register %08x = %08x & %08x\n", machine().describe_context(), 0x0b800000 + (offset << 2), data, mem_mask);
746 		break;
747 	}
748 }
749 
750 
lcd_r(offs_t offset,uint32_t mem_mask)751 uint32_t pockstat_state::lcd_r(offs_t offset, uint32_t mem_mask)
752 {
753 	switch (offset)
754 	{
755 	case 0x0000/4:
756 		LOGMASKED(LOG_LCD, "%s: LCD Control Read: %08x & %08x\n", machine().describe_context(), m_lcd_control | 0x100, mem_mask);
757 		return m_lcd_control;
758 	default:
759 		LOGMASKED(LOG_LCD | LOG_UNKNOWN, "%s: Unknown Register %08x & %08x\n", machine().describe_context(), 0x0d000000 + (offset << 2), mem_mask);
760 		break;
761 	}
762 	return 0;
763 }
764 
lcd_w(offs_t offset,uint32_t data,uint32_t mem_mask)765 void pockstat_state::lcd_w(offs_t offset, uint32_t data, uint32_t mem_mask)
766 {
767 	switch (offset)
768 	{
769 	case 0x0000/4:
770 		LOGMASKED(LOG_LCD, "%s: LCD Control = %08x & %08x\n", machine().describe_context(), data, mem_mask);
771 		COMBINE_DATA(&m_lcd_control);
772 		break;
773 	default:
774 		LOGMASKED(LOG_LCD | LOG_UNKNOWN, "%s: Unknown Register %08x = %08x & %08x\n", machine().describe_context(), 0x0d000000 + (offset << 2), data, mem_mask);
775 		break;
776 	}
777 }
778 
INPUT_CHANGED_MEMBER(pockstat_state::input_update)779 INPUT_CHANGED_MEMBER(pockstat_state::input_update)
780 {
781 	uint32_t buttons = ioport("BUTTONS")->read();
782 
783 	set_interrupt_line(INT_BTN_ACTION, (buttons &  1) ? 1 : 0);
784 	set_interrupt_line(INT_BTN_RIGHT,  (buttons &  2) ? 1 : 0);
785 	set_interrupt_line(INT_BTN_LEFT,   (buttons &  4) ? 1 : 0);
786 	set_interrupt_line(INT_BTN_DOWN,   (buttons &  8) ? 1 : 0);
787 	set_interrupt_line(INT_BTN_UP,     (buttons & 16) ? 1 : 0);
788 }
789 
rombank_r(offs_t offset,uint32_t mem_mask)790 uint32_t pockstat_state::rombank_r(offs_t offset, uint32_t mem_mask)
791 {
792 	int32_t bank = (offset >> 11) & 0x0f;
793 	for (int index = 0; index < 32; index++)
794 	{
795 		if (m_ftlb_regs.valid & (1 << index))
796 		{
797 			if (m_ftlb_regs.entry[index] == bank)
798 			{
799 				return m_cart->read32_rom(index * (0x2000/4) + (offset & (0x1fff/4)), mem_mask);
800 			}
801 		}
802 	}
803 	return m_cart->read32_rom(offset & 0x7fff, mem_mask);
804 }
805 
806 
807 // Horrible hack, probably wrong
flash_w(offs_t offset,uint32_t data,uint32_t mem_mask)808 void pockstat_state::flash_w(offs_t offset, uint32_t data, uint32_t mem_mask)
809 {
810 	if (offset == (0x55a8/4))
811 	{
812 		m_flash_write_enable_count++;
813 		return;
814 	}
815 	if (offset == (0x2a54/4))
816 	{
817 		m_flash_write_enable_count++;
818 		return;
819 	}
820 	if (m_flash_write_enable_count == 3)
821 	{
822 		m_flash_write_enable_count = 0;
823 		m_flash_write_count = 0x40;
824 		return;
825 	}
826 	if (m_flash_write_count)
827 	{
828 		m_flash_write_count--;
829 		COMBINE_DATA(&((uint32_t*)(m_cart_rom->base()))[offset]);
830 	}
831 }
832 
flash_r(offs_t offset,uint32_t mem_mask)833 uint32_t pockstat_state::flash_r(offs_t offset, uint32_t mem_mask)
834 {
835 	return m_cart->read32_rom(offset, mem_mask);
836 }
837 
audio_r(offs_t offset,uint32_t mem_mask)838 uint32_t pockstat_state::audio_r(offs_t offset, uint32_t mem_mask)
839 {
840 	LOGMASKED(LOG_AUDIO | LOG_UNKNOWN, "%s: Unknown Audio Read: %08x = %08x & %08x\n", machine().describe_context(), 0xd800000 + (offset << 2), 0x10, mem_mask);
841 	return 0;
842 }
843 
audio_w(offs_t offset,uint32_t data,uint32_t mem_mask)844 void pockstat_state::audio_w(offs_t offset, uint32_t data, uint32_t mem_mask)
845 {
846 	LOGMASKED(LOG_AUDIO | LOG_UNKNOWN, "%s: Unknown Audio Write: %08x = %08x & %08x\n", machine().describe_context(), 0xd800000 + (offset << 2), data, mem_mask);
847 }
848 
mem_map(address_map & map)849 void pockstat_state::mem_map(address_map &map)
850 {
851 	map(0x00000000, 0x000007ff).ram();
852 	map(0x02000000, 0x02ffffff).r(FUNC(pockstat_state::rombank_r));
853 	map(0x04000000, 0x04003fff).rom().region("maincpu", 0);
854 	map(0x06000000, 0x06000307).rw(FUNC(pockstat_state::ftlb_r), FUNC(pockstat_state::ftlb_w));
855 	map(0x08000000, 0x0801ffff).rw(FUNC(pockstat_state::flash_r), FUNC(pockstat_state::flash_w));
856 	map(0x0a000000, 0x0a000013).rw(FUNC(pockstat_state::intc_r), FUNC(pockstat_state::intc_w));
857 	map(0x0a800000, 0x0a80002b).rw(FUNC(pockstat_state::timer_r), FUNC(pockstat_state::timer_w));
858 	map(0x0b000000, 0x0b000007).rw(FUNC(pockstat_state::clock_r), FUNC(pockstat_state::clock_w));
859 	map(0x0b800000, 0x0b80000f).rw(FUNC(pockstat_state::rtc_r), FUNC(pockstat_state::rtc_w));
860 	map(0x0d000000, 0x0d000003).rw(FUNC(pockstat_state::lcd_r), FUNC(pockstat_state::lcd_w));
861 	map(0x0d000100, 0x0d00017f).ram().share("lcd_buffer");
862 	map(0x0d80000c, 0x0d80000f).rw(FUNC(pockstat_state::audio_r), FUNC(pockstat_state::audio_w));
863 	map(0x0d800014, 0x0d800015).w("dac", FUNC(dac_word_interface::data_w));
864 }
865 
866 /* Input ports */
867 static INPUT_PORTS_START( pockstat )
868 	PORT_START("BUTTONS")
869 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1)        PORT_NAME("Action Button")  PORT_CHANGED_MEMBER(DEVICE_SELF, pockstat_state, input_update, 0)
870 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_NAME("Right")          PORT_CHANGED_MEMBER(DEVICE_SELF, pockstat_state, input_update, 0)
871 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT)  PORT_NAME("Left")           PORT_CHANGED_MEMBER(DEVICE_SELF, pockstat_state, input_update, 0)
872 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN)  PORT_NAME("Down")           PORT_CHANGED_MEMBER(DEVICE_SELF, pockstat_state, input_update, 0)
873 	PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP)    PORT_NAME("Up")             PORT_CHANGED_MEMBER(DEVICE_SELF, pockstat_state, input_update, 0)
874 	PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED)
875 INPUT_PORTS_END
876 
machine_start()877 void pockstat_state::machine_start()
878 {
879 	for (uint32_t index = 0; index < TIMER_COUNT; index++)
880 	{
881 		m_timers[index].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pockstat_state::timer_tick), this));
882 		m_timers[index].timer->adjust(attotime::never, index);
883 	}
884 
885 	m_rtc_regs.time = 0x01000000;
886 	m_rtc_regs.date = 0x19990101;
887 
888 	m_rtc_regs.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pockstat_state::rtc_tick),this));
889 	m_rtc_regs.timer->adjust(attotime::from_hz(1), TIMER_COUNT);
890 
891 	std::string region_tag;
892 	m_cart_rom = memregion(region_tag.assign(m_cart->tag()).append(GENERIC_ROM_REGION_TAG).c_str());
893 
894 	save_item(NAME(m_ftlb_regs.control));
895 	save_item(NAME(m_ftlb_regs.stat));
896 	save_item(NAME(m_ftlb_regs.valid));
897 	save_item(NAME(m_ftlb_regs.wait1));
898 	save_item(NAME(m_ftlb_regs.wait2));
899 	save_item(NAME(m_ftlb_regs.entry));
900 
901 	save_item(NAME(m_intc_regs.hold));
902 	save_item(NAME(m_intc_regs.status));
903 	save_item(NAME(m_intc_regs.enable));
904 	save_item(NAME(m_intc_regs.mask));
905 
906 	save_item(NAME(m_timers[0].period));
907 	save_item(NAME(m_timers[0].count));
908 	save_item(NAME(m_timers[0].control));
909 	save_item(NAME(m_timers[1].period));
910 	save_item(NAME(m_timers[1].count));
911 	save_item(NAME(m_timers[1].control));
912 	save_item(NAME(m_timers[2].period));
913 	save_item(NAME(m_timers[2].count));
914 	save_item(NAME(m_timers[2].control));
915 
916 	save_item(NAME(m_clock_regs.mode));
917 	save_item(NAME(m_clock_regs.control));
918 
919 	save_item(NAME(m_rtc_regs.mode));
920 	save_item(NAME(m_rtc_regs.control));
921 	save_item(NAME(m_rtc_regs.time));
922 	save_item(NAME(m_rtc_regs.date));
923 
924 	save_item(NAME(m_flash_write_enable_count));
925 	save_item(NAME(m_flash_write_count));
926 
927 	save_item(NAME(m_lcd_control));
928 }
929 
machine_reset()930 void pockstat_state::machine_reset()
931 {
932 	m_maincpu->set_state_int(ARM7_R15, 0x4000000);
933 
934 	m_flash_write_enable_count = 0;
935 	m_flash_write_count = 0;
936 }
937 
screen_update_pockstat(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)938 uint32_t pockstat_state::screen_update_pockstat(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
939 {
940 	for (int y = 0; y < 32; y++)
941 	{
942 		uint32_t *const scanline = &bitmap.pix(y);
943 		for (int x = 0; x < 32; x++)
944 		{
945 			if (m_lcd_control != 0) // Hack
946 			{
947 				if (BIT(m_lcd_buffer[y], x))
948 					scanline[x] = 0x00000000;
949 				else
950 					scanline[x] = 0x00ffffff;
951 			}
952 			else
953 				scanline[x] = 0x00ffffff;
954 		}
955 	}
956 	return 0;
957 }
958 
DEVICE_IMAGE_LOAD_MEMBER(pockstat_state::flash_load)959 DEVICE_IMAGE_LOAD_MEMBER(pockstat_state::flash_load)
960 {
961 	static const char *gme_id = "123-456-STD";
962 	char cart_id[0xf40];
963 	uint32_t size = image.length();
964 
965 	if (size != 0x20f40)
966 		return image_init_result::FAIL;
967 
968 	image.fread(cart_id, 0xf40);
969 
970 	for (int i = 0; i < strlen(gme_id); i++)
971 	{
972 		if (cart_id[i] != gme_id[i])
973 			return image_init_result::FAIL;
974 	}
975 
976 	m_cart->rom_alloc(0x20000, GENERIC_ROM32_WIDTH, ENDIANNESS_LITTLE);
977 	image.fread(m_cart->get_rom_base(), 0x20000);
978 
979 	return image_init_result::PASS;
980 }
981 
pockstat(machine_config & config)982 void pockstat_state::pockstat(machine_config &config)
983 {
984 	static constexpr uint32_t DEFAULT_CLOCK = 2000000;
985 
986 	/* basic machine hardware */
987 	ARM7(config, m_maincpu, DEFAULT_CLOCK);
988 	m_maincpu->set_addrmap(AS_PROGRAM, &pockstat_state::mem_map);
989 
990 	/* video hardware */
991 	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
992 	screen.set_refresh_hz(50);
993 	screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
994 	screen.set_size(32, 32);
995 	screen.set_visarea(0, 32-1, 0, 32-1);
996 	screen.set_screen_update(FUNC(pockstat_state::screen_update_pockstat));
997 
998 	PALETTE(config, "palette", palette_device::MONOCHROME);
999 
1000 	SPEAKER(config, "speaker").front_center();
1001 	DAC_16BIT_R2R_TWOS_COMPLEMENT(config, "dac", 0).add_route(ALL_OUTPUTS, "speaker", 0.5); // unknown DAC
1002 
1003 	/* cartridge */
1004 	GENERIC_CARTSLOT(config, m_cart, generic_plain_slot, "pockstat_cart", "gme");
1005 	m_cart->set_width(GENERIC_ROM32_WIDTH);
1006 	m_cart->set_endian(ENDIANNESS_LITTLE);
1007 	m_cart->set_device_load(FUNC(pockstat_state::flash_load));
1008 }
1009 
1010 /* ROM definition */
1011 ROM_START( pockstat )
1012 	ROM_REGION( 0x4000, "maincpu", 0 )
1013 	ROM_LOAD( "kernel.bin", 0x0000, 0x4000, CRC(5fb47dd8) SHA1(6ae880493ddde880827d1e9f08e9cb2c38f9f2ec) )
1014 ROM_END
1015 
1016 /* Driver */
1017 
1018 //    YEAR  NAME      PARENT  COMPAT  MACHINE   INPUT     CLASS           INIT        COMPANY                            FULLNAME              FLAGS
1019 CONS( 1999, pockstat, 0,      0,      pockstat, pockstat, pockstat_state, empty_init, "Sony Computer Entertainment Inc", "Sony PocketStation", MACHINE_SUPPORTS_SAVE )
1020