1 // license:BSD-3-Clause
2 // copyright-holders:Tim Schuerewegen
3 /*******************************************************************************
4 
5     Samsung S3C2400 / S3C2410 / S3C2440
6 
7 *******************************************************************************/
8 
9 #include "emu.h"
10 #include "cpu/arm7/arm7.h"
11 #include "cpu/arm7/arm7core.h"
12 #include "coreutil.h"
13 
14 /*******************************************************************************
15     MACROS & CONSTANTS
16 *******************************************************************************/
17 
18 #define UART_PRINTF
19 
20 #define CLOCK_MULTIPLIER 1
21 
22 #if defined(DEVICE_S3C2400)
23 
24 #define S3C24XX_TPAL_GET_TPALEN(x)  BIT(x,16)
25 #define S3C24XX_TPAL_GET_TPALVAL(x) BITS(x,15,0)
26 
27 #else
28 
29 #define S3C24XX_TPAL_GET_TPALEN(x)  BIT(x,24)
30 #define S3C24XX_TPAL_GET_TPALVAL(x) BITS(x,23,0)
31 
32 #endif
33 
34 #define S3C24XX_DCON_GET_TC(x)      BITS(x,19,0)
35 #define S3C24XX_DCON_GET_DSZ(x)     BITS(x,21,20)
36 #define S3C24XX_DCON_GET_RELOAD(x)  BIT(x,22)
37 #define S3C24XX_DCON_GET_SWHWSEL(x) BIT(x,23)
38 
39 #define S3C24XX_DSTAT_GET_CURR_TC(x)   BITS(x,19,0)
40 #define S3C24XX_DSTAT_SET_CURR_TC(x,m) (CLR_BITS(x,19,0) | m)
41 
42 #define S3C24XX_DMASKTRIG_GET_ON_OFF(x) BIT(x,1)
43 
44 #if defined(DEVICE_S3C2400)
45 
46 #define S3C24XX_DCON_GET_HWSRCSEL(x) BITS(x,25,24)
47 #define S3C24XX_DCON_GET_SERVMODE(x) BIT(x,26)
48 #define S3C24XX_DCON_GET_TSZ(x)      BIT(x,27)
49 #define S3C24XX_DCON_GET_INT(x)      BIT(x,28)
50 
51 #define S3C24XX_DISRC_GET_SADDR(x) BITS(x,28,0)
52 
53 #define S3C24XX_DIDST_GET_DADDR(x) BITS(x,28,0)
54 
55 #define S3C24XX_DCSRC_GET_CURR_SRC(x)   BITS(x,28,0)
56 #define S3C24XX_DCSRC_SET_CURR_SRC(x,m) (CLR_BITS(x,28,0) | m)
57 
58 #define S3C24XX_DCDST_GET_CURR_DST(x)   BITS(x,28,0)
59 #define S3C24XX_DCDST_SET_CURR_DST(x,m) (CLR_BITS(x,28,0) | m)
60 
61 #else
62 
63 #define S3C24XX_DCON_GET_HWSRCSEL(x) BITS(x,26,24)
64 #define S3C24XX_DCON_GET_SERVMODE(x) BIT(x,27)
65 #define S3C24XX_DCON_GET_TSZ(x)      BIT(x,28)
66 #define S3C24XX_DCON_GET_INT(x)      BIT(x,29)
67 
68 #define S3C24XX_DISRC_GET_SADDR(x) BITS(x,30,0)
69 
70 #define S3C24XX_DIDST_GET_DADDR(x) BITS(x,30,0)
71 
72 #define S3C24XX_DCSRC_GET_CURR_SRC(x)   BITS(x,30,0)
73 #define S3C24XX_DCSRC_SET_CURR_SRC(x,m) (CLR_BITS(x,30,0) | m)
74 
75 #define S3C24XX_DCDST_GET_CURR_DST(x)   BITS(x,30,0)
76 #define S3C24XX_DCDST_SET_CURR_DST(x,m) (CLR_BITS(x,30,0) | m)
77 
78 #endif
79 
80 #define LOG_RESET           (u64(1) << 1)
81 #define LOG_ADC             (u64(1) << 2)
82 #define LOG_LCD_DMA         (u64(1) << 3)
83 #define LOG_LCD_TIMER       (u64(1) << 4)
84 #define LOG_LCD_REGS        (u64(1) << 5)
85 #define LOG_SPI             (u64(1) << 6)
86 #define LOG_LCD_CFG         (u64(1) << 7)
87 #define LOG_LCD_TFT         (u64(1) << 8)
88 #define LOG_LCD_STN         (u64(1) << 9)
89 #define LOG_CLKPOW          (u64(1) << 10)
90 #define LOG_MMC             (u64(1) << 11)
91 #define LOG_IRQS            (u64(1) << 12)
92 #define LOG_IRQ_REGS        (u64(1) << 13)
93 #define LOG_FLASH           (u64(1) << 14)
94 #define LOG_PWM             (u64(1) << 15)
95 #define LOG_PWM_REGS        (u64(1) << 16)
96 #define LOG_CAM             (u64(1) << 17)
97 #define LOG_DMA             (u64(1) << 18)
98 #define LOG_DMA_REQS        (u64(1) << 19)
99 #define LOG_DMA_REGS        (u64(1) << 20)
100 #define LOG_AC97            (u64(1) << 21)
101 #define LOG_DMA_TIMERS      (u64(1) << 22)
102 #define LOG_GPIO            (u64(1) << 23)
103 #define LOG_MEMCON          (u64(1) << 24)
104 #define LOG_USBHOST         (u64(1) << 25)
105 #define LOG_UART            (u64(1) << 26)
106 #define LOG_USB             (u64(1) << 27)
107 #define LOG_WDT             (u64(1) << 28)
108 #define LOG_I2C             (u64(1) << 29)
109 #define LOG_I2S             (u64(1) << 30)
110 #define LOG_RTC             (u64(1) << 31)
111 #define LOG_SDI             (u64(1) << 32)
112 
113 #define LOG_ALL             (LOG_RESET | LOG_ADC | LOG_LCD_DMA | LOG_LCD_TIMER | LOG_LCD_REGS | LOG_SPI | LOG_LCD_CFG | LOG_LCD_TFT | LOG_LCD_STN \
114 							| LOG_CLKPOW | LOG_MMC | LOG_IRQS | LOG_IRQ_REGS | LOG_FLASH | LOG_PWM | LOG_PWM_REGS | LOG_CAM | LOG_DMA | LOG_DMA_REQS \
115 							| LOG_DMA_REGS | LOG_AC97 | LOG_DMA_TIMERS | LOG_GPIO | LOG_MEMCON | LOG_USBHOST | LOG_UART | LOG_USB \
116 							| LOG_WDT | LOG_I2C | LOG_I2S | LOG_RTC | LOG_SDI)
117 
118 //#define VERBOSE             (LOG_ALL & ~(LOG_FLASH | LOG_UART))
119 #include "logmacro.h"
120 
121 /***************************************************************************
122     IMPLEMENTATION
123 ***************************************************************************/
124 
125 /* ... */
126 
s3c24xx_reset()127 void S3C24_CLASS_NAME::s3c24xx_reset()
128 {
129 	LOGMASKED(LOG_RESET, "reset\n");
130 	m_cpu->reset();
131 	this->reset();
132 }
133 
iface_core_pin_r(int pin)134 int S3C24_CLASS_NAME::iface_core_pin_r(int pin)
135 {
136 	if (!m_pin_r_cb.isnull())
137 	{
138 		return (m_pin_r_cb)(pin);
139 	}
140 	else
141 	{
142 		return 0;
143 	}
144 }
145 
146 /* LCD Controller */
147 
s3c24xx_lcd_reset()148 void S3C24_CLASS_NAME::s3c24xx_lcd_reset()
149 {
150 	memset( &m_lcd.regs, 0, sizeof( m_lcd.regs));
151 #if defined(DEVICE_S3C2410)
152 	m_lcd.regs.lcdintmsk = 3;
153 	m_lcd.regs.lpcsel = 4;
154 #elif defined(DEVICE_S3C2440)
155 	m_lcd.regs.lcdintmsk = 3;
156 	m_lcd.regs.tconsel = 0x0F84;
157 #endif
158 	m_lcd.vramaddr_cur = m_lcd.vramaddr_max = 0;
159 	m_lcd.offsize = 0;
160 	m_lcd.pagewidth_cur = m_lcd.pagewidth_max = 0;
161 	m_lcd.bppmode = 0;
162 	m_lcd.bswp = m_lcd.hwswp = 0;
163 	m_lcd.vpos = m_lcd.hpos = 0;
164 	m_lcd.framerate = 0;
165 	m_lcd.tpal = 0;
166 	m_lcd.hpos_min = m_lcd.hpos_max = m_lcd.vpos_min = m_lcd.vpos_max = 0;
167 	m_lcd.dma_data = m_lcd.dma_bits = 0;
168 	m_lcd.timer->adjust(attotime::never);
169 }
170 
s3c24xx_get_color_tft_16(uint16_t data)171 rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_tft_16(uint16_t data)
172 {
173 	if ((m_lcd.regs.lcdcon5 & (1 << 11)) == 0)
174 	{
175 		uint8_t r, g, b, i;
176 		r = (BITS( data, 15, 11) << 3);
177 		g = (BITS( data, 10, 6) << 3);
178 		b = (BITS( data, 5, 1) << 3);
179 		i = BIT( data, 1) << 2;
180 		return rgb_t( r | i, g | i, b | i);
181 	}
182 	else
183 	{
184 		uint8_t r, g, b;
185 		r = BITS( data, 15, 11) << 3;
186 		g = BITS( data, 10, 5) << 2;
187 		b = BITS( data, 4, 0) << 3;
188 		return rgb_t( r, g, b);
189 	}
190 }
191 
192 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
193 
s3c24xx_get_color_tft_24(uint32_t data)194 rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_tft_24(uint32_t data)
195 {
196 	uint8_t r, g, b;
197 	r = BITS( data, 23, 16);
198 	g = BITS( data, 15, 8);
199 	b = BITS( data, 7, 0);
200 	return rgb_t( r, g, b);
201 }
202 
203 #endif
204 
s3c24xx_get_color_stn_12(uint16_t data)205 rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_stn_12(uint16_t data)
206 {
207 	uint8_t r, g, b;
208 	r = BITS( data, 11, 8) << 4;
209 	g = BITS( data, 7, 4) << 4;
210 	b = BITS( data, 3, 0) << 4;
211 	return rgb_t( r, g, b);
212 }
213 
s3c24xx_get_color_stn_08(uint8_t data)214 rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_stn_08( uint8_t data)
215 {
216 	uint8_t r, g, b;
217 	r = ((m_lcd.regs.redlut   >> (BITS( data, 7, 5) << 2)) & 0xF) << 4;
218 	g = ((m_lcd.regs.greenlut >> (BITS( data, 4, 2) << 2)) & 0xF) << 4;
219 	b = ((m_lcd.regs.bluelut  >> (BITS( data, 1, 0) << 2)) & 0xF) << 4;
220 	return rgb_t( r, g, b);
221 }
222 
s3c24xx_get_color_stn_01(uint8_t data)223 rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_stn_01(uint8_t data)
224 {
225 	if ((data & 1) == 0)
226 	{
227 		return rgb_t::black();
228 	}
229 	else
230 	{
231 		return rgb_t::white();
232 	}
233 }
234 
s3c24xx_get_color_stn_02(uint8_t data)235 rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_stn_02(uint8_t data)
236 {
237 	uint8_t r, g, b;
238 	r = g = b = ((m_lcd.regs.bluelut >> (BITS( data, 1, 0) << 2)) & 0xF) << 4;
239 	return rgb_t( r, g, b);
240 }
241 
s3c24xx_get_color_stn_04(uint8_t data)242 rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_stn_04(uint8_t data)
243 {
244 	uint8_t r, g, b;
245 	r = g = b = BITS( data, 3, 0) << 4;
246 	return rgb_t( r, g, b);
247 }
248 
s3c24xx_get_color_tpal()249 rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_tpal()
250 {
251 #if defined(DEVICE_S3C2400)
252 	return s3c24xx_get_color_tft_16(S3C24XX_TPAL_GET_TPALVAL( m_lcd.tpal));
253 #else
254 	return s3c24xx_get_color_tft_24(S3C24XX_TPAL_GET_TPALVAL( m_lcd.tpal));
255 #endif
256 }
257 
s3c24xx_lcd_dma_reload()258 void S3C24_CLASS_NAME::s3c24xx_lcd_dma_reload()
259 {
260 	m_lcd.vramaddr_cur = m_lcd.regs.lcdsaddr1 << 1;
261 	m_lcd.vramaddr_max = ((m_lcd.regs.lcdsaddr1 & 0xFFE00000) | m_lcd.regs.lcdsaddr2) << 1;
262 	m_lcd.offsize = BITS( m_lcd.regs.lcdsaddr3, 21, 11);
263 	m_lcd.pagewidth_cur = 0;
264 	m_lcd.pagewidth_max = BITS( m_lcd.regs.lcdsaddr3, 10, 0);
265 	if (m_lcd.pagewidth_max == 0)
266 	{
267 		if (m_lcd.bppmode == S3C24XX_BPPMODE_STN_12_P)
268 		{
269 			m_lcd.pagewidth_max = (m_lcd.hpos_max - m_lcd.hpos_min + 1) / 16 * 12;
270 		}
271 	}
272 	LOGMASKED(LOG_LCD_DMA, "LCD - vramaddr %08X %08X offsize %08X pagewidth %08X\n", m_lcd.vramaddr_cur, m_lcd.vramaddr_max, m_lcd.offsize, m_lcd.pagewidth_max);
273 	m_lcd.dma_data = 0;
274 	m_lcd.dma_bits = 0;
275 }
276 
s3c24xx_lcd_dma_init()277 void S3C24_CLASS_NAME::s3c24xx_lcd_dma_init()
278 {
279 	m_lcd.bppmode = BITS( m_lcd.regs.lcdcon1, 4, 1);
280 	s3c24xx_lcd_dma_reload();
281 	m_lcd.bswp = BIT( m_lcd.regs.lcdcon5, 1);
282 	m_lcd.hwswp = BIT( m_lcd.regs.lcdcon5, 0);
283 	m_lcd.tpal = m_lcd.regs.tpal;
284 	LOGMASKED(LOG_LCD_DMA, "LCD - bppmode %d hwswp %d bswp %d\n", m_lcd.bppmode, m_lcd.hwswp, m_lcd.bswp);
285 	m_lcd.dma_data = 0;
286 	m_lcd.dma_bits = 0;
287 }
288 
289 #if 0
290 uint32_t S3C24_CLASS_NAME::s3c24xx_lcd_dma_read()
291 {
292 	uint8_t data[4];
293 	for (int i = 0; i < 2; i++)
294 	{
295 		data[i*2+0] = m_cache.read_byte(m_lcd.vramaddr_cur + 0);
296 		data[i*2+1] = m_cache.read_byte(m_lcd.vramaddr_cur + 1);
297 		m_lcd.vramaddr_cur += 2;
298 		m_lcd.pagewidth_cur++;
299 		if (m_lcd.pagewidth_cur >= m_lcd.pagewidth_max)
300 		{
301 			m_lcd.vramaddr_cur += m_lcd.offsize << 1;
302 			m_lcd.pagewidth_cur = 0;
303 		}
304 	}
305 	if (m_lcd.hwswp == 0)
306 	{
307 		if (m_lcd.bswp == 0)
308 		{
309 			return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0] << 0);
310 		}
311 		else
312 		{
313 			return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3] << 0);
314 		}
315 	}
316 	else
317 	{
318 		if (m_lcd.bswp == 0)
319 		{
320 			return (data[1] << 24) | (data[0] << 16) | (data[3] << 8) | (data[2] << 0);
321 		}
322 		else
323 		{
324 			return (data[2] << 24) | (data[3] << 16) | (data[0] << 8) | (data[1] << 0);
325 		}
326 	}
327 }
328 #endif
329 
s3c24xx_lcd_dma_read()330 uint32_t S3C24_CLASS_NAME::s3c24xx_lcd_dma_read()
331 {
332 	uint8_t data[4];
333 	for (int i = 0; i < 2; i++)
334 	{
335 		if (m_lcd.hwswp == 0)
336 		{
337 			if (m_lcd.bswp == 0)
338 			{
339 				if ((m_lcd.vramaddr_cur & 2) == 0)
340 				{
341 					data[i*2+0] = m_cache.read_byte(m_lcd.vramaddr_cur + 3);
342 					data[i*2+1] = m_cache.read_byte(m_lcd.vramaddr_cur + 2);
343 				}
344 				else
345 				{
346 					data[i*2+0] = m_cache.read_byte(m_lcd.vramaddr_cur - 1);
347 					data[i*2+1] = m_cache.read_byte(m_lcd.vramaddr_cur - 2);
348 				}
349 			}
350 			else
351 			{
352 				data[i*2+0] = m_cache.read_byte(m_lcd.vramaddr_cur + 0);
353 				data[i*2+1] = m_cache.read_byte(m_lcd.vramaddr_cur + 1);
354 			}
355 		}
356 		else
357 		{
358 			if (m_lcd.bswp == 0)
359 			{
360 				data[i*2+0] = m_cache.read_byte(m_lcd.vramaddr_cur + 1);
361 				data[i*2+1] = m_cache.read_byte(m_lcd.vramaddr_cur + 0);
362 			}
363 			else
364 			{
365 				if ((m_lcd.vramaddr_cur & 2) == 0)
366 				{
367 					data[i*2+0] = m_cache.read_byte(m_lcd.vramaddr_cur + 2);
368 					data[i*2+1] = m_cache.read_byte(m_lcd.vramaddr_cur + 3);
369 				}
370 				else
371 				{
372 					data[i*2+0] = m_cache.read_byte(m_lcd.vramaddr_cur - 2);
373 					data[i*2+1] = m_cache.read_byte(m_lcd.vramaddr_cur - 1);
374 				}
375 			}
376 		}
377 		m_lcd.vramaddr_cur += 2;
378 		m_lcd.pagewidth_cur++;
379 		if (m_lcd.pagewidth_cur >= m_lcd.pagewidth_max)
380 		{
381 			m_lcd.vramaddr_cur += m_lcd.offsize << 1;
382 			m_lcd.pagewidth_cur = 0;
383 		}
384 	}
385 	if (m_flags & S3C24XX_INTERFACE_LCD_REVERSE)
386 	{
387 		return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0] << 0);
388 	}
389 	else
390 	{
391 		return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3] << 0);
392 	}
393 }
394 
s3c24xx_lcd_dma_read_bits(int count)395 uint32_t S3C24_CLASS_NAME::s3c24xx_lcd_dma_read_bits(int count)
396 {
397 	uint32_t data;
398 	if (count <= m_lcd.dma_bits)
399 	{
400 		m_lcd.dma_bits -= count;
401 		data = BITS( m_lcd.dma_data, 31, 32 - count);
402 		m_lcd.dma_data = m_lcd.dma_data << count;
403 	}
404 	else
405 	{
406 		if (m_lcd.dma_bits == 0)
407 		{
408 			if (count == 32)
409 			{
410 				data = s3c24xx_lcd_dma_read();
411 			}
412 			else
413 			{
414 				uint32_t temp = s3c24xx_lcd_dma_read();
415 				data = BITS( temp, 31, 32 - count);
416 				m_lcd.dma_data = temp << count;
417 				m_lcd.dma_bits = 32 - count;
418 			}
419 		}
420 		else
421 		{
422 			uint32_t temp = s3c24xx_lcd_dma_read();
423 			data = (m_lcd.dma_data >> (32 - count)) | BITS( temp, 31, 32 - (count - m_lcd.dma_bits));
424 			m_lcd.dma_data = temp << (count - m_lcd.dma_bits);
425 			m_lcd.dma_bits = 32 - (count - m_lcd.dma_bits);
426 		}
427 	}
428 	return data;
429 }
430 
s3c24xx_lcd_render_tpal()431 void S3C24_CLASS_NAME::s3c24xx_lcd_render_tpal()
432 {
433 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
434 	uint32_t color = s3c24xx_get_color_tpal();
435 	for (int y = m_lcd.vpos_min; y <= m_lcd.vpos_max; y++)
436 	{
437 		uint32_t *scanline = &bitmap.pix(y, m_lcd.hpos_min);
438 		for (int x = m_lcd.hpos_min; x <= m_lcd.hpos_max; x++)
439 		{
440 			*scanline++ = color;
441 		}
442 	}
443 }
444 
s3c24xx_lcd_render_stn_01()445 void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_01()
446 {
447 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
448 	uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
449 	for (int i = 0; i < 4; i++)
450 	{
451 		uint32_t data = s3c24xx_lcd_dma_read();
452 		for (int j = 0; j < 32; j++)
453 		{
454 			if (m_flags & S3C24XX_INTERFACE_LCD_REVERSE)
455 			{
456 				*scanline++ = s3c24xx_get_color_stn_01( data & 0x01);
457 				data = data >> 1;
458 			}
459 			else
460 			{
461 				*scanline++ = s3c24xx_get_color_stn_01((data >> 31) & 0x01);
462 				data = data << 1;
463 			}
464 			m_lcd.hpos++;
465 			if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 4))
466 			{
467 				m_lcd.vpos++;
468 				if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
469 				m_lcd.hpos = m_lcd.hpos_min;
470 				scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
471 			}
472 		}
473 	}
474 }
475 
s3c24xx_lcd_render_stn_02()476 void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_02()
477 {
478 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
479 	uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
480 	for (int i = 0; i < 4; i++)
481 	{
482 		uint32_t data = s3c24xx_lcd_dma_read();
483 		for (int j = 0; j < 16; j++)
484 		{
485 			*scanline++ = s3c24xx_get_color_stn_02((data >> 30) & 0x03);
486 			data = data << 2;
487 			m_lcd.hpos++;
488 			if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 3))
489 			{
490 				m_lcd.vpos++;
491 				if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
492 				m_lcd.hpos = m_lcd.hpos_min;
493 				scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
494 			}
495 		}
496 	}
497 }
498 
s3c24xx_lcd_render_stn_04()499 void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_04()
500 {
501 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
502 	uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
503 	for (int i = 0; i < 4; i++)
504 	{
505 		uint32_t data = s3c24xx_lcd_dma_read();
506 		for (int j = 0; j < 8; j++)
507 		{
508 			*scanline++ = s3c24xx_get_color_stn_04((data >> 28) & 0x0F);
509 			data = data << 4;
510 			m_lcd.hpos++;
511 			if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 2))
512 			{
513 				m_lcd.vpos++;
514 				if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
515 				m_lcd.hpos = m_lcd.hpos_min;
516 				scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
517 			}
518 		}
519 	}
520 }
521 
s3c24xx_lcd_render_stn_08()522 void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_08()
523 {
524 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
525 	uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
526 	for (int i = 0; i < 4; i++)
527 	{
528 		uint32_t data = s3c24xx_lcd_dma_read();
529 		for (int j = 0; j < 4; j++)
530 		{
531 			*scanline++ = s3c24xx_get_color_stn_08((data >> 24) & 0xFF);
532 			data = data << 8;
533 			m_lcd.hpos++;
534 			if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 1))
535 			{
536 				m_lcd.vpos++;
537 				if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
538 				m_lcd.hpos = m_lcd.hpos_min;
539 				scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
540 			}
541 		}
542 	}
543 }
544 
s3c24xx_lcd_render_stn_12_p()545 void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_12_p()
546 {
547 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
548 	uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
549 	for (int i = 0; i < 16; i++)
550 	{
551 		*scanline++ = s3c24xx_get_color_stn_12(s3c24xx_lcd_dma_read_bits(12));
552 		m_lcd.hpos++;
553 		if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max * 16 / 12))
554 		{
555 			m_lcd.vpos++;
556 			if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
557 			m_lcd.hpos = m_lcd.hpos_min;
558 			scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
559 		}
560 	}
561 }
562 
s3c24xx_lcd_render_stn_12_u()563 void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_12_u() // not tested
564 {
565 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
566 	uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
567 	for (int i = 0; i < 4; i++)
568 	{
569 		uint32_t data = s3c24xx_lcd_dma_read();
570 		for (int j = 0; j < 2; j++)
571 		{
572 			*scanline++ = s3c24xx_get_color_stn_12((data >> 16) & 0x0FFF);
573 			data = data << 16;
574 			m_lcd.hpos++;
575 			if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 0))
576 			{
577 				m_lcd.vpos++;
578 				if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
579 				m_lcd.hpos = m_lcd.hpos_min;
580 				scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
581 			}
582 		}
583 	}
584 }
585 
s3c24xx_lcd_render_tft_01()586 void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_01()
587 {
588 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
589 	uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
590 	for (int i = 0; i < 4; i++)
591 	{
592 		uint32_t data = s3c24xx_lcd_dma_read();
593 		for (int j = 0; j < 32; j++)
594 		{
595 			*scanline++ = m_palette->pen_color((data >> 31) & 0x01);
596 			data = data << 1;
597 			m_lcd.hpos++;
598 			if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 4))
599 			{
600 				m_lcd.vpos++;
601 				if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
602 				m_lcd.hpos = m_lcd.hpos_min;
603 				scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
604 			}
605 		}
606 	}
607 }
608 
s3c24xx_lcd_render_tft_02()609 void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_02()
610 {
611 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
612 	uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
613 	for (int i = 0; i < 4; i++)
614 	{
615 		uint32_t data = s3c24xx_lcd_dma_read();
616 		for (int j = 0; j < 16; j++)
617 		{
618 			*scanline++ = m_palette->pen_color((data >> 30) & 0x03);
619 			data = data << 2;
620 			m_lcd.hpos++;
621 			if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 3))
622 			{
623 				m_lcd.vpos++;
624 				if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
625 				m_lcd.hpos = m_lcd.hpos_min;
626 				scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
627 			}
628 		}
629 	}
630 }
631 
s3c24xx_lcd_render_tft_04()632 void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_04()
633 {
634 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
635 	uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
636 	for (int i = 0; i < 4; i++)
637 	{
638 		uint32_t data = s3c24xx_lcd_dma_read();
639 		for (int j = 0; j < 8; j++)
640 		{
641 			*scanline++ = m_palette->pen_color((data >> 28) & 0x0F);
642 			data = data << 4;
643 			m_lcd.hpos++;
644 			if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 2))
645 			{
646 				m_lcd.vpos++;
647 				if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
648 				m_lcd.hpos = m_lcd.hpos_min;
649 				scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
650 			}
651 		}
652 	}
653 }
654 
s3c24xx_lcd_render_tft_08()655 void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_08()
656 {
657 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
658 	uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
659 	for (int i = 0; i < 4; i++)
660 	{
661 		uint32_t data = s3c24xx_lcd_dma_read();
662 		for (int j = 0; j < 4; j++)
663 		{
664 			*scanline++ = m_palette->pen_color((data >> 24) & 0xFF);
665 			data = data << 8;
666 			m_lcd.hpos++;
667 			if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 1))
668 			{
669 				m_lcd.vpos++;
670 				if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
671 				m_lcd.hpos = m_lcd.hpos_min;
672 				scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
673 			}
674 		}
675 	}
676 }
677 
s3c24xx_lcd_render_tft_16()678 void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_16()
679 {
680 	bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
681 	uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
682 	for (int i = 0; i < 4; i++)
683 	{
684 		uint32_t data = s3c24xx_lcd_dma_read();
685 		for (int j = 0; j < 2; j++)
686 		{
687 			*scanline++ = s3c24xx_get_color_tft_16((data >> 16) & 0xFFFF);
688 			data = data << 16;
689 			m_lcd.hpos++;
690 			if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 0))
691 			{
692 				m_lcd.vpos++;
693 				if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
694 				m_lcd.hpos = m_lcd.hpos_min;
695 				scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
696 			}
697 		}
698 	}
699 }
700 
TIMER_CALLBACK_MEMBER(S3C24_CLASS_NAME::s3c24xx_lcd_timer_exp)701 TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_lcd_timer_exp )
702 {
703 	LOGMASKED(LOG_LCD_TIMER, "LCD timer callback\n");
704 	m_lcd.vpos = m_screen->vpos();
705 	m_lcd.hpos = m_screen->hpos();
706 	LOGMASKED(LOG_LCD_TIMER, "LCD - vpos %d hpos %d\n", m_lcd.vpos, m_lcd.hpos);
707 	uint32_t tpalen = S3C24XX_TPAL_GET_TPALEN( m_lcd.tpal);
708 	if (tpalen == 0)
709 	{
710 		if (m_lcd.vramaddr_cur >= m_lcd.vramaddr_max)
711 		{
712 			s3c24xx_lcd_dma_reload();
713 		}
714 		LOGMASKED(LOG_LCD_TIMER, "LCD - vramaddr %08X\n", m_lcd.vramaddr_cur);
715 		while (m_lcd.vramaddr_cur < m_lcd.vramaddr_max)
716 		{
717 			switch (m_lcd.bppmode)
718 			{
719 			case S3C24XX_BPPMODE_STN_01:    s3c24xx_lcd_render_stn_01();   break;
720 			case S3C24XX_BPPMODE_STN_02:    s3c24xx_lcd_render_stn_02();   break;
721 			case S3C24XX_BPPMODE_STN_04:    s3c24xx_lcd_render_stn_04();   break;
722 			case S3C24XX_BPPMODE_STN_08:    s3c24xx_lcd_render_stn_08();   break;
723 			case S3C24XX_BPPMODE_STN_12_P:  s3c24xx_lcd_render_stn_12_p(); break;
724 			case S3C24XX_BPPMODE_STN_12_U:  s3c24xx_lcd_render_stn_12_u(); break;
725 			case S3C24XX_BPPMODE_TFT_01:    s3c24xx_lcd_render_tft_01();   break;
726 			case S3C24XX_BPPMODE_TFT_02:    s3c24xx_lcd_render_tft_02();   break;
727 			case S3C24XX_BPPMODE_TFT_04:    s3c24xx_lcd_render_tft_04();   break;
728 			case S3C24XX_BPPMODE_TFT_08:    s3c24xx_lcd_render_tft_08();   break;
729 			case S3C24XX_BPPMODE_TFT_16:    s3c24xx_lcd_render_tft_16();   break;
730 			default:  LOGMASKED(LOG_LCD_TIMER, "s3c24xx_lcd_timer_exp: bppmode %d not supported\n", m_lcd.bppmode); break;
731 			}
732 			if ((m_lcd.vpos == m_lcd.vpos_min) && (m_lcd.hpos == m_lcd.hpos_min)) break;
733 		}
734 	}
735 	else
736 	{
737 		s3c24xx_lcd_render_tpal();
738 	}
739 	m_lcd.timer->adjust(m_screen->time_until_pos(m_lcd.vpos, m_lcd.hpos));
740 }
741 
s3c24xx_video_start()742 void S3C24_CLASS_NAME::s3c24xx_video_start()
743 {
744 	m_lcd.bitmap[0] = std::make_unique<bitmap_rgb32>(m_screen->width(), m_screen->height());
745 	m_lcd.bitmap[1] = std::make_unique<bitmap_rgb32>(m_screen->width(), m_screen->height());
746 
747 	m_cpu->space(AS_PROGRAM).cache(m_cache);
748 }
749 
bitmap_blend(bitmap_rgb32 & bitmap_dst,bitmap_rgb32 & bitmap_src_1,bitmap_rgb32 & bitmap_src_2)750 void S3C24_CLASS_NAME::bitmap_blend( bitmap_rgb32 &bitmap_dst, bitmap_rgb32 &bitmap_src_1, bitmap_rgb32 &bitmap_src_2)
751 {
752 	for (int y = 0; y < bitmap_dst.height(); y++)
753 	{
754 		uint32_t const *const line0 = &bitmap_src_1.pix(y);
755 		uint32_t const *const line1 = &bitmap_src_2.pix(y);
756 		uint32_t *const line2 = &bitmap_dst.pix(y);
757 		for (int x = 0; x < bitmap_dst.width(); x++)
758 		{
759 			uint32_t color0 = line0[x];
760 			uint32_t color1 = line1[x];
761 			uint16_t r0 = (color0 >> 16) & 0x000000ff;
762 			uint16_t g0 = (color0 >>  8) & 0x000000ff;
763 			uint16_t b0 = (color0 >>  0) & 0x000000ff;
764 			uint16_t r1 = (color1 >> 16) & 0x000000ff;
765 			uint16_t g1 = (color1 >>  8) & 0x000000ff;
766 			uint16_t b1 = (color1 >>  0) & 0x000000ff;
767 			uint8_t r = uint8_t((r0 + r1) >> 1);
768 			uint8_t g = uint8_t((g0 + g1) >> 1);
769 			uint8_t b = uint8_t((b0 + b1) >> 1);
770 			line2[x] = (r << 16) | (g << 8) | b;
771 		}
772 	}
773 }
774 
s3c24xx_video_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)775 uint32_t S3C24_CLASS_NAME::s3c24xx_video_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
776 {
777 	if (m_lcd.regs.lcdcon1 & (1 << 0))
778 	{
779 		if (m_lcd.framerate >= 1195)
780 		{
781 			bitmap_blend( bitmap, *m_lcd.bitmap[0], *m_lcd.bitmap[1]);
782 			copybitmap( *m_lcd.bitmap[1], *m_lcd.bitmap[0], 0, 0, 0, 0, cliprect);
783 		}
784 		else
785 		{
786 			copybitmap( bitmap, *m_lcd.bitmap[0], 0, 0, 0, 0, cliprect);
787 		}
788 		s3c24xx_lcd_dma_init();
789 	}
790 	return 0;
791 }
792 
793 
s3c24xx_lcd_r(offs_t offset,uint32_t mem_mask)794 uint32_t S3C24_CLASS_NAME::s3c24xx_lcd_r(offs_t offset, uint32_t mem_mask)
795 {
796 	uint32_t data = ((uint32_t*)&m_lcd.regs)[offset];
797 	switch (offset)
798 	{
799 	case S3C24XX_LCDCON1:
800 		{
801 			// make sure line counter is going
802 			uint32_t vpos = m_screen->vpos();
803 			if (vpos < m_lcd.vpos_min) vpos = m_lcd.vpos_min;
804 			if (vpos > m_lcd.vpos_max) vpos = m_lcd.vpos_max;
805 			data = (data & ~0xFFFC0000) | ((m_lcd.vpos_max - vpos) << 18);
806 			LOGMASKED(LOG_LCD_REGS, "%s: lcd read: LCDCON1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
807 		}
808 		break;
809 	case S3C24XX_LCDCON5:
810 		{
811 			uint32_t vpos = m_screen->vpos();
812 			data = data & ~0x00018000;
813 			if (vpos < m_lcd.vpos_min) data = data | 0x00000000;
814 			if (vpos > m_lcd.vpos_max) data = data | 0x00018000;
815 			// todo: 00 = VSYNC, 01 = BACK Porch, 10 = ACTIVE, 11 = FRONT Porch
816 			LOGMASKED(LOG_LCD_REGS, "%s: lcd read: LCDCON5 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
817 		}
818 		break;
819 	}
820 	LOGMASKED(LOG_LCD_REGS, "%s: lcd read: %08X = %08X & %08x\n", machine().describe_context(), S3C24XX_BASE_LCD + (offset << 2), data, mem_mask);
821 	return data;
822 }
823 
s3c24xx_lcd_configure_tft()824 int S3C24_CLASS_NAME::s3c24xx_lcd_configure_tft()
825 {
826 	LOGMASKED(LOG_LCD_TFT, "s3c24xx_lcd_configure_tft\n");
827 	uint32_t vspw = BITS( m_lcd.regs.lcdcon2, 5, 0);
828 	uint32_t vbpd = BITS( m_lcd.regs.lcdcon2, 31, 24);
829 	uint32_t lineval = BITS( m_lcd.regs.lcdcon2, 23, 14);
830 	uint32_t vfpd = BITS( m_lcd.regs.lcdcon2, 13, 6);
831 	uint32_t hspw = BITS( m_lcd.regs.lcdcon4, 7, 0);
832 	uint32_t hbpd = BITS( m_lcd.regs.lcdcon3, 25, 19);
833 	uint32_t hfpd = BITS( m_lcd.regs.lcdcon3, 7, 0);
834 	uint32_t hozval = BITS( m_lcd.regs.lcdcon3, 18, 8);
835 	uint32_t clkval = BITS( m_lcd.regs.lcdcon1, 17, 8);
836 	uint32_t hclk = s3c24xx_get_hclk();
837 	LOGMASKED(LOG_LCD_TFT, "LCD - vspw %d vbpd %d lineval %d vfpd %d hspw %d hbpd %d hfpd %d hozval %d clkval %d hclk %d\n", vspw, vbpd, lineval, vfpd, hspw, hbpd, hfpd, hozval, clkval, hclk);
838 
839 	double vclk = (double)(hclk / ((clkval + 1) * 2));
840 	LOGMASKED(LOG_LCD_TFT, "LCD - vclk %f\n", vclk);
841 
842 	double framerate = vclk / (((vspw + 1) + (vbpd + 1) + (lineval + 1) + (vfpd + 1)) * ((hspw + 1) + (hbpd + 1) + (hozval + 1) + (hfpd + 1)));
843 	LOGMASKED(LOG_LCD_TFT, "LCD - framerate %f\n", framerate);
844 	m_lcd.framerate = framerate;
845 
846 	uint32_t width = (hspw + 1) + (hbpd + 1) + (hozval + 1) + (hfpd + 1);
847 	uint32_t height = (vspw + 1) + (vbpd + 1) + (lineval + 1) + (vfpd + 1);
848 
849 	rectangle visarea;
850 	visarea.min_x = (hspw + 1) + (hbpd + 1);
851 	visarea.min_y = (vspw + 1) + (vbpd + 1);
852 	visarea.max_x = visarea.min_x + (hozval + 1) - 1;
853 	visarea.max_y = visarea.min_y + (lineval + 1) - 1;
854 	LOGMASKED(LOG_LCD_TFT, "LCD - visarea min_x %d min_y %d max_x %d max_y %d\n", visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y);
855 	LOGMASKED(LOG_LCD_TFT, "screen->configure %d %d %f\n", width, height, m_lcd.framerate);
856 
857 	m_lcd.hpos_min = (hspw + 1) + (hbpd + 1);
858 	m_lcd.hpos_max = m_lcd.hpos_min + (hozval + 1) - 1;
859 	m_lcd.vpos_min = (vspw + 1) + (vbpd + 1);
860 	m_lcd.vpos_max = m_lcd.vpos_min + (lineval + 1) - 1;
861 	m_screen->configure(width, height, visarea, HZ_TO_ATTOSECONDS(m_lcd.framerate));
862 	return true;
863 }
864 
s3c24xx_lcd_configure_stn()865 int S3C24_CLASS_NAME::s3c24xx_lcd_configure_stn()
866 {
867 	LOGMASKED(LOG_LCD_STN, "s3c24xx_lcd_configure_stn\n");
868 
869 	uint32_t pnrmode = BITS( m_lcd.regs.lcdcon1, 6, 5);
870 	uint32_t bppmode = BITS( m_lcd.regs.lcdcon1, 4, 1);
871 	uint32_t clkval = BITS( m_lcd.regs.lcdcon1, 17, 8);
872 	uint32_t lineval = BITS( m_lcd.regs.lcdcon2, 23, 14);
873 	uint32_t wdly = BITS( m_lcd.regs.lcdcon3, 20, 19);
874 	uint32_t hozval = BITS( m_lcd.regs.lcdcon3, 18, 8);
875 	uint32_t lineblank = BITS( m_lcd.regs.lcdcon3, 7, 0);
876 	uint32_t wlh = BITS( m_lcd.regs.lcdcon4, 1, 0);
877 	uint32_t hclk = s3c24xx_get_hclk();
878 	LOGMASKED(LOG_LCD_STN, "LCD - pnrmode %d bppmode %d clkval %d lineval %d wdly %d hozval %d lineblank %d wlh %d hclk %d\n", pnrmode, bppmode, clkval, lineval, wdly, hozval, lineblank, wlh, hclk);
879 	if (clkval == 0)
880 	{
881 		return false;
882 	}
883 
884 	double vclk = (double)(hclk / ((clkval + 0) * 2));
885 	LOGMASKED(LOG_LCD_STN, "LCD - vclk %f\n", vclk);
886 	double framerate = 1 / (((1 / vclk) * (hozval + 1) + (1 / hclk) * ((1 << (4 + wlh)) + (1 << (4 + wdly)) + (lineblank * 8))) * (lineval + 1));
887 	LOGMASKED(LOG_LCD_STN, "LCD - framerate %f\n", framerate);
888 	m_lcd.framerate = framerate;
889 
890 	uint32_t width = 0;
891 	switch (pnrmode)
892 	{
893 		case S3C24XX_PNRMODE_STN_04_SS: width = ((hozval + 1) * 4); break;
894 		case S3C24XX_PNRMODE_STN_04_DS: width = ((hozval + 1) * 4); break;
895 		case S3C24XX_PNRMODE_STN_08_SS: width = ((hozval + 1) * 8 / 3); break;
896 		default: break;
897 	}
898 
899 	uint32_t height = lineval + 1;
900 
901 	rectangle visarea;
902 	visarea.set(0, width - 1, 0, height - 1);
903 	LOGMASKED(LOG_LCD_STN, "LCD - visarea min_x %d min_y %d max_x %d max_y %d\n", visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y);
904 	LOGMASKED(LOG_LCD_STN, "screen->configure %d %d %f\n", width, height, m_lcd.framerate);
905 
906 	m_lcd.hpos_min = 0;
907 	m_lcd.hpos_max = width - 1;
908 	m_lcd.vpos_min = 0;
909 	m_lcd.vpos_max = height - 1;
910 	m_screen->configure( width, height, visarea, HZ_TO_ATTOSECONDS( m_lcd.framerate));
911 	return true;
912 }
913 
s3c24xx_lcd_configure()914 int S3C24_CLASS_NAME::s3c24xx_lcd_configure()
915 {
916 	LOGMASKED(LOG_LCD_CFG, "s3c24xx_lcd_configure\n");
917 	uint32_t bppmode = BITS(m_lcd.regs.lcdcon1, 4, 1);
918 	if ((bppmode & (1 << 3)) == 0)
919 	{
920 		return s3c24xx_lcd_configure_stn();
921 	}
922 	else
923 	{
924 		return s3c24xx_lcd_configure_tft();
925 	}
926 }
927 
s3c24xx_lcd_start()928 void S3C24_CLASS_NAME::s3c24xx_lcd_start()
929 {
930 	LOGMASKED(LOG_LCD_CFG, "LCD start\n");
931 	if (s3c24xx_lcd_configure())
932 	{
933 		s3c24xx_lcd_dma_init();
934 		m_lcd.timer->adjust(m_screen->time_until_pos(m_lcd.vpos_min, m_lcd.hpos_min));
935 	}
936 }
937 
s3c24xx_lcd_stop()938 void S3C24_CLASS_NAME::s3c24xx_lcd_stop()
939 {
940 	LOGMASKED(LOG_LCD_CFG, "LCD stop\n");
941 	m_lcd.timer->adjust(attotime::never);
942 }
943 
s3c24xx_lcd_recalc()944 void S3C24_CLASS_NAME::s3c24xx_lcd_recalc()
945 {
946 	if (m_lcd.regs.lcdcon1 & (1 << 0))
947 	{
948 		s3c24xx_lcd_start();
949 	}
950 	else
951 	{
952 		s3c24xx_lcd_stop();
953 	}
954 }
955 
s3c24xx_lcd_w(offs_t offset,uint32_t data,uint32_t mem_mask)956 void S3C24_CLASS_NAME::s3c24xx_lcd_w(offs_t offset, uint32_t data, uint32_t mem_mask)
957 {
958 	uint32_t old_value = ((uint32_t*)&m_lcd.regs)[offset];
959 	LOGMASKED(LOG_LCD_REGS, "%s: lcd write: %08X = %08X & %08x\n", machine().describe_context(), S3C24XX_BASE_LCD + (offset << 2), data, mem_mask);
960 	COMBINE_DATA(&((uint32_t*)&m_lcd.regs)[offset]);
961 	switch (offset)
962 	{
963 		case S3C24XX_LCDCON1 :
964 		{
965 			if ((old_value & (1 << 0)) != (data & (1 << 0)))
966 			{
967 				s3c24xx_lcd_recalc();
968 			}
969 		}
970 		break;
971 	}
972 }
973 
974 /* LCD Palette */
975 
s3c24xx_lcd_palette_r(offs_t offset,uint32_t mem_mask)976 uint32_t S3C24_CLASS_NAME::s3c24xx_lcd_palette_r(offs_t offset, uint32_t mem_mask)
977 {
978 	uint32_t data = m_lcdpal.regs.data[offset];
979 	LOGMASKED(LOG_LCD_REGS, "%s: lcd palette read: %08X = %08X & %08x\n", machine().describe_context(), S3C24XX_BASE_LCDPAL + (offset << 2), data, mem_mask);
980 	return data;
981 }
982 
s3c24xx_lcd_palette_w(offs_t offset,uint32_t data,uint32_t mem_mask)983 void S3C24_CLASS_NAME::s3c24xx_lcd_palette_w(offs_t offset, uint32_t data, uint32_t mem_mask)
984 {
985 	LOGMASKED(LOG_LCD_REGS, "%s: lcd palette write: %08X = %08X & %08x\n", machine().describe_context(), S3C24XX_BASE_LCDPAL + (offset << 2), data, mem_mask);
986 	COMBINE_DATA(&m_lcdpal.regs.data[offset]);
987 	if (mem_mask != 0xffffffff)
988 	{
989 		LOGMASKED(LOG_LCD_REGS, "s3c24xx_lcd_palette_w: unknown mask %08x\n", mem_mask);
990 	}
991 	m_palette->set_pen_color( offset, s3c24xx_get_color_tft_16(data & 0xFFFF));
992 }
993 
994 /* Clock & Power Management */
995 
s3c24xx_clkpow_reset()996 void S3C24_CLASS_NAME::s3c24xx_clkpow_reset()
997 {
998 	memset( &m_clkpow.regs, 0, sizeof(m_clkpow.regs));
999 #if defined(DEVICE_S3C2400)
1000 	m_clkpow.regs.locktime = 0x00FFFFFF;
1001 	m_clkpow.regs.mpllcon  = 0x0005C080;
1002 	m_clkpow.regs.upllcon  = 0x00028080;
1003 	m_clkpow.regs.clkcon   = 0x0000FFF8;
1004 #elif defined(DEVICE_S3C2410)
1005 	m_clkpow.regs.locktime = 0x00FFFFFF;
1006 	m_clkpow.regs.mpllcon  = 0x0005C080;
1007 	m_clkpow.regs.upllcon  = 0x00028080;
1008 	m_clkpow.regs.clkcon   = 0x0007FFF0;
1009 #elif defined(DEVICE_S3C2440)
1010 	m_clkpow.regs.locktime = 0xFFFFFFFF;
1011 	m_clkpow.regs.mpllcon  = 0x00096030;
1012 	m_clkpow.regs.upllcon  = 0x0004D030;
1013 	m_clkpow.regs.clkcon   = 0x00FFFFF0;
1014 #endif
1015 	m_clkpow.regs.clkslow = 4;
1016 }
1017 
s3c24xx_get_fclk()1018 uint32_t S3C24_CLASS_NAME::s3c24xx_get_fclk()
1019 {
1020 	uint32_t mpllcon, clkslow, mdiv, pdiv, sdiv, fclk;
1021 	double temp1, temp2;
1022 	mpllcon = m_clkpow.regs.mpllcon;
1023 	mdiv = BITS( mpllcon, 19, 12);
1024 	pdiv = BITS( mpllcon, 9, 4);
1025 	sdiv = BITS( mpllcon, 1, 0);
1026 #if defined(DEVICE_S3C2400) || defined(DEVICE_S3C2410)
1027 	temp1 = 1 * (mdiv + 8) * (double)clock();
1028 #else
1029 	temp1 = 2 * (mdiv + 8) * (double)clock();
1030 #endif
1031 	temp2 = (double)((pdiv + 2) * (1 << sdiv));
1032 	fclk = (uint32_t)(temp1 / temp2);
1033 	clkslow = m_clkpow.regs.clkslow;
1034 	if (BIT(clkslow, 4) == 1)
1035 	{
1036 		uint32_t slow_val = BITS( clkslow, 2, 0);
1037 		if (slow_val > 0)
1038 		{
1039 			fclk = fclk / (2 * slow_val);
1040 		}
1041 	}
1042 	return fclk;
1043 }
1044 
s3c24xx_get_hclk()1045 uint32_t S3C24_CLASS_NAME::s3c24xx_get_hclk()
1046 {
1047 #if defined(DEVICE_S3C2400) || defined(DEVICE_S3C2410)
1048 	return s3c24xx_get_fclk() / (BIT(m_clkpow.regs.clkdivn, 1) + 1);
1049 #else
1050 	switch (BITS(m_clkpow.regs.clkdivn, 2, 1))
1051 	{
1052 	case 0: return s3c24xx_get_fclk() / 1;
1053 	case 1: return s3c24xx_get_fclk() / 2;
1054 	case 2: return s3c24xx_get_fclk() / (4 * (BIT(m_clkpow.regs.camdivn, 9) + 1));
1055 	case 3: return s3c24xx_get_fclk() / (3 * (BIT(m_clkpow.regs.camdivn, 8) + 1));
1056 	}
1057 	return 0;
1058 #endif
1059 }
1060 
s3c24xx_get_pclk()1061 uint32_t S3C24_CLASS_NAME::s3c24xx_get_pclk()
1062 {
1063 	return s3c24xx_get_hclk() / (1 << BIT(m_clkpow.regs.clkdivn, 0));
1064 }
1065 
s3c24xx_clkpow_r(offs_t offset,uint32_t mem_mask)1066 uint32_t S3C24_CLASS_NAME::s3c24xx_clkpow_r(offs_t offset, uint32_t mem_mask)
1067 {
1068 	uint32_t data = ((uint32_t*)&m_clkpow.regs)[offset];
1069 	LOGMASKED(LOG_CLKPOW, "%s: clock/power read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_CLKPOW + (offset << 2), data, mem_mask);
1070 	return data;
1071 }
1072 
s3c24xx_clkpow_w(offs_t offset,uint32_t data,uint32_t mem_mask)1073 void S3C24_CLASS_NAME::s3c24xx_clkpow_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1074 {
1075 	const uint32_t old = ((uint32_t*)&m_clkpow.regs)[offset];
1076 	COMBINE_DATA(&((uint32_t*)&m_clkpow.regs)[offset]);
1077 	switch (offset)
1078 	{
1079 	case S3C24XX_MPLLCON:
1080 		LOGMASKED(LOG_CLKPOW, "%s: clock/power write: MPLLCON = %08x & %08x - fclk %d hclk %d pclk %d\n", machine().describe_context(), data, mem_mask, s3c24xx_get_fclk(), s3c24xx_get_hclk(), s3c24xx_get_pclk());
1081 		m_cpu->set_unscaled_clock(s3c24xx_get_fclk() * CLOCK_MULTIPLIER);
1082 		break;
1083 	case S3C24XX_CLKSLOW:
1084 		LOGMASKED(LOG_CLKPOW, "%s: clock/power write: CLKSLOW = %08x & %08x - fclk %d hclk %d pclk %d\n", machine().describe_context(), data, mem_mask, s3c24xx_get_fclk(), s3c24xx_get_hclk(), s3c24xx_get_pclk());
1085 		m_cpu->set_unscaled_clock(s3c24xx_get_fclk() * CLOCK_MULTIPLIER);
1086 		break;
1087 	case S3C24XX_CLKCON:
1088 		LOGMASKED(LOG_CLKPOW, "%s: clock/power write: CLKCON = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1089 		if (BIT(data, 2) && !BIT(old, 2))
1090 		{
1091 			m_cpu->suspend(SUSPEND_REASON_HALT, 1);
1092 		}
1093 		break;
1094 	default:
1095 		LOGMASKED(LOG_CLKPOW, "%s: clock/power write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_CLKPOW + (offset << 2), data, mem_mask);
1096 	}
1097 }
1098 
1099 /* Interrupt Controller */
1100 
s3c24xx_irq_reset()1101 void S3C24_CLASS_NAME::s3c24xx_irq_reset()
1102 {
1103 	memset(&m_irq.regs, 0, sizeof(m_irq.regs));
1104 	m_irq.line_irq = m_irq.line_fiq = CLEAR_LINE;
1105 	m_irq.regs.intmsk = 0xFFFFFFFF;
1106 	m_irq.regs.priority = 0x7F;
1107 #if defined(DEVICE_S3C2410)
1108 	m_irq.regs.intsubmsk = 0x07FF;
1109 #elif defined(DEVICE_S3C2440)
1110 	m_irq.regs.intsubmsk = 0xFFFF;
1111 #endif
1112 }
1113 
s3c24xx_check_pending_irq()1114 void S3C24_CLASS_NAME::s3c24xx_check_pending_irq()
1115 {
1116 	uint32_t temp;
1117 	// normal irq
1118 
1119 	if ((m_irq.regs.intpnd == 0) && (m_irq.regs.intoffset == 0)) // without this "touryuu" crashes
1120 	{
1121 		temp = (m_irq.regs.srcpnd & ~m_irq.regs.intmsk) & ~m_irq.regs.intmod;
1122 		if (temp != 0)
1123 		{
1124 			uint32_t int_type = 0;
1125 			LOGMASKED(LOG_IRQS, "IRQ: srcpnd %08X intmsk %08X intmod %08X\n", m_irq.regs.srcpnd, m_irq.regs.intmsk, m_irq.regs.intmod);
1126 			while ((temp & 1) == 0)
1127 			{
1128 				int_type++;
1129 				temp = temp >> 1;
1130 			}
1131 			LOGMASKED(LOG_IRQS, "IRQ: intpnd set bit %d\n", int_type);
1132 			m_irq.regs.intpnd |= (1 << int_type);
1133 			m_irq.regs.intoffset = int_type;
1134 			if (m_irq.line_irq != ASSERT_LINE)
1135 			{
1136 				LOGMASKED(LOG_IRQS, "triggering IRQ line\n");
1137 				m_cpu->resume(SUSPEND_REASON_HALT);
1138 				m_cpu->set_input_line(ARM7_IRQ_LINE, ASSERT_LINE);
1139 				m_irq.line_irq = ASSERT_LINE;
1140 			}
1141 		}
1142 		else
1143 		{
1144 			if (m_irq.line_irq != CLEAR_LINE)
1145 			{
1146 				LOGMASKED(LOG_IRQS, "IRQ: srcpnd %08X intmsk %08X intmod %08X\n", m_irq.regs.srcpnd, m_irq.regs.intmsk, m_irq.regs.intmod);
1147 				LOGMASKED(LOG_IRQS, "clearing IRQ line\n");
1148 				m_cpu->set_input_line(ARM7_IRQ_LINE, CLEAR_LINE);
1149 				m_irq.line_irq = CLEAR_LINE;
1150 			}
1151 		}
1152 	}
1153 
1154 	// fast irq
1155 	temp = (m_irq.regs.srcpnd & ~m_irq.regs.intmsk) & m_irq.regs.intmod;
1156 	if (temp != 0)
1157 	{
1158 		uint32_t int_type = 0;
1159 		while ((temp & 1) == 0)
1160 		{
1161 			int_type++;
1162 			temp = temp >> 1;
1163 		}
1164 		if (m_irq.line_fiq != ASSERT_LINE)
1165 		{
1166 			LOGMASKED(LOG_IRQS, "asserting FIQ line\n");
1167 			m_cpu->resume(SUSPEND_REASON_HALT);
1168 			m_cpu->set_input_line(ARM7_FIRQ_LINE, ASSERT_LINE);
1169 			m_irq.line_fiq = ASSERT_LINE;
1170 		}
1171 	}
1172 	else
1173 	{
1174 		if (m_irq.line_fiq != CLEAR_LINE)
1175 		{
1176 			LOGMASKED(LOG_IRQS, "clearing FIQ line\n");
1177 			m_cpu->set_input_line(ARM7_FIRQ_LINE, CLEAR_LINE);
1178 			m_irq.line_fiq = CLEAR_LINE;
1179 		}
1180 	}
1181 }
1182 
s3c24xx_request_irq(uint32_t int_type)1183 void S3C24_CLASS_NAME::s3c24xx_request_irq(uint32_t int_type)
1184 {
1185 	LOGMASKED(LOG_IRQS, "request irq %d\n", int_type);
1186 	m_irq.regs.srcpnd |= (1 << int_type);
1187 	s3c24xx_check_pending_irq();
1188 }
1189 
1190 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
1191 
s3c24xx_check_pending_subirq()1192 void S3C24_CLASS_NAME::s3c24xx_check_pending_subirq()
1193 {
1194 	uint32_t temp = m_irq.regs.subsrcpnd & ~m_irq.regs.intsubmsk;
1195 	if (temp != 0)
1196 	{
1197 		uint32_t int_type = 0;
1198 		while ((temp & 1) == 0)
1199 		{
1200 			int_type++;
1201 			temp = temp >> 1;
1202 		}
1203 		s3c24xx_request_irq( MAP_SUBINT_TO_INT[int_type]);
1204 	}
1205 }
1206 
s3c24xx_request_subirq(uint32_t int_type)1207 ATTR_UNUSED void S3C24_CLASS_NAME::s3c24xx_request_subirq( uint32_t int_type)
1208 {
1209 	LOGMASKED(LOG_IRQS, "request subirq %d\n", int_type);
1210 	m_irq.regs.subsrcpnd |= (1 << int_type);
1211 	s3c24xx_check_pending_subirq();
1212 }
1213 
s3c24xx_check_pending_eint()1214 void S3C24_CLASS_NAME::s3c24xx_check_pending_eint()
1215 {
1216 	uint32_t temp = m_gpio.regs.eintpend & ~m_gpio.regs.eintmask;
1217 	if (temp != 0)
1218 	{
1219 		uint32_t int_type = 0;
1220 		while ((temp & 1) == 0)
1221 		{
1222 			int_type++;
1223 			temp = temp >> 1;
1224 		}
1225 		if (int_type < 8)
1226 		{
1227 			s3c24xx_request_irq(S3C24XX_INT_EINT4_7);
1228 		}
1229 		else
1230 		{
1231 			s3c24xx_request_irq(S3C24XX_INT_EINT8_23);
1232 		}
1233 	}
1234 }
1235 
s3c24xx_request_eint(uint32_t number)1236 ATTR_UNUSED void S3C24_CLASS_NAME::s3c24xx_request_eint(uint32_t number)
1237 {
1238 	LOGMASKED(LOG_IRQS, "request external interrupt %d\n", number);
1239 	if (number < 4)
1240 	{
1241 		s3c24xx_request_irq( S3C24XX_INT_EINT0 + number);
1242 	}
1243 	else
1244 	{
1245 		m_gpio.regs.eintpend |= (1 << number);
1246 		s3c24xx_check_pending_eint();
1247 	}
1248 }
1249 
1250 #endif
1251 
s3c24xx_irq_r(offs_t offset,uint32_t mem_mask)1252 uint32_t S3C24_CLASS_NAME::s3c24xx_irq_r(offs_t offset, uint32_t mem_mask)
1253 {
1254 	const uint32_t data = ((uint32_t*)&m_irq.regs)[offset];
1255 	switch (offset)
1256 	{
1257 		case S3C24XX_SRCPND:
1258 			LOGMASKED(LOG_IRQ_REGS, "%s: irq read: SRCPND = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1259 			break;
1260 		case S3C24XX_INTMOD:
1261 			LOGMASKED(LOG_IRQ_REGS, "%s: irq read: INTMOD = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1262 			break;
1263 		case S3C24XX_INTMSK:
1264 			LOGMASKED(LOG_IRQ_REGS, "%s: irq read: INTMSK = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1265 			break;
1266 		case S3C24XX_PRIORITY:
1267 			LOGMASKED(LOG_IRQ_REGS, "%s: irq read: PRIORITY = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1268 			break;
1269 		case S3C24XX_INTPND:
1270 			LOGMASKED(LOG_IRQ_REGS, "%s: irq read: INTPND = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1271 			break;
1272 		case S3C24XX_INTOFFSET:
1273 			LOGMASKED(LOG_IRQ_REGS, "%s: irq read: INTOFFSET = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1274 			break;
1275 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
1276 		case S3C24XX_SUBSRCPND:
1277 			LOGMASKED(LOG_IRQ_REGS, "%s: irq read: SUBSRCPND = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1278 			break;
1279 		case S3C24XX_INTSUBMSK:
1280 			LOGMASKED(LOG_IRQ_REGS, "%s: irq read: INTSUBMSK = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1281 			break;
1282 #endif
1283 		default:
1284 			LOGMASKED(LOG_IRQ_REGS, "%s: irq read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_INT + (offset << 2), data, mem_mask);
1285 			break;
1286 	}
1287 	return data;
1288 }
1289 
s3c24xx_irq_w(offs_t offset,uint32_t data,uint32_t mem_mask)1290 void S3C24_CLASS_NAME::s3c24xx_irq_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1291 {
1292 	uint32_t old_value = ((uint32_t*)&m_irq.regs)[offset];
1293 	COMBINE_DATA(&((uint32_t*)&m_irq.regs)[offset]);
1294 	switch (offset)
1295 	{
1296 	case S3C24XX_SRCPND:
1297 		LOGMASKED(LOG_IRQ_REGS, "%s: irq write: SRCPND = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1298 		m_irq.regs.srcpnd = (old_value & ~data); // clear only the bit positions of SRCPND corresponding to those set to one in the data
1299 		m_irq.regs.intoffset = 0; // "This bit can be cleared automatically by clearing SRCPND and INTPND."
1300 		s3c24xx_check_pending_irq();
1301 		break;
1302 	case S3C24XX_INTMSK:
1303 		LOGMASKED(LOG_IRQ_REGS, "%s: irq write: INTMSK = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1304 		s3c24xx_check_pending_irq();
1305 		break;
1306 	case S3C24XX_INTPND:
1307 		LOGMASKED(LOG_IRQ_REGS, "%s: irq write: INTPND = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1308 		m_irq.regs.intpnd = (old_value & ~data); // clear only the bit positions of INTPND corresponding to those set to one in the data
1309 		m_irq.regs.intoffset = 0; // "This bit can be cleared automatically by clearing SRCPND and INTPND."
1310 		s3c24xx_check_pending_irq();
1311 		break;
1312 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
1313 	case S3C24XX_SUBSRCPND:
1314 		LOGMASKED(LOG_IRQ_REGS, "%s: irq write: SUBSRCPND = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1315 		m_irq.regs.subsrcpnd = (old_value & ~data); // clear only the bit positions of SRCPND corresponding to those set to one in the data
1316 		s3c24xx_check_pending_subirq();
1317 		break;
1318 	case S3C24XX_INTSUBMSK:
1319 		LOGMASKED(LOG_IRQ_REGS, "%s: irq write: INTSUBMSK = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1320 		s3c24xx_check_pending_subirq();
1321 		break;
1322 #endif
1323 	default:
1324 		LOGMASKED(LOG_IRQ_REGS, "%s: irq write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_INT + (offset << 2), data, mem_mask);
1325 		break;
1326 	}
1327 }
1328 
1329 /* PWM Timer */
1330 
s3c24xx_pwm_r(offs_t offset,uint32_t mem_mask)1331 uint32_t S3C24_CLASS_NAME::s3c24xx_pwm_r(offs_t offset, uint32_t mem_mask)
1332 {
1333 	uint32_t data = ((uint32_t*)&m_pwm.regs)[offset];
1334 	switch (offset)
1335 	{
1336 	case pwm_t::TCNTO0:
1337 		data = (data & ~0x0000FFFF) | m_pwm.calc_observation(0);
1338 		LOGMASKED(LOG_PWM_REGS, "%s: pwm read: TCNTO0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1339 		break;
1340 	case pwm_t::TCNTO1:
1341 		data = (data & ~0x0000FFFF) | m_pwm.calc_observation(1);
1342 		LOGMASKED(LOG_PWM_REGS, "%s: pwm read: TCNTO1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1343 		break;
1344 	case pwm_t::TCNTO2:
1345 		data = (data & ~0x0000FFFF) | m_pwm.calc_observation(2);
1346 		LOGMASKED(LOG_PWM_REGS, "%s: pwm read: TCNTO2 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1347 		break;
1348 	case pwm_t::TCNTO3:
1349 		data = (data & ~0x0000FFFF) | m_pwm.calc_observation(3);
1350 		LOGMASKED(LOG_PWM_REGS, "%s: pwm read: TCNTO3 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1351 		break;
1352 	case pwm_t::TCNTO4:
1353 		data = (data & ~0x0000FFFF) | m_pwm.calc_observation(4);
1354 		LOGMASKED(LOG_PWM_REGS, "%s: pwm read: TCNTO4 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1355 		break;
1356 	default:
1357 		LOGMASKED(LOG_PWM_REGS, "%s: pwm read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_PWM + (offset << 2), data, mem_mask);
1358 	}
1359 	return data;
1360 }
1361 
s3c24xx_pwm_start(int timer)1362 void S3C24_CLASS_NAME::s3c24xx_pwm_start(int timer)
1363 {
1364 	static constexpr int mux_table[] = { 2, 4, 8, 16 };
1365 	static constexpr int prescaler_shift[] = { 0, 0, 8, 8, 8 };
1366 	static constexpr int mux_shift[] = { 0, 4, 8, 12, 16 };
1367 	uint32_t cnt, cmp, auto_reload;
1368 	double freq, hz;
1369 	LOGMASKED(LOG_PWM, "PWM %d start\n", timer);
1370 	uint32_t pclk = s3c24xx_get_pclk();
1371 	uint32_t prescaler = (m_pwm.regs.tcfg0 >> prescaler_shift[timer]) & 0xFF;
1372 	uint32_t mux = (m_pwm.regs.tcfg1 >> mux_shift[timer]) & 0x0F;
1373 	if (mux < 4)
1374 	{
1375 		freq = (double)pclk / (prescaler + 1) / mux_table[mux];
1376 	}
1377 	else
1378 	{
1379 		// todo
1380 		freq = (double)pclk / (prescaler + 1) / 1;
1381 	}
1382 	switch (timer)
1383 	{
1384 	case 0:
1385 		cnt = BITS(m_pwm.regs.tcntb0, 15, 0);
1386 		cmp = BITS(m_pwm.regs.tcmpb0, 15, 0);
1387 		auto_reload = BIT(m_pwm.regs.tcon, 3);
1388 		break;
1389 	case 1:
1390 		cnt = BITS(m_pwm.regs.tcntb1, 15, 0);
1391 		cmp = BITS(m_pwm.regs.tcmpb1, 15, 0);
1392 		auto_reload = BIT(m_pwm.regs.tcon, 11);
1393 		break;
1394 	case 2:
1395 		cnt = BITS(m_pwm.regs.tcntb2, 15, 0);
1396 		cmp = BITS(m_pwm.regs.tcmpb2, 15, 0);
1397 		auto_reload = BIT(m_pwm.regs.tcon, 15);
1398 		break;
1399 	case 3:
1400 		cnt = BITS(m_pwm.regs.tcntb3, 15, 0);
1401 		cmp = BITS(m_pwm.regs.tcmpb3, 15, 0);
1402 		auto_reload = BIT(m_pwm.regs.tcon, 19);
1403 		break;
1404 	case 4:
1405 		cnt = BITS(m_pwm.regs.tcntb4, 15, 0);
1406 		cmp = 0;
1407 		auto_reload = BIT(m_pwm.regs.tcon, 22);
1408 		break;
1409 	default:
1410 		cnt = cmp = auto_reload = 0;
1411 		break;
1412 	}
1413 //  hz = freq / (cnt - cmp + 1);
1414 	if (cnt < 2)
1415 	{
1416 		hz = freq;
1417 	}
1418 	else
1419 	{
1420 		hz = freq / cnt;
1421 	}
1422 	LOGMASKED(LOG_PWM, "PWM %d - pclk=%d prescaler=%d div=%d freq=%f cnt=%d cmp=%d auto_reload=%d hz=%f\n", timer, pclk, prescaler, mux_table[mux], freq, cnt, cmp, auto_reload, hz);
1423 	m_pwm.cnt[timer] = cnt;
1424 	m_pwm.cmp[timer] = cmp;
1425 	m_pwm.freq[timer] = freq;
1426 	if (auto_reload)
1427 	{
1428 		m_pwm.timer[timer]->adjust(attotime::from_hz(hz), timer, attotime::from_hz(hz));
1429 	}
1430 	else
1431 	{
1432 		m_pwm.timer[timer]->adjust(attotime::from_hz(hz), timer);
1433 	}
1434 }
1435 
s3c24xx_pwm_stop(int timer)1436 void S3C24_CLASS_NAME::s3c24xx_pwm_stop(int timer)
1437 {
1438 	LOGMASKED(LOG_PWM, "PWM %d stop\n", timer);
1439 	m_pwm.timer[timer]->adjust(attotime::never);
1440 }
1441 
s3c24xx_pwm_recalc(int timer)1442 void S3C24_CLASS_NAME::s3c24xx_pwm_recalc(int timer)
1443 {
1444 	static constexpr int tcon_shift[] = { 0, 8, 12, 16, 20 };
1445 	if (m_pwm.regs.tcon & (1 << tcon_shift[timer]))
1446 	{
1447 		s3c24xx_pwm_start(timer);
1448 	}
1449 	else
1450 	{
1451 		s3c24xx_pwm_stop(timer);
1452 	}
1453 }
1454 
s3c24xx_pwm_w(offs_t offset,uint32_t data,uint32_t mem_mask)1455 void S3C24_CLASS_NAME::s3c24xx_pwm_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1456 {
1457 	uint32_t const old_value = ((uint32_t*)&m_pwm.regs)[offset];
1458 	COMBINE_DATA(&((uint32_t*)&m_pwm.regs)[offset]);
1459 	switch (offset)
1460 	{
1461 	case pwm_t::TCON:
1462 		LOGMASKED(LOG_PWM_REGS, "%s: pwm write: TCON = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1463 		if (BIT(data ^ old_value, 0))
1464 		{
1465 			s3c24xx_pwm_recalc(0);
1466 		}
1467 		if (BIT(data ^ old_value, 8))
1468 		{
1469 			s3c24xx_pwm_recalc(1);
1470 		}
1471 		if (BIT(data ^ old_value, 12))
1472 		{
1473 			s3c24xx_pwm_recalc(2);
1474 		}
1475 		if (BIT(data ^ old_value, 16))
1476 		{
1477 			s3c24xx_pwm_recalc(3);
1478 		}
1479 		if (BIT(data ^ old_value, 20))
1480 		{
1481 			s3c24xx_pwm_recalc(4);
1482 		}
1483 		break;
1484 	default:
1485 		LOGMASKED(LOG_PWM_REGS, "%s: pwm write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_PWM + (offset << 2), data, mem_mask);
1486 		break;
1487 	}
1488 }
1489 
TIMER_CALLBACK_MEMBER(S3C24_CLASS_NAME::s3c24xx_pwm_timer_exp)1490 TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_pwm_timer_exp )
1491 {
1492 	int ch = param;
1493 	static constexpr int ch_int[] = { S3C24XX_INT_TIMER0, S3C24XX_INT_TIMER1, S3C24XX_INT_TIMER2, S3C24XX_INT_TIMER3, S3C24XX_INT_TIMER4 };
1494 	LOGMASKED(LOG_PWM, "PWM %d timer callback\n", ch);
1495 	if (BITS(m_pwm.regs.tcfg1, 23, 20) == (ch + 1))
1496 	{
1497 		s3c24xx_dma_request_pwm();
1498 	}
1499 	else
1500 	{
1501 		s3c24xx_request_irq(ch_int[ch]);
1502 	}
1503 }
1504 
1505 /* DMA */
1506 
s3c24xx_dma_reset()1507 void S3C24_CLASS_NAME::s3c24xx_dma_reset()
1508 {
1509 	for (dma_t &dma : m_dma)
1510 	{
1511 		memset(&dma.regs, 0, sizeof(dma.regs));
1512 		dma.timer->adjust(attotime::never);
1513 	}
1514 }
1515 
s3c24xx_dma_reload(int ch)1516 void S3C24_CLASS_NAME::s3c24xx_dma_reload(int ch)
1517 {
1518 	dma_regs_t *regs = &m_dma[ch].regs;
1519 	regs->dstat = S3C24XX_DSTAT_SET_CURR_TC(regs->dstat, S3C24XX_DCON_GET_TC(regs->dcon));
1520 	regs->dcsrc = S3C24XX_DCSRC_SET_CURR_SRC(regs->dcsrc, S3C24XX_DISRC_GET_SADDR(regs->disrc));
1521 	regs->dcdst = S3C24XX_DCDST_SET_CURR_DST(regs->dcdst, S3C24XX_DIDST_GET_DADDR(regs->didst));
1522 }
1523 
s3c24xx_dma_trigger(int ch)1524 void S3C24_CLASS_NAME::s3c24xx_dma_trigger(int ch)
1525 {
1526 	dma_regs_t *regs = &m_dma[ch].regs;
1527 	uint32_t curr_tc, curr_src, curr_dst;
1528 	address_space &space = m_cpu->space(AS_PROGRAM);
1529 	int dsz, inc_src, inc_dst, servmode, tsz;
1530 	static constexpr uint32_t ch_int[] = { S3C24XX_INT_DMA0, S3C24XX_INT_DMA1, S3C24XX_INT_DMA2, S3C24XX_INT_DMA3 };
1531 	LOGMASKED(LOG_DMA, "DMA %d trigger\n", ch);
1532 	curr_tc = S3C24XX_DSTAT_GET_CURR_TC(regs->dstat);
1533 	dsz = S3C24XX_DCON_GET_DSZ(regs->dcon);
1534 	curr_src = S3C24XX_DCSRC_GET_CURR_SRC(regs->dcsrc);
1535 	curr_dst = S3C24XX_DCDST_GET_CURR_DST(regs->dcdst);
1536 	servmode = S3C24XX_DCON_GET_SERVMODE(regs->dcon);
1537 	tsz = S3C24XX_DCON_GET_TSZ(regs->dcon);
1538 #if defined(DEVICE_S3C2400)
1539 	inc_src = BIT(regs->disrc, 29);
1540 	inc_dst = BIT(regs->didst, 29);
1541 #else
1542 	inc_src = BIT( regs->disrcc, 0);
1543 	inc_dst = BIT(regs->didstc, 0);
1544 #endif
1545 	LOGMASKED(LOG_DMA, "DMA %d - curr_src %08X curr_dst %08X curr_tc %d dsz %d\n", ch, curr_src, curr_dst, curr_tc, dsz);
1546 	while (curr_tc > 0)
1547 	{
1548 		curr_tc--;
1549 		for (int i = 0; i < 1 << (tsz << 1); i++)
1550 		{
1551 			switch (dsz)
1552 			{
1553 			case 0: space.write_byte(curr_dst, space.read_byte( curr_src)); break;
1554 			case 1: space.write_word(curr_dst, space.read_word( curr_src)); break;
1555 			case 2: space.write_dword(curr_dst, space.read_dword( curr_src)); break;
1556 			}
1557 			if (inc_src == 0) curr_src += (1 << dsz);
1558 			if (inc_dst == 0) curr_dst += (1 << dsz);
1559 		}
1560 		if (servmode == 0) break;
1561 	}
1562 	regs->dcsrc = S3C24XX_DCSRC_SET_CURR_SRC(regs->dcsrc, curr_src);
1563 	regs->dcdst = S3C24XX_DCDST_SET_CURR_DST(regs->dcdst, curr_dst);
1564 	regs->dstat = S3C24XX_DSTAT_SET_CURR_TC(regs->dstat, curr_tc);
1565 	if (curr_tc == 0)
1566 	{
1567 		if (S3C24XX_DCON_GET_RELOAD(regs->dcon) == 0)
1568 		{
1569 			s3c24xx_dma_reload(ch);
1570 		}
1571 		else
1572 		{
1573 			regs->dmasktrig &= ~(1 << 1); // clear on/off
1574 		}
1575 		if (S3C24XX_DCON_GET_INT(regs->dcon) != 0)
1576 		{
1577 			s3c24xx_request_irq(ch_int[ch]);
1578 		}
1579 	}
1580 }
1581 
s3c24xx_dma_request_iis()1582 void S3C24_CLASS_NAME::s3c24xx_dma_request_iis()
1583 {
1584 	dma_regs_t *regs = &m_dma[2].regs;
1585 	LOGMASKED(LOG_DMA_REQS, "s3c24xx_dma_request_iis\n");
1586 	if ((S3C24XX_DMASKTRIG_GET_ON_OFF(regs->dmasktrig) != 0) && (S3C24XX_DCON_GET_SWHWSEL(regs->dcon) != 0) && (S3C24XX_DCON_GET_HWSRCSEL(regs->dcon) == 0))
1587 		s3c24xx_dma_trigger(2);
1588 }
1589 
s3c24xx_dma_request_pwm()1590 void S3C24_CLASS_NAME::s3c24xx_dma_request_pwm()
1591 {
1592 	LOGMASKED(LOG_DMA_REQS, "s3c24xx_dma_request_pwm\n");
1593 	for (int i = 0; i < 4; i++)
1594 	{
1595 		if (i != 1)
1596 		{
1597 			dma_regs_t *regs = &m_dma[i].regs;
1598 			if ((S3C24XX_DMASKTRIG_GET_ON_OFF(regs->dmasktrig) != 0) && (S3C24XX_DCON_GET_SWHWSEL(regs->dcon) != 0) && (S3C24XX_DCON_GET_HWSRCSEL(regs->dcon) == 3))
1599 			{
1600 				s3c24xx_dma_trigger(i);
1601 			}
1602 		}
1603 	}
1604 }
1605 
s3c24xx_dma_start(int ch)1606 void S3C24_CLASS_NAME::s3c24xx_dma_start(int ch)
1607 {
1608 	uint32_t addr_src, addr_dst, tc;
1609 	dma_regs_t *regs = &m_dma[ch].regs;
1610 	uint32_t dsz, tsz, reload;
1611 	int inc_src, inc_dst, _int, servmode, swhwsel, hwsrcsel;
1612 	LOGMASKED(LOG_DMA, "DMA %d start\n", ch);
1613 	addr_src = S3C24XX_DISRC_GET_SADDR(regs->disrc);
1614 	addr_dst = S3C24XX_DIDST_GET_DADDR(regs->didst);
1615 	tc = S3C24XX_DCON_GET_TC(regs->dcon);
1616 	_int = S3C24XX_DCON_GET_INT(regs->dcon);
1617 	servmode = S3C24XX_DCON_GET_SERVMODE(regs->dcon);
1618 	hwsrcsel = S3C24XX_DCON_GET_HWSRCSEL(regs->dcon);
1619 	swhwsel = S3C24XX_DCON_GET_SWHWSEL(regs->dcon);
1620 	reload = S3C24XX_DCON_GET_RELOAD(regs->dcon);
1621 	dsz = S3C24XX_DCON_GET_DSZ(regs->dcon);
1622 	tsz = S3C24XX_DCON_GET_TSZ(regs->dcon);
1623 #if defined(DEVICE_S3C2400)
1624 	inc_src = BIT(regs->disrc, 29);
1625 	inc_dst = BIT(regs->didst, 29);
1626 #else
1627 	inc_src = BIT(regs->disrcc, 0);
1628 	inc_dst = BIT(regs->didstc, 0);
1629 #endif
1630 	LOGMASKED(LOG_DMA, "DMA %d - addr_src %08X inc_src %d addr_dst %08X inc_dst %d int %d tsz %d servmode %d hwsrcsel %d swhwsel %d reload %d dsz %d tc %d\n", ch, addr_src, inc_src, addr_dst, inc_dst, _int, tsz, servmode, hwsrcsel, swhwsel, reload, dsz, tc);
1631 	LOGMASKED(LOG_DMA, "DMA %d - copy %08X bytes from %08X (%s) to %08X (%s)\n", ch, (tc << dsz) << (tsz << 1), addr_src, inc_src ? "fix" : "inc", addr_dst, inc_dst ? "fix" : "inc");
1632 	s3c24xx_dma_reload(ch);
1633 	if (swhwsel == 0)
1634 		s3c24xx_dma_trigger(ch);
1635 }
1636 
s3c24xx_dma_stop(int ch)1637 void S3C24_CLASS_NAME::s3c24xx_dma_stop(int ch)
1638 {
1639 	LOGMASKED(LOG_DMA, "DMA %d stop\n", ch);
1640 }
1641 
s3c24xx_dma_recalc(int ch)1642 void S3C24_CLASS_NAME::s3c24xx_dma_recalc(int ch)
1643 {
1644 	if ((m_dma[ch].regs.dmasktrig & (1 << 1)) != 0)
1645 		s3c24xx_dma_start(ch);
1646 	else
1647 		s3c24xx_dma_stop(ch);
1648 }
1649 
s3c24xx_dma_r(uint32_t ch,uint32_t offset)1650 uint32_t S3C24_CLASS_NAME::s3c24xx_dma_r(uint32_t ch, uint32_t offset)
1651 {
1652 	static const uint32_t s_bases[4] = { S3C24XX_BASE_DMA_0, S3C24XX_BASE_DMA_1, S3C24XX_BASE_DMA_2, S3C24XX_BASE_DMA_3 };
1653 	const uint32_t data = ((uint32_t*)&m_dma[ch].regs)[offset];
1654 	LOGMASKED(LOG_DMA_REGS, "%s: dma %d read: %08x = %08x\n", machine().describe_context(), ch, s_bases[ch] + (offset << 2), data);
1655 	return data;
1656 }
1657 
s3c24xx_dma_w(uint32_t ch,uint32_t offset,uint32_t data,uint32_t mem_mask)1658 void S3C24_CLASS_NAME::s3c24xx_dma_w(uint32_t ch, uint32_t offset, uint32_t data, uint32_t mem_mask)
1659 {
1660 	static const uint32_t s_bases[4] = { S3C24XX_BASE_DMA_0, S3C24XX_BASE_DMA_1, S3C24XX_BASE_DMA_2, S3C24XX_BASE_DMA_3 };
1661 	uint32_t old_value = ((uint32_t*)&m_dma[ch].regs)[offset];
1662 	COMBINE_DATA(&((uint32_t*)&m_dma[ch].regs)[offset]);
1663 	switch (offset)
1664 	{
1665 	case S3C24XX_DCON :
1666 #if 0 // is this code necessary ???
1667 		if (BIT(data, 22)) // reload
1668 		{
1669 			dma_regs_t *regs = &m_dma[ch].regs;
1670 			regs->dmasktrig &= ~(1 << 1); // clear on/off
1671 		}
1672 #endif
1673 		LOGMASKED(LOG_DMA_REGS, "%s: dma %d write: DCON = %08x & %08x\n", machine().describe_context(), ch, data, mem_mask);
1674 		break;
1675 	case S3C24XX_DMASKTRIG :
1676 		LOGMASKED(LOG_DMA_REGS, "%s: dma %d write: DMASKTRIG = %08x & %08x\n", machine().describe_context(), ch, data, mem_mask);
1677 		if (BIT(data ^ old_value, 1))
1678 			s3c24xx_dma_recalc(ch);
1679 		break;
1680 	default:
1681 		LOGMASKED(LOG_DMA_REGS, "%s: dma %d write: %08x = %08x & %08x\n", machine().describe_context(), ch, s_bases[ch] + (offset << 2), data, mem_mask);
1682 		break;
1683 	}
1684 }
1685 
s3c24xx_dma_0_r(offs_t offset,uint32_t mem_mask)1686 uint32_t S3C24_CLASS_NAME::s3c24xx_dma_0_r(offs_t offset, uint32_t mem_mask)
1687 {
1688 	return s3c24xx_dma_r(0, offset);
1689 }
1690 
s3c24xx_dma_1_r(offs_t offset,uint32_t mem_mask)1691 uint32_t S3C24_CLASS_NAME::s3c24xx_dma_1_r(offs_t offset, uint32_t mem_mask)
1692 {
1693 	return s3c24xx_dma_r(1, offset);
1694 }
1695 
s3c24xx_dma_2_r(offs_t offset,uint32_t mem_mask)1696 uint32_t S3C24_CLASS_NAME::s3c24xx_dma_2_r(offs_t offset, uint32_t mem_mask)
1697 {
1698 	return s3c24xx_dma_r(2, offset);
1699 }
1700 
s3c24xx_dma_3_r(offs_t offset,uint32_t mem_mask)1701 uint32_t S3C24_CLASS_NAME::s3c24xx_dma_3_r(offs_t offset, uint32_t mem_mask)
1702 {
1703 	return s3c24xx_dma_r(3, offset);
1704 }
1705 
s3c24xx_dma_0_w(offs_t offset,uint32_t data,uint32_t mem_mask)1706 void S3C24_CLASS_NAME::s3c24xx_dma_0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1707 {
1708 	s3c24xx_dma_w(0, offset, data, mem_mask);
1709 }
1710 
s3c24xx_dma_1_w(offs_t offset,uint32_t data,uint32_t mem_mask)1711 void S3C24_CLASS_NAME::s3c24xx_dma_1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1712 {
1713 	s3c24xx_dma_w(1, offset, data, mem_mask);
1714 }
1715 
s3c24xx_dma_2_w(offs_t offset,uint32_t data,uint32_t mem_mask)1716 void S3C24_CLASS_NAME::s3c24xx_dma_2_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1717 {
1718 	s3c24xx_dma_w(2, offset, data, mem_mask);
1719 }
1720 
s3c24xx_dma_3_w(offs_t offset,uint32_t data,uint32_t mem_mask)1721 void S3C24_CLASS_NAME::s3c24xx_dma_3_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1722 {
1723 	s3c24xx_dma_w(3, offset, data, mem_mask);
1724 }
1725 
TIMER_CALLBACK_MEMBER(S3C24_CLASS_NAME::s3c24xx_dma_timer_exp)1726 TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_dma_timer_exp )
1727 {
1728 	int ch = param;
1729 	LOGMASKED(LOG_DMA_TIMERS, "DMA %d timer callback\n", ch);
1730 }
1731 
1732 /* I/O Port */
1733 
s3c24xx_gpio_reset()1734 void S3C24_CLASS_NAME::s3c24xx_gpio_reset()
1735 {
1736 	memset(&m_gpio.regs, 0, sizeof(m_gpio.regs));
1737 #if defined(DEVICE_S3C2400)
1738 	m_gpio.regs.gpacon = 0x0003FFFF;
1739 	m_gpio.regs.gpbcon = 0xAAAAAAAA;
1740 	m_gpio.regs.gpdup = 0x0620;
1741 	m_gpio.regs.gpeup = 0x0003;
1742 #elif defined(DEVICE_S3C2410)
1743 	m_gpio.regs.gpacon = 0x007FFFFF;
1744 	m_gpio.regs.gpgup = 0xF800;
1745 	m_gpio.regs.misccr = 0x00010330;
1746 	m_gpio.regs.eintmask = 0x00FFFFF0;
1747 	m_gpio.regs.gstatus1 = 0x32410002;
1748 #elif defined(DEVICE_S3C2440)
1749 	m_gpio.regs.gpacon = 0x00FFFFFF;
1750 	m_gpio.regs.gpgup = 0xFC00;
1751 	m_gpio.regs.misccr = 0x00010020;
1752 	m_gpio.regs.eintmask = 0x000FFFFF;
1753 	m_gpio.regs.gstatus1 = 0x32440001;
1754 #endif
1755 	m_gpio.regs.gpdup = 0xF000;
1756 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
1757 	m_gpio.regs.gstatus2 = 1 << 0; // Boot is caused by power on reset
1758 #endif
1759 }
1760 
iface_gpio_port_r(int port,uint32_t mask)1761 uint32_t S3C24_CLASS_NAME::iface_gpio_port_r(int port, uint32_t mask)
1762 {
1763 	if (!m_port_r_cb.isnull())
1764 	{
1765 		// TO CHECK : masking is not done in any of handlers
1766 		// devcb do it automatically so guess is masks are not proper right now
1767 		// without masking works fine
1768 		return (m_port_r_cb)( port ); //, mask);
1769 	}
1770 	else
1771 	{
1772 		return 0;
1773 	}
1774 }
1775 
iface_gpio_port_w(int port,uint32_t mask,uint32_t data)1776 void S3C24_CLASS_NAME::iface_gpio_port_w(int port, uint32_t mask, uint32_t data)
1777 {
1778 	if (!m_port_w_cb.isnull())
1779 	{
1780 		(m_port_w_cb)( port, data, mask );
1781 	}
1782 }
1783 
s3c24xx_gpio_get_mask(uint32_t con,int val)1784 uint16_t S3C24_CLASS_NAME::s3c24xx_gpio_get_mask( uint32_t con, int val)
1785 {
1786 	uint16_t mask = 0;
1787 	for (int i = 0; i < 16; i++)
1788 	{
1789 		if (((con >> (i << 1)) & 3) == val)
1790 			mask = mask | (1 << i);
1791 	}
1792 	return mask;
1793 }
1794 
s3c24xx_gpio_r(offs_t offset,uint32_t mem_mask)1795 uint32_t S3C24_CLASS_NAME::s3c24xx_gpio_r(offs_t offset, uint32_t mem_mask)
1796 {
1797 	uint32_t data = ((uint32_t*)&m_gpio.regs)[offset];
1798 	switch (offset)
1799 	{
1800 	case S3C24XX_GPADAT :
1801 		data = iface_gpio_port_r( S3C24XX_GPIO_PORT_A, 0) & S3C24XX_GPADAT_MASK;
1802 		LOGMASKED(LOG_GPIO, "%s: GPIO read: GPADAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1803 		break;
1804 	case S3C24XX_GPBDAT :
1805 		data = iface_gpio_port_r( S3C24XX_GPIO_PORT_B, s3c24xx_gpio_get_mask(m_gpio.regs.gpbcon, 0) & S3C24XX_GPBDAT_MASK) & S3C24XX_GPBDAT_MASK;
1806 		LOGMASKED(LOG_GPIO, "%s: GPIO read: GPBDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1807 		break;
1808 	case S3C24XX_GPCDAT :
1809 		data = iface_gpio_port_r( S3C24XX_GPIO_PORT_C, s3c24xx_gpio_get_mask(m_gpio.regs.gpccon, 0) & S3C24XX_GPCDAT_MASK) & S3C24XX_GPCDAT_MASK;
1810 		LOGMASKED(LOG_GPIO, "%s: GPIO read: GPCDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1811 		break;
1812 	case S3C24XX_GPDDAT:
1813 		data = iface_gpio_port_r( S3C24XX_GPIO_PORT_D, s3c24xx_gpio_get_mask(m_gpio.regs.gpdcon, 0) & S3C24XX_GPDDAT_MASK) & S3C24XX_GPDDAT_MASK;
1814 		LOGMASKED(LOG_GPIO, "%s: GPIO read: GPDDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1815 		break;
1816 	case S3C24XX_GPEDAT:
1817 		data = iface_gpio_port_r( S3C24XX_GPIO_PORT_E, s3c24xx_gpio_get_mask(m_gpio.regs.gpecon, 0) & S3C24XX_GPEDAT_MASK) & S3C24XX_GPEDAT_MASK;
1818 		//LOGMASKED(LOG_GPIO, "%s: GPIO read: GPEDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1819 		break;
1820 	case S3C24XX_GPFDAT:
1821 		data = iface_gpio_port_r( S3C24XX_GPIO_PORT_F, s3c24xx_gpio_get_mask(m_gpio.regs.gpfcon, 0) & S3C24XX_GPFDAT_MASK) & S3C24XX_GPFDAT_MASK;
1822 		LOGMASKED(LOG_GPIO, "%s: GPIO read: GPFDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1823 		break;
1824 	case S3C24XX_GPGDAT:
1825 		data = iface_gpio_port_r( S3C24XX_GPIO_PORT_G, s3c24xx_gpio_get_mask(m_gpio.regs.gpgcon, 0) & S3C24XX_GPGDAT_MASK) & S3C24XX_GPGDAT_MASK;
1826 		LOGMASKED(LOG_GPIO, "%s: GPIO read: GPGDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1827 		break;
1828 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
1829 	case S3C24XX_GPHDAT:
1830 		data = iface_gpio_port_r( S3C24XX_GPIO_PORT_H, s3c24xx_gpio_get_mask(m_gpio.regs.gphcon, 0) & S3C24XX_GPHDAT_MASK) & S3C24XX_GPHDAT_MASK;
1831 		LOGMASKED(LOG_GPIO, "%s: GPIO read: GPHDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1832 		break;
1833 #endif
1834 #if defined(DEVICE_S3C2440)
1835 	case S3C24XX_GPJDAT:
1836 		data = iface_gpio_port_r( S3C24XX_GPIO_PORT_J, s3c24xx_gpio_get_mask(m_gpio.regs.gpjcon, 0) & S3C24XX_GPJDAT_MASK) & S3C24XX_GPJDAT_MASK;
1837 		LOGMASKED(LOG_GPIO, "%s: GPIO read: GPJDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1838 		break;
1839 #endif
1840 	default:
1841 		LOGMASKED(LOG_GPIO, "%s: GPIO read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_GPIO + (offset << 2), data, mem_mask);
1842 		break;
1843 	}
1844 	return data;
1845 }
1846 
s3c24xx_gpio_w(offs_t offset,uint32_t data,uint32_t mem_mask)1847 void S3C24_CLASS_NAME::s3c24xx_gpio_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1848 {
1849 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
1850 	uint32_t old_value = ((uint32_t*)&m_gpio.regs)[offset];
1851 #endif
1852 	COMBINE_DATA(&((uint32_t*)&m_gpio.regs)[offset]);
1853 	switch (offset)
1854 	{
1855 	case S3C24XX_GPADAT:
1856 		LOGMASKED(LOG_GPIO, "%s: GPIO write: GPADAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1857 		iface_gpio_port_w(S3C24XX_GPIO_PORT_A, m_gpio.regs.gpacon ^ 0xFFFFFFFF, data & S3C24XX_GPADAT_MASK);
1858 		break;
1859 	case S3C24XX_GPBDAT:
1860 		LOGMASKED(LOG_GPIO, "%s: GPIO write: GPBDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1861 		iface_gpio_port_w(S3C24XX_GPIO_PORT_B, s3c24xx_gpio_get_mask(m_gpio.regs.gpbcon, 1) & S3C24XX_GPBDAT_MASK, data & S3C24XX_GPBDAT_MASK);
1862 		break;
1863 	case S3C24XX_GPCDAT:
1864 		LOGMASKED(LOG_GPIO, "%s: GPIO write: GPCDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1865 		iface_gpio_port_w(S3C24XX_GPIO_PORT_C, s3c24xx_gpio_get_mask(m_gpio.regs.gpccon, 1) & S3C24XX_GPCDAT_MASK, data & S3C24XX_GPCDAT_MASK);
1866 		break;
1867 	case S3C24XX_GPDDAT:
1868 		LOGMASKED(LOG_GPIO, "%s: GPIO write: GPDDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1869 		iface_gpio_port_w(S3C24XX_GPIO_PORT_D, s3c24xx_gpio_get_mask(m_gpio.regs.gpdcon, 1) & S3C24XX_GPDDAT_MASK, data & S3C24XX_GPDDAT_MASK);
1870 		break;
1871 	case S3C24XX_GPEDAT:
1872 		//LOGMASKED(LOG_GPIO, "%s: GPIO write: GPEDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1873 		iface_gpio_port_w(S3C24XX_GPIO_PORT_E, s3c24xx_gpio_get_mask(m_gpio.regs.gpecon, 1) & S3C24XX_GPEDAT_MASK, data & S3C24XX_GPEDAT_MASK);
1874 		break;
1875 	case S3C24XX_GPFDAT:
1876 		LOGMASKED(LOG_GPIO, "%s: GPIO write: GPFDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1877 		iface_gpio_port_w(S3C24XX_GPIO_PORT_F, s3c24xx_gpio_get_mask(m_gpio.regs.gpfcon, 1) & S3C24XX_GPFDAT_MASK, data & S3C24XX_GPFDAT_MASK);
1878 		break;
1879 	case S3C24XX_GPGDAT:
1880 		LOGMASKED(LOG_GPIO, "%s: GPIO write: GPGDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1881 		iface_gpio_port_w(S3C24XX_GPIO_PORT_G, s3c24xx_gpio_get_mask(m_gpio.regs.gpgcon, 1) & S3C24XX_GPGDAT_MASK, data & S3C24XX_GPGDAT_MASK);
1882 		break;
1883 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
1884 	case S3C24XX_GPHDAT:
1885 		LOGMASKED(LOG_GPIO, "%s: GPIO write: GPHDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1886 		iface_gpio_port_w(S3C24XX_GPIO_PORT_H, s3c24xx_gpio_get_mask(m_gpio.regs.gphcon, 1) & S3C24XX_GPHDAT_MASK, data & S3C24XX_GPHDAT_MASK);
1887 		break;
1888 	case S3C24XX_EINTPEND:
1889 		LOGMASKED(LOG_GPIO, "%s: GPIO write: EINTPEND = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1890 		m_gpio.regs.eintpend = (old_value & ~data);
1891 		s3c24xx_check_pending_eint();
1892 		break;
1893 	case S3C24XX_EINTMASK:
1894 		LOGMASKED(LOG_GPIO, "%s: GPIO write: EINTMASK = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1895 		s3c24xx_check_pending_eint();
1896 		break;
1897 	case S3C24XX_GSTATUS2:
1898 		LOGMASKED(LOG_GPIO, "%s: GPIO write: GSTATUS2 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1899 		m_gpio.regs.gstatus2 = (old_value & ~data) & 7; // "The setting is cleared by writing '1' to this bit"
1900 		break;
1901 #endif
1902 #if defined(DEVICE_S3C2440)
1903 	case S3C24XX_GPJCON:
1904 	case S3C24XX_GPJUP:
1905 		// Don't log anything, it's really chatty
1906 		break;
1907 	case S3C24XX_GPJDAT:
1908 		//LOGMASKED(LOG_GPIO, "%s: GPIO write: GPJDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1909 		iface_gpio_port_w(S3C24XX_GPIO_PORT_J, s3c24xx_gpio_get_mask(m_gpio.regs.gpjcon, 1) & S3C24XX_GPJDAT_MASK, data & S3C24XX_GPJDAT_MASK);
1910 		break;
1911 #endif
1912 	default:
1913 		LOGMASKED(LOG_GPIO, "%s: GPIO write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_GPIO + (offset << 2), data, mem_mask);
1914 		break;
1915 	}
1916 }
1917 
1918 /* Memory Controller */
1919 
s3c24xx_memcon_r(offs_t offset,uint32_t mem_mask)1920 uint32_t S3C24_CLASS_NAME::s3c24xx_memcon_r(offs_t offset, uint32_t mem_mask)
1921 {
1922 	assert(offset < ARRAY_LENGTH(m_memcon.regs.data));
1923 	uint32_t data = m_memcon.regs.data[offset];
1924 	LOGMASKED(LOG_MEMCON, "%s: memcon read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_MEMCON + (offset << 2), data, mem_mask);
1925 	return data;
1926 }
1927 
s3c24xx_memcon_w(offs_t offset,uint32_t data,uint32_t mem_mask)1928 void S3C24_CLASS_NAME::s3c24xx_memcon_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1929 {
1930 	LOGMASKED(LOG_MEMCON, "%s: memcon write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_MEMCON + (offset << 2), data, mem_mask);
1931 	COMBINE_DATA(&m_memcon.regs.data[offset]);
1932 }
1933 
1934 /* USB Host Controller */
1935 
s3c24xx_usb_host_r(offs_t offset,uint32_t mem_mask)1936 uint32_t S3C24_CLASS_NAME::s3c24xx_usb_host_r(offs_t offset, uint32_t mem_mask)
1937 {
1938 	uint32_t data = m_usbhost.regs.data[offset];
1939 	switch (offset)
1940 	{
1941 	// HcCommandStatus
1942 	case 0x08 / 4:
1943 		data = data & ~(1 << 0); // [bit 0] HostControllerReset
1944 		LOGMASKED(LOG_USBHOST, "%s: USB host read: HcCommandStatus = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1945 		break;
1946 	// HcPeriodStart
1947 	case 0x40 / 4:
1948 		// "After a hardware reset, this field is cleared. This is then set by"
1949 		// "HCD during the HC initialization. The value is calculated"
1950 		// "roughly as 10% off from HcFmInterval.. A typical value will be 3E67h."
1951 		data = (data & ~0x00003FFF) | 0x3E67;
1952 		LOGMASKED(LOG_USBHOST, "%s: USB host read: HcPeriodStart = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1953 		break;
1954 	// HcRhDescriptorA
1955 	case 0x48 / 4:
1956 		data = (data & ~0xFF) | 2; // number of ports
1957 		LOGMASKED(LOG_USBHOST, "%s: USB host read: HcRhDescriptorA = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1958 		break;
1959 	// HcRhStatus
1960 	case 0x50 / 4:
1961 		data = data & ~(1 << 16); // "The Root Hub does not support the local power status feature; thus, this bit is always read as ?0?."
1962 		LOGMASKED(LOG_USBHOST, "%s: USB host read: HcRhStatus = %08x & %08x\n", machine().describe_context(), data, mem_mask);
1963 		break;
1964 	default:
1965 		LOGMASKED(LOG_USBHOST, "%s: USB host read: %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
1966 		break;
1967 	}
1968 	return data;
1969 }
1970 
s3c24xx_usb_host_w(offs_t offset,uint32_t data,uint32_t mem_mask)1971 void S3C24_CLASS_NAME::s3c24xx_usb_host_w(offs_t offset, uint32_t data, uint32_t mem_mask)
1972 {
1973 	LOGMASKED(LOG_USBHOST, "%s: USB host write: %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
1974 	COMBINE_DATA(&m_usbhost.regs.data[offset]);
1975 }
1976 
1977 /* UART */
1978 
s3c24xx_uart_r(uint32_t ch,uint32_t offset)1979 uint32_t S3C24_CLASS_NAME::s3c24xx_uart_r(uint32_t ch, uint32_t offset)
1980 {
1981 	uint32_t data = ((uint32_t*)&m_uart[ch].regs)[offset];
1982 	switch (offset)
1983 	{
1984 	case uart_t::UTRSTAT:
1985 		data = (data & ~0x00000006) | 0x00000004 | 0x00000002; // [bit 2] Transmitter empty / [bit 1] Transmit buffer empty
1986 		LOGMASKED(LOG_UART, "%s: UART %d read: UTRSTAT = %08x\n", machine().describe_context(), ch, data);
1987 		break;
1988 	case uart_t::URXH:
1989 		{
1990 			uint8_t rxdata = data & 0xFF;
1991 			m_uart[ch].regs.utrstat &= ~1; // [bit 0] Receive buffer data ready
1992 			LOGMASKED(LOG_UART, "%s: UART %d read: URXH = %08x (%c)\n", machine().describe_context(), ch, data, ((rxdata >= 0x20 && rxdata < 0x7f) ? (char)rxdata : '?'));
1993 		}
1994 		break;
1995 	default:
1996 		LOGMASKED(LOG_UART, "%s: UART %d read: %08x = %08x\n", machine().describe_context(), ch, offset << 2, data);
1997 		break;
1998 	}
1999 	return data;
2000 }
2001 
s3c24xx_uart_w(uint32_t ch,uint32_t offset,uint32_t data,uint32_t mem_mask)2002 void S3C24_CLASS_NAME::s3c24xx_uart_w(uint32_t ch, uint32_t offset, uint32_t data, uint32_t mem_mask)
2003 {
2004 	COMBINE_DATA(&((uint32_t*)&m_uart[ch].regs)[offset]);
2005 	switch (offset)
2006 	{
2007 	case uart_t::UFCON :
2008 		m_uart[ch].regs.ufcon &= ~((1 << 2) | (1 << 1)); // bits 1 and 2 are auto-cleared after resetting FIFO
2009 		LOGMASKED(LOG_UART, "%s: UART %d write: UFCON = %08x & %08x\n", machine().describe_context(), ch, data, mem_mask);
2010 		break;
2011 	case uart_t::UTXH :
2012 		{
2013 			uint8_t txdata = data & 0xFF;
2014 #ifdef UART_PRINTF
2015 			printf("%c", (txdata >= 32 && txdata < 128) ? (char)txdata : '?');
2016 #endif
2017 			LOGMASKED(LOG_UART, "%s: UART %d write: UTXH = %08x & %08x (%c)\n", machine().describe_context(), ch, data, mem_mask, ((txdata >= 32 && txdata < 128) ? (char)txdata : '?'));
2018 		}
2019 		break;
2020 	default:
2021 		LOGMASKED(LOG_UART, "%s: UART %d write: %08x = %08x & %08x\n", machine().describe_context(), ch, offset << 2, data, mem_mask);
2022 		break;
2023 	}
2024 }
2025 
s3c24xx_uart_0_r(offs_t offset,uint32_t mem_mask)2026 uint32_t S3C24_CLASS_NAME::s3c24xx_uart_0_r(offs_t offset, uint32_t mem_mask)
2027 {
2028 	return s3c24xx_uart_r(0, offset);
2029 }
2030 
s3c24xx_uart_1_r(offs_t offset,uint32_t mem_mask)2031 uint32_t S3C24_CLASS_NAME::s3c24xx_uart_1_r(offs_t offset, uint32_t mem_mask)
2032 {
2033 	return s3c24xx_uart_r(1, offset);
2034 }
2035 
2036 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2037 
s3c24xx_uart_2_r(offs_t offset,uint32_t mem_mask)2038 uint32_t S3C24_CLASS_NAME::s3c24xx_uart_2_r(offs_t offset, uint32_t mem_mask)
2039 {
2040 	return s3c24xx_uart_r(2, offset);
2041 }
2042 
2043 #endif
2044 
s3c24xx_uart_0_w(offs_t offset,uint32_t data,uint32_t mem_mask)2045 void S3C24_CLASS_NAME::s3c24xx_uart_0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2046 {
2047 	s3c24xx_uart_w(0, offset, data, mem_mask);
2048 }
2049 
s3c24xx_uart_1_w(offs_t offset,uint32_t data,uint32_t mem_mask)2050 void S3C24_CLASS_NAME::s3c24xx_uart_1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2051 {
2052 	s3c24xx_uart_w(1, offset, data, mem_mask);
2053 }
2054 
2055 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2056 
s3c24xx_uart_2_w(offs_t offset,uint32_t data,uint32_t mem_mask)2057 void S3C24_CLASS_NAME::s3c24xx_uart_2_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2058 {
2059 	s3c24xx_uart_w(2, offset, data, mem_mask);
2060 }
2061 
2062 #endif
2063 
s3c24xx_uart_fifo_w(int uart,uint8_t data)2064 void S3C24_CLASS_NAME::s3c24xx_uart_fifo_w(int uart, uint8_t data)
2065 {
2066 #if defined(DEVICE_S3C2400)
2067 	static const uint32_t s_int_bits[2] = { S3C24XX_INT_URXD0, S3C24XX_INT_URXD1 };
2068 #else
2069 	static const uint32_t s_int_bits[3] = { S3C24XX_SUBINT_RXD0, S3C24XX_SUBINT_RXD1, S3C24XX_SUBINT_RXD2 };
2070 #endif
2071 
2072 	m_uart[uart].regs.urxh = data;
2073 	m_uart[uart].regs.utrstat |= 1; // [bit 0] Receive buffer data ready
2074 
2075 	bool request_irq = true;
2076 	if (BIT(m_uart[uart].regs.ufcon, 0))
2077 	{
2078 		request_irq = false;
2079 	}
2080 
2081 	if (request_irq)
2082 	{
2083 #if defined(DEVICE_S3C2400)
2084 		s3c24xx_request_irq(s_int_bits[uart]);
2085 #else
2086 		s3c24xx_request_subirq(s_int_bits[uart]);
2087 #endif
2088 	}
2089 }
2090 
2091 /* USB Device */
2092 
s3c24xx_usb_device_reset()2093 void S3C24_CLASS_NAME::s3c24xx_usb_device_reset()
2094 {
2095 	memset(&m_usbdev.regs, 0, sizeof(m_usbdev.regs));
2096 #if defined(DEVICE_S3C2400)
2097 	m_usbdev.regs.data[0x0C/4] = 0x033F;
2098 	m_usbdev.regs.data[0x14/4] = 0x000A;
2099 	m_usbdev.regs.data[0x24/4] = 0x0001;
2100 	m_usbdev.regs.data[0x44/4] = 0x0001;
2101 	m_usbdev.regs.data[0x54/4] = 0x0001;
2102 	m_usbdev.regs.data[0x64/4] = 0x0001;
2103 	m_usbdev.regs.data[0x74/4] = 0x0001;
2104 	m_usbdev.regs.data[0xB8/4] = 0x00FF;
2105 #elif defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2106 	m_usbdev.regs.data[0x1C/4] = 0xFF;
2107 	m_usbdev.regs.data[0x2C/4] = 0x04;
2108 	m_usbdev.regs.data[0x40/4] = 0x01;
2109 	m_usbdev.regs.data[0x48/4] = 0x20;
2110 #endif
2111 }
2112 
s3c24xx_usb_device_r(offs_t offset,uint32_t mem_mask)2113 uint32_t S3C24_CLASS_NAME::s3c24xx_usb_device_r(offs_t offset, uint32_t mem_mask)
2114 {
2115 	const uint32_t data = m_usbdev.regs.data[offset];
2116 	LOGMASKED(LOG_USB, "%s: USB read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_USBDEV + (offset << 2), data, mem_mask);
2117 	return data;
2118 }
2119 
s3c24xx_usb_device_w(offs_t offset,uint32_t data,uint32_t mem_mask)2120 void S3C24_CLASS_NAME::s3c24xx_usb_device_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2121 {
2122 	LOGMASKED(LOG_USB, "%s: USB read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_USBDEV + (offset << 2), data, mem_mask);
2123 	COMBINE_DATA(&m_usbdev.regs.data[offset]);
2124 }
2125 
2126 /* Watchdog Timer */
2127 
s3c24xx_wdt_r(offs_t offset,uint32_t mem_mask)2128 uint32_t S3C24_CLASS_NAME::s3c24xx_wdt_r(offs_t offset, uint32_t mem_mask)
2129 {
2130 	uint32_t data = ((uint32_t*)&m_wdt.regs)[offset];
2131 	switch (offset)
2132 	{
2133 	case wdt_t::WTCNT:
2134 		// is wdt active?
2135 		if (BIT(m_wdt.regs.wtcon, 5))
2136 		{
2137 #if defined(DEVICE_S3C2410)
2138 			data = m_wdt.calc_current_count();
2139 #else
2140 			data = 0;
2141 #endif
2142 		}
2143 		LOGMASKED(LOG_WDT, "%s: watchdog read: WTCNT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2144 		break;
2145 	default:
2146 		LOGMASKED(LOG_WDT, "%s: watchdog read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_WDT + (offset << 2), data, mem_mask);
2147 		break;
2148 	}
2149 	return data;
2150 }
2151 
s3c24xx_wdt_start()2152 void S3C24_CLASS_NAME::s3c24xx_wdt_start()
2153 {
2154 	uint32_t pclk, prescaler, clock;
2155 	double freq, hz;
2156 	LOGMASKED(LOG_WDT, "WDT start\n");
2157 	pclk = s3c24xx_get_pclk();
2158 	prescaler = BITS(m_wdt.regs.wtcon, 15, 8);
2159 	clock = 16 << BITS(m_wdt.regs.wtcon, 4, 3);
2160 	freq = (double)pclk / (prescaler + 1) / clock;
2161 	hz = freq / m_wdt.regs.wtcnt;
2162 	LOGMASKED(LOG_WDT, "watchdog start: pclk %d prescaler %d clock %d freq %f hz %f\n", pclk, prescaler, clock, freq, hz);
2163 	m_wdt.timer->adjust( attotime::from_hz( hz), 0, attotime::from_hz( hz));
2164 #if defined(DEVICE_S3C2410)
2165 	m_wdt.freq = freq;
2166 	m_wdt.cnt = m_wdt.regs.wtcnt;
2167 #endif
2168 }
2169 
s3c24xx_wdt_stop()2170 void S3C24_CLASS_NAME::s3c24xx_wdt_stop()
2171 {
2172 	LOGMASKED(LOG_WDT, "watchdog stop\n");
2173 #if defined(DEVICE_S3C2410)
2174 	m_wdt.regs.wtcnt = m_wdt.calc_current_count();
2175 #else
2176 	m_wdt.regs.wtcnt = 0;
2177 #endif
2178 	m_wdt.timer->adjust(attotime::never);
2179 }
2180 
s3c24xx_wdt_recalc()2181 void S3C24_CLASS_NAME::s3c24xx_wdt_recalc()
2182 {
2183 	if (BIT(m_wdt.regs.wtcon, 5))
2184 		s3c24xx_wdt_start();
2185 	else
2186 		s3c24xx_wdt_stop();
2187 }
2188 
s3c24xx_wdt_w(offs_t offset,uint32_t data,uint32_t mem_mask)2189 void S3C24_CLASS_NAME::s3c24xx_wdt_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2190 {
2191 	uint32_t old_value = ((uint32_t*)&m_wdt.regs)[offset];
2192 	COMBINE_DATA(&((uint32_t*)&m_wdt.regs)[offset]);
2193 	switch (offset)
2194 	{
2195 	case wdt_t::WTCON:
2196 		LOGMASKED(LOG_WDT, "%s: watchdog write: WTCON = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2197 		if (BIT(data ^ old_value, 5))
2198 			s3c24xx_wdt_recalc();
2199 		break;
2200 	default:
2201 		LOGMASKED(LOG_WDT, "%s: watchdog write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_WDT + (offset << 2), data, mem_mask);
2202 		break;
2203 	}
2204 }
2205 
TIMER_CALLBACK_MEMBER(S3C24_CLASS_NAME::s3c24xx_wdt_timer_exp)2206 TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_wdt_timer_exp )
2207 {
2208 	LOGMASKED(LOG_WDT, "WDT timer callback\n");
2209 	if (BIT(m_wdt.regs.wtcon, 2))
2210 	{
2211 #if defined(DEVICE_S3C2400) || defined(DEVICE_S3C2410)
2212 		s3c24xx_request_irq(S3C24XX_INT_WDT);
2213 #else
2214 		s3c24xx_request_subirq(S3C24XX_SUBINT_WDT);
2215 #endif
2216 	}
2217 	if (BIT(m_wdt.regs.wtcon, 0))
2218 	{
2219 		s3c24xx_reset();
2220 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2221 		m_gpio.regs.gstatus2 = 1 << 2; // Watchdog reset
2222 #endif
2223 	}
2224 }
2225 
2226 /* IIC */
2227 
s3c24xx_iic_reset()2228 void S3C24_CLASS_NAME::s3c24xx_iic_reset()
2229 {
2230 	memset(&m_iic.regs, 0, sizeof(m_iic.regs));
2231 	m_iic.count = 0;
2232 	m_iic.timer->adjust(attotime::never);
2233 }
2234 
iface_i2c_scl_w(int state)2235 void S3C24_CLASS_NAME::iface_i2c_scl_w( int state)
2236 {
2237 	if (!m_scl_w_cb.isnull())
2238 		m_scl_w_cb(state);
2239 }
2240 
iface_i2c_sda_w(int state)2241 void S3C24_CLASS_NAME::iface_i2c_sda_w(int state)
2242 {
2243 	if (!m_sda_w_cb.isnull())
2244 		m_sda_w_cb(state);
2245 }
2246 
iface_i2c_sda_r()2247 int S3C24_CLASS_NAME::iface_i2c_sda_r()
2248 {
2249 	if (!m_sda_r_cb.isnull())
2250 		return m_sda_r_cb();
2251 	else
2252 		return 1;
2253 }
2254 
i2c_send_start()2255 void S3C24_CLASS_NAME::i2c_send_start()
2256 {
2257 	// FIXME: this needs to sense busy condition and use realistic timing
2258 	LOGMASKED(LOG_I2C, "i2c_send_start\n");
2259 	iface_i2c_sda_w(1);
2260 	iface_i2c_scl_w(1);
2261 	iface_i2c_sda_w(0);
2262 	iface_i2c_scl_w(0);
2263 }
2264 
i2c_send_stop()2265 void S3C24_CLASS_NAME::i2c_send_stop()
2266 {
2267 	// FIXME: this needs realistic timing
2268 	LOGMASKED(LOG_I2C, "i2c_send_stop\n");
2269 	iface_i2c_sda_w(0);
2270 	iface_i2c_scl_w(1);
2271 	iface_i2c_sda_w(1);
2272 	iface_i2c_scl_w(0);
2273 }
2274 
i2c_receive_byte(int ack)2275 uint8_t S3C24_CLASS_NAME::i2c_receive_byte(int ack)
2276 {
2277 	uint8_t data = 0;
2278 	LOGMASKED(LOG_I2C, "i2c_receive_byte ...\n");
2279 	iface_i2c_sda_w(1);
2280 	for (int i = 0; i < 8; i++)
2281 	{
2282 		iface_i2c_scl_w( 1);
2283 		data = (data << 1) + (iface_i2c_sda_r() ? 1 : 0);
2284 		iface_i2c_scl_w( 0);
2285 	}
2286 	LOGMASKED(LOG_I2C, "recv data %02X\n", data);
2287 	LOGMASKED(LOG_I2C, "send ack %d\n", ack);
2288 	iface_i2c_sda_w(ack ? 0 : 1);
2289 	iface_i2c_scl_w(1);
2290 	iface_i2c_scl_w(0);
2291 	return data;
2292 }
2293 
i2c_send_byte(uint8_t data)2294 int S3C24_CLASS_NAME::i2c_send_byte(uint8_t data)
2295 {
2296 	int ack;
2297 	LOGMASKED(LOG_I2C, "i2c_send_byte ...\n");
2298 	LOGMASKED(LOG_I2C, "send data %02X\n", data);
2299 	for (int i = 0; i < 8; i++)
2300 	{
2301 		iface_i2c_sda_w((data & 0x80) ? 1 : 0);
2302 		data = data << 1;
2303 		iface_i2c_scl_w(1);
2304 		iface_i2c_scl_w(0);
2305 	}
2306 	iface_i2c_sda_w(1); // ack bit
2307 	iface_i2c_scl_w(1);
2308 	ack = iface_i2c_sda_r();
2309 	LOGMASKED(LOG_I2C, "recv ack %d\n", ack);
2310 	iface_i2c_scl_w(0);
2311 	return ack;
2312 }
2313 
iic_start()2314 void S3C24_CLASS_NAME::iic_start()
2315 {
2316 	LOGMASKED(LOG_I2C, "I2C start\n");
2317 	i2c_send_start();
2318 	int mode_selection = BITS(m_iic.regs.iicstat, 7, 6);
2319 	switch (mode_selection)
2320 	{
2321 		case 2: i2c_send_byte(m_iic.regs.iicds | 0x01); break;
2322 		case 3: i2c_send_byte(m_iic.regs.iicds & 0xFE); break;
2323 	}
2324 	m_iic.timer->adjust( attotime::from_usec( 1));
2325 }
2326 
iic_stop()2327 void S3C24_CLASS_NAME::iic_stop()
2328 {
2329 	LOGMASKED(LOG_I2C, "IIC stop\n");
2330 	i2c_send_stop();
2331 	m_iic.timer->adjust(attotime::never);
2332 }
2333 
iic_resume()2334 void S3C24_CLASS_NAME::iic_resume()
2335 {
2336 	LOGMASKED(LOG_I2C, "IIC resume\n");
2337 	int mode_selection = BITS(m_iic.regs.iicstat, 7, 6);
2338 	switch (mode_selection)
2339 	{
2340 		case 2: m_iic.regs.iicds = i2c_receive_byte(BIT(m_iic.regs.iiccon, 7)); break;
2341 		case 3: i2c_send_byte(m_iic.regs.iicds & 0xFF); break;
2342 	}
2343 	m_iic.timer->adjust(attotime::from_usec(1));
2344 }
2345 
s3c24xx_iic_r(offs_t offset,uint32_t mem_mask)2346 uint32_t S3C24_CLASS_NAME::s3c24xx_iic_r(offs_t offset, uint32_t mem_mask)
2347 {
2348 	uint32_t data = ((uint32_t*)&m_iic.regs)[offset];
2349 	switch (offset)
2350 	{
2351 	case S3C24XX_IICSTAT:
2352 		data = data & ~0x0000000F;
2353 		LOGMASKED(LOG_I2C, "%s: i2c read: IICSTAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2354 		break;
2355 	default:
2356 		LOGMASKED(LOG_I2C, "%s: i2c read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_IIC + (offset << 2), data, mem_mask);
2357 		break;
2358 	}
2359 	return data;
2360 }
2361 
s3c24xx_iic_w(offs_t offset,uint32_t data,uint32_t mem_mask)2362 void S3C24_CLASS_NAME::s3c24xx_iic_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2363 {
2364 	uint32_t old_value = ((uint32_t*)&m_iic.regs)[offset];
2365 	COMBINE_DATA(&((uint32_t*)&m_iic.regs)[offset]);
2366 	switch (offset)
2367 	{
2368 	case S3C24XX_IICCON:
2369 		{
2370 			LOGMASKED(LOG_I2C, "%s: i2c write: IICCON = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2371 #if 0
2372 			static constexpr int div_table[] = { 16, 512 };
2373 			int transmit_clock_value = (data >> 0) & 0xF;
2374 			int tx_clock_source_selection = (data >> 6) & 1;
2375 			int enable_interrupt = (data >> 5) & 1;
2376 			double clock = (double)s3c24xx_get_pclk() / div_table[tx_clock_source_selection] / (transmit_clock_value + 1);
2377 #endif
2378 			int interrupt_pending_flag = BIT(old_value, 4);
2379 			if (interrupt_pending_flag != 0)
2380 			{
2381 				interrupt_pending_flag = BIT(data, 4);
2382 				if (interrupt_pending_flag == 0)
2383 				{
2384 					int start_stop_condition;
2385 					start_stop_condition = BIT(m_iic.regs.iicstat, 5);
2386 					if (start_stop_condition != 0)
2387 					{
2388 						if (m_iic.count == 0)
2389 						{
2390 							iic_start();
2391 
2392 						}
2393 						else
2394 						{
2395 							iic_resume();
2396 						}
2397 					}
2398 					else
2399 					{
2400 						iic_stop();
2401 					}
2402 				}
2403 			}
2404 		}
2405 		break;
2406 	case S3C24XX_IICSTAT:
2407 		{
2408 			LOGMASKED(LOG_I2C, "%s: i2c write: IICSTAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2409 			m_iic.count = 0;
2410 			int interrupt_pending_flag = BIT(m_iic.regs.iiccon, 4);
2411 			if (interrupt_pending_flag == 0)
2412 			{
2413 				int start_stop_condition = BIT(data, 5);
2414 				if (start_stop_condition != 0)
2415 				{
2416 					if (m_iic.count == 0)
2417 					{
2418 						iic_start();
2419 
2420 					}
2421 					else
2422 					{
2423 						iic_resume();
2424 					}
2425 				}
2426 				else
2427 				{
2428 					iic_stop();
2429 				}
2430 			}
2431 		}
2432 		break;
2433 	default:
2434 		LOGMASKED(LOG_I2C, "%s: i2c write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_IIC + (offset << 2), data, mem_mask);
2435 		break;
2436 	}
2437 }
2438 
TIMER_CALLBACK_MEMBER(S3C24_CLASS_NAME::s3c24xx_iic_timer_exp)2439 TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_iic_timer_exp )
2440 {
2441 	int enable_interrupt;
2442 	LOGMASKED(LOG_I2C, "I2C timer callback\n");
2443 	m_iic.count++;
2444 	enable_interrupt = BIT(m_iic.regs.iiccon, 5);
2445 	if (enable_interrupt)
2446 	{
2447 		m_iic.regs.iiccon |= (1 << 4); // [bit 4] interrupt is pending
2448 		s3c24xx_request_irq(S3C24XX_INT_IIC);
2449 	}
2450 }
2451 
2452 /* IIS */
2453 
iface_i2s_data_w(int ch,uint16_t data)2454 void S3C24_CLASS_NAME::iface_i2s_data_w(int ch, uint16_t data)
2455 {
2456 	if (!m_data_w_cb.isnull())
2457 		(m_data_w_cb)(ch, data, 0);
2458 }
2459 
s3c24xx_iis_start()2460 void S3C24_CLASS_NAME::s3c24xx_iis_start()
2461 {
2462 	const uint32_t codeclk_table[] = { 256, 384};
2463 	LOGMASKED(LOG_I2S, "IIS start\n");
2464 	int prescaler_enable = BIT(m_iis.regs.iiscon, 1);
2465 	int prescaler_control_a = BITS(m_iis.regs.iispsr, 9, 5);
2466 	int prescaler_control_b = BITS(m_iis.regs.iispsr, 4, 0);
2467 	int codeclk = BIT(m_iis.regs.iismod, 2);
2468 	int pclk = s3c24xx_get_pclk();
2469 	double freq = ((double)pclk / (prescaler_control_a + 1) / codeclk_table[codeclk]) * 2; // why do I have to multiply by two?
2470 	LOGMASKED(LOG_I2S, "IIS - pclk %d psc_enable %d psc_a %d psc_b %d codeclk %d freq %f\n", pclk, prescaler_enable, prescaler_control_a, prescaler_control_b, codeclk_table[codeclk], freq);
2471 	m_iis.timer->adjust( attotime::from_hz( freq), 0, attotime::from_hz( freq));
2472 }
2473 
s3c24xx_iis_stop()2474 void S3C24_CLASS_NAME::s3c24xx_iis_stop()
2475 {
2476 	LOGMASKED(LOG_I2S, "IIS stop\n");
2477 	m_iis.timer->adjust(attotime::never);
2478 }
2479 
s3c24xx_iis_recalc()2480 void S3C24_CLASS_NAME::s3c24xx_iis_recalc()
2481 {
2482 	if (BIT(m_iis.regs.iiscon, 0))
2483 		s3c24xx_iis_start();
2484 	else
2485 		s3c24xx_iis_stop();
2486 }
2487 
s3c24xx_iis_r(offs_t offset,uint32_t mem_mask)2488 uint32_t S3C24_CLASS_NAME::s3c24xx_iis_r(offs_t offset, uint32_t mem_mask)
2489 {
2490 	uint32_t data = ((uint32_t*)&m_iis.regs)[offset];
2491 #if 0
2492 	switch (offset)
2493 	{
2494 	case iis_t::IISCON:
2495 		data = data & ~1; // hack for mp3 player
2496 		LOGMASKED(LOG_I2S, "%s: i2s read: IISCON = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2497 		break;
2498 	}
2499 #endif
2500 	LOGMASKED(LOG_I2S, "%s: i2s read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_IIS + (offset << 2), data, mem_mask);
2501 	return data;
2502 }
2503 
s3c24xx_iis_w(offs_t offset,uint32_t data,uint32_t mem_mask)2504 void S3C24_CLASS_NAME::s3c24xx_iis_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2505 {
2506 	uint32_t old_value = ((uint32_t*)&m_iis.regs)[offset];
2507 	COMBINE_DATA(&((uint32_t*)&m_iis.regs)[offset]);
2508 	switch (offset)
2509 	{
2510 	case iis_t::IISCON:
2511 		LOGMASKED(LOG_I2S, "%s: i2s write: IISCON = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2512 		if (BIT(data ^ old_value, 0))
2513 			s3c24xx_iis_recalc();
2514 		break;
2515 	case iis_t::IISFIFO:
2516 		LOGMASKED(LOG_I2S, "%s: i2s write: IISFIFO = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2517 		if (ACCESSING_BITS_16_31)
2518 		{
2519 			m_iis.fifo[m_iis.fifo_index++] = BITS(data, 31, 16);
2520 		}
2521 		if (ACCESSING_BITS_0_15)
2522 		{
2523 			m_iis.fifo[m_iis.fifo_index++] = BITS(data, 15, 0);
2524 		}
2525 		if (m_iis.fifo_index == 2)
2526 		{
2527 			m_iis.fifo_index = 0;
2528 			iface_i2s_data_w(0, m_iis.fifo[0]);
2529 			iface_i2s_data_w(1, m_iis.fifo[1]);
2530 		}
2531 		break;
2532 	default:
2533 		LOGMASKED(LOG_I2S, "%s: i2s write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_IIS + (offset << 2), data, mem_mask);
2534 		break;
2535 	}
2536 }
2537 
TIMER_CALLBACK_MEMBER(S3C24_CLASS_NAME::s3c24xx_iis_timer_exp)2538 TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_iis_timer_exp )
2539 {
2540 	LOGMASKED(LOG_I2S, "IIS timer callback\n");
2541 	s3c24xx_dma_request_iis();
2542 }
2543 
2544 /* RTC */
2545 
s3c24xx_rtc_r(offs_t offset,uint32_t mem_mask)2546 uint32_t S3C24_CLASS_NAME::s3c24xx_rtc_r(offs_t offset, uint32_t mem_mask)
2547 {
2548 	uint32_t data = ((uint32_t*)&m_rtc.regs)[offset];
2549 	LOGMASKED(LOG_RTC, "%s: rtc read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_RTC + (offset << 2), data, mem_mask);
2550 	return data;
2551 }
2552 
s3c24xx_rtc_w(offs_t offset,uint32_t data,uint32_t mem_mask)2553 void S3C24_CLASS_NAME::s3c24xx_rtc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2554 {
2555 	COMBINE_DATA(&((uint32_t*)&m_rtc.regs)[offset]);
2556 	switch (offset)
2557 	{
2558 	case rtc_t::TICNT:
2559 		LOGMASKED(LOG_RTC, "%s: rtc write: TICNT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2560 		m_rtc.recalc();
2561 		break;
2562 	default:
2563 		LOGMASKED(LOG_RTC, "%s: rtc write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_RTC + (offset << 2), data, mem_mask);
2564 		break;
2565 	}
2566 }
2567 
TIMER_CALLBACK_MEMBER(S3C24_CLASS_NAME::s3c24xx_rtc_timer_tick_count_exp)2568 TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_rtc_timer_tick_count_exp )
2569 {
2570 	LOGMASKED(LOG_RTC, "RTC timer callback (tick count)\n");
2571 	s3c24xx_request_irq(S3C24XX_INT_TICK);
2572 }
2573 
s3c24xx_rtc_update()2574 void S3C24_CLASS_NAME::s3c24xx_rtc_update()
2575 {
2576 	m_rtc.update();
2577 	LOGMASKED(LOG_RTC, "RTC - %04d/%02d/%02d %02d:%02d:%02d\n", bcd_2_dec( m_rtc.regs.bcdyear) + 2000, bcd_2_dec( m_rtc.regs.bcdmon), bcd_2_dec( m_rtc.regs.bcdday), bcd_2_dec( m_rtc.regs.bcdhour), bcd_2_dec( m_rtc.regs.bcdmin), bcd_2_dec( m_rtc.regs.bcdsec));
2578 }
2579 
s3c24xx_rtc_check_alarm()2580 void S3C24_CLASS_NAME::s3c24xx_rtc_check_alarm()
2581 {
2582 	if (m_rtc.check_alarm())
2583 		s3c24xx_request_irq(S3C24XX_INT_RTC);
2584 }
2585 
TIMER_CALLBACK_MEMBER(S3C24_CLASS_NAME::s3c24xx_rtc_timer_update_exp)2586 TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_rtc_timer_update_exp )
2587 {
2588 	LOGMASKED(LOG_RTC, "RTC timer callback (update)\n");
2589 	s3c24xx_rtc_update();
2590 	s3c24xx_rtc_check_alarm();
2591 }
2592 
2593 /* A/D Converter */
2594 
s3c24xx_adc_reset()2595 void S3C24_CLASS_NAME::s3c24xx_adc_reset()
2596 {
2597 	memset(&m_adc.regs, 0, sizeof(m_adc.regs));
2598 	m_adc.regs.adccon = 0x3FC4;
2599 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2600 	m_adc.regs.adctsc = 0x58;
2601 	m_adc.regs.adcdly = 0xFF;
2602 #endif
2603 }
2604 
iface_adc_data_r(int ch)2605 uint32_t S3C24_CLASS_NAME::iface_adc_data_r(int ch)
2606 {
2607 	if (!m_data_r_cb.isnull())
2608 	{
2609 		int offs = ch;
2610 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2611 		if (BIT(m_adc.regs.adctsc, 2) != 0)
2612 		{
2613 			offs += 2;
2614 		}
2615 #endif
2616 		return m_data_r_cb(offs, 0);
2617 	}
2618 	else
2619 	{
2620 		return 0;
2621 	}
2622 }
2623 
s3c24xx_adc_r(offs_t offset,uint32_t mem_mask)2624 uint32_t S3C24_CLASS_NAME::s3c24xx_adc_r(offs_t offset, uint32_t mem_mask)
2625 {
2626 	uint32_t data = ((uint32_t*)&m_adc.regs)[offset];
2627 	switch (offset)
2628 	{
2629 #if defined(DEVICE_S3C2400)
2630 	case S3C24XX_ADCDAT:
2631 		data = (data & ~0x3FF) | (iface_adc_data_r(0) & 0x3FF);
2632 		LOGMASKED(LOG_ADC, "%s: ADC read: ADCDAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2633 		break;
2634 #else
2635 	case S3C24XX_ADCDAT0:
2636 		data = (data & ~0x3FF) | (iface_adc_data_r(0) & 0x3FF);
2637 		LOGMASKED(LOG_ADC, "%s: ADC read: ADCDAT0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2638 		break;
2639 	case S3C24XX_ADCDAT1:
2640 		data = (data & ~0x3FF) | (iface_adc_data_r(1) & 0x3FF);
2641 		LOGMASKED(LOG_ADC, "%s: ADC read: ADCDAT1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2642 		break;
2643 #endif
2644 	default:
2645 		LOGMASKED(LOG_ADC, "%s: ADC read: %08x = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2646 		break;
2647 	}
2648 	return data;
2649 }
2650 
s3c24xx_adc_start()2651 void S3C24_CLASS_NAME::s3c24xx_adc_start()
2652 {
2653 	LOGMASKED(LOG_ADC, "ADC start\n");
2654 	m_adc.regs.adccon &= ~(1 << 0); // A/D conversion is completed
2655 	m_adc.regs.adccon |= (1 << 15); // End of A/D conversion
2656 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2657 	s3c24xx_request_subirq(S3C24XX_SUBINT_ADC);
2658 #endif
2659 }
2660 
s3c24xx_adc_w(offs_t offset,uint32_t data,uint32_t mem_mask)2661 void S3C24_CLASS_NAME::s3c24xx_adc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2662 {
2663 	uint32_t old_value = ((uint32_t*)&m_adc.regs)[offset];
2664 	COMBINE_DATA(&((uint32_t*)&m_adc.regs)[offset]);
2665 	switch (offset)
2666 	{
2667 		case S3C24XX_ADCCON:
2668 			if (((old_value & (1 << 0)) == 0) && ((data & (1 << 0)) != 0))
2669 			{
2670 				s3c24xx_adc_start();
2671 			}
2672 			LOGMASKED(LOG_ADC, "%s: ADC write: ADCCON = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2673 			break;
2674 		default:
2675 			LOGMASKED(LOG_ADC, "%s: ADC write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_ADC + (offset << 2), data, mem_mask);
2676 			break;
2677 	}
2678 }
2679 
2680 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2681 
s3c24xx_touch_screen(int state)2682 void S3C24_CLASS_NAME::s3c24xx_touch_screen(int state)
2683 {
2684 	m_adc.regs.adcdat0 = ((state ? 0 : 1) << 15);
2685 	m_adc.regs.adcdat1 = ((state ? 0 : 1) << 15);
2686 	s3c24xx_request_subirq(S3C24XX_SUBINT_TC);
2687 }
2688 
2689 #endif
2690 
2691 /* SPI */
2692 
s3c24xx_spi_reset()2693 void S3C24_CLASS_NAME::s3c24xx_spi_reset()
2694 {
2695 	for (spi_t &spi : m_spi)
2696 	{
2697 		memset(&spi.regs, 0, sizeof(spi.regs));
2698 		spi.regs.spsta = 1;
2699 #if defined(DEVICE_S3C2400) || defined(DEVICE_S3C2410)
2700 		spi.regs.sppin = 2;
2701 #endif
2702 	}
2703 }
2704 
s3c24xx_spi_r(uint32_t ch,uint32_t offset)2705 uint32_t S3C24_CLASS_NAME::s3c24xx_spi_r(uint32_t ch, uint32_t offset)
2706 {
2707 	uint32_t data = ((uint32_t*)&m_spi[ch].regs)[offset];
2708 	switch (offset)
2709 	{
2710 	case spi_t::SPSTA :
2711 		data = data | (1 << 0); // [bit 0] Transfer Ready Flag
2712 		break;
2713 	}
2714 	return data;
2715 }
2716 
s3c24xx_spi_w(uint32_t ch,uint32_t offset,uint32_t data,uint32_t mem_mask)2717 void S3C24_CLASS_NAME::s3c24xx_spi_w(uint32_t ch, uint32_t offset, uint32_t data, uint32_t mem_mask)
2718 {
2719 	COMBINE_DATA(&((uint32_t*)&m_spi[ch].regs)[offset]);
2720 }
2721 
s3c24xx_spi_0_r(offs_t offset,uint32_t mem_mask)2722 uint32_t S3C24_CLASS_NAME::s3c24xx_spi_0_r(offs_t offset, uint32_t mem_mask)
2723 {
2724 	const uint32_t data = s3c24xx_spi_r(0, offset);
2725 	LOGMASKED(LOG_SPI, "%s: SPI 0 read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_SPI_0 + (offset << 2), data, mem_mask);
2726 	return data;
2727 }
2728 
2729 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2730 
s3c24xx_spi_1_r(offs_t offset,uint32_t mem_mask)2731 uint32_t S3C24_CLASS_NAME::s3c24xx_spi_1_r(offs_t offset, uint32_t mem_mask)
2732 {
2733 	const uint32_t data = s3c24xx_spi_r(1, offset);
2734 	LOGMASKED(LOG_SPI, "%s: SPI 0 read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_SPI_0 + (offset << 2), data, mem_mask);
2735 	return data;
2736 }
2737 
2738 #endif
2739 
s3c24xx_spi_0_w(offs_t offset,uint32_t data,uint32_t mem_mask)2740 void S3C24_CLASS_NAME::s3c24xx_spi_0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2741 {
2742 	LOGMASKED(LOG_SPI, "%s: SPI 0 write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_SPI_0 + (offset << 2), data, mem_mask);
2743 	s3c24xx_spi_w( 0, offset, data, mem_mask);
2744 }
2745 
2746 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2747 
s3c24xx_spi_1_w(offs_t offset,uint32_t data,uint32_t mem_mask)2748 void S3C24_CLASS_NAME::s3c24xx_spi_1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2749 {
2750 	LOGMASKED(LOG_SPI, "%s: SPI 1 write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_SPI_0 + (offset << 2), data, mem_mask);
2751 	s3c24xx_spi_w( 1, offset, data, mem_mask);
2752 }
2753 
2754 #endif
2755 
2756 /* MMC Interface */
2757 
2758 #if defined(DEVICE_S3C2400)
2759 
s3c24xx_mmc_r(offs_t offset,uint32_t mem_mask)2760 uint32_t S3C24_CLASS_NAME::s3c24xx_mmc_r(offs_t offset, uint32_t mem_mask)
2761 {
2762 	const uint32_t data = m_mmc.regs.data[offset];
2763 	LOGMASKED(LOG_MMC, "%s: MMC read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_MMC + (offset << 2), data, mem_mask);
2764 	return data;
2765 }
2766 
s3c24xx_mmc_w(offs_t offset,uint32_t data,uint32_t mem_mask)2767 void S3C24_CLASS_NAME::s3c24xx_mmc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2768 {
2769 	LOGMASKED(LOG_MMC, "%s: MMC write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_MMC + (offset << 2), data, mem_mask);
2770 	COMBINE_DATA(&m_mmc.regs.data[offset]);
2771 }
2772 
2773 #endif
2774 
2775 /* SD Interface */
2776 
2777 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2778 
s3c24xx_sdi_reset()2779 void S3C24_CLASS_NAME::s3c24xx_sdi_reset()
2780 {
2781 	memset(&m_sdi.regs, 0, sizeof(m_sdi.regs));
2782 #if defined(DEVICE_S3C2410)
2783 	m_sdi.regs.data[0x24/4] = 0x2000;
2784 #elif defined(DEVICE_S3C2440)
2785 	m_sdi.regs.data[0x04/4] = 1;
2786 	m_sdi.regs.data[0x24/4] = 0x10000;
2787 #endif
2788 }
2789 
s3c24xx_sdi_r(offs_t offset,uint32_t mem_mask)2790 uint32_t S3C24_CLASS_NAME::s3c24xx_sdi_r(offs_t offset, uint32_t mem_mask)
2791 {
2792 	uint32_t data = m_sdi.regs.data[offset];
2793 	LOGMASKED(LOG_SDI, "%s: SDI read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_SDI + (offset << 2), data, mem_mask);
2794 	return data;
2795 }
2796 
s3c24xx_sdi_w(offs_t offset,uint32_t data,uint32_t mem_mask)2797 void S3C24_CLASS_NAME::s3c24xx_sdi_w(offs_t offset, uint32_t data, uint32_t mem_mask)
2798 {
2799 	LOGMASKED(LOG_SDI, "%s: SDI write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_SDI + (offset << 2), data, mem_mask);
2800 	COMBINE_DATA(&m_sdi.regs.data[offset]);
2801 }
2802 
2803 #endif
2804 
2805 /* NAND Flash */
2806 
2807 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
2808 
s3c24xx_nand_reset()2809 void S3C24_CLASS_NAME::s3c24xx_nand_reset()
2810 {
2811 	memset(&m_nand.regs, 0, sizeof(m_nand.regs));
2812 #if defined(DEVICE_S3C2440)
2813 	m_nand.regs.nfconf = 0x1000;
2814 	m_nand.regs.nfcont = 0x0384;
2815 #endif
2816 }
2817 
iface_nand_command_w(uint8_t data)2818 void S3C24_CLASS_NAME::iface_nand_command_w(uint8_t data)
2819 {
2820 	if (!m_command_w_cb.isnull())
2821 	{
2822 		m_command_w_cb(0, data, 0xff);
2823 	}
2824 }
2825 
iface_nand_address_w(uint8_t data)2826 void S3C24_CLASS_NAME::iface_nand_address_w(uint8_t data)
2827 {
2828 	if (!m_address_w_cb.isnull())
2829 	{
2830 		m_address_w_cb(0, data, 0xff);
2831 	}
2832 }
2833 
iface_nand_data_r()2834 uint8_t S3C24_CLASS_NAME::iface_nand_data_r()
2835 {
2836 	if (!m_nand_data_r_cb.isnull())
2837 		return m_nand_data_r_cb(0, 0xff);
2838 	else
2839 		return 0;
2840 }
2841 
iface_nand_data_w(uint8_t data)2842 void S3C24_CLASS_NAME::iface_nand_data_w(uint8_t data)
2843 {
2844 	if (!m_nand_data_w_cb.isnull())
2845 		m_nand_data_w_cb(0, data, 0xff);
2846 }
2847 
nand_update_mecc(uint8_t * ecc,int pos,uint8_t data)2848 void S3C24_CLASS_NAME::nand_update_mecc(uint8_t *ecc, int pos, uint8_t data)
2849 {
2850 	int bit[8];
2851 	uint8_t temp;
2852 	bit[0] = (data >> 0) & 1;
2853 	bit[1] = (data >> 1) & 1;
2854 	bit[2] = (data >> 2) & 1;
2855 	bit[3] = (data >> 3) & 1;
2856 	bit[4] = (data >> 4) & 1;
2857 	bit[5] = (data >> 5) & 1;
2858 	bit[6] = (data >> 6) & 1;
2859 	bit[7] = (data >> 7) & 1;
2860 	// column parity
2861 	ecc[2] ^= ((bit[6] ^ bit[4] ^ bit[2] ^ bit[0]) << 2);
2862 	ecc[2] ^= ((bit[7] ^ bit[5] ^ bit[3] ^ bit[1]) << 3);
2863 	ecc[2] ^= ((bit[5] ^ bit[4] ^ bit[1] ^ bit[0]) << 4);
2864 	ecc[2] ^= ((bit[7] ^ bit[6] ^ bit[3] ^ bit[2]) << 5);
2865 	ecc[2] ^= ((bit[3] ^ bit[2] ^ bit[1] ^ bit[0]) << 6);
2866 	ecc[2] ^= ((bit[7] ^ bit[6] ^ bit[5] ^ bit[4]) << 7);
2867 	// line parity
2868 	temp = bit[7] ^ bit[6] ^ bit[5] ^ bit[4] ^ bit[3] ^ bit[2] ^ bit[1] ^ bit[0];
2869 	if (pos & 0x001) ecc[0] ^= (temp << 1); else ecc[0] ^= (temp << 0);
2870 	if (pos & 0x002) ecc[0] ^= (temp << 3); else ecc[0] ^= (temp << 2);
2871 	if (pos & 0x004) ecc[0] ^= (temp << 5); else ecc[0] ^= (temp << 4);
2872 	if (pos & 0x008) ecc[0] ^= (temp << 7); else ecc[0] ^= (temp << 6);
2873 	if (pos & 0x010) ecc[1] ^= (temp << 1); else ecc[1] ^= (temp << 0);
2874 	if (pos & 0x020) ecc[1] ^= (temp << 3); else ecc[1] ^= (temp << 2);
2875 	if (pos & 0x040) ecc[1] ^= (temp << 5); else ecc[1] ^= (temp << 4);
2876 	if (pos & 0x080) ecc[1] ^= (temp << 7); else ecc[1] ^= (temp << 6);
2877 	if (pos & 0x100) ecc[2] ^= (temp << 1); else ecc[2] ^= (temp << 0);
2878 	if (pos & 0x200) ecc[3] ^= (temp << 5); else ecc[3] ^= (temp << 4);
2879 	if (pos & 0x400) ecc[3] ^= (temp << 7); else ecc[3] ^= (temp << 6);
2880 }
2881 
2882 #if defined(DEVICE_S3C2440)
2883 
nand_update_secc(uint8_t * ecc,int pos,uint8_t data)2884 void S3C24_CLASS_NAME::nand_update_secc( uint8_t *ecc, int pos, uint8_t data)
2885 {
2886 	int bit[8];
2887 	uint8_t temp;
2888 	bit[0] = (data >> 0) & 1;
2889 	bit[1] = (data >> 1) & 1;
2890 	bit[2] = (data >> 2) & 1;
2891 	bit[3] = (data >> 3) & 1;
2892 	bit[4] = (data >> 4) & 1;
2893 	bit[5] = (data >> 5) & 1;
2894 	bit[6] = (data >> 6) & 1;
2895 	bit[7] = (data >> 7) & 1;
2896 	// column parity
2897 	ecc[1] ^= ((bit[6] ^ bit[4] ^ bit[2] ^ bit[0]) << 6);
2898 	ecc[1] ^= ((bit[7] ^ bit[5] ^ bit[3] ^ bit[1]) << 7);
2899 	ecc[0] ^= ((bit[5] ^ bit[4] ^ bit[1] ^ bit[0]) << 0);
2900 	ecc[0] ^= ((bit[7] ^ bit[6] ^ bit[3] ^ bit[2]) << 1);
2901 	ecc[0] ^= ((bit[3] ^ bit[2] ^ bit[1] ^ bit[0]) << 2);
2902 	ecc[0] ^= ((bit[7] ^ bit[6] ^ bit[5] ^ bit[4]) << 3);
2903 	// line parity
2904 	temp = bit[7] ^ bit[6] ^ bit[5] ^ bit[4] ^ bit[3] ^ bit[2] ^ bit[1] ^ bit[0];
2905 	if (pos & 0x001) ecc[0] ^= (temp << 5); else ecc[0] ^= (temp << 4);
2906 	if (pos & 0x002) ecc[0] ^= (temp << 7); else ecc[0] ^= (temp << 6);
2907 	if (pos & 0x004) ecc[1] ^= (temp << 3); else ecc[1] ^= (temp << 2);
2908 	if (pos & 0x008) ecc[1] ^= (temp << 5); else ecc[1] ^= (temp << 4);
2909 }
2910 
2911 #endif
2912 
s3c24xx_nand_update_ecc(uint8_t data)2913 void S3C24_CLASS_NAME::s3c24xx_nand_update_ecc(uint8_t data)
2914 {
2915 	uint8_t temp[4];
2916 #if defined(DEVICE_S3C2410)
2917 	temp[0] = m_nand.mecc[0];
2918 	temp[1] = m_nand.mecc[1];
2919 	temp[2] = m_nand.mecc[2];
2920 	nand_update_mecc(m_nand.mecc, m_nand.ecc_pos++, data);
2921 	LOGMASKED(LOG_FLASH, "%s: NAND - MECC %03X - %02X %02X %02X -> %02X %02X %02X\n", machine().describe_context(), m_nand.ecc_pos - 1, temp[0], temp[1], temp[2], m_nand.mecc[0], m_nand.mecc[1], m_nand.mecc[2]);
2922 	if (m_nand.ecc_pos == 512)
2923 		m_nand.ecc_pos = 0;
2924 #else
2925 	if (!BIT(m_nand.regs.nfcont, 5))
2926 	{
2927 		temp[0] = m_nand.mecc[0];
2928 		temp[1] = m_nand.mecc[1];
2929 		temp[2] = m_nand.mecc[2];
2930 		temp[3] = m_nand.mecc[3];
2931 		nand_update_mecc( m_nand.mecc, m_nand.ecc_pos++, data);
2932 		LOGMASKED(LOG_FLASH, "%s: NAND - MECC %03X - %02X %02X %02X %02X -> %02X %02X %02X %02X\n", machine().describe_context(), m_nand.ecc_pos - 1, temp[0], temp[1], temp[2], temp[3], m_nand.mecc[0], m_nand.mecc[1], m_nand.mecc[2], m_nand.mecc[3]);
2933 		if (m_nand.ecc_pos == 2048) m_nand.ecc_pos = 0;
2934 	}
2935 	if (!BIT(m_nand.regs.nfcont, 6))
2936 	{
2937 		temp[0] = m_nand.secc[0];
2938 		temp[1] = m_nand.secc[1];
2939 		nand_update_secc(m_nand.secc, m_nand.ecc_pos++, data);
2940 		LOGMASKED(LOG_FLASH, "%s: NAND - SECC %02X - %02X %02X -> %02X %02X\n", machine().describe_context(), m_nand.ecc_pos - 1, temp[0], temp[1], m_nand.secc[0], m_nand.secc[1]);
2941 		if (m_nand.ecc_pos == 16)
2942 			m_nand.ecc_pos = 0;
2943 	}
2944 #endif
2945 }
2946 
s3c24xx_nand_command_w(uint8_t data)2947 void S3C24_CLASS_NAME::s3c24xx_nand_command_w(uint8_t data)
2948 {
2949 	LOGMASKED(LOG_FLASH, "%s: NAND write command %02X\n", machine().describe_context(), data);
2950 	m_nand.data_count = 0;
2951 	iface_nand_command_w(data);
2952 }
2953 
s3c24xx_nand_address_w(uint8_t data)2954 void S3C24_CLASS_NAME::s3c24xx_nand_address_w(uint8_t data)
2955 {
2956 	LOGMASKED(LOG_FLASH, "%s: NAND write address %02X\n", machine().describe_context(), data);
2957 	m_nand.data_count = 0;
2958 	iface_nand_address_w(data);
2959 }
2960 
s3c24xx_nand_data_r()2961 uint8_t S3C24_CLASS_NAME::s3c24xx_nand_data_r()
2962 {
2963 	uint8_t data = iface_nand_data_r();
2964 	LOGMASKED(LOG_FLASH, "%s: NAND read data %02X [%04X]\n", machine().describe_context(), data, m_nand.data_count++);
2965 	s3c24xx_nand_update_ecc(data);
2966 	return data;
2967 }
2968 
s3c24xx_nand_data_w(uint8_t data)2969 void S3C24_CLASS_NAME::s3c24xx_nand_data_w(uint8_t data)
2970 {
2971 	LOGMASKED(LOG_FLASH, "%s: NAND write data %02X [%04X]\n", machine().describe_context(), data, m_nand.data_count++);
2972 	iface_nand_data_w(data);
2973 	s3c24xx_nand_update_ecc(data);
2974 }
2975 
s3c24xx_nand_r(offs_t offset,uint32_t mem_mask)2976 uint32_t S3C24_CLASS_NAME::s3c24xx_nand_r(offs_t offset, uint32_t mem_mask)
2977 {
2978 	uint32_t data = ((uint32_t*)&m_nand.regs)[offset];
2979 	switch (offset)
2980 	{
2981 	case S3C24XX_NFDATA:
2982 		data = 0;
2983 #if defined(DEVICE_S3C2410)
2984 		data = data | s3c24xx_nand_data_r();
2985 #elif defined(DEVICE_S3C2440)
2986 		if ((mem_mask & 0x000000FF) != 0) data = data | (s3c24xx_nand_data_r() <<  0);
2987 		if ((mem_mask & 0x0000FF00) != 0) data = data | (s3c24xx_nand_data_r() <<  8);
2988 		if ((mem_mask & 0x00FF0000) != 0) data = data | (s3c24xx_nand_data_r() << 16);
2989 		if ((mem_mask & 0xFF000000) != 0) data = data | (s3c24xx_nand_data_r() << 24);
2990 #endif
2991 		break;
2992 #if defined(DEVICE_S3C2410)
2993 	case S3C24XX_NFECC :
2994 		data = ((m_nand.mecc[2] << 16) | (m_nand.mecc[1] << 8) | (m_nand.mecc[0] << 0));
2995 		LOGMASKED(LOG_FLASH, "%s: NAND read: NFECC = %08x & %08x\n", machine().describe_context(), data, mem_mask);
2996 		break;
2997 #endif
2998 #if defined(DEVICE_S3C2440)
2999 	case S3C24XX_NFMECC0 :
3000 		data = (m_nand.mecc[3] << 24) | (m_nand.mecc[2] << 16) | (m_nand.mecc[1] << 8) | (m_nand.mecc[0] << 0);
3001 		LOGMASKED(LOG_FLASH, "%s: NAND read: NFMECC0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
3002 		break;
3003 	case S3C24XX_NFSECC :
3004 		data = (m_nand.secc[1] << 8) | (m_nand.secc[0] << 0);
3005 		LOGMASKED(LOG_FLASH, "%s: NAND read: NFSECC = %08x & %08x\n", machine().describe_context(), data, mem_mask);
3006 		break;
3007 	case S3C24XX_NFESTAT0 :
3008 		data &= ~0x000000F; // no main/spare ECC errors
3009 		LOGMASKED(LOG_FLASH, "%s: NAND read: NFESTAT0 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
3010 		break;
3011 	case S3C24XX_NFESTAT1 :
3012 		data &= ~0x000000F; // no main/spare ECC errors
3013 		LOGMASKED(LOG_FLASH, "%s: NAND read: NFESTAT1 = %08x & %08x\n", machine().describe_context(), data, mem_mask);
3014 		break;
3015 #endif
3016 	default:
3017 		LOGMASKED(LOG_FLASH, "%s: NAND read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_NAND + (offset << 2), data, mem_mask);
3018 		break;
3019 	}
3020 	return data;
3021 }
3022 
s3c24xx_nand_init_ecc()3023 void S3C24_CLASS_NAME::s3c24xx_nand_init_ecc()
3024 {
3025 	LOGMASKED(LOG_FLASH, "NAND - init ecc\n");
3026 	m_nand.mecc[0] = 0xFF;
3027 	m_nand.mecc[1] = 0xFF;
3028 	m_nand.mecc[2] = 0xFF;
3029 #if defined(DEVICE_S3C2440)
3030 	m_nand.mecc[3] = 0xFF;
3031 	m_nand.secc[0] = 0;
3032 	m_nand.secc[1] = 0;
3033 #endif
3034 	m_nand.ecc_pos = 0;
3035 }
3036 
s3c24xx_nand_w(offs_t offset,uint32_t data,uint32_t mem_mask)3037 void S3C24_CLASS_NAME::s3c24xx_nand_w(offs_t offset, uint32_t data, uint32_t mem_mask)
3038 {
3039 	uint32_t old_value = ((uint32_t*)&m_nand.regs)[offset];
3040 	COMBINE_DATA(&((uint32_t*)&m_nand.regs)[offset]);
3041 	switch (offset)
3042 	{
3043 #if defined(DEVICE_S3C2410)
3044 	case S3C24XX_NFCONF:
3045 		LOGMASKED(LOG_FLASH, "%s: NAND write: NFCONF = %08x & %08x\n", machine().describe_context(), data, mem_mask);
3046 		if ((data & (1 << 12)) != 0)
3047 			s3c24xx_nand_init_ecc();
3048 		break;
3049 #endif
3050 #if defined(DEVICE_S3C2440)
3051 	case S3C24XX_NFCONT:
3052 		LOGMASKED(LOG_FLASH, "%s: NAND write: NFCONT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
3053 		if ((data & (1 << 4)) != 0)
3054 			s3c24xx_nand_init_ecc();
3055 		break;
3056 #endif
3057 	case S3C24XX_NFSTAT:
3058 		LOGMASKED(LOG_FLASH, "%s: NAND write: NFSTAT = %08x & %08x\n", machine().describe_context(), data, mem_mask);
3059 		m_nand.regs.nfstat = (m_nand.regs.nfstat & ~0x03) | (old_value & 0x03); // read-only
3060 #if defined(DEVICE_S3C2440)
3061 		if ((data & (1 << 2)) != 0)
3062 			m_nand.regs.nfstat &= ~(1 << 2); // "RnB_TransDetect, to clear this value write 1"
3063 #endif
3064 		break;
3065 	case S3C24XX_NFCMD:
3066 		LOGMASKED(LOG_FLASH, "%s: NAND write: NFCMD = %08x & %08x\n", machine().describe_context(), data, mem_mask);
3067 		s3c24xx_nand_command_w(data);
3068 		break;
3069 	case S3C24XX_NFADDR:
3070 		LOGMASKED(LOG_FLASH, "%s: NAND write: NFADDR = %08x & %08x\n", machine().describe_context(), data, mem_mask);
3071 		s3c24xx_nand_address_w(data);
3072 		break;
3073 	case S3C24XX_NFDATA:
3074 #if defined(DEVICE_S3C2410)
3075 		s3c24xx_nand_data_w(data & 0xFF);
3076 #elif defined(DEVICE_S3C2440)
3077 		if ((mem_mask & 0x000000FF) != 0) s3c24xx_nand_data_w((data >>  0) & 0xFF);
3078 		if ((mem_mask & 0x0000FF00) != 0) s3c24xx_nand_data_w((data >>  8) & 0xFF);
3079 		if ((mem_mask & 0x00FF0000) != 0) s3c24xx_nand_data_w((data >> 16) & 0xFF);
3080 		if ((mem_mask & 0xFF000000) != 0) s3c24xx_nand_data_w((data >> 24) & 0xFF);
3081 #endif
3082 		break;
3083 	default:
3084 		LOGMASKED(LOG_FLASH, "%s: NAND write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_NAND + (offset << 2), data, mem_mask);
3085 		break;
3086 	}
3087 }
3088 
WRITE_LINE_MEMBER(S3C24_CLASS_NAME::s3c24xx_pin_frnb_w)3089 ATTR_UNUSED WRITE_LINE_MEMBER( S3C24_CLASS_NAME::s3c24xx_pin_frnb_w )
3090 {
3091 	LOGMASKED(LOG_FLASH, "s3c24xx_pin_frnb_w (%d)\n", state);
3092 #if defined(DEVICE_S3C2440)
3093 	if ((BIT( m_nand.regs.nfstat, 0) == 0) && (state != 0))
3094 	{
3095 		m_nand.regs.nfstat |= (1 << 2);
3096 		if (BIT( m_nand.regs.nfcont, 9) != 0)
3097 			s3c24xx_request_irq( S3C24XX_INT_NFCON);
3098 	}
3099 #endif
3100 	if (state == 0)
3101 		m_nand.regs.nfstat &= ~(1 << 0);
3102 	else
3103 		m_nand.regs.nfstat |= (1 << 0);
3104 }
3105 
3106 #endif
3107 
3108 /* Camera Interface */
3109 
3110 #if defined(DEVICE_S3C2440)
3111 
s3c24xx_cam_r(offs_t offset,uint32_t mem_mask)3112 uint32_t S3C24_CLASS_NAME::s3c24xx_cam_r(offs_t offset, uint32_t mem_mask)
3113 {
3114 	uint32_t data = m_cam.regs.data[offset];
3115 	LOGMASKED(LOG_CAM, "%s: camera read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_CAM + (offset << 2), data, mem_mask);
3116 	return data;
3117 }
3118 
s3c24xx_cam_w(offs_t offset,uint32_t data,uint32_t mem_mask)3119 void S3C24_CLASS_NAME::s3c24xx_cam_w(offs_t offset, uint32_t data, uint32_t mem_mask)
3120 {
3121 	LOGMASKED(LOG_CAM, "%s: camera write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_CAM + (offset << 2), data, mem_mask);
3122 	COMBINE_DATA(&m_cam.regs.data[offset]);
3123 }
3124 
3125 #endif
3126 
3127 /* AC97 Interface */
3128 
3129 #if defined(DEVICE_S3C2440)
3130 
s3c24xx_ac97_r(offs_t offset,uint32_t mem_mask)3131 uint32_t S3C24_CLASS_NAME::s3c24xx_ac97_r(offs_t offset, uint32_t mem_mask)
3132 {
3133 	const uint32_t data = m_ac97.regs.data[offset];
3134 	LOGMASKED(LOG_AC97, "%s: audio codec read: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_AC97 + (offset << 2), data, mem_mask);
3135 	return data;
3136 }
3137 
s3c24xx_ac97_w(offs_t offset,uint32_t data,uint32_t mem_mask)3138 void S3C24_CLASS_NAME::s3c24xx_ac97_w(offs_t offset, uint32_t data, uint32_t mem_mask)
3139 {
3140 	LOGMASKED(LOG_AC97, "%s: audio codec write: %08x = %08x & %08x\n", machine().describe_context(), S3C24XX_BASE_AC97 + (offset << 2), data, mem_mask);
3141 	COMBINE_DATA(&m_ac97.regs.data[offset]);
3142 }
3143 
3144 #endif
3145 
3146 // ...
3147 
3148 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
3149 
s3c24xx_nand_auto_boot()3150 void S3C24_CLASS_NAME::s3c24xx_nand_auto_boot()
3151 {
3152 	int om0 = iface_core_pin_r(S3C24XX_CORE_PIN_OM0);
3153 	int om1 = iface_core_pin_r(S3C24XX_CORE_PIN_OM1);
3154 	if ((om0 == 0) && (om1 == 0))
3155 	{
3156 		int ncon = iface_core_pin_r(S3C24XX_CORE_PIN_NCON);
3157 		uint8_t *ptr = m_steppingstone;
3158 		int page_size, address_cycle;
3159 #if defined(DEVICE_S3C2410)
3160 		page_size = 512;
3161 		if (ncon == 0)
3162 			address_cycle = 3; // byte-page-page
3163 		else
3164 			address_cycle = 4; // byte-page-page-page
3165 #elif defined(DEVICE_S3C2440)
3166 		uint32_t port_g = iface_gpio_port_r( S3C24XX_GPIO_PORT_G, 0);
3167 		if (ncon == 0)
3168 		{
3169 			if (BIT( port_g, 13) == 0)
3170 			{
3171 				page_size = 256;
3172 				address_cycle = 3; // byte-page-page
3173 			}
3174 			else
3175 			{
3176 				page_size = 512;
3177 				address_cycle = 4; // byte-page-page-page
3178 			}
3179 		}
3180 		else
3181 		{
3182 			if (BIT( port_g, 13) == 0)
3183 			{
3184 				page_size = 1024;
3185 				address_cycle = 4; // byte-byte-page-page or byte-page-page-page ??? assume latter
3186 			}
3187 			else
3188 			{
3189 				page_size = 2048;
3190 				address_cycle = 5; // byte-byte-page-page-page
3191 			}
3192 		}
3193 #endif
3194 		iface_nand_command_w(0xFF);
3195 		for (int page = 0; page < (4 * 1024) / page_size; page++)
3196 		{
3197 			iface_nand_command_w(0x00);
3198 			iface_nand_address_w(0x00);
3199 			if (address_cycle > 4)
3200 			{
3201 				iface_nand_address_w(0x00);
3202 			}
3203 			iface_nand_address_w((page >> 0) & 0xFF);
3204 			iface_nand_address_w((page >> 8) & 0xFF);
3205 			if (address_cycle > 3)
3206 			{
3207 				iface_nand_address_w((page >> 16) & 0xFF);
3208 			}
3209 			for (int i = 0; i < page_size; i++)
3210 			{
3211 				*ptr++ = iface_nand_data_r();
3212 			}
3213 		}
3214 		iface_nand_command_w(0xFF);
3215 	}
3216 }
3217 
3218 #endif
3219 
s3c24xx_device_reset()3220 void S3C24_CLASS_NAME::s3c24xx_device_reset()
3221 {
3222 	LOGMASKED(LOG_RESET, "s3c24xx device reset\n");
3223 	for (uart_t &uart : m_uart)
3224 		uart.reset();
3225 	m_pwm.reset();
3226 	s3c24xx_dma_reset();
3227 	s3c24xx_iic_reset();
3228 	m_iis.reset();
3229 	s3c24xx_lcd_reset();
3230 	m_rtc.reset();
3231 	m_wdt.reset();
3232 	s3c24xx_irq_reset();
3233 	s3c24xx_gpio_reset();
3234 	m_memcon.reset();
3235 	s3c24xx_clkpow_reset();
3236 	m_usbhost.reset();
3237 	s3c24xx_usb_device_reset();
3238 	s3c24xx_adc_reset();
3239 	s3c24xx_spi_reset();
3240 #if defined(DEVICE_S3C2400)
3241 	m_mmc.reset();
3242 #endif
3243 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
3244 	s3c24xx_sdi_reset();
3245 	s3c24xx_nand_reset();
3246 #endif
3247 #if defined(DEVICE_S3C2440)
3248 	m_cam.reset();
3249 	m_ac97.reset();
3250 #endif
3251 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
3252 	s3c24xx_nand_auto_boot();
3253 #endif
3254 }
3255 
s3c24xx_device_start()3256 void S3C24_CLASS_NAME::s3c24xx_device_start()
3257 {
3258 	LOGMASKED(LOG_RESET, "s3c24xx device start\n");
3259 	m_pin_r_cb.resolve();
3260 	m_pin_w_cb.resolve_safe();
3261 	m_port_r_cb.resolve();
3262 	m_port_w_cb.resolve();
3263 	m_scl_w_cb.resolve();
3264 	m_sda_r_cb.resolve();
3265 	m_sda_w_cb.resolve();
3266 	m_data_r_cb.resolve();
3267 	m_data_w_cb.resolve();
3268 #if !defined(DEVICE_S3C2400)
3269 	m_command_w_cb.resolve();
3270 	m_address_w_cb.resolve();
3271 	m_nand_data_r_cb.resolve();
3272 	m_nand_data_w_cb.resolve();
3273 #endif
3274 	for (int i = 0; i < 5; i++)
3275 		m_pwm.timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_pwm_timer_exp), this));
3276 	for (auto & elem : m_dma)
3277 		elem.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_dma_timer_exp), this));
3278 	m_iic.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_iic_timer_exp), this));
3279 	m_iis.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_iis_timer_exp), this));
3280 	m_lcd.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_lcd_timer_exp), this));
3281 	m_rtc.timer_tick_count = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_rtc_timer_tick_count_exp), this));
3282 	m_rtc.timer_update = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_rtc_timer_update_exp), this));
3283 	m_wdt.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(S3C24_CLASS_NAME::s3c24xx_wdt_timer_exp), this));
3284 
3285 #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
3286 	int om0 = iface_core_pin_r(S3C24XX_CORE_PIN_OM0);
3287 	int om1 = iface_core_pin_r(S3C24XX_CORE_PIN_OM1);
3288 	if ((om0 == 0) && (om1 == 0))
3289 	{
3290 		address_space &space = m_cpu->space(AS_PROGRAM);
3291 		space.install_ram(0x00000000, 0x00000fff, m_steppingstone);
3292 		space.install_ram(0x40000000, 0x40000fff, m_steppingstone);
3293 	}
3294 #endif
3295 }
3296