|
|
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.10! root 12: const char Video_rcsid[] = "Hatari $Id: video.c,v 1.52 2006/08/09 08:14:24 eerot Exp $";
1.1 root 13:
1.1.1.7 root 14: #include <SDL_endian.h>
1.1.1.4 root 15:
1.1 root 16: #include "main.h"
1.1.1.6 root 17: #include "configuration.h"
1.1.1.10! root 18: #include "cycles.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.9 root 37: #define BORDERMASK_NONE 0x00 /* Borders masks */
38: #define BORDERMASK_LEFT 0x01
39: #define BORDERMASK_RIGHT 0x02
1.1.1.10! root 40: #define BORDERMASK_MIDDLE 0x04
1.1.1.9 root 41:
42:
1.1.1.2 root 43: BOOL bUseHighRes = FALSE; /* Use hi-res (ie Mono monitor) */
1.1 root 44: int nVBLs, nHBL; /* VBL Counter, HBL line */
1.1.1.10! root 45: int nStartHBL, nEndHBL; /* Start/End HBL for visible screen */
1.1 root 46: int OverscanMode; /* OVERSCANMODE_xxxx for current display frame */
1.1.1.8 root 47: Uint16 HBLPalettes[(NUM_VISIBLE_LINES+1)*16]; /* 1x16 colour palette per screen line, +1 line just incase write after line 200 */
48: Uint16 *pHBLPalettes; /* Pointer to current palette lists, one per HBL */
1.1.1.9 root 49: Uint32 HBLPaletteMasks[NUM_VISIBLE_LINES+1]; /* Bit mask of palette colours changes, top bit set is resolution change */
50: Uint32 *pHBLPaletteMasks;
1.1.1.6 root 51: int nScreenRefreshRate = 50; /* 50 or 60 Hz in color, 70 Hz in mono */
1.1.1.8 root 52: Uint32 VideoBase; /* Base address in ST Ram for screen (read on each VBL) */
1.1.1.9 root 53:
1.1.1.10! root 54: int nScanlinesPerFrame = 313; /* Number of scan lines per frame */
! 55: int nCyclesPerLine = 512; /* Cycles per horizontal line scan */
! 56: static int nFirstVisibleHbl = 34; /* The first line of the ST screen that is copied to the PC screen buffer */
! 57:
1.1.1.9 root 58: static Uint8 HWScrollCount; /* HW scroll pixel offset, STe only (0...15) */
59: static Uint8 ScanLineSkip; /* Scan line width add, STe only (words, minus 1) */
1.1.1.8 root 60: static Uint8 *pVideoRaster; /* Pointer to Video raster, after VideoBase in PC address space. Use to copy data on HBL */
61: static Uint8 VideoShifterByte; /* VideoShifter (0xff8260) value store in video chip */
62: static int LeftRightBorder; /* BORDERMASK_xxxx used to simulate left/right border removal */
1.1.1.10! root 63: static int nLastAccessCycleLeft; /* Line cycle where program tried to open left border */
! 64: static BOOL bSteBorderFlag; /* TRUE when screen width has been switched to 336 (e.g. in Obsession) */
1.1 root 65:
66:
67: /*-----------------------------------------------------------------------*/
68: /*
69: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
70: */
71: void Video_MemorySnapShot_Capture(BOOL bSave)
72: {
73: /* Save/Restore details */
74: MemorySnapShot_Store(&VideoShifterByte,sizeof(VideoShifterByte));
75: MemorySnapShot_Store(&bUseHighRes,sizeof(bUseHighRes));
76: MemorySnapShot_Store(&nVBLs,sizeof(nVBLs));
77: MemorySnapShot_Store(&nHBL,sizeof(nHBL));
78: MemorySnapShot_Store(&nStartHBL,sizeof(nStartHBL));
79: MemorySnapShot_Store(&nEndHBL,sizeof(nEndHBL));
80: MemorySnapShot_Store(&OverscanMode,sizeof(OverscanMode));
81: MemorySnapShot_Store(HBLPalettes,sizeof(HBLPalettes));
82: MemorySnapShot_Store(HBLPaletteMasks,sizeof(HBLPaletteMasks));
83: MemorySnapShot_Store(&VideoBase,sizeof(VideoBase));
1.1.1.9 root 84: MemorySnapShot_Store(&ScanLineSkip,sizeof(ScanLineSkip));
85: MemorySnapShot_Store(&HWScrollCount,sizeof(HWScrollCount));
1.1.1.8 root 86: MemorySnapShot_Store(&pVideoRaster,sizeof(pVideoRaster));
1.1.1.10! root 87: MemorySnapShot_Store(&nScanlinesPerFrame, sizeof(nScanlinesPerFrame));
! 88: MemorySnapShot_Store(&nCyclesPerLine, sizeof(nCyclesPerLine));
! 89: MemorySnapShot_Store(&nFirstVisibleHbl, sizeof(nFirstVisibleHbl));
! 90: MemorySnapShot_Store(&bSteBorderFlag, sizeof(bSteBorderFlag));
1.1 root 91: }
92:
1.1.1.8 root 93:
1.1 root 94: /*-----------------------------------------------------------------------*/
95: /*
1.1.1.8 root 96: Calculate and return video address pointer.
1.1 root 97: */
1.1.1.8 root 98: static Uint32 Video_CalculateAddress(void)
1.1 root 99: {
1.1.1.9 root 100: int X, FrameCycles;
101: Uint32 VideoAddress; /* Address of video display in ST screen space */
1.1 root 102:
103: /* Find number of cycles passed during frame */
1.1.1.10! root 104: FrameCycles = Cycles_GetCounterOnReadAccess(CYCLES_COUNTER_VIDEO);
1.1 root 105:
1.1.1.10! root 106: /* Top of screen is usually 63 lines from VBL in 50 Hz */
! 107: if (FrameCycles < nStartHBL*nCyclesPerLine)
1.1.1.8 root 108: {
1.1.1.9 root 109: VideoAddress = VideoBase;
1.1.1.8 root 110: }
111: else
112: {
1.1.1.9 root 113: /* Now find which pixel we are on (ignore left/right borders) */
114: /* 96 + 320 + 96 = 512 pixels per scan line (each pixel is one cycle) */
1.1.1.10! root 115: X = FrameCycles % nCyclesPerLine;
1.1.1.9 root 116: if (X < SCREEN_START_CYCLE) /* Limit if in NULL area outside screen */
1.1 root 117: X = SCREEN_START_CYCLE;
1.1.1.10! root 118: if (X > (nCyclesPerLine - SCREEN_START_CYCLE))
! 119: X = (nCyclesPerLine - SCREEN_START_CYCLE);
1.1.1.9 root 120: /* X is now from 96 to 416 (320 pixels), subtract 96 to give X pixel across screen! */
1.1 root 121: X = ((X-SCREEN_START_CYCLE)>>1)&(~1);
1.1.1.6 root 122:
1.1.1.9 root 123: VideoAddress = pVideoRaster - STRam;
124: /* Add line cycles if we have not reached end of screen yet: */
1.1.1.10! root 125: if (FrameCycles < nEndHBL*nCyclesPerLine)
1.1.1.9 root 126: VideoAddress += X;
1.1 root 127: }
128:
1.1.1.8 root 129: return VideoAddress;
1.1 root 130: }
131:
1.1.1.7 root 132:
1.1 root 133: /*-----------------------------------------------------------------------*/
134: /*
135: HBL interrupt - this is very inaccurate on ST and appears to occur around 1/3rd way into
136: the display!
137: */
138: void Video_InterruptHandler_HBL(void)
139: {
1.1.1.2 root 140: /* Remove this interrupt from list and re-order */
1.1 root 141: Int_AcknowledgeInterrupt();
1.1.1.7 root 142:
1.1.1.10! root 143: /* Generate new HBL, if need to - there are 313 HBLs per frame in 50 Hz */
! 144: if (nHBL < nScanlinesPerFrame-1)
! 145: Int_AddAbsoluteInterrupt(nCyclesPerLine, INTERRUPT_VIDEO_HBL);
1.1 root 146:
1.1.1.7 root 147: M68000_Exception(EXCEPTION_HBLANK); /* Horizontal blank interrupt, level 2! */
1.1 root 148: }
149:
150:
1.1.1.2 root 151: /*-----------------------------------------------------------------------*/
1.1 root 152: /*
1.1.1.7 root 153: Write to VideoShifter (0xff8260), resolution bits
1.1 root 154: */
1.1.1.9 root 155: static void Video_WriteToShifter(Uint8 Byte)
1.1 root 156: {
1.1.1.7 root 157: static int nLastHBL = -1, LastByte, nLastCycles;
158: int nFrameCycles, nLineCycles;
159:
1.1.1.10! root 160: nFrameCycles = Cycles_GetCounterOnWriteAccess(CYCLES_COUNTER_VIDEO);
1.1 root 161:
1.1.1.7 root 162: /* We only care for cycle position in the actual screen line */
1.1.1.10! root 163: nLineCycles = nFrameCycles % nCyclesPerLine;
1.1 root 164:
1.1.1.7 root 165: /*fprintf(stderr,"Shifter=0x%2.2X %d (%d) @ %d\n",
166: Byte, nFrameCycles, nLineCycles, nHBL);*/
1.1 root 167:
1.1.1.7 root 168: /* Check if program tries to open left border.
169: * FIXME: This is a very inaccurate test that should be improved,
170: * but we probably need better CPU cycles emulation first. There's
171: * also no support for sync-scrolling yet :-( */
172: if (nHBL == nLastHBL && LastByte == 0x02 && Byte == 0x00
173: && nLineCycles <= 48 && nLineCycles-nLastCycles <= 16)
174: {
175: LeftRightBorder |= BORDERMASK_LEFT;
1.1.1.10! root 176: nLastAccessCycleLeft = nLineCycles;
1.1.1.7 root 177: }
1.1.1.2 root 178:
1.1.1.7 root 179: nLastHBL = nHBL;
180: LastByte = Byte;
181: nLastCycles = nLineCycles;
1.1 root 182: }
183:
1.1.1.2 root 184:
185: /*-----------------------------------------------------------------------*/
1.1 root 186: /*
1.1.1.7 root 187: Write to VideoSync (0xff820a), Hz setting
1.1 root 188: */
1.1.1.8 root 189: void Video_Sync_WriteByte(void)
1.1 root 190: {
1.1.1.7 root 191: static int nLastHBL = -1, LastByte, nLastCycles;
192: int nFrameCycles, nLineCycles;
1.1.1.8 root 193: Uint8 Byte;
194:
1.1.1.9 root 195: /* Note: We're only interested in lower 2 bits (50/60Hz) */
196: Byte = IoMem[0xff820a] & 3;
1.1.1.8 root 197:
1.1.1.10! root 198: nFrameCycles = Cycles_GetCounterOnWriteAccess(CYCLES_COUNTER_VIDEO);
1.1 root 199:
1.1.1.7 root 200: /* We only care for cycle position in the actual screen line */
1.1.1.10! root 201: nLineCycles = nFrameCycles % nCyclesPerLine;
1.1.1.2 root 202:
1.1.1.7 root 203: /*fprintf(stderr,"Sync=0x%2.2X %d (%d) @ %d\n",
204: Byte, nFrameCycles, nLineCycles, nHBL);*/
1.1 root 205:
1.1.1.7 root 206: /* Check if program tries to open a border.
207: * FIXME: These are very inaccurate tests that should be improved,
208: * but we probably need better CPU cycles emulation first. There's
209: * also no support for sync-scrolling yet :-( */
1.1.1.10! root 210: if (LastByte == 0x02 && Byte == 0x00) /* switched from 50 Hz to 60 Hz? */
1.1.1.7 root 211: {
1.1.1.10! root 212: if (nHBL >= SCREEN_START_HBL_60HZ-1 && nHBL <= SCREEN_START_HBL_60HZ+1)
1.1.1.7 root 213: {
214: /* Top border */
215: OverscanMode |= OVERSCANMODE_TOP; /* Set overscan bit */
1.1.1.10! root 216: nStartHBL = SCREEN_START_HBL_60HZ; /* New start screen line */
1.1.1.7 root 217: pHBLPaletteMasks -= OVERSCAN_TOP;
218: pHBLPalettes -= OVERSCAN_TOP;
1.1 root 219: }
1.1.1.10! root 220: else if (nHBL == SCREEN_START_HBL_50HZ+SCREEN_HEIGHT_HBL)
1.1.1.7 root 221: {
222: /* Bottom border */
223: OverscanMode |= OVERSCANMODE_BOTTOM; /* Set overscan bit */
1.1.1.10! root 224: nEndHBL = SCREEN_START_HBL_50HZ+SCREEN_HEIGHT_HBL+OVERSCAN_BOTTOM; /* New end screen line */
1.1 root 225: }
1.1.1.10! root 226: }
1.1 root 227:
1.1.1.10! root 228: if (LastByte == 0x00 && Byte == 0x02) /* switched from 60 Hz to 50 Hz? */
! 229: {
1.1.1.7 root 230: if (nHBL == nLastHBL && nLineCycles >= 400 && nLineCycles <= 480
231: && nLineCycles-nLastCycles <= 16)
232: {
233: /* Right border */
1.1.1.10! root 234: //fprintf(stderr,"Right sync: %i - %i = %i\n", nLineCycles, nLastAccessCycleLeft, nLineCycles - nLastAccessCycleLeft);
! 235: if (nLineCycles - nLastAccessCycleLeft == 368)
! 236: {
! 237: LeftRightBorder |= BORDERMASK_MIDDLE; /* Program tries to shorten line by 2 bytes */
! 238: }
! 239: else
! 240: {
! 241: LeftRightBorder |= BORDERMASK_RIGHT; /* Program tries to open right border */
! 242: }
1.1.1.7 root 243: }
1.1 root 244: }
245:
1.1.1.7 root 246: nLastHBL = nHBL;
247: LastByte = Byte;
248: nLastCycles = nLineCycles;
1.1 root 249: }
250:
1.1.1.2 root 251:
252: /*-----------------------------------------------------------------------*/
1.1 root 253: /*
254: Reset Sync/Shifter table at start of each HBL
255: */
1.1.1.9 root 256: static void Video_StartHBL(void)
1.1 root 257: {
1.1.1.9 root 258: LeftRightBorder = BORDERMASK_NONE;
1.1 root 259: }
260:
1.1.1.2 root 261:
262: /*-----------------------------------------------------------------------*/
1.1 root 263: /*
264: Store whole palette on first line so have reference to work from
265: */
1.1.1.7 root 266: static void Video_StoreFirstLinePalette(void)
1.1 root 267: {
1.1.1.8 root 268: Uint16 *pp2;
1.1 root 269: int i;
270:
1.1.1.8 root 271: pp2 = (Uint16 *)&IoMem[0xff8240];
1.1 root 272: for(i=0; i<16; i++)
1.1.1.7 root 273: HBLPalettes[i] = SDL_SwapBE16(*pp2++);
1.1.1.2 root 274: /* And set mask flag with palette and resolution */
1.1.1.10! root 275: HBLPaletteMasks[0] = (PALETTEMASK_RESOLUTION|PALETTEMASK_PALETTE) | (((Uint32)IoMem_ReadByte(0xff8260)&0x3)<<16);
1.1 root 276: }
277:
1.1.1.2 root 278:
279: /*-----------------------------------------------------------------------*/
1.1 root 280: /*
281: Store resolution on each line(used to test if mixed low/medium resolutions)
282: */
1.1.1.7 root 283: static void Video_StoreResolution(int y)
1.1 root 284: {
1.1.1.2 root 285: /* Clear resolution, and set with current value */
1.1.1.8 root 286: if (!(bUseHighRes || bUseVDIRes))
287: {
1.1 root 288: HBLPaletteMasks[y] &= ~(0x3<<16);
1.1.1.10! root 289: HBLPaletteMasks[y] |= ((Uint32)IoMem_ReadByte(0xff8260)&0x3)<<16;
1.1 root 290: }
291: }
292:
1.1.1.2 root 293:
294: /*-----------------------------------------------------------------------*/
1.1 root 295: /*
1.1.1.9 root 296: Copy one line of monochrome screen into buffer for conversion later.
1.1 root 297: */
1.1.1.9 root 298: static void Video_CopyScreenLineMono(void)
1.1 root 299: {
1.1.1.9 root 300: int i;
1.1 root 301:
1.1.1.9 root 302: /* Since Hatari does not emulate monochrome HBLs correctly yet
303: * (only 200 are raised, just like in low resolution), we have to
304: * copy two lines each HBL to finally copy all 400 lines. */
305: for (i = 0; i < 2; i++)
306: {
307: /* Copy one line - 80 bytes in ST high resolution */
308: memcpy(pSTScreen, pVideoRaster, SCREENBYTES_MONOLINE);
309: pVideoRaster += SCREENBYTES_MONOLINE;
310:
311: /* Handle STE fine scrolling (HWScrollCount is zero on ST). */
312: if (HWScrollCount)
313: {
314: Uint16 *pScrollAdj;
315: int nNegScrollCnt;
316:
317: pScrollAdj = (Uint16 *)pSTScreen;
318: nNegScrollCnt = 16 - HWScrollCount;
319:
320: /* Shift the whole line by the given scroll count */
321: while ((Uint8*)pScrollAdj < pSTScreen + SCREENBYTES_MONOLINE-2)
322: {
323: do_put_mem_word(pScrollAdj, (do_get_mem_word(pScrollAdj) << HWScrollCount)
324: | (do_get_mem_word(pScrollAdj+1) >> nNegScrollCnt));
325: ++pScrollAdj;
326: }
327:
328: /* Handle the last 16 pixels of the line */
329: do_put_mem_word(pScrollAdj, (do_get_mem_word(pScrollAdj) << HWScrollCount)
330: | (do_get_mem_word(pVideoRaster) >> nNegScrollCnt));
331:
332: /* HW scrolling advances Shifter video counter by one */
333: pVideoRaster += 1 * 2;
334: }
335:
336: /* ScanLineSkip is zero on ST. */
337: /* On STE, the Shifter skips the given amount of words. */
338: pVideoRaster += ScanLineSkip*2;
339:
340: /* Each screen line copied to buffer is always same length */
341: pSTScreen += SCREENBYTES_MONOLINE;
342: }
343: }
344:
345:
346: /*-----------------------------------------------------------------------*/
347: /*
348: Copy one line of color screen into buffer for conversion later.
349: Possible lines may be top/bottom border, and/or left/right borders.
350: */
351: static void Video_CopyScreenLineColor(void)
352: {
353: /* Is total blank line? I.e. top/bottom border? */
354: if (nHBL < nStartHBL || nHBL >= nEndHBL)
355: {
356: /* Clear line to color '0' */
357: memset(pSTScreen, 0, SCREENBYTES_LINE);
358: }
359: else
360: {
361: /* Does have left border? If not, clear to color '0' */
362: if (LeftRightBorder & BORDERMASK_LEFT)
363: {
1.1.1.10! root 364: /* The "-2" in the following line is needed so that the offset is a multiple of 8 */
! 365: pVideoRaster += BORDERBYTES_LEFT-SCREENBYTES_LEFT-2;
1.1.1.9 root 366: memcpy(pSTScreen, pVideoRaster, SCREENBYTES_LEFT);
367: pVideoRaster += SCREENBYTES_LEFT;
368: }
369: else
370: memset(pSTScreen,0,SCREENBYTES_LEFT);
371:
372: /* Copy middle - always present */
373: memcpy(pSTScreen+SCREENBYTES_LEFT, pVideoRaster, SCREENBYTES_MIDDLE);
374: pVideoRaster += SCREENBYTES_MIDDLE;
375:
1.1.1.10! root 376: /* Does have right border? */
1.1.1.9 root 377: if (LeftRightBorder & BORDERMASK_RIGHT)
378: {
379: memcpy(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE, pVideoRaster, SCREENBYTES_RIGHT);
1.1.1.10! root 380: pVideoRaster += BORDERBYTES_RIGHT-SCREENBYTES_RIGHT;
1.1.1.9 root 381: pVideoRaster += SCREENBYTES_RIGHT;
382: }
1.1.1.10! root 383: else if (LeftRightBorder & BORDERMASK_MIDDLE)
! 384: {
! 385: /* Shortened line by 2 bytes? */
! 386: memset(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE-2, 0, SCREENBYTES_RIGHT+2);
! 387: pVideoRaster -= 2;
! 388: }
1.1.1.9 root 389: else
1.1.1.10! root 390: {
! 391: /* Simply clear right border to '0' */
1.1.1.9 root 392: memset(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE,0,SCREENBYTES_RIGHT);
1.1.1.10! root 393: }
1.1.1.9 root 394:
1.1.1.10! root 395: /* Correct the "-2" offset for pVideoRaster from BORDERMASK_LEFT above */
! 396: if (LeftRightBorder & BORDERMASK_LEFT)
! 397: pVideoRaster += 2;
! 398:
! 399: if (bSteBorderFlag)
! 400: {
! 401: memcpy(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE, pVideoRaster, 4*2);
! 402: pVideoRaster += 4 * 2;
! 403: }
! 404: else if (HWScrollCount) /* Handle STE fine scrolling (HWScrollCount is zero on ST) */
1.1.1.9 root 405: {
406: Uint16 *pScrollAdj; /* Pointer to actual position in line */
407: int nNegScrollCnt;
408: Uint16 *pScrollEndAddr; /* Pointer to end of the line */
409:
410: nNegScrollCnt = 16 - HWScrollCount;
411: if (LeftRightBorder & BORDERMASK_LEFT)
412: pScrollAdj = (Uint16 *)pSTScreen;
413: else
414: pScrollAdj = (Uint16 *)(pSTScreen + SCREENBYTES_LEFT);
415: if (LeftRightBorder & BORDERMASK_RIGHT)
416: pScrollEndAddr = (Uint16 *)(pSTScreen + SCREENBYTES_LINE - 8);
417: else
418: pScrollEndAddr = (Uint16 *)(pSTScreen + SCREENBYTES_LEFT + SCREENBYTES_MIDDLE - 8);
419:
420: if (STRes == ST_MEDIUM_RES)
421: {
422: /* TODO: Implement fine scrolling for medium resolution, too */
423: /* HW scrolling advances Shifter video counter by one */
424: pVideoRaster += 2 * 2;
1.1 root 425: }
1.1.1.9 root 426: else
427: {
428: /* Shift the whole line by the given scroll count */
429: while (pScrollAdj < pScrollEndAddr)
430: {
431: do_put_mem_word(pScrollAdj, (do_get_mem_word(pScrollAdj) << HWScrollCount)
432: | (do_get_mem_word(pScrollAdj+4) >> nNegScrollCnt));
433: ++pScrollAdj;
1.1 root 434: }
1.1.1.9 root 435: /* Handle the last 16 pixels of the line */
436: if (LeftRightBorder & BORDERMASK_RIGHT)
437: {
438: /* When right border is open, we have to deal with this ugly offset
439: * of 46-SCREENBYTES_RIGHT=30 - The demo "Mind rewind" is a good example */
440: do_put_mem_word(pScrollAdj+0, (do_get_mem_word(pScrollAdj+0) << HWScrollCount)
441: | (do_get_mem_word(pVideoRaster-30) >> nNegScrollCnt));
442: do_put_mem_word(pScrollAdj+1, (do_get_mem_word(pScrollAdj+1) << HWScrollCount)
443: | (do_get_mem_word(pVideoRaster-28) >> nNegScrollCnt));
444: do_put_mem_word(pScrollAdj+2, (do_get_mem_word(pScrollAdj+2) << HWScrollCount)
445: | (do_get_mem_word(pVideoRaster-26) >> nNegScrollCnt));
446: do_put_mem_word(pScrollAdj+3, (do_get_mem_word(pScrollAdj+3) << HWScrollCount)
447: | (do_get_mem_word(pVideoRaster-24) >> nNegScrollCnt));
1.1 root 448: }
449: else
1.1.1.9 root 450: {
451: do_put_mem_word(pScrollAdj+0, (do_get_mem_word(pScrollAdj+0) << HWScrollCount)
452: | (do_get_mem_word(pVideoRaster+0) >> nNegScrollCnt));
453: do_put_mem_word(pScrollAdj+1, (do_get_mem_word(pScrollAdj+1) << HWScrollCount)
454: | (do_get_mem_word(pVideoRaster+2) >> nNegScrollCnt));
455: do_put_mem_word(pScrollAdj+2, (do_get_mem_word(pScrollAdj+2) << HWScrollCount)
456: | (do_get_mem_word(pVideoRaster+4) >> nNegScrollCnt));
457: do_put_mem_word(pScrollAdj+3, (do_get_mem_word(pScrollAdj+3) << HWScrollCount)
458: | (do_get_mem_word(pVideoRaster+6) >> nNegScrollCnt));
459: }
460: /* HW scrolling advances Shifter video counter by one */
461: pVideoRaster += 4 * 2;
1.1 root 462: }
1.1.1.9 root 463: }
464:
465: /* ScanLineSkip is zero on ST. */
466: /* On STE, the Shifter skips the given amount of words. */
467: pVideoRaster += ScanLineSkip*2;
468: }
469:
470: /* Each screen line copied to buffer is always same length */
471: pSTScreen += SCREENBYTES_LINE;
472: }
473:
1.1.1.6 root 474:
1.1.1.9 root 475: /*-----------------------------------------------------------------------*/
476: /*
477: Copy line of screen into buffer for conversion later.
478: */
479: static void Video_CopyScreenLine(void)
480: {
481: /* Only copy screen line if not doing high VDI resolution */
482: if (!bUseVDIRes)
483: {
484: if (bUseHighRes)
485: {
486: /* Copy for hi-res (no overscan) */
487: Video_CopyScreenLineMono();
488: }
489: else
490: {
491: /* Copy for low and medium resolution */
492: Video_CopyScreenLineColor();
1.1 root 493: }
494: }
495: }
496:
1.1.1.2 root 497:
498: /*-----------------------------------------------------------------------*/
1.1 root 499: /*
500: Copy extended GEM resolution screen
501: */
1.1.1.9 root 502: static void Video_CopyVDIScreen(void)
1.1 root 503: {
1.1.1.2 root 504: /* Copy whole screen, don't care about being exact as for GEM only */
1.1.1.8 root 505: memcpy(pSTScreen, pVideoRaster, ((VDIWidth*VDIPlanes)/8)*VDIHeight); /* 640x400x16colour */
1.1 root 506: }
507:
1.1.1.2 root 508:
509: /*-----------------------------------------------------------------------*/
1.1 root 510: /*
511: Check at end of each HBL to see if any Sync/Shifter hardware tricks have been attempted
512: */
1.1.1.9 root 513: static void Video_EndHBL(void)
1.1 root 514: {
1.1.1.10! root 515: Uint8 nSyncByte = IoMem_ReadByte(0xff820a);
! 516:
! 517: /* Check if we need to open borders: If we are running basically in 50 Hz, but
! 518: * a program switched to 60 Hz at certain screen lines, we have to open the
! 519: * corresponding border. The "Level 16" fullscreen in the Union demo is a good example. */
! 520: if ((nSyncByte & 2) == 0)
! 521: {
! 522: if (nHBL == SCREEN_START_HBL_60HZ-1 && nStartHBL == SCREEN_START_HBL_50HZ)
! 523: {
! 524: /* Top border */
! 525: OverscanMode |= OVERSCANMODE_TOP; /* Set overscan bit */
! 526: nStartHBL = SCREEN_START_HBL_60HZ; /* New start screen line */
! 527: pHBLPaletteMasks -= OVERSCAN_TOP;
! 528: pHBLPalettes -= OVERSCAN_TOP;
! 529: }
! 530: else if (nHBL == SCREEN_START_HBL_50HZ+SCREEN_HEIGHT_HBL-1
! 531: && nEndHBL == SCREEN_START_HBL_50HZ+SCREEN_HEIGHT_HBL)
! 532: {
! 533: /* Bottom border */
! 534: OverscanMode |= OVERSCANMODE_BOTTOM; /* Set overscan bit */
! 535: nEndHBL = SCREEN_START_HBL_50HZ+SCREEN_HEIGHT_HBL+OVERSCAN_BOTTOM; /* New end screen line */
! 536: }
! 537: }
! 538:
1.1.1.2 root 539: /* Are we in possible visible display (including borders)? */
1.1.1.10! root 540: if (nHBL >= nFirstVisibleHbl && nHBL < nFirstVisibleHbl+NUM_VISIBLE_LINES)
1.1.1.9 root 541: {
542: /* Copy line of screen to buffer to simulate TV raster trace
543: * - required for mouse cursor display/game updates
544: * Eg, Lemmings and The Killing Game Show are good examples */
545: Video_CopyScreenLine();
1.1 root 546:
1.1.1.10! root 547: if (nHBL == nFirstVisibleHbl) /* Very first line on screen - HBLPalettes[0] */
1.1.1.9 root 548: {
1.1.1.2 root 549: /* Store ALL palette for this line into raster table for datum */
1.1 root 550: Video_StoreFirstLinePalette();
551: }
1.1.1.2 root 552: /* Store resolution for every line so can check for mix low/medium screens */
1.1.1.10! root 553: Video_StoreResolution(nHBL-nFirstVisibleHbl);
1.1 root 554: }
555:
1.1.1.2 root 556: /* Finally increase HBL count */
1.1 root 557: nHBL++;
558:
1.1.1.2 root 559: Video_StartHBL(); /* Setup next one */
1.1 root 560: }
561:
1.1.1.2 root 562:
1.1.1.9 root 563: /*-----------------------------------------------------------------------*/
564: /*
565: End Of Line interrupt
566: As this occurs at the end of a line we cannot get timing for START of first
567: line (as in Spectrum 512)
568: */
569: void Video_InterruptHandler_EndLine(void)
570: {
571: /* Remove this interrupt from list and re-order */
572: Int_AcknowledgeInterrupt();
573: /* Generate new HBL, if need to - there are 313 HBLs per frame */
1.1.1.10! root 574: if (nHBL < nScanlinesPerFrame-1)
! 575: Int_AddAbsoluteInterrupt(nCyclesPerLine, INTERRUPT_VIDEO_ENDLINE);
1.1.1.9 root 576:
577: /* Is this a good place to send the keyboard packets? Done once per frame */
578: if (nHBL == nStartHBL)
579: {
580: /* On each VBL send automatic keyboard packets for mouse, joysticks etc... */
581: IKBD_SendAutoKeyboardCommands();
582: }
583:
584: /* Timer A/B occur at END of first visible screen line in Event Count mode */
585: if (nHBL >= nStartHBL && nHBL < nEndHBL)
586: {
587: /* Handle Timers A and B when using Event Count mode(timer taken from HBL) */
588: // FIXME: Really raise Timer A here?
589: // if (MFP_TACR==0x08) /* Is timer in Event Count mode? */
590: // MFP_TimerA_EventCount_Interrupt();
591: if (MFP_TBCR==0x08) /* Is timer in Event Count mode? */
592: MFP_TimerB_EventCount_Interrupt();
593: }
594:
595: FDC_UpdateHBL(); /* Update FDC motion */
596: Video_EndHBL(); /* Increase HBL count, copy line to display buffer and do any video trickery */
597:
598: /* If we don't often pump data into the event queue, the SDL misses events... grr... */
599: if (!(nHBL & 63))
600: {
601: Main_EventHandler();
602: }
603: }
604:
605:
606: /*-----------------------------------------------------------------------*/
607: /*
608: Clear raster line table to store changes in palette/resolution on a line
609: basic. Called once on VBL interrupt.
610: */
1.1 root 611: void Video_SetScreenRasters(void)
612: {
613: pHBLPaletteMasks = HBLPaletteMasks;
614: pHBLPalettes = HBLPalettes;
1.1.1.9 root 615: memset(pHBLPaletteMasks, 0, sizeof(Uint32)*NUM_VISIBLE_LINES); /* Clear array */
1.1 root 616: }
617:
1.1.1.2 root 618:
619: /*-----------------------------------------------------------------------*/
1.1 root 620: /*
621: Set pointers to HBLPalette tables to store correct colours/resolutions
622: */
1.1.1.9 root 623: static void Video_SetHBLPaletteMaskPointers(void)
1.1 root 624: {
625: int FrameCycles;
626: int Line;
627:
1.1.1.10! root 628: /* Top of standard screen is 63 lines from VBL (in 50 Hz) */
! 629: /* Each line is 64+320+64+64(Blank) = 512 pixels per scan line */
! 630: /* Timer occurs at end of 64+320+64; Display Enable(DE)=Low */
! 631: /* HBL is incorrect on machine and occurs around 96+ cycles in */
! 632:
! 633: FrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1 root 634:
1.1.1.10! root 635: /* Find 'line' into palette - screen starts 63 lines down, less 29 for top overscan */
1.1 root 636: /* And if write to last 96 cycle of line it will count as the NEXT line(needed else games may flicker) */
1.1.1.10! root 637: Line = (FrameCycles-(nFirstVisibleHbl*nCyclesPerLine)+SCREEN_START_CYCLE)/nCyclesPerLine;
1.1 root 638: if (Line<0) /* Limit to top/bottom of possible visible screen */
639: Line = 0;
640: if (Line>=NUM_VISIBLE_LINES)
641: Line = NUM_VISIBLE_LINES-1;
642:
1.1.1.2 root 643: /* Store pointers */
1.1 root 644: pHBLPaletteMasks = &HBLPaletteMasks[Line]; /* Next mask entry */
645: pHBLPalettes = &HBLPalettes[16*Line]; /* Next colour raster list x16 colours */
646: }
1.1.1.8 root 647:
648:
1.1.1.9 root 649: /*-----------------------------------------------------------------------*/
650: /*
1.1.1.10! root 651: Set video shifter timing variables according to screen refresh rate
! 652: */
! 653: static void Video_ResetShifterTimings(void)
! 654: {
! 655: Uint8 nSyncByte;
! 656:
! 657: nSyncByte = IoMem_ReadByte(0xff820a);
! 658:
! 659: /* Check if running in 50 Hz or in 60 Hz */
! 660: if (nSyncByte & 2)
! 661: {
! 662: /* 50 Hz */
! 663: nStartHBL = SCREEN_START_HBL_50HZ;
! 664: nScanlinesPerFrame = SCANLINES_PER_FRAME_50HZ;
! 665: nCyclesPerLine = CYCLES_PER_LINE_50HZ;
! 666: nFirstVisibleHbl = FIRST_VISIBLE_HBL_50HZ;
! 667: }
! 668: else
! 669: {
! 670: /* 60 Hz */
! 671: nStartHBL = SCREEN_START_HBL_60HZ;
! 672: nScanlinesPerFrame = SCANLINES_PER_FRAME_60HZ;
! 673: nCyclesPerLine = CYCLES_PER_LINE_60HZ;
! 674: nFirstVisibleHbl = FIRST_VISIBLE_HBL_60HZ;
! 675: }
! 676:
! 677: nEndHBL = nStartHBL + SCREEN_HEIGHT_HBL;
! 678:
! 679: /* Set the screen refresh rate */
! 680: #if 0
! 681: if(bUseHighRes)
! 682: nScreenRefreshRate = 70;
! 683: else if (nSyncByte & 2) /* Is it 50Hz or is it 60Hz? */
! 684: nScreenRefreshRate = 50;
! 685: else
! 686: nScreenRefreshRate = 60;
! 687: #endif
! 688: }
! 689:
! 690:
! 691: /*-----------------------------------------------------------------------*/
! 692: /*
1.1.1.9 root 693: Called on VBL, set registers ready for frame
694: */
695: static void Video_ClearOnVBL(void)
696: {
697: /* New screen, so first HBL */
698: nHBL = 0;
699: OverscanMode = OVERSCANMODE_NONE;
700:
1.1.1.10! root 701: Video_ResetShifterTimings();
! 702:
1.1.1.9 root 703: /* Get screen address pointer, aligned to 256 bytes on ST (ie ignore lowest byte) */
1.1.1.10! root 704: VideoBase = (Uint32)IoMem_ReadByte(0xff8201)<<16 | (Uint32)IoMem_ReadByte(0xff8203)<<8;
1.1.1.9 root 705: if (ConfigureParams.System.nMachineType != MACHINE_ST)
706: {
707: /* on STe 2 aligned, on Falcon 4 aligned, on TT 8 aligned. We do STe. */
1.1.1.10! root 708: VideoBase |= IoMem_ReadByte(0xff820d) & ~1;
1.1.1.9 root 709: }
710: pVideoRaster = &STRam[VideoBase];
711: pSTScreen = pFrameBuffer->pSTScreen;
712:
713: Video_StartHBL();
714: Video_SetScreenRasters();
715: Spec512_StartVBL();
716: }
717:
718:
719: /*-----------------------------------------------------------------------*/
720: /*
721: VBL interrupt, draw screen and reset counters
722: */
723: void Video_InterruptHandler_VBL(void)
724: {
725: int PendingCyclesOver;
726:
727: /* Store cycles we went over for this frame(this is our inital count) */
728: PendingCyclesOver = -PendingInterruptCount; /* +ve */
729:
730: /* Remove this interrupt from list and re-order */
731: Int_AcknowledgeInterrupt();
1.1.1.10! root 732: /* Start HBL interrupts */
! 733: Int_AddAbsoluteInterrupt(nCyclesPerLine, INTERRUPT_VIDEO_ENDLINE);
1.1.1.9 root 734: Int_AddAbsoluteInterrupt(CYCLES_HBL,INTERRUPT_VIDEO_HBL);
735: Int_AddAbsoluteInterrupt(CYCLES_PER_FRAME,INTERRUPT_VIDEO_VBL);
736:
737: /* Set frame cycles, used for Video Address */
1.1.1.10! root 738: Cycles_SetCounter(CYCLES_COUNTER_VIDEO, PendingCyclesOver);
1.1.1.9 root 739:
740: /* Clear any key presses which are due to be de-bounced (held for one ST frame) */
741: Keymap_DebounceAllKeys();
1.1.1.10! root 742: /* Act on shortcut keys */
! 743: ShortCut_ActKey();
1.1.1.9 root 744:
745: /* Draw screen, skip frame if need to */
746: if (!ConfigureParams.Screen.bFrameSkip || (nVBLs&1))
747: {
748: /* Use extended VDI resolution?
749: * If so, just copy whole screen on VBL rather than per HBL */
750: if (bUseVDIRes)
751: Video_CopyVDIScreen();
752:
753: /* Now draw the screen! */
754: Screen_Draw();
755: }
756:
757: /* Update counter for number of screen refreshes per second(for debugging) */
758: nVBLs++;
759: /* Set video registers for frame */
760: Video_ClearOnVBL();
761: /* Store off PSG registers for YM file, is enabled */
762: YMFormat_UpdateRecording();
763: /* Generate 1/50th second of sound sample data, to be played by sound thread */
764: Sound_Update_VBL();
765:
766: M68000_Exception(EXCEPTION_VBLANK); /* Vertical blank interrupt, level 4! */
767:
768: /* And handle any messages, check for quit message */
769: Main_EventHandler(); /* Process messages, set 'bQuitProgram' if user tries to quit */
770: if (bQuitProgram)
771: {
772: Int_AddAbsoluteInterrupt(4, 0L); /* Pass NULL interrupt function to quit cleanly */
773: set_special(SPCFLAG_BRK); /* Assure that CPU core shuts down */
774: }
775:
1.1.1.10! root 776: Main_WaitOnVbl();
1.1.1.9 root 777: }
778:
779:
780: /*-----------------------------------------------------------------------*/
781: /*
782: Reset video chip
783: */
784: void Video_Reset(void)
785: {
786: /* NOTE! Must reset all of these register type things here!!!! */
787:
788: /* Are we in high-res? */
789: if (bUseHighRes)
790: VideoShifterByte = ST_HIGH_RES; /* Boot up for mono monitor */
791: else
792: VideoShifterByte = ST_LOW_RES;
793: if(bUseVDIRes)
794: VideoShifterByte = VDIRes;
795:
796: /* Reset VBL counter */
797: nVBLs = 0;
798: /* Reset addresses */
799: VideoBase = 0L;
800: /* Reset STe screen variables */
801: ScanLineSkip = 0;
802: HWScrollCount = 0;
1.1.1.10! root 803: bSteBorderFlag = FALSE;
! 804:
1.1.1.9 root 805: /* Clear ready for new VBL */
806: Video_ClearOnVBL();
807: }
808:
809:
810: /*-----------------------------------------------------------------------*/
811: /*
812: Write to video address base high and med register (0xff8201 and 0xff8203).
813: When a program writes to these registers, some other video registers
814: are reset to zero.
815: */
816: void Video_ScreenBaseSTE_WriteByte(void)
817: {
818: IoMem[0xff820d] = 0; /* Reset screen base low register */
819: }
1.1.1.8 root 820:
821: /*-----------------------------------------------------------------------*/
822: /*
823: Read video address counter high byte (0xff8205)
824: */
825: void Video_ScreenCounterHigh_ReadByte(void)
826: {
827: IoMem[0xff8205] = Video_CalculateAddress() >> 16; /* Get video address counter high byte */
828: }
829:
830: /*-----------------------------------------------------------------------*/
831: /*
832: Read video address counter med byte (0xff8207)
833: */
834: void Video_ScreenCounterMed_ReadByte(void)
835: {
836: IoMem[0xff8207] = Video_CalculateAddress() >> 8; /* Get video address counter med byte */
837: }
838:
839: /*-----------------------------------------------------------------------*/
840: /*
841: Read video address counter low byte (0xff8209)
842: */
843: void Video_ScreenCounterLow_ReadByte(void)
844: {
845: IoMem[0xff8209] = Video_CalculateAddress(); /* Get video address counter low byte */
846: }
847:
1.1.1.9 root 848: /*-----------------------------------------------------------------------*/
849: /*
850: Write to video address counter (0xff8205, 0xff8207 and 0xff8209).
851: Called on STE only and like with base address, you cannot set lowest bit.
852: */
853: void Video_ScreenCounter_WriteByte(void)
854: {
855: Uint32 addr;
856: addr = (IoMem[0xff8205] << 16) | (IoMem[0xff8207] << 8) | IoMem[0xff8209];
857: pVideoRaster = &STRam[addr & ~1];
858: }
1.1.1.8 root 859:
860: /*-----------------------------------------------------------------------*/
861: /*
862: Read video sync register (0xff820a)
863: */
864: void Video_Sync_ReadByte(void)
865: {
866: /* Nothing... */
867: }
868:
869: /*-----------------------------------------------------------------------*/
870: /*
871: Read video base address low byte (0xff820d). A plain ST can only store
872: screen addresses rounded to 256 bytes (i.e. no lower byte).
873: */
874: void Video_BaseLow_ReadByte(void)
875: {
876: if (ConfigureParams.System.nMachineType == MACHINE_ST)
1.1.1.9 root 877: IoMem[0xff820d] = 0; /* On ST this is always 0 */
878:
879: /* Note that you should not do anything here for STe because
880: * VideoBase address is set in an interrupt and would be wrong
881: * here. It's fine like this.
882: */
1.1.1.8 root 883: }
884:
885: /*-----------------------------------------------------------------------*/
886: /*
887: Read video line width register (0xff820f)
888: */
889: void Video_LineWidth_ReadByte(void)
890: {
1.1.1.9 root 891: if (ConfigureParams.System.nMachineType == MACHINE_ST)
892: IoMem[0xff820f] = 0; /* On ST this is always 0 */
1.1.1.10! root 893: else
! 894: IoMem[0xff820f] = ScanLineSkip;
1.1.1.8 root 895: }
896:
897: /*-----------------------------------------------------------------------*/
898: /*
899: Read video shifter mode register (0xff8260)
900: */
901: void Video_ShifterMode_ReadByte(void)
902: {
903: if (bUseHighRes)
904: IoMem[0xff8260] = 2; /* If mono monitor, force to high resolution */
905: else
906: IoMem[0xff8260] = VideoShifterByte; /* Read shifter register */
907: }
908:
1.1.1.10! root 909: /*-----------------------------------------------------------------------*/
! 910: /*
! 911: Read horizontal scroll register (0xff8265)
! 912: */
! 913: void Video_HorScroll_Read(void)
! 914: {
! 915: IoMem[0xff8265] = HWScrollCount;
! 916: }
1.1.1.8 root 917:
918:
919: /*-----------------------------------------------------------------------*/
920: /*
1.1.1.10! root 921: Write video line width register (0xff820f) - STE only.
! 922: */
! 923: void Video_LineWidth_WriteByte(void)
! 924: {
! 925: ScanLineSkip = IoMem_ReadByte(0xff820f);
! 926: }
! 927:
! 928: /*-----------------------------------------------------------------------*/
! 929: /*
1.1.1.8 root 930: Write to video shifter palette registers (0xff8240-0xff825e)
931: */
932: static void Video_ColorReg_WriteWord(Uint32 addr)
933: {
1.1.1.9 root 934: if (!bUseHighRes) /* Don't store if hi-res */
1.1.1.8 root 935: {
1.1.1.9 root 936: int idx;
1.1.1.8 root 937: Uint16 col;
1.1.1.9 root 938: Video_SetHBLPaletteMaskPointers(); /* Set 'pHBLPalettes' etc.. according cycles into frame */
1.1.1.8 root 939: col = IoMem_ReadWord(addr);
1.1.1.9 root 940: if (ConfigureParams.System.nMachineType == MACHINE_ST)
941: col &= 0x777; /* Mask off to ST 512 palette */
942: else
943: col &= 0xfff; /* Mask off to STe 4096 palette */
944: IoMem_WriteWord(addr, col); /* (some games write 0xFFFF and read back to see if STe) */
945: Spec512_StoreCyclePalette(col, addr); /* Store colour into CyclePalettes[] */
946: idx = (addr-0xff8240)/2; /* words */
947: pHBLPalettes[idx] = col; /* Set colour x */
948: *pHBLPaletteMasks |= 1 << idx; /* And mask */
1.1.1.8 root 949: }
950: }
951:
952: void Video_Color0_WriteWord(void)
953: {
954: Video_ColorReg_WriteWord(0xff8240);
955: }
956:
957: void Video_Color1_WriteWord(void)
958: {
959: Video_ColorReg_WriteWord(0xff8242);
960: }
961:
962: void Video_Color2_WriteWord(void)
963: {
964: Video_ColorReg_WriteWord(0xff8244);
965: }
966:
967: void Video_Color3_WriteWord(void)
968: {
969: Video_ColorReg_WriteWord(0xff8246);
970: }
971:
972: void Video_Color4_WriteWord(void)
973: {
974: Video_ColorReg_WriteWord(0xff8248);
975: }
976:
977: void Video_Color5_WriteWord(void)
978: {
979: Video_ColorReg_WriteWord(0xff824a);
980: }
981:
982: void Video_Color6_WriteWord(void)
983: {
984: Video_ColorReg_WriteWord(0xff824c);
985: }
986:
987: void Video_Color7_WriteWord(void)
988: {
989: Video_ColorReg_WriteWord(0xff824e);
990: }
991:
992: void Video_Color8_WriteWord(void)
993: {
994: Video_ColorReg_WriteWord(0xff8250);
995: }
996:
997: void Video_Color9_WriteWord(void)
998: {
999: Video_ColorReg_WriteWord(0xff8252);
1000: }
1001:
1002: void Video_Color10_WriteWord(void)
1003: {
1004: Video_ColorReg_WriteWord(0xff8254);
1005: }
1006:
1007: void Video_Color11_WriteWord(void)
1008: {
1009: Video_ColorReg_WriteWord(0xff8256);
1010: }
1011:
1012: void Video_Color12_WriteWord(void)
1013: {
1014: Video_ColorReg_WriteWord(0xff8258);
1015: }
1016:
1017: void Video_Color13_WriteWord(void)
1018: {
1019: Video_ColorReg_WriteWord(0xff825a);
1020: }
1021:
1022: void Video_Color14_WriteWord(void)
1023: {
1024: Video_ColorReg_WriteWord(0xff825c);
1025: }
1026:
1027: void Video_Color15_WriteWord(void)
1028: {
1029: Video_ColorReg_WriteWord(0xff825e);
1030: }
1031:
1032:
1033: /*-----------------------------------------------------------------------*/
1034: /*
1035: Write video shifter mode register (0xff860)
1036: */
1037: void Video_ShifterMode_WriteByte(void)
1038: {
1039: if (!bUseHighRes && !bUseVDIRes) /* Don't store if hi-res and don't store if VDI resolution */
1040: {
1041: VideoShifterByte = IoMem[0xff8260] & 3; /* We only care for lower 2-bits */
1042: Video_WriteToShifter(VideoShifterByte);
1043: Video_SetHBLPaletteMaskPointers();
1044: *pHBLPaletteMasks &= 0xff00ffff;
1045: /* Store resolution after palette mask and set resolution write bit: */
1.1.1.10! root 1046: *pHBLPaletteMasks |= (((Uint32)VideoShifterByte|0x04)<<16);
! 1047: }
! 1048: }
! 1049:
! 1050: /*-----------------------------------------------------------------------*/
! 1051: /*
! 1052: Write to horizontal scroll register (0xff8265).
! 1053: Note: The STE shifter has a funny "bug" that allows to increase the
! 1054: resolution to 336x200 instead of 320x200. It occurs when a program writes
! 1055: certain values to 0xff8264:
! 1056: move.w #1,$ffff8264 ; Word access!
! 1057: clr.b $ffff8264 ; Byte access!
! 1058: Some games (Obsession, Skulls) and demos (Pacemaker by Paradox) use this
! 1059: feature to increase the resolution, so we have to emulate this bug, too!
! 1060: */
! 1061: void Video_HorScroll_Write(void)
! 1062: {
! 1063: static BOOL bFirstSteAccess = FALSE;
! 1064:
! 1065: HWScrollCount = IoMem[0xff8265];
! 1066:
! 1067: /*fprintf(stderr, "Write to 0x%x (0x%x, 0x%x, %i)\n", IoAccessBaseAddress,
! 1068: IoMem[0xff8264], HWScrollCount, nIoMemAccessSize);*/
! 1069:
! 1070: if (IoAccessBaseAddress == 0xff8264 && nIoMemAccessSize == SIZE_WORD
! 1071: && HWScrollCount == 1)
! 1072: {
! 1073: /*fprintf(stderr, "STE border removal - access 1\n");*/
! 1074: bFirstSteAccess = TRUE;
1.1.1.8 root 1075: }
1.1.1.10! root 1076: else if (bFirstSteAccess && HWScrollCount == 1 &&
! 1077: IoAccessBaseAddress == 0xff8264 && nIoMemAccessSize == SIZE_BYTE)
! 1078: {
! 1079: /*fprintf(stderr, "STE border removal - access 2\n");*/
! 1080: bSteBorderFlag = TRUE;
! 1081: }
! 1082: else
! 1083: {
! 1084: bFirstSteAccess = bSteBorderFlag = FALSE;
! 1085: }
! 1086:
! 1087: HWScrollCount &= 0x0f;
1.1.1.8 root 1088: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.