branches/alto2/src/emu/cpu/alto2/a2disp.c
| r26391 | r26392 | |
| 272 | 272 | void alto2_cpu_device::unload_word() |
| 273 | 273 | { |
| 274 | 274 | int x = m_unload_word; |
| 275 | | int y = ((m_dsp.hlc - m_dsp.vblank) & ~(1024|1)) | HLC1024; |
| 275 | int y = ((m_dsp.hlc - m_dsp.vblank) & ~02001) ^ HLC1024; |
| 276 | |
| 277 | if (y < 0 || y >= ALTO2_DISPLAY_HEIGHT || x >= ALTO2_DISPLAY_VISIBLE_WORDS) |
| 278 | { |
| 279 | m_unload_time = -1; |
| 280 | return; |
| 281 | } |
| 276 | 282 | UINT16* scanline = m_dsp.raw_bitmap + y * ALTO2_DISPLAY_SCANLINE_WORDS; |
| 277 | | |
| 278 | 283 | UINT32 word = m_dsp.inverse; |
| 279 | 284 | UINT8 a38 = m_disp_a38[m_dsp.fifo_rd * 16 + m_dsp.fifo_wr]; |
| 280 | | if (FIFO_MBEMPTY(a38)) { |
| 285 | if (FIFO_MBEMPTY(a38)) |
| 286 | { |
| 281 | 287 | LOG((LOG_DISPL,1, " DSP FIFO underrun y:%d x:%d\n", y, x)); |
| 282 | | } else { |
| 288 | } |
| 289 | else |
| 290 | { |
| 283 | 291 | word ^= m_dsp.fifo[m_dsp.fifo_rd]; |
| 284 | 292 | m_dsp.fifo_rd = (m_dsp.fifo_rd + 1) % ALTO2_DISPLAY_FIFO; |
| 285 | 293 | LOG((LOG_DISPL,3, " DSP pull %04x from FIFO[%02o] y:%d x:%d\n", |
| 286 | | word, (m_dsp.fifo_rd - 1) & (ALTO2_DISPLAY_FIFO - 1), y, x)); |
| 294 | word, (m_dsp.fifo_rd - 1) & (ALTO2_DISPLAY_FIFO - 1), y, x)); |
| 287 | 295 | } |
| 288 | 296 | |
| 289 | | if (y >= 0 && y < ALTO2_DISPLAY_HEIGHT && x < ALTO2_DISPLAY_VISIBLE_WORDS) { |
| 290 | | if (m_dsp.halfclock) { |
| 291 | | UINT16 word1 = double_bits[word / 256]; |
| 292 | | UINT16 word2 = double_bits[word % 256]; |
| 297 | if (m_dsp.halfclock) |
| 298 | { |
| 299 | UINT16 word1 = double_bits[word / 256]; |
| 300 | UINT16 word2 = double_bits[word % 256]; |
| 301 | /* mixing with the cursor */ |
| 302 | if (x == m_dsp.curword + 0) |
| 303 | word1 ^= m_dsp.curdata >> 16; |
| 304 | if (x == m_dsp.curword + 1) |
| 305 | word1 ^= m_dsp.curdata & 0177777; |
| 306 | if (word1 != scanline[x]) |
| 307 | { |
| 308 | scanline[x] = word1; |
| 309 | update_bitmap_word(16 * x, y, word1); |
| 310 | } |
| 311 | x++; |
| 312 | if (x < ALTO2_DISPLAY_VISIBLE_WORDS) |
| 313 | { |
| 293 | 314 | /* mixing with the cursor */ |
| 294 | 315 | if (x == m_dsp.curword + 0) |
| 295 | | word1 ^= m_dsp.curdata >> 16; |
| 316 | word2 ^= m_dsp.curdata >> 16; |
| 296 | 317 | if (x == m_dsp.curword + 1) |
| 297 | | word1 ^= m_dsp.curdata & 0177777; |
| 298 | | if (word1 != scanline[x]) { |
| 299 | | scanline[x] = word1; |
| 300 | | update_bitmap_word(16 * x, y, word1); |
| 318 | word2 ^= m_dsp.curdata & 0177777; |
| 319 | if (word2 != scanline[x]) |
| 320 | { |
| 321 | scanline[x] = word2; |
| 322 | update_bitmap_word(16 * x, y, word2); |
| 301 | 323 | } |
| 302 | 324 | x++; |
| 303 | | if (x < ALTO2_DISPLAY_VISIBLE_WORDS) { |
| 304 | | /* mixing with the cursor */ |
| 305 | | if (x == m_dsp.curword + 0) |
| 306 | | word2 ^= m_dsp.curdata >> 16; |
| 307 | | if (x == m_dsp.curword + 1) |
| 308 | | word2 ^= m_dsp.curdata & 0177777; |
| 309 | | if (word2 != scanline[x]) { |
| 310 | | scanline[x] = word2; |
| 311 | | update_bitmap_word(16 * x, y, word2); |
| 312 | | } |
| 313 | | x++; |
| 314 | | } |
| 315 | | } else { |
| 316 | | /* mixing with the cursor */ |
| 317 | | if (x == m_dsp.curword + 0) |
| 318 | | word ^= m_dsp.curdata >> 16; |
| 319 | | if (x == m_dsp.curword + 1) |
| 320 | | word ^= m_dsp.curdata & 0177777; |
| 321 | | if (word != scanline[x]) { |
| 322 | | scanline[x] = word; |
| 323 | | update_bitmap_word(16 * x, y, word); |
| 324 | | } |
| 325 | | x++; |
| 326 | 325 | } |
| 326 | m_unload_time += ALTO2_DISPLAY_BITTIME(32); |
| 327 | 327 | } |
| 328 | | if (x < ALTO2_DISPLAY_VISIBLE_WORDS) { |
| 329 | | m_unload_time += ALTO2_DISPLAY_BITTIME(m_dsp.halfclock ? 32 : 16); |
| 328 | else |
| 329 | { |
| 330 | /* mixing with the cursor */ |
| 331 | if (x == m_dsp.curword + 0) |
| 332 | word ^= m_dsp.curdata >> 16; |
| 333 | if (x == m_dsp.curword + 1) |
| 334 | word ^= m_dsp.curdata & 0177777; |
| 335 | if (word != scanline[x]) |
| 336 | { |
| 337 | scanline[x] = word; |
| 338 | update_bitmap_word(16 * x, y, word); |
| 339 | } |
| 340 | x++; |
| 341 | m_unload_time += ALTO2_DISPLAY_BITTIME(16); |
| 342 | } |
| 343 | if (x < ALTO2_DISPLAY_VISIBLE_WORDS) |
| 330 | 344 | m_unload_word = x; |
| 331 | | } else { |
| 345 | else |
| 332 | 346 | m_unload_time = -1; |
| 333 | | } |
| 334 | 347 | } |
| 335 | 348 | |
| 336 | 349 | |
| r26391 | r26392 | |
| 345 | 358 | void alto2_cpu_device::display_state_machine() |
| 346 | 359 | { |
| 347 | 360 | LOG((LOG_DISPL,5,"DSP%03o:", m_dsp.state)); |
| 348 | | if (020 == m_dsp.state) { |
| 361 | if (020 == m_dsp.state) |
| 362 | { |
| 349 | 363 | LOG((LOG_DISPL,2," HLC=%d", m_dsp.hlc)); |
| 350 | 364 | } |
| 351 | 365 | |
| 352 | 366 | UINT8 a63 = m_disp_a63[m_dsp.state]; |
| 353 | | if (A63_HLCGATE(a63)) { |
| 354 | | // reset or count horizontal line counters |
| 367 | if (A63_HLCGATE(a63)) |
| 368 | { |
| 369 | // count horizontal line counters and wrap |
| 355 | 370 | m_dsp.hlc += 1; |
| 356 | 371 | if (m_dsp.hlc == ALTO2_DISPLAY_HLC_END + 1) |
| 357 | 372 | m_dsp.hlc = ALTO2_DISPLAY_HLC_START; |
| 358 | | /* start the refresh task _twice_ on each scanline */ |
| 373 | // wake up the memory refresh task _twice_ on each scanline |
| 359 | 374 | m_task_wakeup |= 1 << task_mrt; |
| 360 | | if (m_ewfct) { |
| 361 | | /* The Ether task wants a wakeup, too */ |
| 362 | | m_task_wakeup |= 1 << task_ether; |
| 363 | | } |
| 364 | 375 | } |
| 365 | 376 | // PROM a66 is disabled, if any of HLC256 or HLC512 are high |
| 366 | 377 | UINT8 a66 = (HLC256 || HLC512) ? 017 : m_disp_a66[m_dsp.hlc & 0377]; |
| r26391 | r26392 | |
| 368 | 379 | // next address from PROM a63, use A4 from HLC1 |
| 369 | 380 | UINT8 next = ((HLC1 ^ 1) << 4) | A63_NEXT(a63); |
| 370 | 381 | |
| 371 | | if (A66_VBLANK(a66)) { |
| 372 | | /* VBLANK: remember hlc */ |
| 382 | if (A66_VBLANK(a66)) |
| 383 | { |
| 384 | // Rising edge of VBLANK: remember HLC[1-10] where the VBLANK starts |
| 373 | 385 | m_dsp.vblank = m_dsp.hlc & ~02000; |
| 374 | 386 | |
| 375 | 387 | LOG((LOG_DISPL,1, " VBLANK")); |
| 376 | 388 | |
| 377 | 389 | // VSYNC is always within VBLANK, thus we handle it only here |
| 378 | | if (A66_VSYNC(a66)) { |
| 379 | | if (!A66_VSYNC(m_dsp.a66)) { |
| 390 | if (A66_VSYNC(a66)) |
| 391 | { |
| 392 | if (!A66_VSYNC(m_dsp.a66)) |
| 393 | { |
| 380 | 394 | LOG((LOG_DISPL,1, " VSYNC↗ (wake DVT)")); |
| 381 | 395 | /* |
| 382 | | * The display vertical task DVT is awakened once per field, |
| 396 | * The display vertical task DVT is woken once per field |
| 383 | 397 | * at the beginning of vertical retrace. |
| 384 | 398 | */ |
| 385 | 399 | m_task_wakeup |= 1 << task_dvt; |
| 386 | | // TODO: upade odd or even field of the internal bitmap |
| 387 | | } else { |
| 400 | // TODO: upade odd or even field of the internal bitmap now? |
| 401 | } |
| 402 | else |
| 403 | { |
| 388 | 404 | LOG((LOG_DISPL,1, " VSYNC")); |
| 389 | 405 | } |
| 390 | 406 | } |
| 391 | | } else { |
| 392 | | if (A66_VBLANK(m_dsp.a66)) { |
| 407 | } |
| 408 | else |
| 409 | { |
| 410 | // Falling edge of VBLANK? |
| 411 | if (A66_VBLANK(m_dsp.a66)) |
| 412 | { |
| 393 | 413 | /* |
| 394 | 414 | * VBLANKPULSE: |
| 395 | | * The display horizontal task DHT is awakened once at the |
| 415 | * The display horizontal task DHT is woken once at the |
| 396 | 416 | * beginning of each field, and thereafter whenever the |
| 397 | 417 | * display word task blocks. |
| 418 | * |
| 398 | 419 | * The DHT can block itself, in which case neither it nor |
| 399 | | * the word task can be awakened until the start of the |
| 420 | * the word task can be woken until the start of the |
| 400 | 421 | * next field. |
| 401 | 422 | */ |
| 402 | 423 | LOG((LOG_DISPL,1, " VBLANKPULSE (wake DHT)")); |
| r26391 | r26392 | |
| 409 | 430 | */ |
| 410 | 431 | m_dsp.curt_blocks = false; |
| 411 | 432 | } |
| 412 | | if (!A63_HBLANK(a63) && A63_HBLANK(m_dsp.a63)) { |
| 413 | | // falling edge of a63 HBLANK starts unloading of FIFO words |
| 433 | if (!A63_HBLANK(a63) && A63_HBLANK(m_dsp.a63)) |
| 434 | { |
| 435 | // Falling edge of a63 HBLANK starts unloading of FIFO words |
| 414 | 436 | LOG((LOG_DISPL,1, " HBLANK↘ UNLOAD")); |
| 415 | 437 | m_unload_time = ALTO2_DISPLAY_BITTIME(m_dsp.halfclock ? 32 : 16); |
| 416 | 438 | m_unload_word = 0; |
| 417 | | #if DEBUG_DISPLAY_TIMING |
| 418 | | printf("@%lld: first unload_word @%lldns hlc:+%d (id:%d)\n", |
| 419 | | ntime(), ntime() + DISPLAY_BITTIME(m_dsp.halfclock ? 32 : 16), |
| 420 | | m_dsp.hlc - DISPLAY_HLC_START, m_dsp.unload_id); |
| 421 | | #endif |
| 422 | 439 | } |
| 423 | 440 | } |
| 424 | 441 | |
| r26391 | r26392 | |
| 429 | 446 | * are generated. |
| 430 | 447 | */ |
| 431 | 448 | UINT8 a38 = m_disp_a38[m_dsp.fifo_rd * 16 + m_dsp.fifo_wr]; |
| 432 | | if (!m_dsp.dwt_blocks && !m_dsp.dht_blocks && !FIFO_STOPWAKE(a38)) { |
| 449 | if (!m_dsp.dwt_blocks && !m_dsp.dht_blocks && !FIFO_STOPWAKE(a38)) |
| 450 | { |
| 433 | 451 | m_task_wakeup |= 1 << task_dwt; |
| 434 | 452 | LOG((LOG_DISPL,1, " (wake DWT)")); |
| 435 | 453 | } |
| 436 | 454 | |
| 437 | | // Stop waking the display word task at SCANEND time |
| 438 | | if (A63_SCANEND(a63)) { |
| 455 | // Stop waking up the DWT when SCANEND is active |
| 456 | if (A63_SCANEND(a63)) |
| 457 | { |
| 458 | m_task_wakeup &= ~(1 << task_dwt); |
| 439 | 459 | LOG((LOG_DISPL,1, " SCANEND")); |
| 440 | | m_task_wakeup &= ~(1 << task_dwt); |
| 441 | 460 | } |
| 442 | 461 | |
| 443 | 462 | LOG((LOG_DISPL,1, "%s", A63_HBLANK(a63) ? " HBLANK": "")); |
| 444 | 463 | |
| 445 | | if (A63_HSYNC(a63)) { |
| 446 | | if (!A63_HSYNC(m_dsp.a63)) { |
| 464 | if (A63_HSYNC(a63)) |
| 465 | { |
| 466 | // Active HSYNC |
| 467 | if (!A63_HSYNC(m_dsp.a63)) |
| 468 | { |
| 469 | // Rising edge of HSYNC => CLRBUF |
| 447 | 470 | LOG((LOG_DISPL,1, " HSYNC↗ (CLRBUF)")); |
| 448 | 471 | /* |
| 449 | 472 | * The hardware sets the buffer empty and clears the DWT block |
| r26391 | r26392 | |
| 456 | 479 | // now take the new values from the last SETMODE← |
| 457 | 480 | m_dsp.inverse = GET_SETMODE_INVERSE(m_dsp.setmode) ? 0xffff : 0x0000; |
| 458 | 481 | m_dsp.halfclock = GET_SETMODE_SPEEDY(m_dsp.setmode); |
| 459 | | // stop the CPU from calling unload_word() |
| 482 | // stop the CPU execution loop from calling unload_word() |
| 460 | 483 | m_unload_time = -1; |
| 461 | | } else { |
| 484 | } |
| 485 | else |
| 486 | { |
| 462 | 487 | LOG((LOG_DISPL,1, " HSYNC")); |
| 463 | 488 | } |
| 464 | 489 | } |
| 465 | | // FIXME: jiggly cursor issue; try to wake up CURT at the end of HSYNC |
| 466 | | if (A63_HSYNC(m_dsp.a63) && !A63_HSYNC(a63)) { |
| 490 | else |
| 491 | // Falling edge of HSYNC? |
| 492 | if (A63_HSYNC(m_dsp.a63)) |
| 493 | { |
| 467 | 494 | /* |
| 468 | 495 | * CLRBUF' also resets the 2nd cursor task block flip flop, |
| 469 | 496 | * which is built from two NAND gates a30c and a30d (74H00). |
| r26391 | r26392 | |
| 471 | 498 | * decodes this as WAKECURT signal. |
| 472 | 499 | */ |
| 473 | 500 | m_dsp.curt_wakeup = true; |
| 501 | if (!m_dsp.curt_blocks) |
| 502 | m_task_wakeup |= 1 << task_curt; |
| 474 | 503 | } |
| 475 | 504 | |
| 476 | | |
| 477 | 505 | LOG((LOG_DISPL,1, " NEXT:%03o\n", next)); |
| 478 | 506 | |
| 479 | | if (!m_dsp.curt_blocks && m_dsp.curt_wakeup) |
| 480 | | m_task_wakeup |= 1 << task_curt; |
| 481 | | |
| 482 | 507 | m_dsp.a63 = a63; |
| 483 | 508 | m_dsp.a66 = a66; |
| 484 | 509 | m_dsp.state = next; |
| r26391 | r26392 | |
| 849 | 874 | int dx = 6 * x; |
| 850 | 875 | if (dx >= ALTO2_DISPLAY_WIDTH) |
| 851 | 876 | return; |
| 852 | | for (int dy = 0; dy < 10; dy++) { |
| 877 | for (int dy = 0; dy < 10; dy++) |
| 878 | { |
| 853 | 879 | UINT8* pix = m_dsp.scanline[ALTO2_DISPLAY_HEIGHT + 1 + dy] + dx; |
| 854 | 880 | UINT8 bits = ~pf->bits[dy]; |
| 855 | 881 | pix[0] = (bits >> 7) & 1; |