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