Previous 199869 Revisions Next

r28726 Wednesday 19th March, 2014 at 17:11:10 UTC by Oliver Stöneberg
renamed s3c24xx.c to s3c24xx.inc
[src/emu/machine]machine.mak s3c2400.c s3c2410.c s3c2440.c s3c24xx.c s3c24xx.inc*

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

Previous 199869 Revisions Next


© 1997-2024 The MAME Team