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