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; |