|
|
1.1 ! root 1: /* ! 2: Hatari ! 3: ! 4: Video hardware handling. This code handling all to do with the video chip. So, we handle ! 5: VBLs, HBLs, copying the ST screen to a buffer to simulate the TV raster trace, border ! 6: removal, palette changes per HBL, the 'video address pointer' etc... ! 7: */ ! 8: ! 9: //#include <SDL.h> ! 10: ! 11: #include "main.h" ! 12: #include "debug.h" ! 13: #include "decode.h" ! 14: #include "dialog.h" ! 15: #include "fdc.h" ! 16: #include "int.h" ! 17: #include "ikbd.h" ! 18: #include "m68000.h" ! 19: #include "memAlloc.h" ! 20: #include "memorySnapShot.h" ! 21: #include "mfp.h" ! 22: #include "screen.h" ! 23: #include "shortcut.h" ! 24: #include "sound.h" ! 25: #include "spec512.h" ! 26: #include "stMemory.h" ! 27: #include "vdi.h" ! 28: #include "video.h" ! 29: #include "ymFormat.h" ! 30: #include "syncTables.h" /* Clock-cycle tables */ ! 31: ! 32: long VideoAddress; /* Address of video display in ST screen space */ ! 33: unsigned char VideoSyncByte,VideoShifterByte; /* VideoSync (0xff820a) and VideoShifter(0xff8260) values store in video chip */ ! 34: BOOL bUseHighRes = TRUE; /* Use hi-res (ie Mono monitor) */ ! 35: int nVBLs, nHBL; /* VBL Counter, HBL line */ ! 36: int nStartHBL,nEndHBL; /* Start/End HBL for visible screen(64 lines in Top border) */ ! 37: int OverscanMode; /* OVERSCANMODE_xxxx for current display frame */ ! 38: unsigned short int HBLPalettes[(NUM_VISIBLE_LINES+1)*16]; /* 1x16 colour palette per screen line, +1 line just incase write after line 200 */ ! 39: unsigned long HBLPaletteMasks[NUM_VISIBLE_LINES+1]; /* Bit mask of palette colours changes, top bit set is resolution change */ ! 40: unsigned short int *pHBLPalettes; /* Pointer to current palette lists, one per HBL */ ! 41: unsigned long *pHBLPaletteMasks; ! 42: unsigned long VideoBase; /* Base address in ST Ram for screen(read on each VBL) */ ! 43: unsigned long VideoRaster; /* Pointer to Video raster, after VideoBase in PC address space. Use to copy data on HBL */ ! 44: int SyncHandler_Value; /* Value to pass to 'Video_SyncHandler_xxxx' functions */ ! 45: int LeftRightBorder; /* BORDERMASK_xxxx used to simulate left/right border removal */ ! 46: ! 47: ! 48: /*-----------------------------------------------------------------------*/ ! 49: /* ! 50: Reset video chip ! 51: */ ! 52: void Video_Reset(void) ! 53: { ! 54: /* NOTE! Must reset all of these register type things here!!!! */ ! 55: VideoSyncByte = 0; ! 56: /* Are we in high-res? */ ! 57: if (bUseHighRes) ! 58: VideoShifterByte = ST_HIGH_RES; /* Boot up for mono monitor */ ! 59: else ! 60: VideoShifterByte = ST_LOW_RES; ! 61: ! 62: /* Reset VBL counter */ ! 63: nVBLs = 0; ! 64: /* Reset addresses */ ! 65: VideoBase = 0L; ! 66: /* Clear ready for new VBL */ ! 67: Video_ClearOnVBL(); ! 68: } ! 69: ! 70: /*-----------------------------------------------------------------------*/ ! 71: /* ! 72: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type) ! 73: */ ! 74: void Video_MemorySnapShot_Capture(BOOL bSave) ! 75: { ! 76: /* Save/Restore details */ ! 77: MemorySnapShot_Store(&VideoAddress,sizeof(VideoAddress)); ! 78: MemorySnapShot_Store(&VideoSyncByte,sizeof(VideoSyncByte)); ! 79: MemorySnapShot_Store(&VideoShifterByte,sizeof(VideoShifterByte)); ! 80: MemorySnapShot_Store(&bUseHighRes,sizeof(bUseHighRes)); ! 81: MemorySnapShot_Store(&nVBLs,sizeof(nVBLs)); ! 82: MemorySnapShot_Store(&nHBL,sizeof(nHBL)); ! 83: MemorySnapShot_Store(&nStartHBL,sizeof(nStartHBL)); ! 84: MemorySnapShot_Store(&nEndHBL,sizeof(nEndHBL)); ! 85: MemorySnapShot_Store(&OverscanMode,sizeof(OverscanMode)); ! 86: MemorySnapShot_Store(HBLPalettes,sizeof(HBLPalettes)); ! 87: MemorySnapShot_Store(HBLPaletteMasks,sizeof(HBLPaletteMasks)); ! 88: MemorySnapShot_Store(&VideoBase,sizeof(VideoBase)); ! 89: MemorySnapShot_Store(&VideoRaster,sizeof(VideoRaster)); ! 90: } ! 91: ! 92: /*-----------------------------------------------------------------------*/ ! 93: /* ! 94: Called on VBL, set registers ready for frame ! 95: */ ! 96: void Video_ClearOnVBL(void) ! 97: { ! 98: /* New screen, so first HBL */ ! 99: nHBL = 0; ! 100: nStartHBL = SCREEN_START_HBL; ! 101: nEndHBL = SCREEN_START_HBL+SCREEN_HEIGHT_HBL; ! 102: OverscanMode = OVERSCANMODE_NONE; ! 103: ! 104: /* Get screen address pointer, align to 256 bytes(ie ignore lowest byte) */ ! 105: VideoBase = (unsigned long)STMemory_ReadByte(0xff8201)<<16 | (unsigned long)STMemory_ReadByte(0xff8203)<<8; ! 106: VideoRaster = (unsigned long)STRam+VideoBase; ! 107: pSTScreen = pFrameBuffer->pSTScreen; ! 108: ! 109: Video_StartHBL(); ! 110: Video_SetScreenRasters(); ! 111: Spec512_StartVBL(); ! 112: } ! 113: ! 114: /*-----------------------------------------------------------------------*/ ! 115: /* ! 116: Calculate Video address pointer and store in 'VideoAddress' ! 117: */ ! 118: void Video_CalculateAddress(void) ! 119: { ! 120: int X,Y,FrameCycles,nPixelsIn; ! 121: ! 122: /* Find number of cycles passed during frame */ ! 123: FrameCycles = Int_FindFrameCycles(); ! 124: ! 125: /* Top of screen is usually 64 lines from VBL(64x512=32768 cycles) */ ! 126: if (FrameCycles<(nStartHBL*CYCLES_PER_LINE)) ! 127: VideoAddress = 0; ! 128: else { ! 129: /* Now find which pixel we are on(ignore left/right borders) */ ! 130: /* 96 + 320 + 96 = 512 pixels per scan line(each pixel is one cycle) */ ! 131: nPixelsIn = FrameCycles-(nStartHBL*CYCLES_PER_LINE); ! 132: /* Convert this to an X,Y pixel on screen */ ! 133: Y = nPixelsIn/512; ! 134: X = nPixelsIn - (Y*512); ! 135: if (X<SCREEN_START_CYCLE) /* Limit if in NULL area outside screen */ ! 136: X = SCREEN_START_CYCLE; ! 137: if (X>(512-SCREEN_START_CYCLE)) ! 138: X = (512-SCREEN_START_CYCLE); ! 139: /* X is now from 96 to 416(320 pixels), subtract 96 to give X pixel across screen! */ ! 140: X = ((X-SCREEN_START_CYCLE)>>1)&(~1); ! 141: ! 142: if (Y<(nEndHBL-nStartHBL)) /* Limit to end of screen */ ! 143: VideoAddress = (Y*160) + X; ! 144: else ! 145: VideoAddress = ((nEndHBL-nStartHBL)*160); ! 146: } ! 147: ! 148: /* Offset from start of screen(MUST use address loading into video display) */ ! 149: VideoAddress += VideoBase; ! 150: } ! 151: ! 152: /*-----------------------------------------------------------------------*/ ! 153: /* ! 154: Read Video address pointer(from current cycle count), and return 24-bit address in 'ebx' ! 155: */ ! 156: unsigned long Video_ReadAddress(void) ! 157: { ! 158: Video_CalculateAddress(); /* Find address from current cycle count into display frame */ ! 159: return( VideoAddress ); ! 160: } ! 161: ! 162: /*-----------------------------------------------------------------------*/ ! 163: /* ! 164: VBL interrupt, draw screen and reset counters ! 165: */ ! 166: void Video_InterruptHandler_VBL(void) ! 167: { ! 168: int PendingCyclesOver; ! 169: ! 170: /* Store cycles we went over for this frame(this is our inital count) */ ! 171: PendingCyclesOver = -PendingInterruptCount; /* +ve */ ! 172: ! 173: /* Remove this interrupt from list and re-order */ ! 174: Int_AcknowledgeInterrupt(); ! 175: /* Start HBL interrupts(313 per frame) - MUST do before add in cycles */ ! 176: Int_AddAbsoluteInterrupt(CYCLES_ENDLINE,INTERRUPT_VIDEO_ENDLINE); ! 177: Int_AddAbsoluteInterrupt(CYCLES_HBL,INTERRUPT_VIDEO_HBL); ! 178: Int_AddAbsoluteInterrupt(CYCLES_PER_FRAME,INTERRUPT_VIDEO_VBL); ! 179: ! 180: /* Set frame cycles, used for Video Address */ ! 181: nFrameCyclesOver = PendingCyclesOver; /* Number of cycles into frame */ ! 182: ! 183: /* Clear any key presses which are due to be de-bounced(held for one ST frame) */ ! 184: //FIXME View_DebounceAllKeys(); ! 185: /* Check 'Function' keys, so if press F12 we update screen correctly to Window! */ ! 186: ShortCut_CheckKeys(); ! 187: /* See if need to save/restore emulation state during this 'safe-zone' */ ! 188: MemorySnapShot_CheckSaveRestore(); ! 189: /* Use extended VDI resolution? If so, just copy whole screen on VBL rather than per HBL */ ! 190: if (bUseVDIRes) ! 191: Video_CopyVDIScreen(); ! 192: /* Draw screen, skip frame if need to */ ! 193: if (ConfigureParams.Screen.Advanced.bFrameSkip) { ! 194: if (nVBLs&1) ! 195: Screen_Draw(); ! 196: } ! 197: else ! 198: Screen_Draw(); ! 199: /* Update counter for number of screen refreshes per second(for debugging) */ ! 200: nVBLs++; ! 201: /* Set video registers for frame */ ! 202: Video_ClearOnVBL(); ! 203: /* Store off PSG registers for YM file, is enabled */ ! 204: YMFormat_UpdateRecording(); ! 205: /* Generate 1/50th second of sound sample data, to be played by DirectSound thread */ ! 206: Sound_Update_VBL(); ! 207: ! 208: if (4>FIND_IPL) { /* Vertical blank, level 4! */ ! 209: ADD_CYCLES(44+4,5,3); /* Interrupt */ ! 210: ExceptionVector = EXCEPTION_VBLANK; ! 211: M68000_Exception(); /* VBL interrupt */ ! 212: } ! 213: else { ! 214: /* Higher priority interrupt is currently being executed(eg MFP). Set VBL to occur later */ ! 215: if (!Int_InterruptActive(INTERRUPT_VIDEO_VBL_PENDING)) ! 216: Int_AddAbsoluteInterrupt(100,INTERRUPT_VIDEO_VBL_PENDING); ! 217: } ! 218: ! 219: /* Is this a good place to send the keyboard packets? Done once per frame */ ! 220: /* And handle any windows messages, check for quit message */ ! 221: Main_EventHandler(); /* Process messages, set 'bQuitProgram' if user tries to quit */ ! 222: IKBD_SendAutoKeyboardCommands(); /* On each VBL send automatic keyboard packets for mouse, joysticks etc... */ ! 223: if(bQuitProgram) ! 224: Int_AddAbsoluteInterrupt(4, 0L); /* Pass NULL interrupt function to quit cleanly */ ! 225: ! 226: } ! 227: ! 228: ! 229: /*-----------------------------------------------------------------------*/ ! 230: /* ! 231: This doesn't make sense... I always thought if a 68000 interrupt, eg the VBL, occurs while a ! 232: higher priority interrupt was in service the interrupt was ignored. This does not seem to be ! 233: the case. This really needs checking on a real ST, but I have noticed some menu discs run ! 234: sound routines from the MFP timers which overlap the VBL, yet the VBL still occurs... ! 235: */ ! 236: void Video_InterruptHandler_VBL_Pending(void) ! 237: { ! 238: /* Remove this interrupt from list and re-order */ ! 239: Int_AcknowledgeInterrupt(); ! 240: ! 241: /* Check if can execute VBL */ ! 242: if (4>FIND_IPL) { /* Vertical blank, level 4! */ ! 243: ADD_CYCLES(44+4,5,3); /* Interrupt */ ! 244: ExceptionVector = EXCEPTION_VBLANK; ! 245: M68000_Exception(); /* VBL interrupt */ ! 246: } ! 247: else ! 248: Int_AddAbsoluteInterrupt(100,INTERRUPT_VIDEO_VBL_PENDING); ! 249: } ! 250: ! 251: ! 252: /*-----------------------------------------------------------------------*/ ! 253: /* ! 254: End Of Line interrupt ! 255: As this occurs at the end of a line we cannot get timing for START of first line(as in Spectrum 512) ! 256: */ ! 257: void Video_InterruptHandler_EndLine(void) ! 258: { ! 259: /* Remove this interrupt from list and re-order */ ! 260: Int_AcknowledgeInterrupt(); ! 261: /* Generate new HBL, if need to - there are 313 HBLs per frame */ ! 262: if (nHBL<(SCANLINES_PER_FRAME-1)) ! 263: Int_AddAbsoluteInterrupt(CYCLES_PER_LINE,INTERRUPT_VIDEO_ENDLINE); ! 264: ! 265: /* Timer A/B occur at END of first visible screen line in Event Count mode */ ! 266: if ( (nHBL>=nStartHBL) && (nHBL<nEndHBL) ) ! 267: { ! 268: /* Handle Timers A and B when using Event Count mode(timer taken from HBL) */ ! 269: if (MFP_TACR==0x08) // Is timer in Event Count mode? ! 270: MFP_TimerA_EventCount_Interrupt(); ! 271: if (MFP_TBCR==0x08) // Is timer in Event Count mode? ! 272: MFP_TimerB_EventCount_Interrupt(); ! 273: } ! 274: ! 275: FDC_UpdateHBL(); // Update FDC motion ! 276: Video_EndHBL(); // Increase HBL count, copy line to display buffer and do any video trickery ! 277: ! 278: /* If we don't often pump data into the event queue, the SDL misses events... grr... */ ! 279: if( !(nHBL&63) ) ! 280: { ! 281: Main_EventHandler(); ! 282: /*IKBD_SendAutoKeyboardCommands();*/ ! 283: } ! 284: } ! 285: ! 286: ! 287: //----------------------------------------------------------------------- ! 288: /* ! 289: HBL interrupt - this is very inaccurate on ST and appears to occur around 1/3rd way into ! 290: the display! ! 291: */ ! 292: void Video_InterruptHandler_HBL(void) ! 293: { ! 294: // Remove this interrupt from list and re-order ! 295: Int_AcknowledgeInterrupt(); ! 296: // Generate new Timer AB, if need to - there are 313 HBLs per frame ! 297: if (nHBL<(SCANLINES_PER_FRAME-1)) ! 298: Int_AddAbsoluteInterrupt(CYCLES_PER_LINE,INTERRUPT_VIDEO_HBL); ! 299: ! 300: if (2>FIND_IPL) { // Horizontal blank, level 2! ! 301: ADD_CYCLES(44+4,5,3); // Interrupt ! 302: ExceptionVector = EXCEPTION_HBLANK; ! 303: M68000_Exception(); // HBL interrupt ! 304: } ! 305: } ! 306: ! 307: ! 308: //----------------------------------------------------------------------- ! 309: /* ! 310: Sync Table handlers ! 311: */ ! 312: void Video_SyncHandler_SetLeftRightBorder(void) ! 313: { ! 314: LeftRightBorder |= SyncHandler_Value; // Turn on left/right borders ! 315: } ! 316: ! 317: void Video_SyncHandler_SetSyncScrollOffset(void) ! 318: { ! 319: VideoRaster += SyncHandler_Value; // Add offset to video address(sync-scroll) ! 320: } ! 321: ! 322: void Video_SyncHandler_SetTopBorder(void) ! 323: { ! 324: OverscanMode |= OVERSCANMODE_TOP; // Set overscan bit ! 325: nStartHBL = FIRST_VISIBLE_HBL; // New start screen line ! 326: } ! 327: ! 328: void Video_SyncHandler_SetBottomBorder(void) ! 329: { ! 330: OverscanMode |= OVERSCANMODE_BOTTOM; // Set overscan bit ! 331: nEndHBL = SCREEN_START_HBL+SCREEN_HEIGHT_HBL+OVERSCAN_BOTTOM; // New end screen line ! 332: } ! 333: ! 334: //----------------------------------------------------------------------- ! 335: /* ! 336: Write to VideoShifter(0xff8260), resolution bits ! 337: */ ! 338: void Video_WriteToShifter(void) ! 339: { ! 340: // Store into table so can test at end of HBL ! 341: Video_StoreSyncShifterAccess(0xff8260,VideoShifterByte); ! 342: } ! 343: ! 344: //----------------------------------------------------------------------- ! 345: /* ! 346: Write to VideoSync(0xff820a), Hz setting ! 347: */ ! 348: void Video_WriteToSync(void) ! 349: { ! 350: // Store into table so can test at end of HBL ! 351: Video_StoreSyncShifterAccess(0xff820a,VideoSyncByte); ! 352: } ! 353: ! 354: //----------------------------------------------------------------------- ! 355: /* ! 356: Check access Video(0xff8260 or 0xff820a) to see if opened top/bottom/left/right borders or ! 357: even tried for a SyncScroll ! 358: */ ! 359: BOOL Video_CheckSyncShifterTable(unsigned int Address, unsigned char Byte, int FrameCycles, SYNCSHIFTER_ACCESS_TABLE *pAccessTable) ! 360: { ! 361: SYNCSHIFTER_ACCESS *pSyncShifter; ! 362: BOOL bFoundMatch=FALSE; ! 363: int i=0; ! 364: ! 365: // Scan each shifter entry to see if this new values matches - if not rest ! 366: while(pAccessTable[i].nChecks) { ! 367: // Get table of entries, index at 'counter' ! 368: pSyncShifter = &pAccessTable[i].pSyncShifterAccess[pAccessTable[i].nCount]; ! 369: // Does next value match table? ! 370: if ( (pSyncShifter->Address==Address) && (pSyncShifter->Byte==Byte) && (pSyncShifter->FrameCycles==FrameCycles) ) { ! 371: // Set flag(used for debugging) ! 372: bFoundMatch = TRUE; ! 373: ! 374: // Got match increase count ! 375: pAccessTable[i].nCount++; ! 376: // Is table complete? ! 377: if (pAccessTable[i].nCount==pAccessTable[i].nChecks) { ! 378: // Reset count, ready for next time ! 379: pAccessTable[i].nCount = 0; ! 380: // Yes, call handler function with passed variable ! 381: SyncHandler_Value = pAccessTable[i].Value; ! 382: CALL_VAR(pAccessTable[i].pFunc); ! 383: } ! 384: } ! 385: else { ! 386: // No match, reset table count ! 387: pAccessTable[i].nCount = 0; ! 388: } ! 389: ! 390: i++; ! 391: } ! 392: ! 393: return(bFoundMatch); ! 394: } ! 395: ! 396: //----------------------------------------------------------------------- ! 397: /* ! 398: Store Sync/Shifter write into table so can check at end of HBL for border/sync-scroll hardware tricks ! 399: */ ! 400: void Video_StoreSyncShifterAccess(unsigned int Address,unsigned char Byte) ! 401: { ! 402: int FrameCycles = Int_FindFrameCycles(); ! 403: ! 404: // Get back to where instruction started for timing ! 405: FrameCycles -= M68000_FindLastInstructionCycles(); ! 406: ! 407: // char szString[256]; ! 408: // sprintf(szString,"0x%X=0x%2.2X %d(%d) @ %d",Address,Byte,FrameCycles,FrameCycles&511,nHBL); ! 409: // debug << szString << endl; ! 410: ! 411: Video_CheckSyncShifterTable(Address,Byte,FrameCycles, pTopBorderAccessTable); ! 412: Video_CheckSyncShifterTable(Address,Byte,FrameCycles, pBottomBorderAccessTable); ! 413: Video_CheckSyncShifterTable(Address,Byte,FrameCycles&511, pLeftRightBorderAccessTable); ! 414: // Video_CheckSyncShifterTable(Address,Byte,FrameCycles&511, pSyncScrollerAccessTable); ! 415: } ! 416: ! 417: //----------------------------------------------------------------------- ! 418: /* ! 419: Reset Sync/Shifter table at start of each HBL ! 420: */ ! 421: void Video_StartHBL(void) ! 422: { ! 423: LeftRightBorder = 0; ! 424: } ! 425: ! 426: //----------------------------------------------------------------------- ! 427: /* ! 428: Store whole palette on first line so have reference to work from ! 429: */ ! 430: void Video_StoreFirstLinePalette(void) ! 431: { ! 432: unsigned short int *pp2; ! 433: int i; ! 434: ! 435: pp2 = (unsigned short int *)((unsigned long)STRam+0xff8240); ! 436: for(i=0; i<16; i++) ! 437: HBLPalettes[i] = STMemory_Swap68000Int(*pp2++); ! 438: // And set mask flag with palette and resolution ! 439: HBLPaletteMasks[0] = (PALETTEMASK_RESOLUTION|PALETTEMASK_PALETTE) | (((unsigned long)STMemory_ReadByte(0xff8260)&0x3)<<16); ! 440: } ! 441: ! 442: //----------------------------------------------------------------------- ! 443: /* ! 444: Store resolution on each line(used to test if mixed low/medium resolutions) ! 445: */ ! 446: void Video_StoreResolution(int y) ! 447: { ! 448: // Clear resolution, and set with current value ! 449: if (!(bUseHighRes || bUseVDIRes) ) { ! 450: HBLPaletteMasks[y] &= ~(0x3<<16); ! 451: HBLPaletteMasks[y] |= ((unsigned long)STMemory_ReadByte(0xff8260)&0x3)<<16; ! 452: } ! 453: } ! 454: ! 455: //----------------------------------------------------------------------- ! 456: /* ! 457: Copy line of screen into buffer for conversion later. ! 458: Possible lines may be top/bottom border, and/or left/right borders ! 459: */ ! 460: void Video_CopyScreenLine(int BorderMask) ! 461: { ! 462: // Only copy screen line if not doing high VDI resolution ! 463: if (!bUseVDIRes) { ! 464: BorderMask |= LeftRightBorder; ! 465: ! 466: if (bUseHighRes) { ! 467: // Copy for hi-res(no overscan) ! 468: memcpy(pSTScreen,(char *)VideoRaster,SCREENBYTES_MIDDLE); ! 469: VideoRaster += SCREENBYTES_MIDDLE; ! 470: // Each screen line copied to buffer is always same length ! 471: pSTScreen += SCREENBYTES_MIDDLE; ! 472: } ! 473: else { ! 474: // Is total blank line? Ie top/bottom border? ! 475: if (BorderMask&(BORDERMASK_TOP|BORDERMASK_BOTTOM)) { ! 476: // Clear line to colour '0' ! 477: memset(pSTScreen,0,SCREENBYTES_LINE); ! 478: } ! 479: else { ! 480: // Does have left border? If not, clear to colour '0' ! 481: if (BorderMask&BORDERMASK_LEFT) { ! 482: VideoRaster += 24-SCREENBYTES_LEFT; ! 483: memcpy(pSTScreen,(char *)VideoRaster,SCREENBYTES_LEFT); ! 484: VideoRaster += SCREENBYTES_LEFT; ! 485: } ! 486: else ! 487: memset(pSTScreen,0,SCREENBYTES_LEFT); ! 488: // Copy middle - always present ! 489: memcpy(pSTScreen+SCREENBYTES_LEFT,(char *)VideoRaster,SCREENBYTES_MIDDLE); ! 490: VideoRaster += SCREENBYTES_MIDDLE; ! 491: // Does have right border? If not, clear to colour '0' ! 492: if (BorderMask&BORDERMASK_RIGHT) { ! 493: memcpy(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE,(char *)VideoRaster,SCREENBYTES_RIGHT); ! 494: VideoRaster += 46-SCREENBYTES_RIGHT; ! 495: VideoRaster += SCREENBYTES_RIGHT; ! 496: } ! 497: else ! 498: memset(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE,0,SCREENBYTES_RIGHT); ! 499: } ! 500: ! 501: // Each screen line copied to buffer is always same length ! 502: pSTScreen += SCREENBYTES_LINE; ! 503: } ! 504: } ! 505: } ! 506: ! 507: //----------------------------------------------------------------------- ! 508: /* ! 509: Copy extended GEM resolution screen ! 510: */ ! 511: void Video_CopyVDIScreen(void) ! 512: { ! 513: // Copy whole screen, don't care about being exact as for GEM only ! 514: memcpy(pSTScreen,(char *)VideoRaster,((VDIWidth*VDIPlanes)/8)*VDIHeight); // 640x400x16colour ! 515: } ! 516: ! 517: //----------------------------------------------------------------------- ! 518: /* ! 519: Check at end of each HBL to see if any Sync/Shifter hardware tricks have been attempted ! 520: */ ! 521: void Video_EndHBL(void) ! 522: { ! 523: // Are we in possible visible display(including borders)? ! 524: if ( (nHBL>=FIRST_VISIBLE_HBL) && (nHBL<(FIRST_VISIBLE_HBL+NUM_VISIBLE_LINES)) ) { ! 525: // Copy line of screen to buffer to simulate TV raster trace - required for mouse cursor display/game updates ! 526: // Eg, Lemmings and The Killing Game Show are good examples ! 527: ! 528: if (nHBL<nStartHBL) // Are we in top border blank(ie no top overscan enabled) ! 529: Video_CopyScreenLine(BORDERMASK_TOP); ! 530: else if (nHBL>=nEndHBL) // Are we in bottom border blank ! 531: Video_CopyScreenLine(BORDERMASK_BOTTOM); ! 532: else // Must be in visible screen(including overscan), ignore left/right borders for now ! 533: Video_CopyScreenLine(BORDERMASK_NONE); ! 534: ! 535: if (nHBL==FIRST_VISIBLE_HBL) { // Very first line on screen - HBLPalettes[0] ! 536: // Store ALL palette for this line into raster table for datum ! 537: Video_StoreFirstLinePalette(); ! 538: } ! 539: // Store resolution for every line so can check for mix low/medium screens ! 540: Video_StoreResolution(nHBL-FIRST_VISIBLE_HBL); ! 541: } ! 542: ! 543: // Finally increase HBL count ! 544: nHBL++; ! 545: ! 546: Video_StartHBL(); // Setup next one ! 547: } ! 548: ! 549: // Clear raster line table to store changes in palette/resolution on a line basic ! 550: // Call once on VBL interrupt ! 551: void Video_SetScreenRasters(void) ! 552: { ! 553: pHBLPaletteMasks = HBLPaletteMasks; ! 554: pHBLPalettes = HBLPalettes; ! 555: Memory_Clear(pHBLPaletteMasks,sizeof(unsigned long)*NUM_VISIBLE_LINES); ! 556: } ! 557: ! 558: //----------------------------------------------------------------------- ! 559: /* ! 560: Set pointers to HBLPalette tables to store correct colours/resolutions ! 561: */ ! 562: void Video_SetHBLPaletteMaskPointers(void) ! 563: { ! 564: int FrameCycles; ! 565: int Line; ! 566: ! 567: /* Top of standard screen is 64 lines from VBL(64x512=32768 cycles) */ ! 568: /* Each line is 64+320+64+64(Blank) = 512 pixels per scan line */ ! 569: /* Timer occurs at end of 64+320+64; Display Enable(DE)=Low */ ! 570: /* HBL is incorrect on machine and occurs around 96+ cycles in */ ! 571: ! 572: /* Top of standard screen is 64 lines from VBL(64x512=32768 cycles) */ ! 573: /* Each line is 96 + 320 + 96 = 512 pixels per scan line(each pixel is one cycle) */ ! 574: FrameCycles = Int_FindFrameCycles(); ! 575: ! 576: /* Find 'line' into palette - screen starts 64 lines down, less 28 for top overscan */ ! 577: /* And if write to last 96 cycle of line it will count as the NEXT line(needed else games may flicker) */ ! 578: Line = (FrameCycles-(FIRST_VISIBLE_HBL*CYCLES_PER_LINE)+SCREEN_START_CYCLE)/CYCLES_PER_LINE; ! 579: if (Line<0) /* Limit to top/bottom of possible visible screen */ ! 580: Line = 0; ! 581: if (Line>=NUM_VISIBLE_LINES) ! 582: Line = NUM_VISIBLE_LINES-1; ! 583: ! 584: // Store pointers ! 585: pHBLPaletteMasks = &HBLPaletteMasks[Line]; /* Next mask entry */ ! 586: pHBLPalettes = &HBLPalettes[16*Line]; /* Next colour raster list x16 colours */ ! 587: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.