|
|
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:
1.1.1.7 root 7: Video hardware handling. This code handling all to do with the video chip.
8: So, we handle VBLs, HBLs, copying the ST screen to a buffer to simulate the
9: TV raster trace, border removal, palette changes per HBL, the 'video address
10: pointer' etc...
1.1 root 11: */
1.1.1.8 ! root 12: char Video_rcsid[] = "Hatari $Id: video.c,v 1.28 2005/04/05 14:41:32 thothy Exp $";
1.1 root 13:
1.1.1.4 root 14: #include <SDL.h>
1.1.1.7 root 15: #include <SDL_endian.h>
1.1.1.4 root 16:
1.1 root 17: #include "main.h"
1.1.1.6 root 18: #include "configuration.h"
1.1 root 19: #include "fdc.h"
20: #include "int.h"
21: #include "ikbd.h"
1.1.1.8 ! root 22: #include "ioMem.h"
1.1.1.4 root 23: #include "keymap.h"
1.1 root 24: #include "m68000.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:
36:
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 */
1.1.1.8 ! root 39: int nStartHBL, nEndHBL; /* Start/End HBL for visible screen(64 lines in Top border) */
1.1 root 40: int OverscanMode; /* OVERSCANMODE_xxxx for current display frame */
1.1.1.8 ! root 41: Uint16 HBLPalettes[(NUM_VISIBLE_LINES+1)*16]; /* 1x16 colour palette per screen line, +1 line just incase write after line 200 */
! 42: Uint16 *pHBLPalettes; /* Pointer to current palette lists, one per HBL */
1.1 root 43: unsigned long HBLPaletteMasks[NUM_VISIBLE_LINES+1]; /* Bit mask of palette colours changes, top bit set is resolution change */
44: unsigned long *pHBLPaletteMasks;
1.1.1.6 root 45: int VBLCounter; /* VBL counter */
46: int nScreenRefreshRate = 50; /* 50 or 60 Hz in color, 70 Hz in mono */
1.1.1.8 ! root 47: Uint32 VideoBase; /* Base address in ST Ram for screen (read on each VBL) */
! 48: static Uint8 *pVideoRaster; /* Pointer to Video raster, after VideoBase in PC address space. Use to copy data on HBL */
! 49: static Uint8 VideoShifterByte; /* VideoShifter (0xff8260) value store in video chip */
! 50: static int LeftRightBorder; /* BORDERMASK_xxxx used to simulate left/right border removal */
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!!!! */
1.1.1.7 root 60:
1.1 root 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(&VideoShifterByte,sizeof(VideoShifterByte));
85: MemorySnapShot_Store(&bUseHighRes,sizeof(bUseHighRes));
86: MemorySnapShot_Store(&nVBLs,sizeof(nVBLs));
87: MemorySnapShot_Store(&nHBL,sizeof(nHBL));
88: MemorySnapShot_Store(&nStartHBL,sizeof(nStartHBL));
89: MemorySnapShot_Store(&nEndHBL,sizeof(nEndHBL));
90: MemorySnapShot_Store(&OverscanMode,sizeof(OverscanMode));
91: MemorySnapShot_Store(HBLPalettes,sizeof(HBLPalettes));
92: MemorySnapShot_Store(HBLPaletteMasks,sizeof(HBLPaletteMasks));
93: MemorySnapShot_Store(&VideoBase,sizeof(VideoBase));
1.1.1.8 ! root 94: MemorySnapShot_Store(&pVideoRaster,sizeof(pVideoRaster));
1.1 root 95: }
96:
97: /*-----------------------------------------------------------------------*/
98: /*
99: Called on VBL, set registers ready for frame
100: */
101: void Video_ClearOnVBL(void)
102: {
103: /* New screen, so first HBL */
104: nHBL = 0;
105: nStartHBL = SCREEN_START_HBL;
106: nEndHBL = SCREEN_START_HBL+SCREEN_HEIGHT_HBL;
107: OverscanMode = OVERSCANMODE_NONE;
108:
1.1.1.8 ! root 109: /* Get screen address pointer, aligned to 256 bytes on ST (ie ignore lowest byte) */
! 110: VideoBase = (Uint32)STMemory_ReadByte(0xff8201)<<16 | (Uint32)STMemory_ReadByte(0xff8203)<<8;
! 111: if (ConfigureParams.System.nMachineType != MACHINE_ST)
! 112: VideoBase |= STMemory_ReadByte(0xff820d);
! 113:
! 114: pVideoRaster = &STRam[VideoBase];
1.1 root 115: pSTScreen = pFrameBuffer->pSTScreen;
116:
117: Video_StartHBL();
118: Video_SetScreenRasters();
119: Spec512_StartVBL();
120: }
121:
1.1.1.8 ! root 122:
1.1 root 123: /*-----------------------------------------------------------------------*/
124: /*
1.1.1.8 ! root 125: Calculate and return video address pointer.
1.1 root 126: */
1.1.1.8 ! root 127: static Uint32 Video_CalculateAddress(void)
1.1 root 128: {
129: int X,Y,FrameCycles,nPixelsIn;
1.1.1.8 ! root 130: Uint32 VideoAddress; /* Address of video display in ST screen space */
1.1 root 131:
132: /* Find number of cycles passed during frame */
133: FrameCycles = Int_FindFrameCycles();
134:
135: /* Top of screen is usually 64 lines from VBL(64x512=32768 cycles) */
136: if (FrameCycles<(nStartHBL*CYCLES_PER_LINE))
1.1.1.8 ! root 137: {
1.1 root 138: VideoAddress = 0;
1.1.1.8 ! root 139: }
! 140: else
! 141: {
1.1 root 142: /* Now find which pixel we are on(ignore left/right borders) */
143: /* 96 + 320 + 96 = 512 pixels per scan line(each pixel is one cycle) */
144: nPixelsIn = FrameCycles-(nStartHBL*CYCLES_PER_LINE);
145: /* Convert this to an X,Y pixel on screen */
146: Y = nPixelsIn/512;
147: X = nPixelsIn - (Y*512);
148: if (X<SCREEN_START_CYCLE) /* Limit if in NULL area outside screen */
149: X = SCREEN_START_CYCLE;
150: if (X>(512-SCREEN_START_CYCLE))
151: X = (512-SCREEN_START_CYCLE);
152: /* X is now from 96 to 416(320 pixels), subtract 96 to give X pixel across screen! */
153: X = ((X-SCREEN_START_CYCLE)>>1)&(~1);
1.1.1.6 root 154:
1.1 root 155: if (Y<(nEndHBL-nStartHBL)) /* Limit to end of screen */
156: VideoAddress = (Y*160) + X;
157: else
158: VideoAddress = ((nEndHBL-nStartHBL)*160);
159: }
160:
161: /* Offset from start of screen(MUST use address loading into video display) */
162: VideoAddress += VideoBase;
163:
1.1.1.8 ! root 164: return VideoAddress;
1.1 root 165: }
166:
1.1.1.7 root 167:
1.1 root 168: /*-----------------------------------------------------------------------*/
169: /*
170: VBL interrupt, draw screen and reset counters
171: */
172: void Video_InterruptHandler_VBL(void)
173: {
174: int PendingCyclesOver;
1.1.1.6 root 175: int nNewMilliTicks;
176: static int nOldMilliTicks = 0;
177: signed int nDelay;
1.1 root 178:
179: /* Store cycles we went over for this frame(this is our inital count) */
180: PendingCyclesOver = -PendingInterruptCount; /* +ve */
181:
182: /* Remove this interrupt from list and re-order */
183: Int_AcknowledgeInterrupt();
1.1.1.6 root 184: /* Start HBL interrupts - MUST do before add in cycles */
1.1 root 185: Int_AddAbsoluteInterrupt(CYCLES_ENDLINE,INTERRUPT_VIDEO_ENDLINE);
186: Int_AddAbsoluteInterrupt(CYCLES_HBL,INTERRUPT_VIDEO_HBL);
187: Int_AddAbsoluteInterrupt(CYCLES_PER_FRAME,INTERRUPT_VIDEO_VBL);
188:
189: /* Set frame cycles, used for Video Address */
190: nFrameCyclesOver = PendingCyclesOver; /* Number of cycles into frame */
191:
1.1.1.6 root 192: /* Set the screen refresh rate */
193: #if 0
194: if(bUseHighRes)
195: nScreenRefreshRate = 70;
1.1.1.8 ! root 196: else if(IoMem[0xff820a] & 2) /* Is it 50Hz or is it 60Hz? */
1.1.1.6 root 197: nScreenRefreshRate = 50;
198: else
199: nScreenRefreshRate = 60;
200: #endif
201:
202: VBLCounter += 1;
1.1.1.2 root 203:
1.1.1.3 root 204: /* Clear any key presses which are due to be de-bounced (held for one ST frame) */
205: Keymap_DebounceAllKeys();
1.1.1.7 root 206: /* Check shortcut keys */
1.1 root 207: ShortCut_CheckKeys();
1.1.1.7 root 208:
1.1 root 209: /* Use extended VDI resolution? If so, just copy whole screen on VBL rather than per HBL */
210: if (bUseVDIRes)
211: Video_CopyVDIScreen();
1.1.1.5 root 212:
1.1 root 213: /* Draw screen, skip frame if need to */
1.1.1.6 root 214: if (ConfigureParams.Screen.bFrameSkip)
1.1.1.5 root 215: {
1.1 root 216: if (nVBLs&1)
217: Screen_Draw();
218: }
219: else
220: Screen_Draw();
1.1.1.5 root 221:
1.1 root 222: /* Update counter for number of screen refreshes per second(for debugging) */
223: nVBLs++;
224: /* Set video registers for frame */
225: Video_ClearOnVBL();
226: /* Store off PSG registers for YM file, is enabled */
227: YMFormat_UpdateRecording();
1.1.1.4 root 228: /* Generate 1/50th second of sound sample data, to be played by sound thread */
1.1 root 229: Sound_Update_VBL();
230:
1.1.1.7 root 231: M68000_Exception(EXCEPTION_VBLANK); /* Vertical blank interrupt, level 4! */
1.1 root 232:
1.1.1.5 root 233: /* And handle any messages, check for quit message */
1.1 root 234: Main_EventHandler(); /* Process messages, set 'bQuitProgram' if user tries to quit */
1.1.1.7 root 235: if (bQuitProgram)
236: {
1.1 root 237: Int_AddAbsoluteInterrupt(4, 0L); /* Pass NULL interrupt function to quit cleanly */
1.1.1.7 root 238: set_special(SPCFLAG_BRK); /* Assure that CPU core shuts down */
239: }
1.1.1.6 root 240:
1.1.1.7 root 241: if (ConfigureParams.System.nMinMaxSpeed != MINMAXSPEED_MAX)
1.1.1.6 root 242: {
1.1.1.7 root 243: /* Wait, so we stay in sync with the sound */
244: do
1.1.1.6 root 245: {
1.1.1.7 root 246: nNewMilliTicks = SDL_GetTicks();
247: nDelay = 1000/nScreenRefreshRate - (nNewMilliTicks-nOldMilliTicks);
248: if(nDelay > 2)
249: {
250: /* SDL_Delay seems to be quite inaccurate, so we don't wait the whole time */
251: SDL_Delay(nDelay - 1);
252: }
1.1.1.6 root 253: }
1.1.1.7 root 254: while(nDelay > 0);
255: nOldMilliTicks = nNewMilliTicks;
1.1.1.6 root 256: }
1.1 root 257: }
258:
259:
260: /*-----------------------------------------------------------------------*/
261: /*
262: End Of Line interrupt
1.1.1.5 root 263: As this occurs at the end of a line we cannot get timing for START of first
264: line (as in Spectrum 512)
1.1 root 265: */
266: void Video_InterruptHandler_EndLine(void)
267: {
268: /* Remove this interrupt from list and re-order */
269: Int_AcknowledgeInterrupt();
270: /* Generate new HBL, if need to - there are 313 HBLs per frame */
271: if (nHBL<(SCANLINES_PER_FRAME-1))
272: Int_AddAbsoluteInterrupt(CYCLES_PER_LINE,INTERRUPT_VIDEO_ENDLINE);
273:
1.1.1.5 root 274: /* Is this a good place to send the keyboard packets? Done once per frame */
275: if(nHBL == nStartHBL)
276: {
277: /* On each VBL send automatic keyboard packets for mouse, joysticks etc... */
278: IKBD_SendAutoKeyboardCommands();
279: }
280:
1.1 root 281: /* Timer A/B occur at END of first visible screen line in Event Count mode */
282: if ( (nHBL>=nStartHBL) && (nHBL<nEndHBL) )
283: {
284: /* Handle Timers A and B when using Event Count mode(timer taken from HBL) */
1.1.1.2 root 285: if (MFP_TACR==0x08) /* Is timer in Event Count mode? */
1.1 root 286: MFP_TimerA_EventCount_Interrupt();
1.1.1.2 root 287: if (MFP_TBCR==0x08) /* Is timer in Event Count mode? */
1.1 root 288: MFP_TimerB_EventCount_Interrupt();
289: }
290:
1.1.1.2 root 291: FDC_UpdateHBL(); /* Update FDC motion */
292: Video_EndHBL(); /* Increase HBL count, copy line to display buffer and do any video trickery */
1.1 root 293:
294: /* If we don't often pump data into the event queue, the SDL misses events... grr... */
295: if( !(nHBL&63) )
1.1.1.5 root 296: {
1.1 root 297: Main_EventHandler();
1.1.1.5 root 298: }
1.1 root 299: }
300:
301:
1.1.1.2 root 302: /*-----------------------------------------------------------------------*/
1.1 root 303: /*
304: HBL interrupt - this is very inaccurate on ST and appears to occur around 1/3rd way into
305: the display!
306: */
307: void Video_InterruptHandler_HBL(void)
308: {
1.1.1.2 root 309: /* Remove this interrupt from list and re-order */
1.1 root 310: Int_AcknowledgeInterrupt();
1.1.1.7 root 311:
1.1.1.2 root 312: /* Generate new Timer AB, if need to - there are 313 HBLs per frame */
1.1.1.7 root 313: if(nHBL < (SCANLINES_PER_FRAME-1))
1.1 root 314: Int_AddAbsoluteInterrupt(CYCLES_PER_LINE,INTERRUPT_VIDEO_HBL);
315:
1.1.1.7 root 316: M68000_Exception(EXCEPTION_HBLANK); /* Horizontal blank interrupt, level 2! */
1.1 root 317: }
318:
319:
1.1.1.2 root 320: /*-----------------------------------------------------------------------*/
1.1 root 321: /*
1.1.1.7 root 322: Write to VideoShifter (0xff8260), resolution bits
1.1 root 323: */
1.1.1.7 root 324: void Video_WriteToShifter(Uint8 Byte)
1.1 root 325: {
1.1.1.7 root 326: static int nLastHBL = -1, LastByte, nLastCycles;
327: int nFrameCycles, nLineCycles;
328:
329: nFrameCycles = Int_FindFrameCycles();
1.1 root 330:
1.1.1.7 root 331: /* We only care for cycle position in the actual screen line */
332: nLineCycles = nFrameCycles % CYCLES_PER_LINE;
1.1 root 333:
1.1.1.7 root 334: /*fprintf(stderr,"Shifter=0x%2.2X %d (%d) @ %d\n",
335: Byte, nFrameCycles, nLineCycles, nHBL);*/
1.1 root 336:
1.1.1.7 root 337: /* Check if program tries to open left border.
338: * FIXME: This is a very inaccurate test that should be improved,
339: * but we probably need better CPU cycles emulation first. There's
340: * also no support for sync-scrolling yet :-( */
341: if (nHBL == nLastHBL && LastByte == 0x02 && Byte == 0x00
342: && nLineCycles <= 48 && nLineCycles-nLastCycles <= 16)
343: {
344: LeftRightBorder |= BORDERMASK_LEFT;
345: }
1.1.1.2 root 346:
1.1.1.7 root 347: nLastHBL = nHBL;
348: LastByte = Byte;
349: nLastCycles = nLineCycles;
1.1 root 350: }
351:
1.1.1.2 root 352:
353: /*-----------------------------------------------------------------------*/
1.1 root 354: /*
1.1.1.7 root 355: Write to VideoSync (0xff820a), Hz setting
1.1 root 356: */
1.1.1.8 ! root 357: void Video_Sync_WriteByte(void)
1.1 root 358: {
1.1.1.7 root 359: static int nLastHBL = -1, LastByte, nLastCycles;
360: int nFrameCycles, nLineCycles;
1.1.1.8 ! root 361: Uint8 Byte;
! 362:
! 363: Byte = IoMem[0xff820a] & 3; /* Note: We're only interested in lower 2 bits (50/60Hz) */
! 364:
1.1.1.7 root 365: nFrameCycles = Int_FindFrameCycles();
1.1 root 366:
1.1.1.7 root 367: /* We only care for cycle position in the actual screen line */
368: nLineCycles = nFrameCycles % CYCLES_PER_LINE;
1.1.1.2 root 369:
1.1.1.7 root 370: /*fprintf(stderr,"Sync=0x%2.2X %d (%d) @ %d\n",
371: Byte, nFrameCycles, nLineCycles, nHBL);*/
1.1 root 372:
1.1.1.7 root 373: /* Check if program tries to open a border.
374: * FIXME: These are very inaccurate tests that should be improved,
375: * but we probably need better CPU cycles emulation first. There's
376: * also no support for sync-scrolling yet :-( */
377: if (LastByte == 0x00 && Byte == 0x02) /* switched from 50 Hz to 60 Hz and back to 50 Hz? */
378: {
379: if (nHBL >= OVERSCAN_TOP && nHBL <= 39 && nStartHBL > FIRST_VISIBLE_HBL)
380: {
381: /* Top border */
382: OverscanMode |= OVERSCANMODE_TOP; /* Set overscan bit */
383: nStartHBL = FIRST_VISIBLE_HBL; /* New start screen line */
384: pHBLPaletteMasks -= OVERSCAN_TOP;
385: pHBLPalettes -= OVERSCAN_TOP;
1.1 root 386: }
1.1.1.7 root 387: else if (nHBL == SCREEN_START_HBL+SCREEN_HEIGHT_HBL)
388: {
389: /* Bottom border */
390: OverscanMode |= OVERSCANMODE_BOTTOM; /* Set overscan bit */
391: nEndHBL = SCREEN_START_HBL+SCREEN_HEIGHT_HBL+OVERSCAN_BOTTOM; /* New end screen line */
1.1 root 392: }
393:
1.1.1.7 root 394: if (nHBL == nLastHBL && nLineCycles >= 400 && nLineCycles <= 480
395: && nLineCycles-nLastCycles <= 16)
396: {
397: /* Right border */
398: LeftRightBorder |= BORDERMASK_RIGHT;
399: }
1.1 root 400: }
401:
1.1.1.7 root 402: nLastHBL = nHBL;
403: LastByte = Byte;
404: nLastCycles = nLineCycles;
1.1 root 405: }
406:
1.1.1.2 root 407:
408: /*-----------------------------------------------------------------------*/
1.1 root 409: /*
410: Reset Sync/Shifter table at start of each HBL
411: */
412: void Video_StartHBL(void)
413: {
414: LeftRightBorder = 0;
415: }
416:
1.1.1.2 root 417:
418: /*-----------------------------------------------------------------------*/
1.1 root 419: /*
420: Store whole palette on first line so have reference to work from
421: */
1.1.1.7 root 422: static void Video_StoreFirstLinePalette(void)
1.1 root 423: {
1.1.1.8 ! root 424: Uint16 *pp2;
1.1 root 425: int i;
426:
1.1.1.8 ! root 427: pp2 = (Uint16 *)&IoMem[0xff8240];
1.1 root 428: for(i=0; i<16; i++)
1.1.1.7 root 429: HBLPalettes[i] = SDL_SwapBE16(*pp2++);
1.1.1.2 root 430: /* And set mask flag with palette and resolution */
1.1.1.8 ! root 431: HBLPaletteMasks[0] = (PALETTEMASK_RESOLUTION|PALETTEMASK_PALETTE) | (((unsigned long)IoMem_ReadByte(0xff8260)&0x3)<<16);
1.1 root 432: }
433:
1.1.1.2 root 434:
435: /*-----------------------------------------------------------------------*/
1.1 root 436: /*
437: Store resolution on each line(used to test if mixed low/medium resolutions)
438: */
1.1.1.7 root 439: static void Video_StoreResolution(int y)
1.1 root 440: {
1.1.1.2 root 441: /* Clear resolution, and set with current value */
1.1.1.8 ! root 442: if (!(bUseHighRes || bUseVDIRes))
! 443: {
1.1 root 444: HBLPaletteMasks[y] &= ~(0x3<<16);
1.1.1.8 ! root 445: HBLPaletteMasks[y] |= ((unsigned long)IoMem_ReadByte(0xff8260)&0x3)<<16;
1.1 root 446: }
447: }
448:
1.1.1.2 root 449:
450: /*-----------------------------------------------------------------------*/
1.1 root 451: /*
452: Copy line of screen into buffer for conversion later.
453: Possible lines may be top/bottom border, and/or left/right borders
454: */
1.1.1.7 root 455: static void Video_CopyScreenLine(int BorderMask)
1.1 root 456: {
1.1.1.2 root 457: /* Only copy screen line if not doing high VDI resolution */
1.1 root 458: if (!bUseVDIRes) {
459: BorderMask |= LeftRightBorder;
460:
461: if (bUseHighRes) {
1.1.1.2 root 462: /* Copy for hi-res (no overscan) */
1.1.1.8 ! root 463: memcpy(pSTScreen, pVideoRaster, SCREENBYTES_MIDDLE);
! 464: pVideoRaster += SCREENBYTES_MIDDLE;
1.1.1.2 root 465: /* Each screen line copied to buffer is always same length */
1.1 root 466: pSTScreen += SCREENBYTES_MIDDLE;
467: }
468: else {
1.1.1.2 root 469: /* Is total blank line? Ie top/bottom border? */
1.1 root 470: if (BorderMask&(BORDERMASK_TOP|BORDERMASK_BOTTOM)) {
1.1.1.2 root 471: /* Clear line to colour '0' */
1.1 root 472: memset(pSTScreen,0,SCREENBYTES_LINE);
473: }
474: else {
1.1.1.2 root 475: /* Does have left border? If not, clear to colour '0' */
1.1 root 476: if (BorderMask&BORDERMASK_LEFT) {
1.1.1.8 ! root 477: pVideoRaster += 24-SCREENBYTES_LEFT;
! 478: memcpy(pSTScreen, pVideoRaster, SCREENBYTES_LEFT);
! 479: pVideoRaster += SCREENBYTES_LEFT;
1.1 root 480: }
481: else
482: memset(pSTScreen,0,SCREENBYTES_LEFT);
1.1.1.2 root 483: /* Copy middle - always present */
1.1.1.8 ! root 484: memcpy(pSTScreen+SCREENBYTES_LEFT, pVideoRaster, SCREENBYTES_MIDDLE);
! 485: pVideoRaster += SCREENBYTES_MIDDLE;
1.1.1.2 root 486: /* Does have right border? If not, clear to colour '0' */
1.1 root 487: if (BorderMask&BORDERMASK_RIGHT) {
1.1.1.8 ! root 488: memcpy(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE, pVideoRaster, SCREENBYTES_RIGHT);
! 489: pVideoRaster += 46-SCREENBYTES_RIGHT;
! 490: pVideoRaster += SCREENBYTES_RIGHT;
1.1 root 491: }
492: else
493: memset(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE,0,SCREENBYTES_RIGHT);
494: }
1.1.1.6 root 495:
1.1.1.2 root 496: /* Each screen line copied to buffer is always same length */
1.1 root 497: pSTScreen += SCREENBYTES_LINE;
498: }
499: }
500: }
501:
1.1.1.2 root 502:
503: /*-----------------------------------------------------------------------*/
1.1 root 504: /*
505: Copy extended GEM resolution screen
506: */
507: void Video_CopyVDIScreen(void)
508: {
1.1.1.2 root 509: /* Copy whole screen, don't care about being exact as for GEM only */
1.1.1.8 ! root 510: memcpy(pSTScreen, pVideoRaster, ((VDIWidth*VDIPlanes)/8)*VDIHeight); /* 640x400x16colour */
1.1 root 511: }
512:
1.1.1.2 root 513:
514: /*-----------------------------------------------------------------------*/
1.1 root 515: /*
516: Check at end of each HBL to see if any Sync/Shifter hardware tricks have been attempted
517: */
518: void Video_EndHBL(void)
519: {
1.1.1.2 root 520: /* Are we in possible visible display (including borders)? */
1.1 root 521: if ( (nHBL>=FIRST_VISIBLE_HBL) && (nHBL<(FIRST_VISIBLE_HBL+NUM_VISIBLE_LINES)) ) {
1.1.1.2 root 522: /* Copy line of screen to buffer to simulate TV raster trace - required for mouse cursor display/game updates */
523: /* Eg, Lemmings and The Killing Game Show are good examples */
1.1 root 524:
1.1.1.2 root 525: if (nHBL<nStartHBL) /* Are we in top border blank (ie no top overscan enabled) */
1.1 root 526: Video_CopyScreenLine(BORDERMASK_TOP);
1.1.1.2 root 527: else if (nHBL>=nEndHBL) /* Are we in bottom border blank */
1.1 root 528: Video_CopyScreenLine(BORDERMASK_BOTTOM);
1.1.1.2 root 529: else /* Must be in visible screen(including overscan), ignore left/right borders for now */
1.1 root 530: Video_CopyScreenLine(BORDERMASK_NONE);
531:
1.1.1.2 root 532: if (nHBL==FIRST_VISIBLE_HBL) { /* Very first line on screen - HBLPalettes[0] */
533: /* Store ALL palette for this line into raster table for datum */
1.1 root 534: Video_StoreFirstLinePalette();
535: }
1.1.1.2 root 536: /* Store resolution for every line so can check for mix low/medium screens */
1.1 root 537: Video_StoreResolution(nHBL-FIRST_VISIBLE_HBL);
538: }
539:
1.1.1.2 root 540: /* Finally increase HBL count */
1.1 root 541: nHBL++;
542:
1.1.1.2 root 543: Video_StartHBL(); /* Setup next one */
1.1 root 544: }
545:
1.1.1.2 root 546:
547: /* Clear raster line table to store changes in palette/resolution on a line basic */
548: /* Call once on VBL interrupt */
1.1 root 549: void Video_SetScreenRasters(void)
550: {
551: pHBLPaletteMasks = HBLPaletteMasks;
552: pHBLPalettes = HBLPalettes;
1.1.1.8 ! root 553: memset(pHBLPaletteMasks, 0, sizeof(unsigned long)*NUM_VISIBLE_LINES); /* Clear array */
1.1 root 554: }
555:
1.1.1.2 root 556:
557: /*-----------------------------------------------------------------------*/
1.1 root 558: /*
559: Set pointers to HBLPalette tables to store correct colours/resolutions
560: */
561: void Video_SetHBLPaletteMaskPointers(void)
562: {
563: int FrameCycles;
564: int Line;
565:
566: /* Top of standard screen is 64 lines from VBL(64x512=32768 cycles) */
567: /* Each line is 64+320+64+64(Blank) = 512 pixels per scan line */
568: /* Timer occurs at end of 64+320+64; Display Enable(DE)=Low */
569: /* HBL is incorrect on machine and occurs around 96+ cycles in */
570:
571: /* Top of standard screen is 64 lines from VBL(64x512=32768 cycles) */
572: /* Each line is 96 + 320 + 96 = 512 pixels per scan line(each pixel is one cycle) */
573: FrameCycles = Int_FindFrameCycles();
574:
575: /* Find 'line' into palette - screen starts 64 lines down, less 28 for top overscan */
576: /* And if write to last 96 cycle of line it will count as the NEXT line(needed else games may flicker) */
577: Line = (FrameCycles-(FIRST_VISIBLE_HBL*CYCLES_PER_LINE)+SCREEN_START_CYCLE)/CYCLES_PER_LINE;
578: if (Line<0) /* Limit to top/bottom of possible visible screen */
579: Line = 0;
580: if (Line>=NUM_VISIBLE_LINES)
581: Line = NUM_VISIBLE_LINES-1;
582:
1.1.1.2 root 583: /* Store pointers */
1.1 root 584: pHBLPaletteMasks = &HBLPaletteMasks[Line]; /* Next mask entry */
585: pHBLPalettes = &HBLPalettes[16*Line]; /* Next colour raster list x16 colours */
586: }
1.1.1.8 ! root 587:
! 588:
! 589:
! 590: /*-----------------------------------------------------------------------*/
! 591: /*
! 592: Read video address counter high byte (0xff8205)
! 593: */
! 594: void Video_ScreenCounterHigh_ReadByte(void)
! 595: {
! 596: IoMem[0xff8205] = Video_CalculateAddress() >> 16; /* Get video address counter high byte */
! 597: }
! 598:
! 599: /*-----------------------------------------------------------------------*/
! 600: /*
! 601: Read video address counter med byte (0xff8207)
! 602: */
! 603: void Video_ScreenCounterMed_ReadByte(void)
! 604: {
! 605: IoMem[0xff8207] = Video_CalculateAddress() >> 8; /* Get video address counter med byte */
! 606: }
! 607:
! 608: /*-----------------------------------------------------------------------*/
! 609: /*
! 610: Read video address counter low byte (0xff8209)
! 611: */
! 612: void Video_ScreenCounterLow_ReadByte(void)
! 613: {
! 614: IoMem[0xff8209] = Video_CalculateAddress(); /* Get video address counter low byte */
! 615: }
! 616:
! 617:
! 618: /*-----------------------------------------------------------------------*/
! 619: /*
! 620: Read video sync register (0xff820a)
! 621: */
! 622: void Video_Sync_ReadByte(void)
! 623: {
! 624: /* Nothing... */
! 625: }
! 626:
! 627: /*-----------------------------------------------------------------------*/
! 628: /*
! 629: Read video base address low byte (0xff820d). A plain ST can only store
! 630: screen addresses rounded to 256 bytes (i.e. no lower byte).
! 631: */
! 632: void Video_BaseLow_ReadByte(void)
! 633: {
! 634: if (ConfigureParams.System.nMachineType == MACHINE_ST)
! 635: IoMem[0xff820d] = 0;
! 636: }
! 637:
! 638: /*-----------------------------------------------------------------------*/
! 639: /*
! 640: Read video line width register (0xff820f)
! 641: */
! 642: void Video_LineWidth_ReadByte(void)
! 643: {
! 644: IoMem[0xff820f] = 0; /* On ST this is always 0 */
! 645: }
! 646:
! 647: /*-----------------------------------------------------------------------*/
! 648: /*
! 649: Read video shifter mode register (0xff8260)
! 650: */
! 651: void Video_ShifterMode_ReadByte(void)
! 652: {
! 653: if (bUseHighRes)
! 654: IoMem[0xff8260] = 2; /* If mono monitor, force to high resolution */
! 655: else
! 656: IoMem[0xff8260] = VideoShifterByte; /* Read shifter register */
! 657: }
! 658:
! 659:
! 660:
! 661: /*-----------------------------------------------------------------------*/
! 662: /*
! 663: Write to video shifter palette registers (0xff8240-0xff825e)
! 664: */
! 665: static void Video_ColorReg_WriteWord(Uint32 addr)
! 666: {
! 667: if (!bUseHighRes) /* Don't store if hi-res */
! 668: {
! 669: Uint16 col;
! 670: Video_SetHBLPaletteMaskPointers(); /* Set 'pHBLPalettes' etc.. according cycles into frame */
! 671: col = IoMem_ReadWord(addr);
! 672: col &= 0x777; /* Mask off to 512 palette */
! 673: IoMem_WriteWord(addr, col); /* (some games write 0xFFFF and read back to see if STe) */
! 674: Spec512_StoreCyclePalette(col, addr); /* Store colour into CyclePalettes[] */
! 675: pHBLPalettes[(addr-0xff8240)/2] = col; /* Set colour x */
! 676: *pHBLPaletteMasks |= 1 << ((addr-0xff8240)/2); /* And mask */
! 677: }
! 678: }
! 679:
! 680: void Video_Color0_WriteWord(void)
! 681: {
! 682: Video_ColorReg_WriteWord(0xff8240);
! 683: }
! 684:
! 685: void Video_Color1_WriteWord(void)
! 686: {
! 687: Video_ColorReg_WriteWord(0xff8242);
! 688: }
! 689:
! 690: void Video_Color2_WriteWord(void)
! 691: {
! 692: Video_ColorReg_WriteWord(0xff8244);
! 693: }
! 694:
! 695: void Video_Color3_WriteWord(void)
! 696: {
! 697: Video_ColorReg_WriteWord(0xff8246);
! 698: }
! 699:
! 700: void Video_Color4_WriteWord(void)
! 701: {
! 702: Video_ColorReg_WriteWord(0xff8248);
! 703: }
! 704:
! 705: void Video_Color5_WriteWord(void)
! 706: {
! 707: Video_ColorReg_WriteWord(0xff824a);
! 708: }
! 709:
! 710: void Video_Color6_WriteWord(void)
! 711: {
! 712: Video_ColorReg_WriteWord(0xff824c);
! 713: }
! 714:
! 715: void Video_Color7_WriteWord(void)
! 716: {
! 717: Video_ColorReg_WriteWord(0xff824e);
! 718: }
! 719:
! 720: void Video_Color8_WriteWord(void)
! 721: {
! 722: Video_ColorReg_WriteWord(0xff8250);
! 723: }
! 724:
! 725: void Video_Color9_WriteWord(void)
! 726: {
! 727: Video_ColorReg_WriteWord(0xff8252);
! 728: }
! 729:
! 730: void Video_Color10_WriteWord(void)
! 731: {
! 732: Video_ColorReg_WriteWord(0xff8254);
! 733: }
! 734:
! 735: void Video_Color11_WriteWord(void)
! 736: {
! 737: Video_ColorReg_WriteWord(0xff8256);
! 738: }
! 739:
! 740: void Video_Color12_WriteWord(void)
! 741: {
! 742: Video_ColorReg_WriteWord(0xff8258);
! 743: }
! 744:
! 745: void Video_Color13_WriteWord(void)
! 746: {
! 747: Video_ColorReg_WriteWord(0xff825a);
! 748: }
! 749:
! 750: void Video_Color14_WriteWord(void)
! 751: {
! 752: Video_ColorReg_WriteWord(0xff825c);
! 753: }
! 754:
! 755: void Video_Color15_WriteWord(void)
! 756: {
! 757: Video_ColorReg_WriteWord(0xff825e);
! 758: }
! 759:
! 760:
! 761: /*-----------------------------------------------------------------------*/
! 762: /*
! 763: Write video shifter mode register (0xff860)
! 764: */
! 765: void Video_ShifterMode_WriteByte(void)
! 766: {
! 767: if (!bUseHighRes && !bUseVDIRes) /* Don't store if hi-res and don't store if VDI resolution */
! 768: {
! 769: VideoShifterByte = IoMem[0xff8260] & 3; /* We only care for lower 2-bits */
! 770: Video_WriteToShifter(VideoShifterByte);
! 771: Video_SetHBLPaletteMaskPointers();
! 772: *pHBLPaletteMasks &= 0xff00ffff;
! 773: /* Store resolution after palette mask and set resolution write bit: */
! 774: *pHBLPaletteMasks |= (((unsigned long)VideoShifterByte|0x04)<<16);
! 775: }
! 776: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.