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