trunk/src/emu/machine/s3c24xx.c
| r28725 | r28726 | |
| 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) |
| 88 | | typedef s3c2400_interface s3c24xx_interface; |
| 89 | | #elif defined(DEVICE_S3C2410) |
| 90 | | typedef s3c2410_interface s3c24xx_interface; |
| 91 | | #elif defined(DEVICE_S3C2440) |
| 92 | | typedef s3c2440_interface s3c24xx_interface; |
| 93 | | #endif |
| 94 | | |
| 95 | | /*************************************************************************** |
| 96 | | PROTOTYPES |
| 97 | | ***************************************************************************/ |
| 98 | | |
| 99 | | static UINT32 s3c24xx_get_fclk( device_t *device); |
| 100 | | static UINT32 s3c24xx_get_hclk( device_t *device); |
| 101 | | static UINT32 s3c24xx_get_pclk( device_t *device); |
| 102 | | |
| 103 | | static void s3c24xx_dma_request_iis( device_t *device); |
| 104 | | static void s3c24xx_dma_request_pwm( device_t *device); |
| 105 | | |
| 106 | | /*************************************************************************** |
| 107 | | INLINE FUNCTIONS |
| 108 | | ***************************************************************************/ |
| 109 | | |
| 110 | | INLINE 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 | | |
| 128 | | static 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 | | |
| 136 | | INLINE 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 | | |
| 151 | | static 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 | | |
| 176 | | static 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 | | |
| 200 | | static 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 | | |
| 211 | | static 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 | | |
| 220 | | static 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 | | |
| 230 | | static 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 | | |
| 242 | | static 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 | | |
| 250 | | static 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 | | |
| 257 | | static 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 | | |
| 267 | | static 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 | | |
| 287 | | static 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 |
| 301 | | static 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 | | |
| 345 | | static 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 | | |
| 418 | | static 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 | | |
| 455 | | static 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 | | |
| 470 | | static 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 | | |
| 502 | | static 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 | | |
| 526 | | static 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 | | |
| 550 | | static 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 | | |
| 574 | | static 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 | | |
| 593 | | static 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 | | |
| 617 | | static 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 | | |
| 641 | | static 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 | | |
| 665 | | static 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 | | |
| 689 | | static 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 | | |
| 713 | | static 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 | | |
| 737 | | static 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 | | |
| 782 | | static 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 | | |
| 790 | | static 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 | | |
| 815 | | static 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) |
| 835 | | READ32_DEVICE_HANDLER( s3c2400_lcd_r ) |
| 836 | | #elif defined(DEVICE_S3C2410) |
| 837 | | READ32_DEVICE_HANDLER( s3c2410_lcd_r ) |
| 838 | | #elif defined(DEVICE_S3C2440) |
| 839 | | READ32_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 | | |
| 869 | | static 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 | | |
| 910 | | static 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 | | |
| 957 | | static 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 | | |
| 973 | | static 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 | | |
| 985 | | static 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 | | |
| 992 | | static 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 | | |
| 1005 | | static 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 | | |
| 1026 | | static 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 | | |
| 1034 | | static 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 | | |
| 1048 | | static 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 | | |
| 1072 | | static 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 | | |
| 1100 | | static 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 | | |
| 1117 | | static 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 | | |
| 1123 | | static 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 | | |
| 1131 | | static 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 | | |
| 1155 | | static 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 | | |
| 1170 | | static 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 | | |
| 1238 | | static 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 | | |
| 1248 | | static 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 | | |
| 1264 | | ATTR_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 | | |
| 1272 | | static 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 | | |
| 1295 | | ATTR_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 | | |
| 1312 | | static 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 | | |
| 1320 | | static 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 | | |
| 1365 | | static 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 | | |
| 1376 | | static 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 | | |
| 1391 | | static 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 | | |
| 1427 | | static 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 | | |
| 1514 | | static 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 | | |
| 1521 | | static 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 | | |
| 1535 | | static 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 | | |
| 1570 | | static 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 | | |
| 1589 | | static 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 | | |
| 1600 | | static 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 | | |
| 1609 | | static 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 | | |
| 1668 | | static 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 | | |
| 1679 | | static 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 | | |
| 1696 | | static 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 | | |
| 1730 | | static void s3c24xx_dma_stop( device_t *device, int ch) |
| 1731 | | { |
| 1732 | | verboselog( device->machine(), 1, "DMA %d stop\n", ch); |
| 1733 | | } |
| 1734 | | |
| 1735 | | static 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 | | |
| 1748 | | static 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 | | |
| 1754 | | static 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 | | |
| 1783 | | static 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 | | |
| 1790 | | static 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 | | |
| 1797 | | static 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 | | |
| 1804 | | static 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 | | |
| 1811 | | static 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 | | |
| 1817 | | static 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 | | |
| 1823 | | static 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 | | |
| 1829 | | static 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 | | |
| 1835 | | static 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 | | |
| 1843 | | static 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 | | |
| 1872 | | INLINE 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 | | |
| 1885 | | INLINE 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 | | |
| 1894 | | static 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 | | |
| 1907 | | static 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 | | |
| 1968 | | static 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 | | |
| 2049 | | static 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 | | |
| 2065 | | static 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 | | |
| 2073 | | static 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 | | |
| 2082 | | static 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 | | |
| 2089 | | static 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 | | |
| 2127 | | static 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 | | |
| 2136 | | static 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 | | |
| 2147 | | static 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 | | |
| 2169 | | static 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 | | |
| 2192 | | static 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 | | |
| 2199 | | static 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 | | |
| 2208 | | static 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 | | |
| 2217 | | static 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 | | |
| 2223 | | static 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 | | |
| 2231 | | static 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 | | |
| 2239 | | static 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 | | |
| 2249 | | static 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 | | |
| 2271 | | static 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 | | |
| 2279 | | static 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 | | |
| 2288 | | static 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 | | |
| 2301 | | static 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 | | |
| 2318 | | static UINT16 s3c24xx_wdt_calc_current_count( device_t *device) |
| 2319 | | { |
| 2320 | | return 0; |
| 2321 | | } |
| 2322 | | |
| 2323 | | #endif |
| 2324 | | |
| 2325 | | static 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 | | |
| 2345 | | static 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 | | |
| 2364 | | static 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 | | |
| 2372 | | static 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 | | |
| 2385 | | static 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 | | |
| 2404 | | static 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 | | |
| 2428 | | static 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 | | |
| 2437 | | INLINE 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 | | |
| 2446 | | INLINE 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 | | |
| 2455 | | INLINE 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 | | |
| 2468 | | static 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 | | |
| 2477 | | static 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 | | |
| 2486 | | static 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 | | |
| 2505 | | static 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 | | |
| 2525 | | static 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 | | |
| 2540 | | static 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 | | |
| 2548 | | static 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 | | |
| 2562 | | static 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 | | |
| 2578 | | static 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 | | |
| 2657 | | static 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 | | |
| 2674 | | static 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 | | |
| 2684 | | INLINE 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 | | |
| 2693 | | static 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 | | |
| 2710 | | static 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 | | |
| 2717 | | static 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 | | |
| 2730 | | static 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 | | |
| 2748 | | static 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 | | |
| 2785 | | static 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 | | |
| 2794 | | static 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 | | |
| 2805 | | static 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 | | |
| 2813 | | static 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 | | |
| 2831 | | static 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 | | |
| 2846 | | static 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 | | |
| 2853 | | static 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 | | |
| 2899 | | static 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 | | |
| 2918 | | static 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 | | |
| 2928 | | static 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 | | |
| 2940 | | static 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 | | |
| 2960 | | static 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 | | |
| 2989 | | static 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 | | |
| 3000 | | static 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 | | |
| 3021 | | static 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 | | |
| 3033 | | static 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 | | |
| 3047 | | static 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 | | |
| 3062 | | static 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 | | |
| 3068 | | static 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 | | |
| 3077 | | static 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 | | |
| 3086 | | static 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 | | |
| 3094 | | static 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 | | |
| 3106 | | static 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 | | |
| 3113 | | static 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 | | |
| 3121 | | static 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 | | |
| 3134 | | static 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 | | |
| 3147 | | static 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 | | |
| 3155 | | static 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 | | |
| 3168 | | static 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 | | |
| 3179 | | INLINE 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 | | |
| 3188 | | INLINE 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 | | |
| 3197 | | INLINE 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 | | |
| 3210 | | INLINE 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 | | |
| 3219 | | static 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 | | |
| 3255 | | static 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 | | |
| 3284 | | static 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 | | |
| 3318 | | static 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 | | |
| 3326 | | static 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 | | |
| 3334 | | static 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 | | |
| 3343 | | static 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 | | |
| 3351 | | static 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 | | |
| 3404 | | static 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 | | |
| 3419 | | static 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 | | |
| 3483 | | ATTR_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 | | |
| 3513 | | static 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 | | |
| 3520 | | static 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 | | |
| 3528 | | static 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 | | |
| 3541 | | static 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 | | |
| 3548 | | static 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 | | |
| 3556 | | static 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 | | |
| 3569 | | static 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 | | |
| 3644 | | static 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 | | |
| 3679 | | static 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/s3c24xx.inc
| r0 | r28726 | |
| 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) |
| 88 | typedef s3c2400_interface s3c24xx_interface; |
| 89 | #elif defined(DEVICE_S3C2410) |
| 90 | typedef s3c2410_interface s3c24xx_interface; |
| 91 | #elif defined(DEVICE_S3C2440) |
| 92 | typedef s3c2440_interface s3c24xx_interface; |
| 93 | #endif |
| 94 | |
| 95 | /*************************************************************************** |
| 96 | PROTOTYPES |
| 97 | ***************************************************************************/ |
| 98 | |
| 99 | static UINT32 s3c24xx_get_fclk( device_t *device); |
| 100 | static UINT32 s3c24xx_get_hclk( device_t *device); |
| 101 | static UINT32 s3c24xx_get_pclk( device_t *device); |
| 102 | |
| 103 | static void s3c24xx_dma_request_iis( device_t *device); |
| 104 | static void s3c24xx_dma_request_pwm( device_t *device); |
| 105 | |
| 106 | /*************************************************************************** |
| 107 | INLINE FUNCTIONS |
| 108 | ***************************************************************************/ |
| 109 | |
| 110 | INLINE 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 | |
| 128 | static 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 | |
| 136 | INLINE 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 | |
| 151 | static 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 | |
| 176 | static 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 | |
| 200 | static 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 | |
| 211 | static 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 | |
| 220 | static 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 | |
| 230 | static 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 | |
| 242 | static 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 | |
| 250 | static 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 | |
| 257 | static 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 | |
| 267 | static 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 | |
| 287 | static 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 |
| 301 | static 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 | |
| 345 | static 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 | |
| 418 | static 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 | |
| 455 | static 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 | |
| 470 | static 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 | |
| 502 | static 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 | |
| 526 | static 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 | |
| 550 | static 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 | |
| 574 | static 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 | |
| 593 | static 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 | |
| 617 | static 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 | |
| 641 | static 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 | |
| 665 | static 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 | |
| 689 | static 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 | |
| 713 | static 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 | |
| 737 | static 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 | |
| 782 | static 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 | |
| 790 | static 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 | |
| 815 | static 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) |
| 835 | READ32_DEVICE_HANDLER( s3c2400_lcd_r ) |
| 836 | #elif defined(DEVICE_S3C2410) |
| 837 | READ32_DEVICE_HANDLER( s3c2410_lcd_r ) |
| 838 | #elif defined(DEVICE_S3C2440) |
| 839 | READ32_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 | |
| 869 | static 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 | |
| 910 | static 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 | |
| 957 | static 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 | |
| 973 | static 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 | |
| 985 | static 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 | |
| 992 | static 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 | |
| 1005 | static 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 | |
| 1026 | static 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 | |
| 1034 | static 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 | |
| 1048 | static 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 | |
| 1072 | static 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 | |
| 1100 | static 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 | |
| 1117 | static 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 | |
| 1123 | static 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 | |
| 1131 | static 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 | |
| 1155 | static 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 | |
| 1170 | static 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 | |
| 1238 | static 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 | |
| 1248 | static 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 | |
| 1264 | ATTR_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 | |
| 1272 | static 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 | |
| 1295 | ATTR_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 | |
| 1312 | static 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 | |
| 1320 | static 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 | |
| 1365 | static 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 | |
| 1376 | static 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 | |
| 1391 | static 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 | |
| 1427 | static 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 | |
| 1514 | static 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 | |
| 1521 | static 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 | |
| 1535 | static 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 | |
| 1570 | static 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 | |
| 1589 | static 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 | |
| 1600 | static 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 | |
| 1609 | static 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 | |
| 1668 | static 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 | |
| 1679 | static 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 | |
| 1696 | static 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 | |
| 1730 | static void s3c24xx_dma_stop( device_t *device, int ch) |
| 1731 | { |
| 1732 | verboselog( device->machine(), 1, "DMA %d stop\n", ch); |
| 1733 | } |
| 1734 | |
| 1735 | static 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 | |
| 1748 | static 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 | |
| 1754 | static 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 | |
| 1783 | static 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 | |
| 1790 | static 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 | |
| 1797 | static 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 | |
| 1804 | static 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 | |
| 1811 | static 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 | |
| 1817 | static 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 | |
| 1823 | static 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 | |
| 1829 | static 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 | |
| 1835 | static 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 | |
| 1843 | static 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 | |
| 1872 | INLINE 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 | |
| 1885 | INLINE 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 | |
| 1894 | static 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 | |
| 1907 | static 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 | |
| 1968 | static 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 | |
| 2049 | static 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 | |
| 2065 | static 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 | |
| 2073 | static 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 | |
| 2082 | static 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 | |
| 2089 | static 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 | |
| 2127 | static 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 | |
| 2136 | static 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 | |
| 2147 | static 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 | |
| 2169 | static 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 | |
| 2192 | static 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 | |
| 2199 | static 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 | |
| 2208 | static 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 | |
| 2217 | static 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 | |
| 2223 | static 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 | |
| 2231 | static 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 | |
| 2239 | static 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 | |
| 2249 | static 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 | |
| 2271 | static 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 | |
| 2279 | static 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 | |
| 2288 | static 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 | |
| 2301 | static 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 | |
| 2318 | static UINT16 s3c24xx_wdt_calc_current_count( device_t *device) |
| 2319 | { |
| 2320 | return 0; |
| 2321 | } |
| 2322 | |
| 2323 | #endif |
| 2324 | |
| 2325 | static 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 | |
| 2345 | static 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 | |
| 2364 | static 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 | |
| 2372 | static 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 | |
| 2385 | static 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 | |
| 2404 | static 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 | |
| 2428 | static 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 | |
| 2437 | INLINE 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 | |
| 2446 | INLINE 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 | |
| 2455 | INLINE 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 | |
| 2468 | static 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 | |
| 2477 | static 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 | |
| 2486 | static 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 | |
| 2505 | static 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 | |
| 2525 | static 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 | |
| 2540 | static 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 | |
| 2548 | static 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 | |
| 2562 | static 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 | |
| 2578 | static 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 | |
| 2657 | static 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 | |
| 2674 | static 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 | |
| 2684 | INLINE 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 | |
| 2693 | static 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 | |
| 2710 | static 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 | |
| 2717 | static 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 | |
| 2730 | static 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 | |
| 2748 | static 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 | |
| 2785 | static 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 | |
| 2794 | static 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 | |
| 2805 | static 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 | |
| 2813 | static 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 | |
| 2831 | static 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 | |
| 2846 | static 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 | |
| 2853 | static 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 | |
| 2899 | static 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 | |
| 2918 | static 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 | |
| 2928 | static 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 | |
| 2940 | static 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 | |
| 2960 | static 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 | |
| 2989 | static 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 | |
| 3000 | static 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 | |
| 3021 | static 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 | |
| 3033 | static 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 | |
| 3047 | static 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 | |
| 3062 | static 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 | |
| 3068 | static 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 | |
| 3077 | static 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 | |
| 3086 | static 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 | |
| 3094 | static 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 | |
| 3106 | static 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 | |
| 3113 | static 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 | |
| 3121 | static 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 | |
| 3134 | static 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 | |
| 3147 | static 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 | |
| 3155 | static 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 | |
| 3168 | static 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 | |
| 3179 | INLINE 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 | |
| 3188 | INLINE 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 | |
| 3197 | INLINE 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 | |
| 3210 | INLINE 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 | |
| 3219 | static 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 | |
| 3255 | static 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 | |
| 3284 | static 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 | |
| 3318 | static 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 | |
| 3326 | static 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 | |
| 3334 | static 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 | |
| 3343 | static 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 | |
| 3351 | static 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 | |
| 3404 | static 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 | |
| 3419 | static 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 | |
| 3483 | ATTR_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 | |
| 3513 | static 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 | |
| 3520 | static 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 | |
| 3528 | static 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 | |
| 3541 | static 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 | |
| 3548 | static 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 | |
| 3556 | static 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 | |
| 3569 | static 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 | |
| 3644 | static 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 | |
| 3679 | static 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 | } |