@@ -54,6 +54,39 @@ static inline uint32_t lcd_rgb888out(uint32_t rgb888) {
5454 return lcd_argb8888out (UINT32_C (0xFF000000 ) | (rgb888 & 0xF8FCF8 ));
5555}
5656
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+
5790void emu_set_lcd_callback (bool (* callback )(void * ), void * data ) {
5891 lcd .gui_callback = callback ;
5992 lcd .gui_callback_data = data ;
@@ -187,15 +220,22 @@ static uint32_t lcd_process_pixel(uint32_t ticks, uint16_t bgr565) {
187220 }
188221 panel_hsync ();
189222 panel_clock_porch (lcd .HSW + lcd .HBP );
223+ lcd_crsr_update ();
190224 }
191225
192226 if (unlikely (sched_active (SCHED_PANEL ))) {
193227 panel_scan_until (sched_ticks_remaining_relative (SCHED_PANEL , SCHED_LCD_DMA , ticks ));
194228 }
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+ }
196236 panel .clock_pixel (bgr565 );
197237
198- if (unlikely (++ lcd .curCol >= lcd .PPL )) {
238+ if (unlikely (++ lcd .curCol >= lcd .CPL )) {
199239 panel_clock_porch (lcd .HFP );
200240 lcd .curCol = 0 ;
201241 lcd .curRow ++ ;
@@ -301,6 +341,7 @@ static void lcd_event(enum sched_item_id id) {
301341 enum lcd_comp compare = lcd .control >> 12 & 3 ;
302342 switch (lcd .compare ) {
303343 case LCD_FRONT_PORCH :
344+ lcd .ris |= !lcd .crsrIntrptd << 0 ;
304345 if (lcd .VFP ) {
305346 if (compare == LCD_FRONT_PORCH ) {
306347 lcd .ris |= 1 << 3 ;
@@ -348,6 +389,8 @@ static void lcd_event(enum sched_item_id id) {
348389 duration = ((lcd .VSW - 1 ) * (lcd .HSW + lcd .HBP + lcd .CPL + lcd .HFP ) +
349390 lcd .HSW ) * lcd .PCD + 1 ;
350391 lcd .prefill = true;
392+ lcd .crsrIntrptd = false;
393+ lcd .crsrRegs [1 ] = lcd .crsrRegs [0 ];
351394 if (lcd .useDma ) {
352395 lcd .pos = 0 ;
353396 lcd .curRow = lcd .curCol = 0 ;
@@ -385,7 +428,7 @@ static void lcd_event(enum sched_item_id id) {
385428 lcd .compare = LCD_FRONT_PORCH ;
386429 break ;
387430 }
388- intrpt_set ( INT_LCD , lcd . ris & lcd . imsc );
431+ lcd_intrpt_check ( );
389432 sched_repeat (id , duration );
390433}
391434
@@ -418,6 +461,7 @@ static void lcd_init_events(void) {
418461
419462void lcd_reset (void ) {
420463 memset (& lcd , 0 , offsetof(lcd_state_t , useDma ));
464+ lcd .crsrPalette [3 ] = 0xFFFF ;
421465 lcd_update ();
422466 lcd_init_events ();
423467 gui_console_printf ("[CEmu] LCD reset.\n" );
@@ -432,9 +476,9 @@ static uint8_t lcd_read(const uint16_t pio, bool peek) {
432476 if (index < 0x014 && index >= 0x010 ) { return read8 (lcd .upbase , bit_offset ); }
433477 if (index < 0x018 && index >= 0x014 ) { return read8 (lcd .lpbase , bit_offset ); }
434478 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 ; }
438482 if (index < 0x030 && index >= 0x02C ) {
439483 if (!peek ) {
440484 sched_process_pending_dma (0 );
@@ -453,15 +497,15 @@ static uint8_t lcd_read(const uint16_t pio, bool peek) {
453497 if (!peek ) {
454498 cpu .cycles -- ;
455499 }
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 ; }
458502 if (index < 0xC0C && index >= 0xC08 ) { return read8 (lcd .crsrPalette0 , bit_offset ); }
459503 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 ; }
465509 } else if (index >= 0xFE0 ) {
466510 static const uint8_t id [1 ][8 ] = {
467511 { 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) {
620664 }
621665 }
622666 } 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+ }
626672 } 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+ }
629677 }
630678 lcd_update ();
631679 } else if (index < 0x400 ) {
@@ -643,40 +691,58 @@ static void lcd_write(const uint16_t pio, const uint8_t value, bool poke) {
643691 }
644692 } else if (index < 0xC00 ) {
645693 if (index >= 0x800 ) {
694+ if (!poke && unlikely (lcd .crsrControl )) {
695+ sched_process_pending_dma (0 );
696+ }
646697 lcd .crsrImageBytes [pio - 0x800 ] = value ;
647698 }
648699 } 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- }
678700 if (!poke ) {
679701 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+ }
680746 }
681747 }
682748}
0 commit comments