@@ -54,6 +54,39 @@ static inline uint32_t lcd_rgb888out(uint32_t rgb888) {
54
54
return lcd_argb8888out (UINT32_C (0xFF000000 ) | (rgb888 & 0xF8FCF8 ));
55
55
}
56
56
57
+ static inline void lcd_intrpt_check (void ) {
58
+ intrpt_set (INT_LCD , lcd .ris & lcd .imsc );
59
+ }
60
+
61
+ static inline void lcd_crsr_update (void ) {
62
+ if (lcd .compare != LCD_FRONT_PORCH ) {
63
+ return ;
64
+ }
65
+ lcd_crsr_state_t * crsrRegs = & lcd .crsrRegs [lcd .crsrConfig >> 1 & 1 ];
66
+ uint32_t crsrSize = ((lcd .crsrConfig & 1 ) + 1 ) * 32 ;
67
+ uint32_t crsrClipX = crsrRegs -> crsrClip & 0xFF ;
68
+ uint32_t crsrClipY = crsrRegs -> crsrClip >> 8 ;
69
+ uint32_t crsrRow = crsrRegs -> crsrXY >> 16 ;
70
+ uint32_t crsrRowUnclipped = crsrRow - crsrClipY ;
71
+ /* This value is treated as a signed 12-bit value for the cursor interrupt check */
72
+ crsrRowUnclipped = (int32_t )(crsrRowUnclipped << 20 ) >> 20 ;
73
+ uint32_t crsrRowOffset = lcd .curRow - crsrRowUnclipped ;
74
+ if (likely ((int32_t )crsrRowOffset >= (int32_t )crsrSize )) {
75
+ if (!likely (lcd .crsrIntrptd )) {
76
+ lcd .crsrIntrptd = true;
77
+ lcd .ris |= 1 << 0 ;
78
+ lcd_intrpt_check ();
79
+ }
80
+ lcd .curCrsrWidth = 0 ;
81
+ } else if (!unlikely (lcd .crsrControl ) || likely (lcd .curRow < crsrRow ) || crsrClipX >= crsrSize ) {
82
+ lcd .curCrsrWidth = 0 ;
83
+ } else {
84
+ lcd .curCrsrOffset = ((crsrRegs -> crsrImage * crsrSize + crsrRowOffset ) * crsrSize + crsrClipX ) & 0xFFF ;
85
+ lcd .curCrsrCol = crsrRegs -> crsrXY & 0xFFFF ;
86
+ lcd .curCrsrWidth = crsrSize - crsrClipX ;
87
+ }
88
+ }
89
+
57
90
void emu_set_lcd_callback (bool (* callback )(void * ), void * data ) {
58
91
lcd .gui_callback = callback ;
59
92
lcd .gui_callback_data = data ;
@@ -187,15 +220,22 @@ static uint32_t lcd_process_pixel(uint32_t ticks, uint16_t bgr565) {
187
220
}
188
221
panel_hsync ();
189
222
panel_clock_porch (lcd .HSW + lcd .HBP );
223
+ lcd_crsr_update ();
190
224
}
191
225
192
226
if (unlikely (sched_active (SCHED_PANEL ))) {
193
227
panel_scan_until (sched_ticks_remaining_relative (SCHED_PANEL , SCHED_LCD_DMA , ticks ));
194
228
}
195
- assert (lcd .curCol < lcd .PPL );
229
+ assert (lcd .curCol < lcd .CPL );
230
+ uint32_t crsrColOffset = lcd .curCol - lcd .curCrsrCol ;
231
+ if (unlikely (crsrColOffset < lcd .curCrsrWidth )) {
232
+ uint32_t crsrOffset = lcd .curCrsrOffset + crsrColOffset ;
233
+ uint8_t crsrPixel = lcd .crsrImageBytes [crsrOffset >> 2 ] >> ((~crsrOffset & 3 ) * 2 ) & 3 ;
234
+ bgr565 = (crsrPixel & 2 ? bgr565 : 0 ) ^ lcd .crsrPalette [crsrPixel ];
235
+ }
196
236
panel .clock_pixel (bgr565 );
197
237
198
- if (unlikely (++ lcd .curCol >= lcd .PPL )) {
238
+ if (unlikely (++ lcd .curCol >= lcd .CPL )) {
199
239
panel_clock_porch (lcd .HFP );
200
240
lcd .curCol = 0 ;
201
241
lcd .curRow ++ ;
@@ -301,6 +341,7 @@ static void lcd_event(enum sched_item_id id) {
301
341
enum lcd_comp compare = lcd .control >> 12 & 3 ;
302
342
switch (lcd .compare ) {
303
343
case LCD_FRONT_PORCH :
344
+ lcd .ris |= !lcd .crsrIntrptd << 0 ;
304
345
if (lcd .VFP ) {
305
346
if (compare == LCD_FRONT_PORCH ) {
306
347
lcd .ris |= 1 << 3 ;
@@ -348,6 +389,8 @@ static void lcd_event(enum sched_item_id id) {
348
389
duration = ((lcd .VSW - 1 ) * (lcd .HSW + lcd .HBP + lcd .CPL + lcd .HFP ) +
349
390
lcd .HSW ) * lcd .PCD + 1 ;
350
391
lcd .prefill = true;
392
+ lcd .crsrIntrptd = false;
393
+ lcd .crsrRegs [1 ] = lcd .crsrRegs [0 ];
351
394
if (lcd .useDma ) {
352
395
lcd .pos = 0 ;
353
396
lcd .curRow = lcd .curCol = 0 ;
@@ -385,7 +428,7 @@ static void lcd_event(enum sched_item_id id) {
385
428
lcd .compare = LCD_FRONT_PORCH ;
386
429
break ;
387
430
}
388
- intrpt_set ( INT_LCD , lcd . ris & lcd . imsc );
431
+ lcd_intrpt_check ( );
389
432
sched_repeat (id , duration );
390
433
}
391
434
@@ -418,6 +461,7 @@ static void lcd_init_events(void) {
418
461
419
462
void lcd_reset (void ) {
420
463
memset (& lcd , 0 , offsetof(lcd_state_t , useDma ));
464
+ lcd .crsrPalette [3 ] = 0xFFFF ;
421
465
lcd_update ();
422
466
lcd_init_events ();
423
467
gui_console_printf ("[CEmu] LCD reset.\n" );
@@ -432,9 +476,9 @@ static uint8_t lcd_read(const uint16_t pio, bool peek) {
432
476
if (index < 0x014 && index >= 0x010 ) { return read8 (lcd .upbase , bit_offset ); }
433
477
if (index < 0x018 && index >= 0x014 ) { return read8 (lcd .lpbase , bit_offset ); }
434
478
if (index < 0x01C && index >= 0x018 ) { return read8 (lcd .control , bit_offset ); }
435
- if (index < 0x020 && index >= 0x01C ) { return read8 ( lcd .imsc , bit_offset ) ; }
436
- if (index < 0x024 && index >= 0x020 ) { return read8 ( lcd .ris , bit_offset ) ; }
437
- if (index < 0x028 && index >= 0x024 ) { return read8 ( lcd .imsc & lcd .ris , bit_offset ) ; }
479
+ if (index == 0x01C ) { return lcd .imsc & ~ 1 ; }
480
+ if (index == 0x020 ) { return lcd .ris & ~ 1 ; }
481
+ if (index == 0x024 ) { return lcd .imsc & lcd .ris & ~ 1 ; }
438
482
if (index < 0x030 && index >= 0x02C ) {
439
483
if (!peek ) {
440
484
sched_process_pending_dma (0 );
@@ -453,15 +497,15 @@ static uint8_t lcd_read(const uint16_t pio, bool peek) {
453
497
if (!peek ) {
454
498
cpu .cycles -- ;
455
499
}
456
- if (index == 0xC00 ) { return read8 ( lcd .crsrControl , bit_offset ); }
457
- if (index == 0xC04 ) { return read8 ( lcd .crsrConfig , bit_offset ) ; }
500
+ if (index == 0xC00 ) { return lcd .crsrControl | ( lcd . crsrRegs [ 0 ]. crsrImage << 4 ); }
501
+ if (index == 0xC04 ) { return lcd .crsrConfig ; }
458
502
if (index < 0xC0C && index >= 0xC08 ) { return read8 (lcd .crsrPalette0 , bit_offset ); }
459
503
if (index < 0xC10 && index >= 0xC0C ) { return read8 (lcd .crsrPalette1 , bit_offset ); }
460
- if (index < 0xC14 && index >= 0xC10 ) { return read8 (lcd .crsrXY , bit_offset ); }
461
- if (index < 0xC16 && index >= 0xC14 ) { return read8 (lcd .crsrClip , bit_offset ); }
462
- if (index == 0xC20 ) { return read8 ( lcd .crsrImsc , bit_offset ) ; }
463
- if (index == 0xC28 ) { return read8 ( lcd .crsrRis , bit_offset ) ; }
464
- if (index == 0xC2C ) { return read8 ( lcd .crsrRis & lcd .crsrImsc , bit_offset ) ; }
504
+ if (index < 0xC14 && index >= 0xC10 ) { return read8 (lcd .crsrRegs [ 0 ]. crsrXY , bit_offset ); }
505
+ if (index < 0xC16 && index >= 0xC14 ) { return read8 (lcd .crsrRegs [ 0 ]. crsrClip , bit_offset ); }
506
+ if (index == 0xC20 ) { return lcd .imsc & 1 ; }
507
+ if (index == 0xC28 ) { return lcd .ris & 1 ; }
508
+ if (index == 0xC2C ) { return lcd .ris & lcd .imsc & 1 ; }
465
509
} else if (index >= 0xFE0 ) {
466
510
static const uint8_t id [1 ][8 ] = {
467
511
{ 0x11 , 0x11 , 0x14 , 0x00 , 0x0D , 0xF0 , 0x05 , 0xB1 }
@@ -620,12 +664,16 @@ static void lcd_write(const uint16_t pio, const uint8_t value, bool poke) {
620
664
}
621
665
}
622
666
} else if (index == 0x01C ) {
623
- write8 (lcd .imsc , bit_offset , value );
624
- lcd .imsc &= 0x1E ;
625
- intrpt_set (INT_LCD , lcd .ris & lcd .imsc );
667
+ if (likely (bit_offset == 0 )) {
668
+ lcd .imsc &= ~0x1E ;
669
+ lcd .imsc |= value & 0x1E ;
670
+ lcd_intrpt_check ();
671
+ }
626
672
} else if (index == 0x028 ) {
627
- lcd .ris &= ~(value << bit_offset );
628
- intrpt_set (INT_LCD , lcd .ris & lcd .imsc );
673
+ if (likely (bit_offset == 0 )) {
674
+ lcd .ris &= ~(value & 0x1E );
675
+ lcd_intrpt_check ();
676
+ }
629
677
}
630
678
lcd_update ();
631
679
} else if (index < 0x400 ) {
@@ -643,40 +691,58 @@ static void lcd_write(const uint16_t pio, const uint8_t value, bool poke) {
643
691
}
644
692
} else if (index < 0xC00 ) {
645
693
if (index >= 0x800 ) {
694
+ if (!poke && unlikely (lcd .crsrControl )) {
695
+ sched_process_pending_dma (0 );
696
+ }
646
697
lcd .crsrImageBytes [pio - 0x800 ] = value ;
647
698
}
648
699
} else if (index < 0xE00 ) {
649
- if (index == 0xC00 ) {
650
- write8 (lcd .crsrControl , bit_offset , value );
651
- }
652
- if (index == 0xC04 ) {
653
- write8 (lcd .crsrConfig , bit_offset , value );
654
- lcd .crsrConfig &= 0xF ;
655
- }
656
- if (index == 0xC08 ) {
657
- write8 (lcd .crsrPalette0 , bit_offset , value );
658
- }
659
- if (index == 0xC0C ) {
660
- write8 (lcd .crsrPalette1 , bit_offset , value );
661
- }
662
- if (index == 0xC10 ) {
663
- write8 (lcd .crsrXY , bit_offset , value );
664
- lcd .crsrXY &= (0xFFF | (0xFFF << 16 ));
665
- }
666
- if (index == 0xC14 ) {
667
- write8 (lcd .crsrClip , bit_offset , value );
668
- lcd .crsrClip &= (0x3F | (0x3F << 8 ));
669
- }
670
- if (index == 0xC20 ) {
671
- write8 (lcd .crsrImsc , bit_offset , value );
672
- lcd .crsrImsc &= 0xF ;
673
- }
674
- if (index == 0xC24 ) {
675
- lcd .crsrRis &= ~(value << bit_offset );
676
- lcd .crsrRis &= 0xF ;
677
- }
678
700
if (!poke ) {
679
701
lcd_write_crsr_delay ();
702
+ if (index < 0xC18 ) {
703
+ sched_process_pending_dma (0 );
704
+ }
705
+ }
706
+ if (index == 0xC00 ) {
707
+ if (likely (bit_offset == 0 )) {
708
+ lcd .crsrControl = value & 1 ;
709
+ lcd .crsrRegs [0 ].crsrImage = value >> 4 & 3 ;
710
+ lcd_crsr_update ();
711
+ }
712
+ } else if (index == 0xC04 ) {
713
+ if (likely (bit_offset == 0 )) {
714
+ lcd .crsrConfig = value & 3 ;
715
+ lcd_crsr_update ();
716
+ }
717
+ } else if (index == 0xC08 ) {
718
+ if (likely (bit_offset < 24 )) {
719
+ write8 (lcd .crsrPalette0 , bit_offset , value );
720
+ lcd .crsrPalette [0 ] = c888 (lcd .crsrPalette0 );
721
+ }
722
+ } else if (index == 0xC0C ) {
723
+ if (likely (bit_offset < 24 )) {
724
+ write8 (lcd .crsrPalette1 , bit_offset , value );
725
+ lcd .crsrPalette [1 ] = c888 (lcd .crsrPalette1 );
726
+ }
727
+ } else if (index == 0xC10 ) {
728
+ write8 (lcd .crsrRegs [0 ].crsrXY , bit_offset , value );
729
+ lcd .crsrRegs [0 ].crsrXY &= (0xFFF | (0xFFF << 16 ));
730
+ lcd_crsr_update ();
731
+ } else if (index == 0xC14 ) {
732
+ write8 (lcd .crsrRegs [0 ].crsrClip , bit_offset , value );
733
+ lcd .crsrRegs [0 ].crsrClip &= (0x3F | (0x3F << 8 ));
734
+ lcd_crsr_update ();
735
+ } else if (index == 0xC20 ) {
736
+ if (likely (bit_offset == 0 )) {
737
+ lcd .imsc &= ~1 ;
738
+ lcd .imsc |= value & 1 ;
739
+ lcd_intrpt_check ();
740
+ }
741
+ } else if (index == 0xC24 ) {
742
+ if (likely (bit_offset == 0 )) {
743
+ lcd .ris &= ~(value & 1 );
744
+ lcd_intrpt_check ();
745
+ }
680
746
}
681
747
}
682
748
}
0 commit comments