trunk/src/emu/video/i8275x.c
| r0 | r20180 | |
| 1 | /********************************************************************** |
| 2 | |
| 3 | Intel 8275 Programmable CRT Controller emulation |
| 4 | |
| 5 | Copyright MESS Team. |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | |
| 8 | **********************************************************************/ |
| 9 | |
| 10 | /* |
| 11 | |
| 12 | TODO: |
| 13 | |
| 14 | - double spaced rows |
| 15 | |
| 16 | */ |
| 17 | |
| 18 | #include "i8275x.h" |
| 19 | |
| 20 | |
| 21 | |
| 22 | //************************************************************************** |
| 23 | // MACROS / CONSTANTS |
| 24 | //************************************************************************** |
| 25 | |
| 26 | const int DMA_BURST_SPACING[] = { 0, 7, 15, 23, 31, 39, 47, 55 }; |
| 27 | |
| 28 | #define DOUBLE_SPACED_ROWS \ |
| 29 | BIT(m_param[REG_SCN1], 7) |
| 30 | |
| 31 | #define CHARACTERS_PER_ROW \ |
| 32 | ((m_param[REG_SCN1] & 0x7f) + 1) |
| 33 | |
| 34 | #define VRTC_ROW_COUNT \ |
| 35 | ((m_param[REG_SCN2] >> 5) + 1) |
| 36 | |
| 37 | #define CHARACTER_ROWS_PER_FRAME \ |
| 38 | ((m_param[REG_SCN2] & 0x3f) + 1) |
| 39 | |
| 40 | #define UNDERLINE \ |
| 41 | (m_param[REG_SCN3] >> 4) |
| 42 | |
| 43 | #define SCANLINES_PER_ROW \ |
| 44 | ((m_param[REG_SCN3] & 0x0f) + 1) |
| 45 | |
| 46 | #define OFFSET_LINE_COUNTER \ |
| 47 | BIT(m_param[REG_SCN4], 7) |
| 48 | |
| 49 | #define VISIBLE_FIELD_ATTRIBUTE \ |
| 50 | BIT(m_param[REG_SCN4], 6) |
| 51 | |
| 52 | #define CURSOR_FORMAT \ |
| 53 | ((m_param[REG_SCN4] >> 4) & 0x03) |
| 54 | |
| 55 | #define HRTC_COUNT \ |
| 56 | (((m_param[REG_SCN4] & 0x0f) + 1) * 2) |
| 57 | |
| 58 | #define DMA_BURST_COUNT \ |
| 59 | (1 << (m_param[REG_DMA] & 0x03)) |
| 60 | |
| 61 | #define DMA_BURST_SPACE \ |
| 62 | DMA_BURST_SPACING[(m_param[REG_DMA] >> 2) & 0x07] |
| 63 | |
| 64 | |
| 65 | |
| 66 | //************************************************************************** |
| 67 | // somethign |
| 68 | //************************************************************************** |
| 69 | |
| 70 | // device type definition |
| 71 | const device_type I8275x = &device_creator<i8275x_device>; |
| 72 | |
| 73 | |
| 74 | //************************************************************************** |
| 75 | // LIVE DEVICE |
| 76 | //************************************************************************** |
| 77 | |
| 78 | //------------------------------------------------- |
| 79 | // i8275x_device - constructor |
| 80 | //------------------------------------------------- |
| 81 | |
| 82 | i8275x_device::i8275x_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 83 | : device_t(mconfig, I8275x, "I8275", tag, owner, clock), |
| 84 | m_status(0), |
| 85 | m_param_idx(0), |
| 86 | m_param_end(0), |
| 87 | m_buffer_idx(0), |
| 88 | m_fifo_next(false), |
| 89 | m_buffer_dma(0), |
| 90 | m_lpen(0), |
| 91 | m_hlgt(0), |
| 92 | m_vsp(0), |
| 93 | m_gpa(0), |
| 94 | m_rvv(0), |
| 95 | m_lten(0), |
| 96 | m_scanline(0), |
| 97 | m_du(false), |
| 98 | m_cursor_blink(0), |
| 99 | m_char_blink(0) |
| 100 | { |
| 101 | } |
| 102 | |
| 103 | |
| 104 | //------------------------------------------------- |
| 105 | // device_config_complete - perform any |
| 106 | // operations now that the configuration is |
| 107 | // complete |
| 108 | //------------------------------------------------- |
| 109 | |
| 110 | void i8275x_device::device_config_complete() |
| 111 | { |
| 112 | // inherit a copy of the static data |
| 113 | const i8275_interface *intf = reinterpret_cast<const i8275_interface *>(static_config()); |
| 114 | if (intf != NULL) |
| 115 | *static_cast<i8275_interface *>(this) = *intf; |
| 116 | |
| 117 | // or initialize to defaults if none provided |
| 118 | else |
| 119 | { |
| 120 | memset(&m_out_drq_cb, 0, sizeof(m_out_drq_cb)); |
| 121 | memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb)); |
| 122 | memset(&m_out_hrtc_cb, 0, sizeof(m_out_hrtc_cb)); |
| 123 | memset(&m_out_vrtc_cb, 0, sizeof(m_out_vrtc_cb)); |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | |
| 128 | //------------------------------------------------- |
| 129 | // device_start - device-specific startup |
| 130 | //------------------------------------------------- |
| 131 | |
| 132 | void i8275x_device::device_start() |
| 133 | { |
| 134 | // get the screen device |
| 135 | m_screen = machine().device<screen_device>(m_screen_tag); |
| 136 | assert(m_screen != NULL); |
| 137 | m_screen->register_screen_bitmap(m_bitmap); |
| 138 | |
| 139 | // resolve callbacks |
| 140 | m_out_drq_func.resolve(m_out_drq_cb, *this); |
| 141 | m_out_irq_func.resolve(m_out_irq_cb, *this); |
| 142 | m_out_hrtc_func.resolve(m_out_hrtc_cb, *this); |
| 143 | m_out_vrtc_func.resolve(m_out_vrtc_cb, *this); |
| 144 | |
| 145 | // allocate timers |
| 146 | m_hrtc_on_timer = timer_alloc(TIMER_HRTC_ON); |
| 147 | m_drq_on_timer = timer_alloc(TIMER_DRQ_ON); |
| 148 | m_drq_off_timer = timer_alloc(TIMER_DRQ_OFF); |
| 149 | m_scanline_timer = timer_alloc(TIMER_SCANLINE); |
| 150 | |
| 151 | // state saving |
| 152 | save_item(NAME(m_status)); |
| 153 | save_item(NAME(m_param)); |
| 154 | save_item(NAME(m_param_idx)); |
| 155 | save_item(NAME(m_param_end)); |
| 156 | save_item(NAME(m_buffer[0])); |
| 157 | save_item(NAME(m_buffer[1])); |
| 158 | save_item(NAME(m_buffer_idx)); |
| 159 | save_item(NAME(m_fifo_idx)); |
| 160 | save_item(NAME(m_fifo_next)); |
| 161 | save_item(NAME(m_buffer_dma)); |
| 162 | save_item(NAME(m_lpen)); |
| 163 | } |
| 164 | |
| 165 | |
| 166 | //------------------------------------------------- |
| 167 | // device_reset - device-specific reset |
| 168 | //------------------------------------------------- |
| 169 | |
| 170 | void i8275x_device::device_reset() |
| 171 | { |
| 172 | m_status &= ~ST_IE; |
| 173 | |
| 174 | m_out_irq_func(CLEAR_LINE); |
| 175 | } |
| 176 | |
| 177 | |
| 178 | //------------------------------------------------- |
| 179 | // device_timer - handle timer events |
| 180 | //------------------------------------------------- |
| 181 | |
| 182 | void i8275x_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 183 | { |
| 184 | int y = m_screen->vpos(); |
| 185 | int x = m_screen->hpos(); |
| 186 | int rc = m_scanline / SCANLINES_PER_ROW; |
| 187 | int lc = m_scanline % SCANLINES_PER_ROW; |
| 188 | |
| 189 | switch (id) |
| 190 | { |
| 191 | case TIMER_HRTC_ON: |
| 192 | //logerror("I8275 '%s' y %u x %u HRTC 1\n", tag(), y, x); |
| 193 | m_out_hrtc_func(1); |
| 194 | break; |
| 195 | |
| 196 | case TIMER_DRQ_ON: |
| 197 | logerror("I8275 '%s' y %u x %u DRQ 1\n", tag(), y, x); |
| 198 | m_out_drq_func(1); |
| 199 | m_drq_off_timer->adjust(clocks_to_attotime(DMA_BURST_COUNT)); |
| 200 | break; |
| 201 | |
| 202 | case TIMER_DRQ_OFF: |
| 203 | if (m_buffer_idx == 0) |
| 204 | { |
| 205 | m_status |= ST_DU; |
| 206 | m_du = true; |
| 207 | logerror("I8275 '%s' y %u x %u DRQ 0\n", tag(), y, x); |
| 208 | m_out_drq_func(0); |
| 209 | } |
| 210 | else if (m_buffer_idx == CHARACTERS_PER_ROW) |
| 211 | { |
| 212 | logerror("I8275 '%s' y %u x %u DRQ 0\n", tag(), y, x); |
| 213 | m_out_drq_func(0); |
| 214 | } |
| 215 | else if (DMA_BURST_SPACE > 0) |
| 216 | { |
| 217 | logerror("I8275 '%s' y %u x %u DRQ 0\n", tag(), y, x); |
| 218 | m_out_drq_func(0); |
| 219 | m_drq_on_timer->adjust(clocks_to_attotime(DMA_BURST_SPACE)); |
| 220 | } |
| 221 | break; |
| 222 | |
| 223 | case TIMER_SCANLINE: |
| 224 | if (!(m_status & ST_VE)) break; |
| 225 | |
| 226 | //logerror("I8275 '%s' y %u x %u HRTC 0\n", tag(), y, x); |
| 227 | m_out_hrtc_func(0); |
| 228 | |
| 229 | if (m_scanline == 0) |
| 230 | { |
| 231 | //logerror("I8275 '%s' y %u x %u VRTC 0\n", tag(), y, x); |
| 232 | m_out_vrtc_func(0); |
| 233 | } |
| 234 | else if (m_scanline == m_irq_scanline) |
| 235 | { |
| 236 | if (m_status & ST_IE) |
| 237 | { |
| 238 | //logerror("I8275 '%s' y %u x %u IRQ 1\n", tag(), y, x); |
| 239 | m_status |= ST_IR; |
| 240 | m_out_irq_func(ASSERT_LINE); |
| 241 | } |
| 242 | } |
| 243 | else if (m_scanline == m_vrtc_scanline) |
| 244 | { |
| 245 | //logerror("I8275 '%s' y %u x %u VRTC 1\n", tag(), y, x); |
| 246 | m_out_vrtc_func(1); |
| 247 | |
| 248 | // reset field attributes |
| 249 | m_hlgt = 0; |
| 250 | m_vsp = 0; |
| 251 | m_gpa = 0; |
| 252 | m_rvv = 0, |
| 253 | m_lten = 0; |
| 254 | |
| 255 | m_du = false; |
| 256 | |
| 257 | m_cursor_blink++; |
| 258 | m_cursor_blink &= 0x1f; |
| 259 | |
| 260 | m_char_blink++; |
| 261 | m_char_blink &= 0x3f; |
| 262 | } |
| 263 | |
| 264 | if (lc == 0) |
| 265 | { |
| 266 | // swap line buffers |
| 267 | m_buffer_dma = !m_buffer_dma; |
| 268 | m_buffer_idx = 0; |
| 269 | m_fifo_idx = 0; |
| 270 | |
| 271 | if (!m_du && ((m_scanline < m_vrtc_scanline - SCANLINES_PER_ROW) || (m_scanline == m_vrtc_drq_scanline))) |
| 272 | { |
| 273 | // start DMA burst |
| 274 | m_drq_on_timer->adjust(clocks_to_attotime(DMA_BURST_SPACE)); |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | if (m_scanline < m_vrtc_scanline) |
| 279 | { |
| 280 | for (int sx = 0; sx < CHARACTERS_PER_ROW; sx++) |
| 281 | { |
| 282 | int m_lineattr = 0; |
| 283 | int lten = 0; |
| 284 | int vsp = 0; |
| 285 | |
| 286 | UINT8 data = m_buffer[!m_buffer_dma][sx]; |
| 287 | |
| 288 | if (data & 0x80) |
| 289 | { |
| 290 | if ((data & 0xc0) == 0x80) |
| 291 | { |
| 292 | // field attribute code |
| 293 | m_hlgt = (data & FAC_H) ? 1 : 0; |
| 294 | m_vsp = (data & FAC_B) ? 1 : 0; |
| 295 | m_gpa = (data & FAC_GG) >> 2; |
| 296 | m_rvv = (data & FAC_R) ? 1 : 0; |
| 297 | m_lten = (data & FAC_U) ? 1 : 0; |
| 298 | |
| 299 | if (!VISIBLE_FIELD_ATTRIBUTE) |
| 300 | { |
| 301 | int fifo_idx = 0; |
| 302 | |
| 303 | data = m_fifo[!m_buffer_dma][fifo_idx]; |
| 304 | |
| 305 | fifo_idx++; |
| 306 | fifo_idx &= 0xf; |
| 307 | } |
| 308 | else |
| 309 | { |
| 310 | vsp = 1; |
| 311 | } |
| 312 | } |
| 313 | else |
| 314 | { |
| 315 | // character attribute code |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | if (!vsp && m_vsp) |
| 320 | { |
| 321 | vsp = (m_char_blink < 32) ? 1 : 0; |
| 322 | } |
| 323 | |
| 324 | if ((rc == m_param[REG_CUR_ROW]) && (sx == m_param[REG_CUR_COL])) |
| 325 | { |
| 326 | int vis = 1; |
| 327 | |
| 328 | if (!(CURSOR_FORMAT & 0x02)) |
| 329 | { |
| 330 | vis = (m_cursor_blink < 16) ? 1 : 0; |
| 331 | } |
| 332 | |
| 333 | if (CURSOR_FORMAT & 0x01) |
| 334 | { |
| 335 | lten = (lc == UNDERLINE) ? vis : 0; |
| 336 | } |
| 337 | else |
| 338 | { |
| 339 | lten = vis; |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | if (OFFSET_LINE_COUNTER) |
| 344 | { |
| 345 | lc = (lc - 1) & 0x0f; |
| 346 | } |
| 347 | |
| 348 | m_display_pixels_func(this, m_bitmap, |
| 349 | sx * m_hpixels_per_column, // x position on screen of starting point |
| 350 | m_scanline, // y position on screen |
| 351 | lc, // current line of char |
| 352 | (data & 0x7f), // char code to be displayed |
| 353 | m_lineattr, // line attribute code |
| 354 | lten | m_lten, // light enable signal |
| 355 | m_rvv, // reverse video signal |
| 356 | vsp, // video suppression |
| 357 | m_gpa, // general purpose attribute code |
| 358 | m_hlgt // highlight |
| 359 | ); |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | m_scanline++; |
| 364 | m_scanline %= ((CHARACTER_ROWS_PER_FRAME + VRTC_ROW_COUNT) * SCANLINES_PER_ROW); |
| 365 | break; |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | |
| 370 | //------------------------------------------------- |
| 371 | // read - |
| 372 | //------------------------------------------------- |
| 373 | |
| 374 | READ8_MEMBER( i8275x_device::read ) |
| 375 | { |
| 376 | UINT8 data = 0; |
| 377 | |
| 378 | if (offset & 0x01) |
| 379 | { |
| 380 | data = m_status; |
| 381 | |
| 382 | if (m_status & ST_IR) |
| 383 | { |
| 384 | //logerror("I8275 '%s' IRQ 0\n", tag()); |
| 385 | m_out_irq_func(CLEAR_LINE); |
| 386 | } |
| 387 | |
| 388 | m_status &= ~(ST_IR | ST_LP | ST_IC | ST_DU | ST_FO); |
| 389 | } |
| 390 | else |
| 391 | { |
| 392 | data = m_param[m_param_idx]; |
| 393 | m_param_idx++; |
| 394 | |
| 395 | if (m_param_idx > m_param_end) |
| 396 | { |
| 397 | m_status |= ST_IC; |
| 398 | } |
| 399 | } |
| 400 | |
| 401 | return data; |
| 402 | } |
| 403 | |
| 404 | |
| 405 | //------------------------------------------------- |
| 406 | // write - |
| 407 | //------------------------------------------------- |
| 408 | |
| 409 | WRITE8_MEMBER( i8275x_device::write ) |
| 410 | { |
| 411 | if (offset & 0x01) |
| 412 | { |
| 413 | logerror("I8275 '%s' Command %02x\n", tag(), data); |
| 414 | |
| 415 | switch (data >> 5) |
| 416 | { |
| 417 | case CMD_RESET: |
| 418 | logerror("I8275 '%s' Reset\n", tag()); |
| 419 | |
| 420 | m_status &= ~ST_IE; |
| 421 | logerror("I8275 '%s' IRQ 0\n", tag()); |
| 422 | m_out_irq_func(CLEAR_LINE); |
| 423 | |
| 424 | m_param_idx = REG_SCN1; |
| 425 | m_param_end = REG_SCN4; |
| 426 | break; |
| 427 | |
| 428 | case CMD_START_DISPLAY: |
| 429 | { |
| 430 | m_param[REG_DMA] = data; |
| 431 | logerror("I8275 '%s' Start Display %u %u\n", tag(), DMA_BURST_COUNT, DMA_BURST_SPACE); |
| 432 | m_status |= (ST_IE | ST_VE); |
| 433 | } |
| 434 | break; |
| 435 | |
| 436 | case CMD_STOP_DISPLAY: |
| 437 | logerror("I8275 '%s' Stop Display\n", tag()); |
| 438 | m_status &= ~ST_VE; |
| 439 | break; |
| 440 | |
| 441 | case CMD_READ_LIGHT_PEN: |
| 442 | logerror("I8275 '%s' Read Light Pen\n", tag()); |
| 443 | m_param_idx = REG_LPEN_COL; |
| 444 | m_param_end = REG_LPEN_ROW; |
| 445 | break; |
| 446 | |
| 447 | case CMD_LOAD_CURSOR: |
| 448 | logerror("I8275 '%s' Load Cursor\n", tag()); |
| 449 | m_param_idx = REG_CUR_COL; |
| 450 | m_param_end = REG_CUR_ROW; |
| 451 | break; |
| 452 | |
| 453 | case CMD_ENABLE_INTERRUPT: |
| 454 | logerror("I8275 '%s' Enable Interrupt\n", tag()); |
| 455 | m_status |= ST_IE; |
| 456 | break; |
| 457 | |
| 458 | case CMD_DISABLE_INTERRUPT: |
| 459 | logerror("I8275 '%s' Disable Interrupt\n", tag()); |
| 460 | m_status &= ~ST_IE; |
| 461 | break; |
| 462 | |
| 463 | case CMD_PRESET_COUNTERS: |
| 464 | logerror("I8275 '%s' Preset Counters\n", tag()); |
| 465 | m_scanline = 0; |
| 466 | break; |
| 467 | } |
| 468 | } |
| 469 | else |
| 470 | { |
| 471 | logerror("I8275 '%s' Parameter %02x\n", tag(), data); |
| 472 | |
| 473 | m_param[m_param_idx] = data; |
| 474 | |
| 475 | if (m_param_idx == REG_SCN4) |
| 476 | { |
| 477 | recompute_parameters(); |
| 478 | } |
| 479 | |
| 480 | m_param_idx++; |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | |
| 485 | //------------------------------------------------- |
| 486 | // dack_w - |
| 487 | //------------------------------------------------- |
| 488 | |
| 489 | WRITE8_MEMBER( i8275x_device::dack_w ) |
| 490 | { |
| 491 | logerror("DACK write %02x %u\n", data, m_buffer_idx); |
| 492 | |
| 493 | if (m_fifo_next) |
| 494 | { |
| 495 | if (m_fifo_idx == 16) |
| 496 | { |
| 497 | m_fifo_idx = 0; |
| 498 | m_status |= ST_FO; |
| 499 | } |
| 500 | |
| 501 | m_fifo[m_buffer_dma][m_fifo_idx++] = data; |
| 502 | |
| 503 | m_fifo_next = false; |
| 504 | } |
| 505 | else |
| 506 | { |
| 507 | m_buffer[m_buffer_dma][m_buffer_idx++] = data; |
| 508 | |
| 509 | if (!VISIBLE_FIELD_ATTRIBUTE && ((data & 0xc0) == 0x80)) |
| 510 | { |
| 511 | m_fifo_next = true; |
| 512 | } |
| 513 | |
| 514 | if (m_buffer_idx == CHARACTERS_PER_ROW) |
| 515 | { |
| 516 | m_drq_off_timer->adjust(attotime::zero); |
| 517 | } |
| 518 | } |
| 519 | } |
| 520 | |
| 521 | |
| 522 | //------------------------------------------------- |
| 523 | // lpen_w - |
| 524 | //------------------------------------------------- |
| 525 | |
| 526 | WRITE_LINE_MEMBER( i8275x_device::lpen_w ) |
| 527 | { |
| 528 | if (!m_lpen && state) |
| 529 | { |
| 530 | m_param[REG_LPEN_COL] = m_screen->hpos() / m_hpixels_per_column; |
| 531 | m_param[REG_LPEN_ROW] = m_screen->vpos() / SCANLINES_PER_ROW; |
| 532 | |
| 533 | m_status |= ST_LP; |
| 534 | } |
| 535 | |
| 536 | m_lpen = state; |
| 537 | } |
| 538 | |
| 539 | |
| 540 | //------------------------------------------------- |
| 541 | // screen_update - |
| 542 | //------------------------------------------------- |
| 543 | |
| 544 | UINT32 i8275x_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) |
| 545 | { |
| 546 | if (!(m_status & ST_VE)) |
| 547 | { |
| 548 | m_bitmap.fill(RGB_BLACK); |
| 549 | } |
| 550 | |
| 551 | copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); |
| 552 | |
| 553 | return 0; |
| 554 | } |
| 555 | |
| 556 | |
| 557 | //------------------------------------------------- |
| 558 | // recompute_parameters - |
| 559 | //------------------------------------------------- |
| 560 | |
| 561 | void i8275x_device::recompute_parameters() |
| 562 | { |
| 563 | int y = m_screen->vpos(); |
| 564 | |
| 565 | int horiz_pix_total = (CHARACTERS_PER_ROW + HRTC_COUNT) * m_hpixels_per_column; |
| 566 | int vert_pix_total = (CHARACTER_ROWS_PER_FRAME + VRTC_ROW_COUNT) * SCANLINES_PER_ROW; |
| 567 | attoseconds_t refresh = m_screen->frame_period().attoseconds; |
| 568 | int max_visible_x = (CHARACTERS_PER_ROW * m_hpixels_per_column) - 1; |
| 569 | int max_visible_y = (CHARACTER_ROWS_PER_FRAME * SCANLINES_PER_ROW) - 1; |
| 570 | |
| 571 | logerror("width %u height %u max_x %u max_y %u refresh %f\n", horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, 1 / ATTOSECONDS_TO_DOUBLE(refresh)); |
| 572 | |
| 573 | rectangle visarea; |
| 574 | visarea.set(0, max_visible_x, 0, max_visible_y); |
| 575 | m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh); |
| 576 | |
| 577 | int hrtc_on_pos = CHARACTERS_PER_ROW * m_hpixels_per_column; |
| 578 | m_hrtc_on_timer->adjust(m_screen->time_until_pos(y, hrtc_on_pos), 0, m_screen->scan_period()); |
| 579 | |
| 580 | m_irq_scanline = (CHARACTER_ROWS_PER_FRAME - 1) * SCANLINES_PER_ROW; |
| 581 | m_vrtc_scanline = CHARACTER_ROWS_PER_FRAME * SCANLINES_PER_ROW; |
| 582 | m_vrtc_drq_scanline = vert_pix_total - SCANLINES_PER_ROW; |
| 583 | |
| 584 | m_scanline_timer->adjust(m_screen->time_until_pos(0, 0), 0, m_screen->scan_period()); |
| 585 | } |
trunk/src/emu/video/i8275x.h
| r0 | r20180 | |
| 1 | /********************************************************************** |
| 2 | |
| 3 | Intel 8275 Programmable CRT Controller emulation |
| 4 | |
| 5 | Copyright MESS Team. |
| 6 | Visit http://mamedev.org for licensing and usage restrictions. |
| 7 | |
| 8 | ********************************************************************** |
| 9 | _____ _____ |
| 10 | LC3 1 |* \_/ | 40 Vcc |
| 11 | LC2 2 | | 39 LA0 |
| 12 | LC1 3 | | 38 LA1 |
| 13 | LC0 4 | | 37 LTEN |
| 14 | DRQ 5 | | 36 RVV |
| 15 | _DACK 6 | | 35 VSP |
| 16 | HRTC 7 | | 34 GPA1 |
| 17 | VRTC 8 | | 33 GPA0 |
| 18 | _RD 9 | | 32 HLGT |
| 19 | _WR 10 | 8275 | 31 IRQ |
| 20 | LPEN 11 | | 30 CCLK |
| 21 | DB0 12 | | 29 CC6 |
| 22 | DB1 13 | | 28 CC5 |
| 23 | DB2 14 | | 27 CC4 |
| 24 | DB3 15 | | 26 CC3 |
| 25 | DB4 16 | | 25 CC2 |
| 26 | DB5 17 | | 24 CC1 |
| 27 | DB6 18 | | 23 CC0 |
| 28 | DB7 19 | | 22 _CS |
| 29 | GND 20 |_____________| 21 A0 |
| 30 | |
| 31 | **********************************************************************/ |
| 32 | |
| 33 | #pragma once |
| 34 | |
| 35 | #ifndef __I8275x__ |
| 36 | #define __I8275x__ |
| 37 | |
| 38 | #include "emu.h" |
| 39 | |
| 40 | |
| 41 | |
| 42 | //************************************************************************** |
| 43 | // INTERFACE CONFIGURATION MACROS |
| 44 | //************************************************************************** |
| 45 | |
| 46 | #define MCFG_I8275_ADD(_tag, _clock, _config) \ |
| 47 | MCFG_DEVICE_ADD(_tag, I8275x, _clock) \ |
| 48 | MCFG_DEVICE_CONFIG(_config) |
| 49 | |
| 50 | |
| 51 | #define I8275_INTERFACE(name) \ |
| 52 | const i8275_interface (name) = |
| 53 | |
| 54 | |
| 55 | |
| 56 | //************************************************************************** |
| 57 | // TYPE DEFINITIONS |
| 58 | //************************************************************************** |
| 59 | |
| 60 | class i8275x_device; |
| 61 | |
| 62 | |
| 63 | // ======================> i8275_display_pixels_func |
| 64 | |
| 65 | typedef void (*i8275_display_pixels_func)(i8275x_device *device, bitmap_rgb32 &bitmap, int x, int y, UINT8 linecount, UINT8 charcode, UINT8 lineattr, UINT8 lten, UINT8 rvv, UINT8 vsp, UINT8 gpa, UINT8 hlgt); |
| 66 | #define I8275_DISPLAY_PIXELS(name) void name(i8275x_device *device, bitmap_rgb32 &bitmap, int x, int y, UINT8 linecount, UINT8 charcode, UINT8 lineattr, UINT8 lten, UINT8 rvv, UINT8 vsp, UINT8 gpa, UINT8 hlgt) |
| 67 | |
| 68 | |
| 69 | // ======================> i8275_interface |
| 70 | |
| 71 | struct i8275_interface |
| 72 | { |
| 73 | const char *m_screen_tag; |
| 74 | int m_hpixels_per_column; |
| 75 | int m_dummy; |
| 76 | |
| 77 | devcb_write_line m_out_drq_cb; |
| 78 | devcb_write_line m_out_irq_cb; |
| 79 | |
| 80 | devcb_write_line m_out_hrtc_cb; |
| 81 | devcb_write_line m_out_vrtc_cb; |
| 82 | |
| 83 | i8275_display_pixels_func m_display_pixels_func; |
| 84 | }; |
| 85 | |
| 86 | |
| 87 | |
| 88 | // ======================> i8275x_device |
| 89 | |
| 90 | class i8275x_device : public device_t, |
| 91 | public i8275_interface |
| 92 | { |
| 93 | public: |
| 94 | // construction/destruction |
| 95 | i8275x_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 96 | |
| 97 | DECLARE_READ8_MEMBER( read ); |
| 98 | DECLARE_WRITE8_MEMBER( write ); |
| 99 | |
| 100 | DECLARE_WRITE8_MEMBER( dack_w ); |
| 101 | |
| 102 | DECLARE_WRITE_LINE_MEMBER( lpen_w ); |
| 103 | |
| 104 | UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); |
| 105 | |
| 106 | protected: |
| 107 | // device-level overrides |
| 108 | virtual void device_config_complete(); |
| 109 | virtual void device_start(); |
| 110 | virtual void device_reset(); |
| 111 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); |
| 112 | |
| 113 | void recompute_parameters(); |
| 114 | |
| 115 | enum |
| 116 | { |
| 117 | TIMER_HRTC_ON, |
| 118 | TIMER_DRQ_ON, |
| 119 | TIMER_DRQ_OFF, |
| 120 | TIMER_SCANLINE |
| 121 | }; |
| 122 | |
| 123 | enum |
| 124 | { |
| 125 | ST_IE = 0x40, |
| 126 | ST_IR = 0x20, |
| 127 | ST_LP = 0x10, |
| 128 | ST_IC = 0x08, |
| 129 | ST_VE = 0x04, |
| 130 | ST_DU = 0x02, |
| 131 | ST_FO = 0x01 |
| 132 | }; |
| 133 | |
| 134 | enum |
| 135 | { |
| 136 | CMD_RESET = 0, |
| 137 | CMD_START_DISPLAY, |
| 138 | CMD_STOP_DISPLAY, |
| 139 | CMD_READ_LIGHT_PEN, |
| 140 | CMD_LOAD_CURSOR, |
| 141 | CMD_ENABLE_INTERRUPT, |
| 142 | CMD_DISABLE_INTERRUPT, |
| 143 | CMD_PRESET_COUNTERS |
| 144 | }; |
| 145 | |
| 146 | enum |
| 147 | { |
| 148 | REG_SCN1 = 0, |
| 149 | REG_SCN2, |
| 150 | REG_SCN3, |
| 151 | REG_SCN4, |
| 152 | REG_CUR_COL, |
| 153 | REG_CUR_ROW, |
| 154 | REG_LPEN_COL, |
| 155 | REG_LPEN_ROW, |
| 156 | REG_DMA |
| 157 | }; |
| 158 | |
| 159 | enum |
| 160 | { |
| 161 | CA_H = 0x01, |
| 162 | CA_B = 0x02, |
| 163 | CA_CCCC = 0x3c |
| 164 | }; |
| 165 | |
| 166 | enum |
| 167 | { |
| 168 | FAC_H = 0x01, |
| 169 | FAC_B = 0x02, |
| 170 | FAC_GG = 0x0c, |
| 171 | FAC_R = 0x10, |
| 172 | FAC_U = 0x20 |
| 173 | }; |
| 174 | |
| 175 | devcb_resolved_write_line m_out_drq_func; |
| 176 | devcb_resolved_write_line m_out_irq_func; |
| 177 | devcb_resolved_write_line m_out_hrtc_func; |
| 178 | devcb_resolved_write_line m_out_vrtc_func; |
| 179 | |
| 180 | screen_device *m_screen; |
| 181 | bitmap_rgb32 m_bitmap; |
| 182 | |
| 183 | UINT8 m_status; |
| 184 | UINT8 m_param[REG_DMA + 1]; |
| 185 | int m_param_idx; |
| 186 | int m_param_end; |
| 187 | |
| 188 | UINT8 m_buffer[2][80]; |
| 189 | UINT8 m_fifo[2][16]; |
| 190 | int m_buffer_idx; |
| 191 | int m_fifo_idx; |
| 192 | bool m_fifo_next; |
| 193 | int m_buffer_dma; |
| 194 | |
| 195 | int m_lpen; |
| 196 | |
| 197 | int m_hlgt; |
| 198 | int m_vsp; |
| 199 | int m_gpa; |
| 200 | int m_rvv; |
| 201 | int m_lten; |
| 202 | |
| 203 | int m_scanline; |
| 204 | int m_irq_scanline; |
| 205 | int m_vrtc_scanline; |
| 206 | int m_vrtc_drq_scanline; |
| 207 | bool m_du; |
| 208 | |
| 209 | int m_cursor_blink; |
| 210 | int m_char_blink; |
| 211 | |
| 212 | // timers |
| 213 | emu_timer *m_hrtc_on_timer; |
| 214 | emu_timer *m_drq_on_timer; |
| 215 | emu_timer *m_drq_off_timer; |
| 216 | emu_timer *m_scanline_timer; |
| 217 | }; |
| 218 | |
| 219 | |
| 220 | // device type definition |
| 221 | extern const device_type I8275x; |
| 222 | |
| 223 | |
| 224 | |
| 225 | #endif |