Annotation of hatari/src/video.c, revision 1.1.1.10

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.