Previous 15994 Revisions Next

r1127 Tuesday 16th October, 2007 at 19:45:44 UTC by Wilbert Pol
[GAMEBOY] Some more small timing fixes
[src/mess/video]gb.c

src/mess/video/gb.c
r1126r1127
8383   int   previous_line;      /* Previous line we've drawn in */
8484   int   start_x;         /* Pixel to start drawing from (inclusive) */
8585   int   end_x;            /* Pixel to end drawing (exclusive) */
86   int lcd_int_state;      /* Keep track of LCD_INT state */
8786   int mode;            /* Keep track of internal STAT mode */
87   int lcd_irq_line;
88   int line_irq;
8889   int mode_irq;
90   int delayed_line_irq;
8991   struct layer_struct   layer[2];
9092   mame_timer   *lcd_timer;
91   mame_timer   *vblank_delay_timer;
9293} gb_lcd;
9394
9495void (*update_scanline)(void);
9596
9697/* Prototypes */
9798static TIMER_CALLBACK(gb_lcd_timer_proc);
98static TIMER_CALLBACK(gb_vblank_delay_proc);
9999static void gb_lcd_switch_on( void );
100static void gb_lcd_int_check( void );
101100
102101static unsigned char palette[] =
103102{
r1126r1127
10521051
10531052   gb_lcd.lcd_timer = mame_timer_alloc( gb_lcd_timer_proc );
10541053   mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(456,0), 0, time_never );
1055
1056   gb_lcd.vblank_delay_timer = mame_timer_alloc( gb_vblank_delay_proc );
1057   mame_timer_adjust( gb_lcd.vblank_delay_timer, time_never, 0, time_never );
10581054}
10591055
10601056void sgb_video_init( void ) {
r1126r1127
11421138   }
11431139}
11441140
1145static TIMER_CALLBACK(gb_vblank_delay_proc)
1146{
1147   /* Trigger VBlank interrupt */
1148   cpunum_set_input_line(0, VBL_INT, HOLD_LINE);
1149}
1150
1151/* Check whether an LCD_INT interrupt should be triggered */
1152static void gb_lcd_int_check( void ) {
1153   int   lcd_int_state = gb_lcd.mode_irq;
1154
1155   /* Check if LY==LYC should trigger an interrupt */
1156   if ( LCDSTAT & 0x40 && LCDSTAT & 0x04 ) {
1157      lcd_int_state = 1;
1158   }
1159
1160   if ( gb_lcd.lcd_int_state == 0 && lcd_int_state == 1 ) {
1161      cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1162   }
1163
1164   gb_lcd.lcd_int_state = lcd_int_state;
1165}
1166
1167static void gb_lcd_check_mode_irq( void ) {
1168   gb_lcd.mode_irq = 0;
1169
1170   /* Check if stat 0 should trigger an interrupt */
1171   if ( LCDSTAT & 0x08 && gb_lcd.mode == 0x00 ) {
1172      gb_lcd.mode_irq = 1;
1173   }
1174
1175   /* Check if stat 2 should trigger an interrupt */
1176   if ( LCDSTAT & 0x20 && gb_lcd.mode == 0x02 ) {
1177      gb_lcd.mode_irq = 1;
1178   }
1179
1180   /* Check if stat 1 should trigger an interrupt */
1181   if ( LCDSTAT & 0x10 && gb_lcd.mode == 0x01 ) {
1182      gb_lcd.mode_irq = 1;
1183   }
1184
1185   gb_lcd_int_check();
1186}
1187
11881141enum {
11891142   GB_LCD_STATE_LYXX_M3=1,
11901143   GB_LCD_STATE_LYXX_M0,
1144   GB_LCD_STATE_LYXX_M0_2,
11911145   GB_LCD_STATE_LYXX_M0_INC,
11921146   GB_LCD_STATE_LY00_M2,
11931147   GB_LCD_STATE_LYXX_M2,
11941148   GB_LCD_STATE_LY9X_M1,
11951149   GB_LCD_STATE_LY9X_M1_INC,
11961150   GB_LCD_STATE_LY00_M1,
1151   GB_LCD_STATE_LY00_M1_1,
11971152   GB_LCD_STATE_LY00_M1_2,
11981153   GB_LCD_STATE_LY00_M0
11991154};
r1126r1127
12151170         gb_lcd.mode = 0;
12161171         LCDSTAT &= 0xFC;
12171172         /* Generate lcd interrupt if requested */
1218         gb_lcd_check_mode_irq();
1173         if ( ( LCDSTAT & 0x08 ) && ! gb_lcd.line_irq && gb_lcd.delayed_line_irq ) {
1174            cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1175         }
12191176         /* Check for HBLANK DMA */
12201177         if( gbc_hdma_enabled )
12211178            gbc_hdma(0x10);
r1126r1127
12231180         break;
12241181      case GB_LCD_STATE_LYXX_M0_INC:   /* Increment LY, stay in M0 for 4 more cycles */
12251182         gb_increment_scanline();
1183         gb_lcd.delayed_line_irq = gb_lcd.line_irq;
1184         gb_lcd.line_irq = ( ( CMPLINE == CURLINE ) && ( LCDSTAT & 0x40 ) ) ? 1 : 0;
1185         if ( ! gb_lcd.delayed_line_irq && gb_lcd.line_irq ) {
1186            cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1187         }
12261188         /* Reset LY==LYC STAT bit */
12271189         LCDSTAT &= 0xFB;
12281190         /* Check if we're going into VBlank next */
r1126r1127
12321194            /* Internally switch to mode 2 */
12331195            gb_lcd.mode = 2;
12341196            /* Generate lcd interrupt if requested */
1235            gb_lcd_check_mode_irq();
1197            if ( ( ! gb_lcd.delayed_line_irq || ! ( LCDSTAT & 0x40 ) ) && ( LCDSTAT & 0x20 ) ) {
1198               cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1199            }
12361200            mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(4,0), GB_LCD_STATE_LYXX_M2, time_never );
12371201         }
12381202         break;
r1126r1127
12411205         gb_lcd.mode = 2;
12421206         LCDSTAT = ( LCDSTAT & 0xFC ) | 0x02;
12431207         /* Generate lcd interrupt if requested */
1244         gb_lcd_check_mode_irq();
1208         if ( LCDSTAT & 0x20 ) {
1209            cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1210         }
12451211         /* Mode 2 lasts approximately 80 clock cycles */
12461212         mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(80,0), GB_LCD_STATE_LYXX_M3, time_never );
12471213         break;
12481214      case GB_LCD_STATE_LYXX_M2:      /* Switch to mode 2 */
12491215         /* Update STAT register to the correct state */
12501216         LCDSTAT = (LCDSTAT & 0xFC) | 0x02;
1217         /* Generate lcd interrupt if requested */
1218         if ( gb_lcd.delayed_line_irq && gb_lcd.line_irq ) {
1219            cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1220         }
12511221         /* Check if LY==LYC STAT bit should be set */
12521222         if ( CURLINE == CMPLINE ) {
12531223            LCDSTAT |= 0x04;
1254            /* Generate lcd interrupt if requested */
1255            gb_lcd_int_check();
12561224         }
12571225         /* Mode 2 last for approximately 80 clock cycles */
12581226         mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(80,0), GB_LCD_STATE_LYXX_M3, time_never );
r1126r1127
12621230         /* Set Mode 3 lcdstate */
12631231         gb_lcd.mode = 3;
12641232         LCDSTAT = (LCDSTAT & 0xFC) | 0x03;
1265         gb_lcd_check_mode_irq();
12661233         /* Mode 3 lasts for approximately 172+#sprites*10 clock cycles */
12671234         mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(172 + 10 * gb_lcd.sprCount,0), GB_LCD_STATE_LYXX_M0, time_never );
12681235         gb_lcd.start_x = 0;
12691236         break;
12701237      case GB_LCD_STATE_LY9X_M1:      /* Switch to or stay in mode 1 */
12711238         if ( CURLINE == 144 ) {
1272            /* Trigger VBlank interrupt generation */
1273            mame_timer_adjust( gb_lcd.vblank_delay_timer, MAME_TIME_IN_CYCLES(1,0), 0, time_never );
1239            /* Trigger VBlank interrupt */
1240            cpunum_set_input_line( 0, VBL_INT, HOLD_LINE );
12741241            /* Set VBlank lcdstate */
12751242            gb_lcd.mode = 1;
12761243            LCDSTAT = (LCDSTAT & 0xFC) | 0x01;
12771244            /* Trigger LCD interrupt if requested */
1278            gb_lcd_check_mode_irq();
1245            if ( LCDSTAT & 0x10 ) {
1246               cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1247            }
12791248         }
12801249         /* Check if LY==LYC STAT bit should be set */
12811250         if ( CURLINE == CMPLINE ) {
12821251            LCDSTAT |= 0x04;
1283            /* Trigger LCD interrupt if requested */
1284            gb_lcd_int_check();
12851252         }
12861253         mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(452,0), GB_LCD_STATE_LY9X_M1_INC, time_never );
12871254         break;
12881255      case GB_LCD_STATE_LY9X_M1_INC:      /* Increment scanline counter */
12891256         gb_increment_scanline();
1257         gb_lcd.delayed_line_irq = gb_lcd.line_irq;
1258         gb_lcd.line_irq = ( ( CMPLINE == CURLINE ) && ( LCDSTAT & 0x40 ) ) ? 1 : 0;
1259         if ( ! gb_lcd.delayed_line_irq && gb_lcd.line_irq ) {
1260            cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1261         }
12901262         /* Reset LY==LYC STAT bit */
12911263         LCDSTAT &= 0xFB;
12921264         if ( gb_lcd.current_line == 153 ) {
r1126r1127
12971269         break;
12981270      case GB_LCD_STATE_LY00_M1:      /* we stay in VBlank but current line counter should already be incremented */
12991271         /* Check LY=LYC for line #153 */
1272         if ( gb_lcd.delayed_line_irq ) {
1273            if ( gb_lcd.line_irq ) {
1274               cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1275            }
1276         } else {
1277            gb_lcd.delayed_line_irq = gb_lcd.line_irq;
1278         }
13001279         if ( CURLINE == CMPLINE ) {
13011280            LCDSTAT |= 0x04;
1302            gb_lcd_int_check();
13031281         }
13041282         gb_increment_scanline();
1283         gb_lcd.line_irq = ( ( CMPLINE == CURLINE ) && ( LCDSTAT & 0x40 ) ) ? 1 : 0;
1284//         if ( ! gb_lcd.delayed_line_irq && gb_lcd.line_irq ) {
1285//            cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1286//         }
13051287         LCDSTAT &= 0xFB;
1306         /* This 8 cycle period still needs to be verified on hardware */
1307         mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(8,0), GB_LCD_STATE_LY00_M1_2, time_never );
1288         mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(4/*8*/,0), GB_LCD_STATE_LY00_M1_1, time_never );
13081289         break;
1290      case GB_LCD_STATE_LY00_M1_1:
1291         if ( ! gb_lcd.delayed_line_irq && gb_lcd.line_irq ) {
1292            cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1293         }
1294         mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(4,0), GB_LCD_STATE_LY00_M1_2, time_never );
1295         break;
13091296      case GB_LCD_STATE_LY00_M1_2:   /* Rest of line #0 during VBlank */
1297         if ( gb_lcd.delayed_line_irq && gb_lcd.line_irq ) {
1298            cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1299         }
13101300         if ( CURLINE == CMPLINE ) {
13111301            LCDSTAT |= 0x04;
1312            gb_lcd_int_check();
13131302         }
13141303         mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(444,0), GB_LCD_STATE_LY00_M0, time_never );
13151304         break;
r1126r1127
13171306         /* Set Mode 0 lcdstat */
13181307         gb_lcd.mode = 0;
13191308         LCDSTAT = ( LCDSTAT & 0xFC );
1320         gb_lcd_check_mode_irq();
13211309         mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(4,0), GB_LCD_STATE_LY00_M2, time_never );
13221310         break;
13231311      }
r1126r1127
13341322   gb_lcd.current_line = 0;
13351323   gb_lcd.previous_line = 153;
13361324   gb_lcd.window_lines_drawn = 0;
1337   gb_lcd.lcd_int_state = 0;
1338   gb_lcd.mode_irq = 0;
1325   gb_lcd.line_irq = 0;
1326   gb_lcd.delayed_line_irq = 0;
13391327   gb_lcd.mode = 0;
13401328   /* Check for LY=LYC coincidence */
13411329   if ( CURLINE == CMPLINE ) {
13421330      LCDSTAT |= 0x04;
13431331      /* Generate lcd interrupt if requested */
1344      gb_lcd_int_check();
1332      if ( LCDSTAT & 0x40 ) {
1333         cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1334      }
13451335   }
13461336   mame_timer_adjust( gb_lcd.lcd_timer, MAME_TIME_IN_CYCLES(80,0), GB_LCD_STATE_LYXX_M3, time_never );
13471337}
r1126r1127
14021392         interrupt to be triggered.
14031393       */
14041394      if ( LCDCONT & 0x80 ) {
1395         /* Are these triggers correct? */
14051396         if ( ( gb_lcd.mode != 2 ) || ( ! ( data & 0x40 ) && ! ( LCDSTAT & 0x40 ) ) ) {
14061397            cpunum_set_input_line(0, LCD_INT, HOLD_LINE);
14071398         }
1399         if ( ! ( LCDSTAT & 0x40 ) && ( data & 0x40 ) ) {
1400            if ( LCDSTAT & 0x04 ) {
1401               cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1402            }
1403         }
14081404      }
14091405      break;
14101406   case 0x04:                  /* LY - LCD Y-coordinate */
14111407      return;
14121408   case 0x05:                  /* LYC */
1413      if ( CURLINE == data ) {
1414         LCDSTAT |= 0x04;
1415         /* Generate lcd interrupt if requested */
1416         gb_lcd_int_check();
1417      } else {
1418         LCDSTAT &= 0xFB;
1409      if ( CMPLINE != data ) {
1410         if ( CURLINE == data ) {
1411            LCDSTAT |= 0x04;
1412            /* Generate lcd interrupt if requested */
1413            if ( LCDSTAT & 0x40 ) {
1414               cpunum_set_input_line( 0, LCD_INT, HOLD_LINE );
1415            }
1416         } else {
1417            LCDSTAT &= 0xFB;
1418         }
14191419      }
1420      /* Generate lcd interrupt if requested */
1421      gb_lcd_int_check();
14221420      break;
14231421   case 0x06:                  /* DMA - DMA Transfer and Start Address */
14241422      {

Previous 15994 Revisions Next


© 1998-2018 The MESS Team