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

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.11! root       12: 
        !            13: /* 2007/03/xx  [NP]    Support for cycle precise border removal / hardware scrolling by using  */
        !            14: /*                     Cycles_GetCounterOnWriteAccess (support left/right border and lines with*/
        !            15: /*                     length of +26, +2, -2, +44, -106 bytes).                                */
        !            16: /*                     Add support for 'Enchanted Lands' second removal of right border.       */
        !            17: /*                     More precise support for reading video counter $ff8205/07/09.           */
        !            18: /* 2007/04/14  [NP]    Precise reloading of $ff8201/03 into $ff8205/07/09 at line 310 on cycle */
        !            19: /*                     RESTART_VIDEO_COUNTER_CYCLE (ULM DSOTS Demo).                           */
        !            20: /* 2007/04/16  [NP]    Better Video_CalculateAddress. We must substract a "magic" 12 cycles to */
        !            21: /*                     Cycles_GetCounterOnReadAccess(CYCLES_COUNTER_VIDEO) to get a correct    */
        !            22: /*                     value (No Cooper's video synchro protection is finaly OK :) ).          */
        !            23: /* 2007/04/17  [NP]    - Switch to 60 Hz to remove top border on line 33 should occur before   */
        !            24: /*                     LINE_REMOVE_TOP_CYCLE (a few cycles before the HBL)                     */
        !            25: /* 2007/04/23  [NP]    - Slight change in Video_StoreResolution to ignore hi res if the line   */
        !            26: /*                     has left/right border removed -> assume of lo res line.                 */
        !            27: /*                     - Handle simultaneous removal of right border and bottom border with    */
        !            28: /*                     the same long switch to 60 Hz (Sync Screen in SNY II).                  */
        !            29: /* 2007/05/06  [NP]    More precise tests for top border's removal.                            */
        !            30: /* 2007/05/11  [NP]    Add support for mid res overscan (No Cooper Greetings).                 */
        !            31: /* 2007/05/12  [NP]    - LastCycleSync50 and LastCycleSync60 for better top border's removal   */
        !            32: /*                     in Video_EndHBL.                                                        */
        !            33: /*                     - Use VideoOffset in Video_CopyScreenLineColor to handle missing planes */
        !            34: /*                     depending on line (mid/lo and borders).                                 */
        !            35: /* 2007/09/25  [NP]    Replace printf by calls to HATARI_TRACE.                                */
        !            36: /* 2007/10/02  [NP]    Use the new int.c to add interrupts with INT_CPU_CYCLE / INT_MFP_CYCLE. */
        !            37: /* 2007/10/23  [NP]    Add support for 0 byte line (60/50 switch at cycle 56). Allow 5 lines   */
        !            38: /*                     hardscroll (e.g. SHFORSTV.EXE by Paulo Simmoes).                        */
        !            39: /* 2007/10/31  [NP]    Use BORDERMASK_LEFT_OFF_MID when left border is removed with hi/med     */
        !            40: /*                     switch (ST CNX in PYM).                                                 */
        !            41: /* 2007/11/02  [NP]    Add support for 4 pixel hardware scrolling ("Let's Do The Twist" by     */
        !            42: /*                     ST CNX in Punish Your Machine).                                         */
        !            43: /* 2007/11/05  [NP]    Depending on the position of the mid res switch, the planes will be     */
        !            44: /*                     shifted when doing midres overscan (Best Part Of the Creation in PYM    */
        !            45: /*                     or No Cooper Greetings).                                                */
        !            46: /* 2007/11/30  [NP]    A hi/mid switch to remove the left border can be either used to initiate*/
        !            47: /*                     a right hardware scrolling in low res (St Cnx) or a complete mid res    */
        !            48: /*                     overscan line (Dragonnels Reset Part).                                  */
        !            49: /*                     Use bit 0-15, 16-19 and 20-23 in ScreenBorderMask[] to track border     */
        !            50: /*                     trick, STF hardware scrolling and plane shifting.                       */
        !            51: /* 2007/12/22  [NP]    Very precise values for VBL_VIDEO_CYCLE_OFFSET, HBL_VIDEO_CYCLE_OFFSET  */
        !            52: /*                     TIMERB_VIDEO_CYCLE_OFFSET and RESTART_VIDEO_COUNTER_CYCLE. These values */
        !            53: /*                     were calculated using sttiming.s on a real STF and should give some very*/
        !            54: /*                     accurate results (also uses 56 cycles instead of 44 to process an       */
        !            55: /*                     exception).                                                             */
        !            56: /* 2007/12/29  [NP]    Better support for starting line 2 bytes earlier (if the line starts in */
        !            57: /*                     60 Hz and goes back to 50 Hz later), when combined with top border      */
        !            58: /*                     removal (Mindbomb Demo - D.I. No Shit).                                 */
        !            59: /* 2007/12/30  [NP]    Slight improvement of VideoAdress in Video_CalculateAddress when reading*/
        !            60: /*                     during the top border.                                                  */
        !            61: /*                     Correct the case where removing top border on line 33 could also be     */
        !            62: /*                     interpreted as a right border removal (which is not possible since the  */
        !            63: /*                     display is still off at that point).                                    */
        !            64: /* 2008/01/03  [NP]    Better handling of nStartHBL and nEndHBL when switching freq from       */
        !            65: /*                     50 to 60 Hz. Allows emulation of a "short" 50 Hz screen of 171 lines    */
        !            66: /*                     and a more precise removal of bottom border in 50 and 60 Hz.            */
        !            67: /* 2008/01/04  [NP]    More generic detection for removing 2 bytes to the right of the line    */
        !            68: /*                     when switching from 60 to 50 Hz (works even with a big number of cycles */
        !            69: /*                     between the freq changes) (Phaleon's Menus).                            */
        !            70: /* 2008/01/06  [NP]    More generic detection for stopping the display in the middle of a line */
        !            71: /*                     with a hi / lo res switch (-106 bytes per line). Although switch to     */
        !            72: /*                     hi res should occur at cycle 160, some demos use 164 (Phaleon's Menus). */
        !            73: /* 2008/01/06  [NP]    Better bottom border's removal in 50 Hz : switch to 60 Hz must occur    */
        !            74: /*                     before cycle LINE_REMOVE_BOTTOM_CYCLE on line 263 and switch back to 50 */
        !            75: /*                     Hz must occur after LINE_REMOVE_BOTTOM_CYCLE on line 263 (this means    */
        !            76: /*                     we can already be in 50 Hz when Video_EndHBL is called and still remove */
        !            77: /*                     the bottom border). This is similar to the tests used to remove the     */
        !            78: /*                     top border.                                                             */
        !            79: /* 2008/01/12  [NP]    In Video_SetHBLPaletteMaskPointers, consider that if a color's change   */
        !            80: /*                     occurs after cycle LINE_END_CYCLE_NO_RIGHT, then it's related to the    */
        !            81: /*                     next line.                                                              */
        !            82: /*                     FIXME : it would be better to handle all color changes through spec512.c*/
        !            83: /*                     and drop the 16 colors palette per line.                                */
        !            84: /*                     FIXME : we should use Cycles_GetCounterOnWriteAccess, but it doesn't    */
        !            85: /*                     support multiple accesses like move.l or movem.                         */
        !            86: /* 2008/01/12  [NP]    Handle 60 Hz switch during the active display of the last line to remove*/
        !            87: /*                     the bottom border : this should also shorten line by 2 bytes (F.N.I.L.  */
        !            88: /*                     Demo by TNT).                                                           */
        !            89: /* 2008/01/15  [NP]    Don't do 'left+2' if switch back to 50 Hz occurs when line is not active*/
        !            90: /*                     (after cycle LINE_END_CYCLE_60) (XXX International Demos).              */
        !            91: /* 2008/01/31  [NP]    Improve left border detection : allow switch to low res on cycle <= 28  */
        !            92: /*                     instead of <= 20 (Vodka Demo Main Menu).                                */
        !            93: /* 2008/02/02  [NP]    Added 0 byte line detection when switching hi/lo res at position 28     */
        !            94: /*                     (Lemmings screen in Nostalgic-o-demo).                                  */
        !            95: /* 2008/02/03  [NP]    On STE, write to video counter $ff8205/07/09 should only be applied     */
        !            96: /*                     immediatly if display has not started for the line (before cycle        */
        !            97: /*                     LINE_END_CYCLE_50). If write occurs after, the change to pVideoRaster   */
        !            98: /*                     should be delayed to the end of the line, after processing the current  */
        !            99: /*                     line with Video_CopyScreenLineColor (Stardust Tunnel Demo).             */
        !           100: /* 2008/02/04  [NP]    The problem is similar when writing to hwscroll $ff8264, we must delay  */
        !           101: /*                     the change until the end of the line if display was already started     */
        !           102: /*                     (Mindrewind by Reservoir Gods).                                         */
        !           103: /* 2008/02/06  [NP]    On STE, when left/right borders are off and hwscroll > 0, we must read  */
        !           104: /*                     6 bytes less than the expected value (E605 by Light).                   */
        !           105: /* 2008/02/17  [NP]    In Video_CopyScreenLine, LineWidth*2 bytes should be added after        */
        !           106: /*                     pNewVideoRaster is copied to pVideoRaster (Braindamage Demo).           */
        !           107: /*                     When reading a byte at ff8205/07/09, all video address bytes should be  */
        !           108: /*                     updated in Video_ScreenCounter_ReadByte, not just the byte that was     */
        !           109: /*                     read. Fix programs that just modify one byte in the video address       */
        !           110: /*                     counter (e.g. sub #1,$ff8207 in Braindamage Demo).                      */
        !           111: /* 2008/02/19  [NP]    In Video_CalculateAddress, use pVideoRaster instead of VideoBase to     */
        !           112: /*                     determine the video address when display is off in the upper part of    */
        !           113: /*                     the screen (in case ff8205/07/09 were modified on STE).                 */
        !           114: /* 2008/02/20  [NP]    Better handling in Video_ScreenCounter_WriteByte by changing only one   */
        !           115: /*                     byte and keeping the other (Braindamage End Part).                      */
        !           116: /* 2008/03/08  [NP]    Use M68000_INT_VIDEO when calling M68000_Exception().                   */
        !           117: /* 2008/03/13  [NP]    On STE, LineWidth value in $ff820f is added to the shifter counter just */
        !           118: /*                     when display is turned off on a line (when right border is started,     */
        !           119: /*                     which is usually on cycle 376).                                         */
        !           120: /*                     This means a write to $ff820f should be applied immediatly only if it   */
        !           121: /*                     occurs before cycle LineEndCycle. Else, it is stored in NewLineWidth    */
        !           122: /*                     and used after Video_CopyScreenLine has processed the current line      */
        !           123: /*                     (improve the bump mapping part in Pacemaker by Paradox).                */
        !           124: /*                     LineWidth should be added to pVideoRaster before checking the possible  */
        !           125: /*                     modification of $ff8205/07/09 in Video_CopyScreenLine.                  */
        !           126: /* 2008/03/14  [NP]    Rename ScanLineSkip to LineWidth (more consistent with STE docs).       */
        !           127: /*                     On STE, better support for writing to video counter, line width and     */
        !           128: /*                     hw scroll. If write to register occurs just at the start of a new line  */
        !           129: /*                     but before Video_EndHBL (because the move started just before cycle 512)*/
        !           130: /*                     then the new value should not be set immediatly but stored and set      */
        !           131: /*                     during Video_EndHBL (fix the bump mapping part in Pacemaker by Paradox).*/
        !           132: 
        !           133: 
        !           134: const char Video_rcsid[] = "Hatari $Id: video.c,v 1.96 2008/03/14 20:13:37 npomarede Exp $";
1.1       root      135: 
1.1.1.7   root      136: #include <SDL_endian.h>
1.1.1.4   root      137: 
1.1       root      138: #include "main.h"
1.1.1.6   root      139: #include "configuration.h"
1.1.1.10  root      140: #include "cycles.h"
1.1       root      141: #include "fdc.h"
                    142: #include "int.h"
                    143: #include "ikbd.h"
1.1.1.8   root      144: #include "ioMem.h"
1.1.1.4   root      145: #include "keymap.h"
1.1       root      146: #include "m68000.h"
                    147: #include "memorySnapShot.h"
                    148: #include "mfp.h"
1.1.1.11! root      149: #include "printer.h"
1.1       root      150: #include "screen.h"
                    151: #include "shortcut.h"
                    152: #include "sound.h"
                    153: #include "spec512.h"
                    154: #include "stMemory.h"
                    155: #include "vdi.h"
                    156: #include "video.h"
                    157: #include "ymFormat.h"
1.1.1.11! root      158: #include "falcon/videl.h"
        !           159: #include "falcon/hostscreen.h"
        !           160: #include "trace.h"
1.1.1.4   root      161: 
                    162: 
1.1.1.9   root      163: #define BORDERMASK_NONE    0x00                 /* Borders masks */
                    164: #define BORDERMASK_LEFT    0x01
                    165: #define BORDERMASK_RIGHT   0x02
1.1.1.10  root      166: #define BORDERMASK_MIDDLE  0x04
1.1.1.9   root      167: 
1.1.1.11! root      168: /* The border's mask allows to keep track of all the border tricks             */
        !           169: /* applied to one video line. The masks for all lines are stored in the array  */
        !           170: /* ScreenBorderMask[].                                                         */
        !           171: /* - bits 0-15 are used to describe the border tricks.                         */
        !           172: /* - bits 16-19 are used to store the pixels count in case of right hardware   */
        !           173: /*   scrolling on STF.                                                         */
        !           174: /* - bits 20-23 are used to store the bytes offset to apply for some particular        */
        !           175: /*   tricks (for example mid res overscan can shift display by 0 or 2 bytes    */
        !           176: /*   depending on when the switch to mid res is done after removing the left   */
        !           177: /*   border).                                                                  */
        !           178: 
        !           179: #define BORDERMASK_LEFT_OFF            0x01    /* removal of left border with hi/lo res switch -> +26 bytes */
        !           180: #define BORDERMASK_LEFT_PLUS_2         0x02    /* line starts earlier in 60 Hz -> +2 bytes */
        !           181: #define BORDERMASK_STOP_MIDDLE         0x04    /* line ends in hires at cycle 160 -> -106 bytes */
        !           182: #define BORDERMASK_RIGHT_MINUS_2       0x08    /* line ends earlier in 60 Hz -> -2 bytes */
        !           183: #define BORDERMASK_RIGHT_OFF           0x10    /* removal of right border -> +44 bytes */
        !           184: #define BORDERMASK_RIGHT_OFF_FULL      0x20    /* full removal of right border and next left border -> +22 bytes */
        !           185: #define BORDERMASK_OVERSCAN_MID_RES    0x40    /* some borders were removed and the line is in mid res instead of low res */
        !           186: #define BORDERMASK_EMPTY_LINE          0x80    /* 60/50 Hz switch prevents the line to start, video counter is not incremented */
        !           187: #define BORDERMASK_LEFT_OFF_MID                0x100   /* removal of left border with hi/mid res switch -> +26 bytes (for 4 pixels hardware scrolling) */
        !           188: 
        !           189: 
        !           190: 
        !           191: int STRes = ST_LOW_RES;                         /* current ST resolution */
        !           192: int TTRes;                                      /* TT shifter resolution mode */
1.1.1.9   root      193: 
1.1.1.11! root      194: BOOL bUseSTShifter;                             /* Falcon: whether to use ST palette */
        !           195: BOOL bUseHighRes;                               /* Use hi-res (ie Mono monitor) */
1.1       root      196: int OverscanMode;                               /* OVERSCANMODE_xxxx for current display frame */
1.1.1.8   root      197: Uint16 HBLPalettes[(NUM_VISIBLE_LINES+1)*16];   /* 1x16 colour palette per screen line, +1 line just incase write after line 200 */
                    198: Uint16 *pHBLPalettes;                           /* Pointer to current palette lists, one per HBL */
1.1.1.9   root      199: Uint32 HBLPaletteMasks[NUM_VISIBLE_LINES+1];    /* Bit mask of palette colours changes, top bit set is resolution change */
                    200: Uint32 *pHBLPaletteMasks;
1.1.1.6   root      201: int nScreenRefreshRate = 50;                    /* 50 or 60 Hz in color, 70 Hz in mono */
1.1.1.8   root      202: Uint32 VideoBase;                               /* Base address in ST Ram for screen (read on each VBL) */
1.1.1.9   root      203: 
1.1.1.11! root      204: int nVBLs;                                      /* VBL Counter */
        !           205: int nHBL;                                       /* HBL line */
        !           206: int nStartHBL;                                  /* Start HBL for visible screen */
        !           207: int nEndHBL;                                    /* End HBL for visible screen */
1.1.1.10  root      208: int nScanlinesPerFrame = 313;                   /* Number of scan lines per frame */
                    209: int nCyclesPerLine = 512;                       /* Cycles per horizontal line scan */
                    210: static int nFirstVisibleHbl = 34;               /* The first line of the ST screen that is copied to the PC screen buffer */
                    211: 
1.1.1.9   root      212: static Uint8 HWScrollCount;                     /* HW scroll pixel offset, STe only (0...15) */
1.1.1.11! root      213: int NewHWScrollCount = -1;                      /* Used in STE mode when writing to the scrolling register $ff8265 */
        !           214: static Uint8 LineWidth;                         /* Scan line width add, STe only (words, minus 1) */
        !           215: int NewLineWidth = -1;                         /* Used in STE mode when writing to the line width register $ff820f */
1.1.1.8   root      216: static Uint8 *pVideoRaster;                     /* Pointer to Video raster, after VideoBase in PC address space. Use to copy data on HBL */
                    217: static Uint8 VideoShifterByte;                  /* VideoShifter (0xff8260) value store in video chip */
                    218: static int LeftRightBorder;                     /* BORDERMASK_xxxx used to simulate left/right border removal */
1.1.1.11! root      219: static int LineStartCycle;                      /* Cycle where display starts for the current line */
        !           220: static int LineEndCycle;                        /* Cycle where display ends for the current line */
1.1.1.10  root      221: static BOOL bSteBorderFlag;                     /* TRUE when screen width has been switched to 336 (e.g. in Obsession) */
1.1.1.11! root      222: static BOOL bTTColorsSync, bTTColorsSTSync;     /* whether TT colors need convertion to SDL */
1.1       root      223: 
1.1.1.11! root      224: int    ScreenBorderMask[ MAX_SCANLINES_PER_FRAME ];
        !           225: int    LastCycleSync50;                        /* value of Cycles_GetCounterOnWriteAccess last time ff820a was set to 0x02 for the current VBL */
        !           226: int    LastCycleSync60;                        /* value of Cycles_GetCounterOnWriteAccess last time ff820a was set to 0x00 for the current VBL */
        !           227: int    NewVideoHi = -1;                        /* new value for $ff8205 on STE */
        !           228: int    NewVideoMed = -1;                       /* new value for $ff8207 on STE */
        !           229: int    NewVideoLo = -1;                        /* new value for $ff8209 on STE */
1.1       root      230: 
                    231: /*-----------------------------------------------------------------------*/
1.1.1.11! root      232: /**
        !           233:  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
        !           234:  */
1.1       root      235: void Video_MemorySnapShot_Capture(BOOL bSave)
                    236: {
1.1.1.11! root      237:        /* Save/Restore details */
        !           238:        MemorySnapShot_Store(&VideoShifterByte, sizeof(VideoShifterByte));
        !           239:        MemorySnapShot_Store(&TTRes, sizeof(TTRes));
        !           240:        MemorySnapShot_Store(&bUseSTShifter, sizeof(bUseSTShifter));
        !           241:        MemorySnapShot_Store(&bUseHighRes, sizeof(bUseHighRes));
        !           242:        MemorySnapShot_Store(&nVBLs, sizeof(nVBLs));
        !           243:        MemorySnapShot_Store(&nHBL, sizeof(nHBL));
        !           244:        MemorySnapShot_Store(&nStartHBL, sizeof(nStartHBL));
        !           245:        MemorySnapShot_Store(&nEndHBL, sizeof(nEndHBL));
        !           246:        MemorySnapShot_Store(&OverscanMode, sizeof(OverscanMode));
        !           247:        MemorySnapShot_Store(HBLPalettes, sizeof(HBLPalettes));
        !           248:        MemorySnapShot_Store(HBLPaletteMasks, sizeof(HBLPaletteMasks));
        !           249:        MemorySnapShot_Store(&VideoBase, sizeof(VideoBase));
        !           250:        MemorySnapShot_Store(&LineWidth, sizeof(LineWidth));
        !           251:        MemorySnapShot_Store(&HWScrollCount, sizeof(HWScrollCount));
        !           252:        MemorySnapShot_Store(&pVideoRaster, sizeof(pVideoRaster));
        !           253:        MemorySnapShot_Store(&nScanlinesPerFrame, sizeof(nScanlinesPerFrame));
        !           254:        MemorySnapShot_Store(&nCyclesPerLine, sizeof(nCyclesPerLine));
        !           255:        MemorySnapShot_Store(&nFirstVisibleHbl, sizeof(nFirstVisibleHbl));
        !           256:        MemorySnapShot_Store(&bSteBorderFlag, sizeof(bSteBorderFlag));
1.1       root      257: }
                    258: 
1.1.1.8   root      259: 
1.1       root      260: /*-----------------------------------------------------------------------*/
1.1.1.11! root      261: /**
        !           262:  * Calculate and return video address pointer.
        !           263:  */
1.1.1.8   root      264: static Uint32 Video_CalculateAddress(void)
1.1       root      265: {
1.1.1.11! root      266:        int X, nFrameCycles, NbBytes;
        !           267:        int HblCounterVideo;
        !           268:        Uint32 VideoAddress;      /* Address of video display in ST screen space */
        !           269:        int nSyncByte;
        !           270:        int LineBorderMask;
        !           271:        int PrevSize;
        !           272:        int CurSize;
        !           273: 
        !           274: 
        !           275:        /* Find number of cycles passed during frame */
        !           276:        /* We need to substract '12' for correct video address calculation */
        !           277:        nFrameCycles = Cycles_GetCounterOnReadAccess(CYCLES_COUNTER_VIDEO) - 12;
        !           278: 
        !           279:        /* Now find which pixel we are on (ignore left/right borders) */
        !           280:        X = nFrameCycles % nCyclesPerLine;
        !           281: 
        !           282:        /* Get real video line count (can be different from nHBL) */
        !           283:        HblCounterVideo = nFrameCycles / nCyclesPerLine;
        !           284: 
        !           285: 
        !           286:        nSyncByte = IoMem_ReadByte(0xff820a) & 2;       /* only keep bit 1 */
        !           287:        if (nSyncByte)                          /* 50 Hz */
        !           288:        {
        !           289:                LineStartCycle = LINE_START_CYCLE_50;
        !           290:                LineEndCycle = LINE_END_CYCLE_50;
        !           291:        }
        !           292:        else                                            /* 60 Hz */
        !           293:        {
        !           294:                LineStartCycle = LINE_START_CYCLE_60;
        !           295:                LineEndCycle = LINE_END_CYCLE_60;
        !           296:        }
        !           297: 
        !           298: 
        !           299:        /* Top of screen is usually 63 lines from VBL in 50 Hz */
        !           300:        if (nFrameCycles < nStartHBL*nCyclesPerLine)
        !           301:        {
        !           302:                /* pVideoRaster was set during Video_ClearOnVBL using VideoBase */
        !           303:                /* and it could also have been modified on STE by writing to ff8205/07/09 */
        !           304:                /* We should not use ff8201/ff8203  which are reloaded in ff8205/ff8207 only once per VBL */
        !           305:                VideoAddress = pVideoRaster - STRam;
        !           306:        }
        !           307: 
        !           308:        else if (nFrameCycles > RESTART_VIDEO_COUNTER_CYCLE)
        !           309:        {
        !           310:                /* This is where ff8205/ff8207 are reloaded with the content of ff8201/ff8203 on a real ST */
        !           311:                /* (used in ULM DSOTS demos). VideoBase is also reloaded in Video_ClearOnVBL to be sure */
        !           312:                VideoBase = (Uint32)IoMem_ReadByte(0xff8201)<<16 | (Uint32)IoMem_ReadByte(0xff8203)<<8;
        !           313:                if (ConfigureParams.System.nMachineType != MACHINE_ST)
        !           314:                {
        !           315:                        /* on STe 2 aligned, on Falcon 4 aligned, on TT 8 aligned. We do STe. */
        !           316:                        VideoBase |= IoMem_ReadByte(0xff820d) & ~1;
        !           317:                }
        !           318: 
        !           319:                VideoAddress = VideoBase;
        !           320:        }
        !           321: 
        !           322:        else
        !           323:        {
        !           324:                VideoAddress = pVideoRaster - STRam;            /* pVideoRaster is updated by Video_CopyScreenLineColor */
        !           325: 
        !           326:                /* Now find which pixel we are on (ignore left/right borders) */
        !           327:                X = ( Cycles_GetCounterOnReadAccess(CYCLES_COUNTER_VIDEO) - 12 ) % nCyclesPerLine;
        !           328: 
        !           329:                /* Get real video line count (can be different from nHBL) */
        !           330:                HblCounterVideo = ( Cycles_GetCounterOnReadAccess(CYCLES_COUNTER_VIDEO) - 12 ) / nCyclesPerLine;
        !           331: 
        !           332:                /* Correct the case when read overlaps end of line / start of next line */
        !           333:                /* Video_CopyScreenLineColor was not called yet to update VideoAddress */
        !           334:                /* so we need to determine the size of the previous line to get the */
        !           335:                /* correct value of VideoAddress. */
        !           336:                PrevSize = 0;
        !           337:                if ( HblCounterVideo < nHBL )
        !           338:                        X = 0;
        !           339:                else if ( ( HblCounterVideo > nHBL )            /* HblCounterVideo = nHBL+1 */
        !           340:                          &&  ( nHBL >= nStartHBL ) )           /* if nHBL was not visible, PrevSize = 0 */
        !           341:                {
        !           342:                        LineBorderMask = ScreenBorderMask[ HblCounterVideo-1 ]; /* get border mask for nHBL */
        !           343:                        PrevSize = BORDERBYTES_NORMAL;          /* normal line */
        !           344: 
        !           345:                        if (LineBorderMask & BORDERMASK_LEFT_OFF)
        !           346:                                PrevSize += BORDERBYTES_LEFT;
        !           347:                        else if (LineBorderMask & BORDERMASK_LEFT_PLUS_2)
        !           348:                                PrevSize += 2;
        !           349: 
        !           350:                        if (LineBorderMask & BORDERMASK_STOP_MIDDLE)
        !           351:                                PrevSize -= 106;
        !           352:                        else if (LineBorderMask & BORDERMASK_RIGHT_MINUS_2)
        !           353:                                PrevSize -= 2;
        !           354:                        else if (LineBorderMask & BORDERMASK_RIGHT_OFF)
        !           355:                                PrevSize += BORDERBYTES_RIGHT;
        !           356: 
        !           357:                        if (LineBorderMask & BORDERMASK_EMPTY_LINE)
        !           358:                                PrevSize = 0;
        !           359:                }
        !           360: 
        !           361: 
        !           362:                LineBorderMask = ScreenBorderMask[ HblCounterVideo ];
        !           363: 
        !           364:                CurSize = BORDERBYTES_NORMAL;                   /* normal line */
        !           365: 
        !           366:                if (LineBorderMask & BORDERMASK_LEFT_OFF)
        !           367:                        CurSize += BORDERBYTES_LEFT;
        !           368:                else if (LineBorderMask & BORDERMASK_LEFT_PLUS_2)
        !           369:                        CurSize += 2;
        !           370: 
        !           371:                if (LineBorderMask & BORDERMASK_STOP_MIDDLE)
        !           372:                        CurSize -= 106;
        !           373:                else if (LineBorderMask & BORDERMASK_RIGHT_MINUS_2)
        !           374:                        CurSize -= 2;
        !           375:                else if (LineBorderMask & BORDERMASK_RIGHT_OFF)
        !           376:                        CurSize += BORDERBYTES_RIGHT;
        !           377:                if (LineBorderMask & BORDERMASK_RIGHT_OFF_FULL)
        !           378:                        CurSize += BORDERBYTES_RIGHT_FULL;
        !           379: 
        !           380:                if ( LineBorderMask & BORDERMASK_LEFT_PLUS_2)
        !           381:                        LineStartCycle = LINE_START_CYCLE_60;
        !           382:                else if ( LineBorderMask & BORDERMASK_LEFT_OFF )
        !           383:                        LineStartCycle = LINE_START_CYCLE_70;
        !           384: 
        !           385:                LineEndCycle = LineStartCycle + CurSize*2;
        !           386: 
        !           387: 
        !           388:                if ( X < LineStartCycle )
        !           389:                        X = LineStartCycle;                             /* display is disabled in the left border */
        !           390:                else if ( X > LineEndCycle )
        !           391:                        X = LineEndCycle;                               /* display is disabled in the right border */
        !           392: 
        !           393:                NbBytes = ( (X-LineStartCycle)>>1 ) & (~1);     /* 2 cycles per byte */
        !           394: 
        !           395: 
        !           396:                /* when left border is open, we have 2 bytes less than theorical value */
        !           397:                /* (26 bytes in left border, which is not a multiple of 4 cycles) */
        !           398:                if ( LineBorderMask & BORDERMASK_LEFT_OFF )
        !           399:                        NbBytes -= 2;
        !           400: 
        !           401:                if ( LineBorderMask & BORDERMASK_EMPTY_LINE )
        !           402:                        NbBytes = 0;
        !           403: 
        !           404:                /* Add line cycles if we have not reached end of screen yet: */
        !           405:                if (nFrameCycles < nEndHBL*nCyclesPerLine)
        !           406:                        VideoAddress += PrevSize + NbBytes;
        !           407:        }
        !           408: 
        !           409:        HATARI_TRACE ( HATARI_TRACE_VIDEO_ADDR , "video base=%x raster=%x addr=%x video_cyc=%d line_cyc=%d/X=%d @ nHBL=%d/video_hbl=%d %d<->%d pc=%x instr_cyc=%d\n",
        !           410:                       VideoBase, pVideoRaster - STRam, VideoAddress, Cycles_GetCounter(CYCLES_COUNTER_VIDEO),
        !           411:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO) %  nCyclesPerLine, X,
        !           412:                       nHBL, HblCounterVideo, LineStartCycle, LineEndCycle, M68000_GetPC(), CurrentInstrCycles );
        !           413: 
        !           414:        return VideoAddress;
        !           415: }
        !           416: 
        !           417: 
        !           418: /*-----------------------------------------------------------------------*/
        !           419: /**
        !           420:  * Write to VideoShifter (0xff8260), resolution bits
        !           421:  */
1.1.1.9   root      422: static void Video_WriteToShifter(Uint8 Byte)
1.1       root      423: {
1.1.1.11! root      424:        static int nLastHBL = -1, nLastVBL = -1, nLastByte, nLastCycles, nLastFrameCycles;
        !           425:        int nFrameCycles, nLineCycles;
        !           426:        int HblCounterVideo;
        !           427: 
        !           428:        nFrameCycles = Cycles_GetCounterOnWriteAccess(CYCLES_COUNTER_VIDEO);
        !           429: 
        !           430:        /* We only care for cycle position in the actual screen line */
        !           431:        nLineCycles = nFrameCycles % nCyclesPerLine;
        !           432: 
        !           433:        HblCounterVideo = nFrameCycles / nCyclesPerLine;
        !           434: 
        !           435:        HATARI_TRACE ( HATARI_TRACE_VIDEO_RES ,"shifter=0x%2.2X video_cyc_w=%d line_cyc_w=%d @ nHBL=%d/video_hbl_w=%d pc=%x instr_cyc=%d\n",
        !           436:                       Byte, nFrameCycles, nLineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
        !           437: 
        !           438:        /* Remove left border : +26 bytes */
        !           439:        /* this can be done with a hi/lo res switch or a hi/med res switch */
        !           440:        if (nLastByte == 0x02 && Byte == 0x00
        !           441:                && nLineCycles <= (LINE_START_CYCLE_70+28)
        !           442:                && nFrameCycles-nLastFrameCycles <= 30)
        !           443:        {
        !           444:                HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect remove left\n" );
        !           445:                LeftRightBorder |= BORDERMASK_LEFT;
        !           446:                ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_LEFT_OFF;
        !           447:                LineStartCycle = LINE_START_CYCLE_70;
        !           448:        }
        !           449: 
        !           450:        if (nLastByte == 0x02 && Byte == 0x01
        !           451:                && nLineCycles <= (LINE_START_CYCLE_70+20)
        !           452:                && nFrameCycles-nLastFrameCycles <= 30)
        !           453:        {
        !           454:                HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect remove left mid\n" );
        !           455:                LeftRightBorder |= BORDERMASK_LEFT;
        !           456:                ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_LEFT_OFF_MID; /* a later switch to low res might gives right scrolling */
        !           457:                /* By default, this line will be in mid res, except if we detect hardware scrolling later */
        !           458:                ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_OVERSCAN_MID_RES | ( 2 << 20 );
        !           459:                LineStartCycle = LINE_START_CYCLE_70;
        !           460:        }
        !           461: 
        !           462:        /* Empty line switching res */
        !           463:        else if ( ( nFrameCycles-nLastFrameCycles <= 16 )
        !           464:                  && ( nLastCycles == LINE_EMPTY_CYCLE_70 ) )
        !           465:        {
        !           466:                HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect empty line res\n" );
        !           467:                ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_EMPTY_LINE;
        !           468:                LineStartCycle = LINE_START_CYCLE_60;
        !           469:        }
        !           470: 
        !           471:        /* Start right border near middle of the line : -106 bytes */
        !           472: //     if (nLastByte == 0x02 && Byte == 0x00
        !           473: //      && nFrameCycles-nLastFrameCycles <= 20
        !           474: //      && nLineCycles >= LINE_END_CYCLE_70 && nLineCycles <= (LINE_END_CYCLE_70+20) )
        !           475:        if ( ( nLastByte == 0x02 && Byte == 0x00 )
        !           476:                && ( nLastHBL == HblCounterVideo )                      /* switch during the same line */
        !           477:                && ( nLastCycles <= LINE_END_CYCLE_70+4 )               /* switch to hi res before cycle 164 */
        !           478:                && ( nLineCycles >= LINE_END_CYCLE_70+4 ) )             /* switch to lo res after cycle 164 */
        !           479:        {
        !           480:                HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect stop middle\n" );
        !           481:                ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_STOP_MIDDLE;
        !           482:                LineEndCycle = LINE_END_CYCLE_70;
        !           483:        }
        !           484: 
        !           485:        /* Remove right border a second time after removing it a first time : */
        !           486:        /* this removes left border on next line too  (used in 'Enchanted Lands')*/
        !           487:        if ( ScreenBorderMask[ HblCounterVideo ] & BORDERMASK_RIGHT_OFF
        !           488:                && nLastByte == 0x02 && Byte == 0x00
        !           489:                && nFrameCycles-nLastFrameCycles <= 20
        !           490:                && nLastCycles == LINE_END_CYCLE_50_2 )
        !           491:        {
        !           492:                HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect remove right full\n" );
        !           493:                LeftRightBorder |= BORDERMASK_RIGHT;    /* Program tries to open right border */
        !           494:                ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_RIGHT_OFF_FULL;
        !           495:                ScreenBorderMask[ HblCounterVideo+1 ] |= BORDERMASK_LEFT_OFF;   /* no left border on next line */
        !           496:                LineEndCycle = LINE_END_CYCLE_FULL;
        !           497:        }
        !           498: 
        !           499:        /* If left border is opened and we switch to medium resolution */
        !           500:        /* during the next cycles, then we assume a mid res overscan line */
        !           501:        /* instead of a low res overscan line */
        !           502:        /* Used in 'No Cooper' greetings by 1984 and 'Punish Your Machine' by Delta Force */
        !           503:        if ( ScreenBorderMask[ HblCounterVideo ] & BORDERMASK_LEFT_OFF
        !           504:                && Byte == 0x01 )
        !           505:        {
        !           506:                if ( nLineCycles == LINE_LEFT_MID_CYCLE_1 )             /* 'No Cooper' timing */
        !           507:                {
        !           508:                        HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect midres overscan offset 0 byte\n" );
        !           509:                        ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_OVERSCAN_MID_RES | ( 0 << 20 );
        !           510:                }
        !           511:                else if ( nLineCycles == LINE_LEFT_MID_CYCLE_2 )        /* 'Best Part Of The Creation / PYM' timing */
        !           512:                {
        !           513:                        HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect midres overscan offset 2 bytes\n" );
        !           514:                        ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_OVERSCAN_MID_RES | ( 2 << 20 );
        !           515:                }
        !           516:        }
        !           517: 
        !           518:        /* If left border was opened with a hi/mid res switch */
        !           519:        /* we need to check if the switch to low res can trigger */
        !           520:        /* a right hardware scrolling. */
        !           521:        /* We store the pixels count in the upper 16 bits */
        !           522:        if ( ScreenBorderMask[ HblCounterVideo ] & BORDERMASK_LEFT_OFF_MID
        !           523:                && Byte == 0x00 && nLineCycles <= LINE_SCROLL_1_CYCLE_50 )
        !           524:        {
        !           525:                /* The hi/mid switch was a switch to do low res hardware scrolling, */
        !           526:                /* so we must cancel the mid res overscan bit. */
        !           527:                ScreenBorderMask[ HblCounterVideo ] &= (~BORDERMASK_OVERSCAN_MID_RES);
        !           528: 
        !           529:                if ( nLineCycles == LINE_SCROLL_13_CYCLE_50 )           /* cycle 20 */
        !           530:                {
        !           531:                        HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect 13 pixels right scroll\n" );
        !           532:                        ScreenBorderMask[ HblCounterVideo ] |= ( 13 << 16 );
        !           533:                }
        !           534:                else if ( nLineCycles == LINE_SCROLL_9_CYCLE_50 )       /* cycle 24 */
        !           535:                {
        !           536:                        HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect 9 pixels right scroll\n" );
        !           537:                        ScreenBorderMask[ HblCounterVideo ] |= ( 9 << 16 );
        !           538:                }
        !           539:                else if ( nLineCycles == LINE_SCROLL_5_CYCLE_50 )       /* cycle 28 */
        !           540:                {
        !           541:                        HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect 5 pixels right scroll\n" );
        !           542:                        ScreenBorderMask[ HblCounterVideo ] |= ( 5 << 16 );
        !           543:                }
        !           544:                else if ( nLineCycles == LINE_SCROLL_1_CYCLE_50 )       /* cycle 32 */
        !           545:                {
        !           546:                        HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect 1 pixel right scroll\n" );
        !           547:                        ScreenBorderMask[ HblCounterVideo ] |= ( 1 << 16 );
        !           548:                }
        !           549:        }
        !           550: 
        !           551:        nLastVBL = nVBLs;
        !           552:        nLastHBL = HblCounterVideo;
        !           553:        nLastByte = Byte;
        !           554:        nLastCycles = nLineCycles;
        !           555:        nLastFrameCycles = nFrameCycles;
        !           556: }
        !           557: 
        !           558: 
        !           559: /*-----------------------------------------------------------------------*/
        !           560: /**
        !           561:  * Write to VideoSync (0xff820a), Hz setting
        !           562:  */
1.1.1.8   root      563: void Video_Sync_WriteByte(void)
1.1       root      564: {
1.1.1.11! root      565:        static int nLastHBL = -1, nLastVBL = -1, nLastByte, nLastCycles, nLastFrameCycles;
        !           566:        int nFrameCycles, nLineCycles;
        !           567:        int HblCounterVideo;
        !           568:        Uint8 Byte;
        !           569: 
        !           570:        /* We're only interested in lower 2 bits (50/60Hz) */
        !           571:        Byte = IoMem[0xff820a] & 2;                     /* only keep bit 1 (50/60 Hz) */
        !           572: 
        !           573:        nFrameCycles = Cycles_GetCounterOnWriteAccess(CYCLES_COUNTER_VIDEO);
        !           574: 
        !           575:        /* We only care for cycle position in the actual screen line */
        !           576:        nLineCycles = nFrameCycles % nCyclesPerLine;
        !           577: 
        !           578:        HblCounterVideo = nFrameCycles / nCyclesPerLine;
        !           579: 
        !           580:        HATARI_TRACE ( HATARI_TRACE_VIDEO_SYNC ,"sync=0x%2.2X video_cyc_w=%d line_cyc_w=%d @ nHBL=%d/video_hbl_w=%d pc=%x instr_cyc=%d\n",
        !           581:                       Byte, nFrameCycles, nLineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
        !           582: 
        !           583: 
        !           584:        if ( ( nLastByte == 0x00 ) && ( Byte == 0x02 )/* switched from 60 Hz to 50 Hz? */
        !           585:                && ( nLastVBL == nVBLs ) )                      /* switched during the same VBL */
        !           586:        {
        !           587:                /* Add 2 bytes to left border */
        !           588: //             if ( nFrameCycles-nLastFrameCycles <= 24
        !           589: //              && nLastCycles <= LINE_START_CYCLE_60 && nLineCycles >= LINE_START_CYCLE_50 )
        !           590:                if ( ( LastCycleSync60 <= HblCounterVideo * nCyclesPerLine + LINE_START_CYCLE_60 )
        !           591:                        && ( nLineCycles >= LINE_START_CYCLE_50 )       /* The line started in 60 Hz and continues in 50 Hz */
        !           592:                        && ( nLineCycles <= LINE_END_CYCLE_60 )         /* change when line is active */
        !           593:                        && ( ( ScreenBorderMask[ HblCounterVideo ] & ( BORDERMASK_LEFT_OFF | BORDERMASK_LEFT_OFF_MID ) ) == 0 ) )
        !           594:                {
        !           595:                        HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect left+2\n" );
        !           596:                        ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_LEFT_PLUS_2;
        !           597:                        LineStartCycle = LINE_START_CYCLE_60;
        !           598:                }
        !           599: 
        !           600:                /* Empty line switching freq */
        !           601:                else if ( ( nFrameCycles-nLastFrameCycles <= 24 )
        !           602:                          && ( nLastCycles == LINE_START_CYCLE_50 ) && ( nLineCycles > LINE_START_CYCLE_50 ) )
        !           603:                {
        !           604:                        HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect empty line freq\n" );
        !           605:                        ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_EMPTY_LINE;
        !           606:                        LineStartCycle = LINE_START_CYCLE_60;
        !           607:                }
        !           608: 
        !           609:                /* Remove 2 bytes to the right */
        !           610: //      else if ( nFrameCycles-nLastFrameCycles <= 128
        !           611: //     && nLastCycles <= LINE_END_CYCLE_60 && nLineCycles > LINE_END_CYCLE_60
        !           612:                if ( ( nLineCycles > LINE_END_CYCLE_60 )
        !           613:                        && ( ( nLastCycles > LINE_START_CYCLE_60 ) && ( nLastCycles <= LINE_END_CYCLE_60 ) )
        !           614:                        && ( nLastHBL == HblCounterVideo )
        !           615:                        && ( ( ScreenBorderMask[ HblCounterVideo ] & BORDERMASK_STOP_MIDDLE ) == 0 ) )
        !           616:                {
        !           617:                        HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect right-2\n" );
        !           618:                        LeftRightBorder |= BORDERMASK_MIDDLE;   /* Program tries to shorten line by 2 bytes */
        !           619:                        ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_RIGHT_MINUS_2;
        !           620:                        LineEndCycle = LINE_END_CYCLE_60;
        !           621:                }
        !           622:        }
        !           623: 
        !           624:        /* special case for right border : some programs don't switch back to */
        !           625:        /* 50 Hz immediatly (sync screen in SNY II), so we just check if */
        !           626:        /* freq changes to 60 Hz at the position where line should end in 50 Hz */
        !           627:        if ( ( nLastByte == 0x02 && Byte == 0x00 )      /* switched from 50 Hz to 60 Hz? */
        !           628:                && ( HblCounterVideo >= nStartHBL ) )   /* only if display is on */
        !           629:        {
        !           630:                if ( ( nLineCycles == LINE_END_CYCLE_50 )
        !           631:                        && ( ( ScreenBorderMask[ HblCounterVideo ] & BORDERMASK_STOP_MIDDLE ) == 0 ) )
        !           632:                {
        !           633:                        HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect remove right\n" );
        !           634:                        LeftRightBorder |= BORDERMASK_RIGHT;    /* Program tries to open right border */
        !           635:                        ScreenBorderMask[ HblCounterVideo ] |= BORDERMASK_RIGHT_OFF;
        !           636:                        LineEndCycle = LINE_END_CYCLE_NO_RIGHT;
        !           637:                }
        !           638:        }
        !           639: 
        !           640: 
        !           641:        /* Store cycle position of freq 50/60 to check for top/bottom border removal in Video_EndHBL. */
        !           642:        /* Also update start/end line depending on the current value of nHBL */
        !           643:        if ( Byte == 0x02 )                                             /* switch to 50 Hz */
        !           644:        {
        !           645:                LastCycleSync50 = nFrameCycles;
        !           646: 
        !           647:                if ( ( nHBL < SCREEN_START_HBL_50HZ )                   /* nStartHBL can change only if display is not ON yet */
        !           648:                        && ( OverscanMode & OVERSCANMODE_TOP ) == 0 )           /* update only if top was not removed */
        !           649:                        nStartHBL = SCREEN_START_HBL_50HZ;
        !           650: 
        !           651:                if ( ( nHBL < SCREEN_END_HBL_50HZ )                     /* nEndHBL can change only if display is not OFF yet */
        !           652:                        && ( OverscanMode & OVERSCANMODE_BOTTOM ) == 0 )        /* update only if bottom was not removed */
        !           653:                        nEndHBL = SCREEN_END_HBL_50HZ;                          /* 263 */
        !           654:        }
        !           655:        else if ( Byte == 0x00 )                                        /* switch to 60 Hz */
        !           656:        {
        !           657:                LastCycleSync60 = nFrameCycles;
        !           658: 
        !           659:                if ( nHBL < SCREEN_START_HBL_60HZ )                     /* nStartHBL can change only if display is not ON yet */
        !           660:                        nStartHBL = SCREEN_START_HBL_60HZ;
        !           661: 
        !           662:                if ( ( nHBL < SCREEN_END_HBL_60HZ )                     /* nEndHBL can change only if display is not OFF yet */
        !           663:                        && ( OverscanMode & OVERSCANMODE_BOTTOM ) == 0 )        /* update only if bottom was not removed */
        !           664:                        nEndHBL = SCREEN_END_HBL_60HZ;                          /* 234 */
        !           665:        }
        !           666: 
        !           667:        nLastVBL = nVBLs;
        !           668:        nLastHBL = HblCounterVideo;
        !           669:        nLastByte = Byte;
        !           670:        nLastCycles = nLineCycles;
        !           671:        nLastFrameCycles = nFrameCycles;
        !           672: }
        !           673: 
        !           674: 
        !           675: /*-----------------------------------------------------------------------*/
        !           676: /**
        !           677:  * Reset Sync/Shifter table at start of each HBL
        !           678:  */
1.1.1.9   root      679: static void Video_StartHBL(void)
1.1       root      680: {
1.1.1.11! root      681:        int nSyncByte;
        !           682: 
        !           683:        LeftRightBorder = BORDERMASK_NONE;
        !           684: 
        !           685:        nSyncByte = IoMem_ReadByte(0xff820a);
        !           686:        if (nSyncByte & 2)                              /* 50 Hz */
        !           687:        {
        !           688:                LineStartCycle = LINE_START_CYCLE_50;
        !           689:                LineEndCycle = LINE_END_CYCLE_50;
        !           690:        }
        !           691:        else                                            /* 60 Hz */
        !           692:        {
        !           693:                LineStartCycle = LINE_START_CYCLE_60;
        !           694:                LineEndCycle = LINE_END_CYCLE_60;
        !           695:        }
1.1       root      696: }
                    697: 
1.1.1.2   root      698: 
                    699: /*-----------------------------------------------------------------------*/
1.1.1.11! root      700: /**
        !           701:  * Store whole palette on first line so have reference to work from
        !           702:  */
1.1.1.7   root      703: static void Video_StoreFirstLinePalette(void)
1.1       root      704: {
1.1.1.11! root      705:        Uint16 *pp2;
        !           706:        int i;
        !           707: 
        !           708:        pp2 = (Uint16 *)&IoMem[0xff8240];
        !           709:        for (i = 0; i < 16; i++)
        !           710:                HBLPalettes[i] = SDL_SwapBE16(*pp2++);
1.1       root      711: 
1.1.1.11! root      712:        /* And set mask flag with palette and resolution */
        !           713: //     FIXME ; enlever PALETTEMASK_RESOLUTION
        !           714: 
        !           715: //     if ( ScreenBorderMask[ nFirstVisibleHbl ] == BORDERMASK_NONE )  // no border trick, store the current res
        !           716:        HBLPaletteMasks[0] = (PALETTEMASK_RESOLUTION|PALETTEMASK_PALETTE) | (((Uint32)IoMem_ReadByte(0xff8260)&0x3)<<16);
        !           717: //     else                                            // border removal, assume low res for the whole line
        !           718: //             HBLPaletteMasks[0] = (PALETTEMASK_RESOLUTION|PALETTEMASK_PALETTE) | (0<<16);
1.1       root      719: }
                    720: 
1.1.1.2   root      721: 
                    722: /*-----------------------------------------------------------------------*/
1.1.1.11! root      723: /**
        !           724:  * Store resolution on each line (used to test if mixed low/medium resolutions)
        !           725:  */
1.1.1.7   root      726: static void Video_StoreResolution(int y)
1.1       root      727: {
1.1.1.11! root      728:        Uint8 res;
        !           729:        int Mask;
1.1       root      730: 
1.1.1.11! root      731:        /* Clear resolution, and set with current value */
        !           732:        if (!(bUseHighRes || bUseVDIRes))
        !           733:        {
        !           734:                HBLPaletteMasks[y] &= ~(0x3<<16);
        !           735:                res = IoMem_ReadByte(0xff8260)&0x3;
        !           736: 
        !           737:                Mask = ScreenBorderMask[ y+nFirstVisibleHbl ];
        !           738: 
        !           739:                if ( Mask & BORDERMASK_OVERSCAN_MID_RES )               /* special case for mid res to render the overscan line */
        !           740:                        res = 1;                                                /* mid res instead of low res */
        !           741:                else if ( Mask != BORDERMASK_NONE )                     /* border removal : assume low res for the whole line */
        !           742:                        res = 0;
1.1.1.2   root      743: 
1.1.1.11! root      744:                HBLPaletteMasks[y] |= PALETTEMASK_RESOLUTION|((Uint32)res)<<16;
        !           745: 
        !           746: #if 0
        !           747:                if ( ( Mask == BORDERMASK_NONE )                        /* no border trick, store the current res */
        !           748:                        || ( res == 0 ) || ( res == 1 ) )                       /* if border trick, ignore passage to hi res */
        !           749:                        HBLPaletteMasks[y] |= PALETTEMASK_RESOLUTION|((Uint32)res)<<16;
        !           750:                else                                            /* border removal or hi res : assume low res for the whole line */
        !           751:                        HBLPaletteMasks[y] |= (0)<<16;
        !           752: 
        !           753:                /* special case for mid res to render the overscan line */
        !           754:                if ( Mask & BORDERMASK_OVERSCAN_MID_RES )
        !           755:                        HBLPaletteMasks[y] |= PALETTEMASK_RESOLUTION|((Uint32)1)<<16;   /* mid res instead of low res */
        !           756: #endif
1.1       root      757: 
1.1.1.11! root      758: //   fprintf ( stderr , "store res %d line %d %x %x\n" , res , y , Mask , HBLPaletteMasks[y] );
        !           759:        }
1.1.1.9   root      760: }
                    761: 
                    762: 
                    763: /*-----------------------------------------------------------------------*/
1.1.1.11! root      764: /**
        !           765:  * Copy one line of monochrome screen into buffer for conversion later.
        !           766:  */
        !           767: static void Video_CopyScreenLineMono(void)
        !           768: {
        !           769:        Uint32 addr;
        !           770: 
        !           771:        /* Copy one line - 80 bytes in ST high resolution */
        !           772:        memcpy(pSTScreen, pVideoRaster, SCREENBYTES_MONOLINE);
        !           773:        pVideoRaster += SCREENBYTES_MONOLINE;
        !           774: 
        !           775:        /* Handle STE fine scrolling (HWScrollCount is zero on ST). */
        !           776:        if (HWScrollCount)
        !           777:        {
        !           778:                Uint16 *pScrollAdj;
        !           779:                int nNegScrollCnt;
        !           780: 
        !           781:                pScrollAdj = (Uint16 *)pSTScreen;
        !           782:                nNegScrollCnt = 16 - HWScrollCount;
        !           783: 
        !           784:                /* Shift the whole line by the given scroll count */
        !           785:                while ((Uint8*)pScrollAdj < pSTScreen + SCREENBYTES_MONOLINE-2)
        !           786:                {
        !           787:                        do_put_mem_word(pScrollAdj, (do_get_mem_word(pScrollAdj) << HWScrollCount)
        !           788:                                        | (do_get_mem_word(pScrollAdj+1) >> nNegScrollCnt));
        !           789:                        ++pScrollAdj;
        !           790:                }
        !           791: 
        !           792:                /* Handle the last 16 pixels of the line */
        !           793:                do_put_mem_word(pScrollAdj, (do_get_mem_word(pScrollAdj) << HWScrollCount)
        !           794:                                | (do_get_mem_word(pVideoRaster) >> nNegScrollCnt));
        !           795: 
        !           796:                /* HW scrolling advances Shifter video counter by one */
        !           797:                pVideoRaster += 1 * 2;
        !           798:        }
        !           799: 
        !           800:        /* LineWidth is zero on ST. */
        !           801:        /* On STE, the Shifter skips the given amount of words. */
        !           802:        pVideoRaster += LineWidth*2;
        !           803: 
        !           804:        /* On STE, handle modifications of the video counter address $ff8205/07/09 */
        !           805:        /* that occurred while the display was already ON */
        !           806:        if ( NewVideoHi >= 0 )
        !           807:        {
        !           808:                addr = ( ( pVideoRaster - STRam ) & 0x00ffff ) | ( NewVideoHi << 16 );
        !           809:                pVideoRaster = &STRam[addr & ~1];
        !           810:                NewVideoHi = -1;
        !           811:        }
        !           812:        if ( NewVideoMed >= 0 )
        !           813:        {
        !           814:                addr = ( ( pVideoRaster - STRam ) & 0xff00ff ) | ( NewVideoMed << 8 );
        !           815:                pVideoRaster = &STRam[addr & ~1];
        !           816:                NewVideoMed = -1;
        !           817:        }
        !           818:        if ( NewVideoLo >= 0 )
        !           819:        {
        !           820:                addr = ( ( pVideoRaster - STRam ) & 0xffff00 ) | ( NewVideoLo );
        !           821:                pVideoRaster = &STRam[addr & ~1];
        !           822:                NewVideoLo = -1;
        !           823:        }
        !           824: 
        !           825:        /* On STE, if we wrote to the hwscroll register, we set the */
        !           826:        /* new value here, once the current line was processed */
        !           827:        if ( NewHWScrollCount >= 0 )
        !           828:        {
        !           829:                HWScrollCount = NewHWScrollCount;
        !           830:                NewHWScrollCount = -1;
        !           831:        }
        !           832: 
        !           833:        /* On STE, if we wrote to the linewidth register, we set the */
        !           834:        /* new value here, once the current line was processed */
        !           835:        if ( NewLineWidth >= 0 )
        !           836:        {
        !           837:                LineWidth = NewLineWidth;
        !           838:                NewLineWidth = -1;
        !           839:        }
        !           840: 
        !           841:        /* Each screen line copied to buffer is always same length */
        !           842:        pSTScreen += SCREENBYTES_MONOLINE;
        !           843: }
        !           844: 
        !           845: 
        !           846: /*-----------------------------------------------------------------------*/
        !           847: /**
        !           848:  * Copy one line of color screen into buffer for conversion later.
        !           849:  * Possible lines may be top/bottom border, and/or left/right borders.
        !           850:  */
1.1.1.9   root      851: static void Video_CopyScreenLineColor(void)
                    852: {
1.1.1.11! root      853:        int LineBorderMask = ScreenBorderMask[ nHBL ];
        !           854:        int VideoOffset = 0;
        !           855:        int STF_PixelScroll = 0;
        !           856:        Uint32 addr;
        !           857: 
        !           858:        //fprintf(stderr , "copy line %d start %d end %d %d %x\n" , nHBL, nStartHBL, nEndHBL, LineBorderMask, pVideoRaster - STRam);
        !           859: 
        !           860:        /* If left border is opened, we need to compensate one missing word in low res (1 plan) */
        !           861:        /* If overscan is in mid res, the offset is variable */
        !           862:        if ( LineBorderMask & BORDERMASK_OVERSCAN_MID_RES )
        !           863:                VideoOffset = - ( ( LineBorderMask >> 20 ) & 0x0f );            /* No Cooper=0  PYM=-2 in mid res overscan */
        !           864: 
        !           865:        else if ( LineBorderMask & BORDERMASK_LEFT_OFF )
        !           866:                VideoOffset = -2;                                                       /* always 2 bytes in low res overscan */
        !           867: 
        !           868:        /* Handle 4 pixels hardware scrolling ('ST Cnx' demo in 'Punish Your Machine') */
        !           869:        /* Depending on the number of pixels, we need to compensate for some skipped words */
        !           870:        else if ( LineBorderMask & BORDERMASK_LEFT_OFF_MID )
        !           871:        {
        !           872:                STF_PixelScroll = ( LineBorderMask >> 16 ) & 0x0f;
        !           873: 
        !           874:                if      ( STF_PixelScroll == 13 )       VideoOffset = 2+8;
        !           875:                else if ( STF_PixelScroll == 9 )        VideoOffset = 0+8;
        !           876:                else if ( STF_PixelScroll == 5 )        VideoOffset = -2+8;
        !           877:                else if ( STF_PixelScroll == 1 )        VideoOffset = -4+8;
        !           878:                else                                    VideoOffset = 0;        /* never used ? */
        !           879: 
        !           880:                // fprintf(stderr , "scr off %d %d\n" , STF_PixelScroll , VideoOffset);
        !           881:        }
        !           882: 
        !           883:        /* Is total blank line? I.e. top/bottom border? */
        !           884:        if ((nHBL < nStartHBL) || (nHBL >= nEndHBL)
        !           885:            || (LineBorderMask & BORDERMASK_EMPTY_LINE))        /* 60/50 Hz trick to obtain an empty line */
        !           886:        {
        !           887:                /* Clear line to color '0' */
        !           888:                memset(pSTScreen, 0, SCREENBYTES_LINE);
        !           889:        }
        !           890:        else
        !           891:        {
        !           892:                /* Does have left border? If not, clear to color '0' */
        !           893:                if ((LineBorderMask & BORDERMASK_LEFT_OFF)
        !           894:                    || (LineBorderMask & BORDERMASK_LEFT_OFF_MID))
        !           895:                {
        !           896:                        /* The "-2" in the following line is needed so that the offset is a multiple of 8 */
        !           897:                        pVideoRaster += BORDERBYTES_LEFT-SCREENBYTES_LEFT+VideoOffset;
        !           898:                        memcpy(pSTScreen, pVideoRaster, SCREENBYTES_LEFT);
        !           899:                        pVideoRaster += SCREENBYTES_LEFT;
        !           900:                }
        !           901:                else if (LineBorderMask & BORDERMASK_LEFT_PLUS_2)
        !           902:                {
        !           903:                        /* bigger line by 2 bytes */
        !           904:                        memcpy(pSTScreen+SCREENBYTES_LEFT-2, pVideoRaster, 2);
        !           905:                        pVideoRaster += 2;
        !           906:                }
        !           907:                else
        !           908:                        memset(pSTScreen,0,SCREENBYTES_LEFT);
        !           909: 
        !           910:                /* Short line due to hires in the middle ? */
        !           911:                if (LineBorderMask & BORDERMASK_STOP_MIDDLE)
        !           912:                {
        !           913:                        /* 106 bytes less in the line */
        !           914:                        memcpy(pSTScreen+SCREENBYTES_LEFT, pVideoRaster, SCREENBYTES_MIDDLE-106);
        !           915:                        pVideoRaster += (SCREENBYTES_MIDDLE-106);
        !           916:                }
        !           917:                else
        !           918:                {
        !           919:                        /* normal middle part (160 bytes) */
        !           920:                        memcpy(pSTScreen+SCREENBYTES_LEFT, pVideoRaster, SCREENBYTES_MIDDLE);
        !           921:                        pVideoRaster += SCREENBYTES_MIDDLE;
        !           922:                }
        !           923: 
        !           924:                /* Does have right border ? */
        !           925:                if (LineBorderMask & BORDERMASK_RIGHT_OFF)
        !           926:                {
        !           927:                        memcpy(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE, pVideoRaster, SCREENBYTES_RIGHT);
        !           928:                        pVideoRaster += BORDERBYTES_RIGHT-SCREENBYTES_RIGHT;
        !           929:                        pVideoRaster += SCREENBYTES_RIGHT;
        !           930:                }
        !           931:                else if (LineBorderMask & BORDERMASK_RIGHT_MINUS_2)
        !           932:                {
        !           933:                        /* Shortened line by 2 bytes */
        !           934:                        memset(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE-2, 0, SCREENBYTES_RIGHT+2);
        !           935:                        pVideoRaster -= 2;
        !           936:                }
        !           937:                else
        !           938:                {
        !           939:                        /* Simply clear right border to '0' */
        !           940:                        memset(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE,0,SCREENBYTES_RIGHT);
        !           941:                }
        !           942: 
        !           943:                /* Full right border removal up to the end of the line (cycle 512) */
        !           944:                if (LineBorderMask & BORDERMASK_RIGHT_OFF_FULL)
        !           945:                        pVideoRaster += BORDERBYTES_RIGHT_FULL;
        !           946: 
        !           947:                /* Correct the offset for pVideoRaster from BORDERMASK_LEFT_OFF above if needed */
        !           948:                pVideoRaster -= VideoOffset;            /* VideoOffset is 0 or -2 */
        !           949: 
        !           950: 
        !           951:                /* Handle 4 pixels hardware scrolling ('ST Cnx' demo in 'Punish Your Machine') */
        !           952:                /* Shift the line by STF_PixelScroll pixels to the right (we don't need to scroll */
        !           953:                /* the first 16 pixels / 8 bytes). */
        !           954:                if (STF_PixelScroll != 0)
        !           955:                {
        !           956:                        Uint16 *pScreenLineEnd;
        !           957:                        int count;
        !           958: 
        !           959:                        pScreenLineEnd = (Uint16 *) ( pSTScreen + SCREENBYTES_LINE - 2 );
        !           960:                        for ( count = 0 ; count < ( SCREENBYTES_LINE - 8 ) / 2 ; count++ , pScreenLineEnd-- )
        !           961:                                do_put_mem_word ( pScreenLineEnd , ( ( do_get_mem_word ( pScreenLineEnd - 4 ) << 16 ) | ( do_get_mem_word ( pScreenLineEnd ) ) ) >> STF_PixelScroll );
        !           962:                }
        !           963: 
        !           964: 
        !           965:                /* STE specific */
        !           966:                if (bSteBorderFlag)
        !           967:                {
        !           968:                        memcpy(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE, pVideoRaster, 4*2);
        !           969:                        pVideoRaster += 4 * 2;
        !           970:                }
        !           971:                else if (HWScrollCount)     /* Handle STE fine scrolling (HWScrollCount is zero on ST) */
        !           972:                {
        !           973:                        Uint16 *pScrollAdj;     /* Pointer to actual position in line */
        !           974:                        int nNegScrollCnt;
        !           975:                        Uint16 *pScrollEndAddr; /* Pointer to end of the line */
        !           976: 
        !           977:                        nNegScrollCnt = 16 - HWScrollCount;
        !           978:                        if (LineBorderMask & BORDERMASK_LEFT_OFF)
        !           979:                                pScrollAdj = (Uint16 *)pSTScreen;
        !           980:                        else
        !           981:                                pScrollAdj = (Uint16 *)(pSTScreen + SCREENBYTES_LEFT);
        !           982:                        if (LineBorderMask & BORDERMASK_RIGHT_OFF)
        !           983:                                pScrollEndAddr = (Uint16 *)(pSTScreen + SCREENBYTES_LINE - 8);
        !           984:                        else
        !           985:                                pScrollEndAddr = (Uint16 *)(pSTScreen + SCREENBYTES_LEFT + SCREENBYTES_MIDDLE - 8);
        !           986: 
        !           987:                        if (STRes == ST_MEDIUM_RES)
        !           988:                        {
        !           989:                                /* TODO: Implement fine scrolling for medium resolution, too */
        !           990:                                /* HW scrolling advances Shifter video counter by one */
        !           991:                                pVideoRaster += 2 * 2;
        !           992:                        }
        !           993:                        else
        !           994:                        {
        !           995:                                /* Shift the whole line to the left by the given scroll count */
        !           996:                                while (pScrollAdj < pScrollEndAddr)
        !           997:                                {
        !           998:                                        do_put_mem_word(pScrollAdj, (do_get_mem_word(pScrollAdj) << HWScrollCount)
        !           999:                                                        | (do_get_mem_word(pScrollAdj+4) >> nNegScrollCnt));
        !          1000:                                        ++pScrollAdj;
        !          1001:                                }
        !          1002:                                /* Handle the last 16 pixels of the line */
        !          1003:                                if (LineBorderMask & BORDERMASK_RIGHT_OFF)
        !          1004:                                {
        !          1005:                                        /* When right border is open, we have to deal with this ugly offset
        !          1006:                                         * of 46-SCREENBYTES_RIGHT - The demo "Mind rewind" is a good example */
        !          1007:                                        Uint16 *pVideoLineEnd = (Uint16 *)(pVideoRaster - (46 - SCREENBYTES_RIGHT));
        !          1008:                                        do_put_mem_word(pScrollAdj+0, (do_get_mem_word(pScrollAdj+0) << HWScrollCount)
        !          1009:                                                        | (do_get_mem_word(pVideoLineEnd++) >> nNegScrollCnt));
        !          1010:                                        do_put_mem_word(pScrollAdj+1, (do_get_mem_word(pScrollAdj+1) << HWScrollCount)
        !          1011:                                                        | (do_get_mem_word(pVideoLineEnd++) >> nNegScrollCnt));
        !          1012:                                        do_put_mem_word(pScrollAdj+2, (do_get_mem_word(pScrollAdj+2) << HWScrollCount)
        !          1013:                                                        | (do_get_mem_word(pVideoLineEnd++) >> nNegScrollCnt));
        !          1014:                                        do_put_mem_word(pScrollAdj+3, (do_get_mem_word(pScrollAdj+3) << HWScrollCount)
        !          1015:                                                        | (do_get_mem_word(pVideoLineEnd++) >> nNegScrollCnt));
        !          1016:                                }
        !          1017:                                else
        !          1018:                                {
        !          1019:                                        do_put_mem_word(pScrollAdj+0, (do_get_mem_word(pScrollAdj+0) << HWScrollCount)
        !          1020:                                                        | (do_get_mem_word(pVideoRaster+0) >> nNegScrollCnt));
        !          1021:                                        do_put_mem_word(pScrollAdj+1, (do_get_mem_word(pScrollAdj+1) << HWScrollCount)
        !          1022:                                                        | (do_get_mem_word(pVideoRaster+2) >> nNegScrollCnt));
        !          1023:                                        do_put_mem_word(pScrollAdj+2, (do_get_mem_word(pScrollAdj+2) << HWScrollCount)
        !          1024:                                                        | (do_get_mem_word(pVideoRaster+4) >> nNegScrollCnt));
        !          1025:                                        do_put_mem_word(pScrollAdj+3, (do_get_mem_word(pScrollAdj+3) << HWScrollCount)
        !          1026:                                                        | (do_get_mem_word(pVideoRaster+6) >> nNegScrollCnt));
        !          1027:                                }
        !          1028:                                /* HW scrolling advances Shifter video counter by one */
        !          1029:                                pVideoRaster += 4 * 2;
        !          1030: 
        !          1031:                                /* On STE, when we have a 230 bytes overscan line and HWScrollCount > 0 */
        !          1032:                                /* we must read 6 bytes less than expected */
        !          1033:                                if ( (LineBorderMask & BORDERMASK_LEFT_OFF) && (LineBorderMask & BORDERMASK_RIGHT_OFF) )
        !          1034:                                        pVideoRaster -= 6;              /* we don't add 8 bytes, but 2 */
        !          1035: 
        !          1036:                        }
        !          1037:                }
        !          1038: 
        !          1039:                /* LineWidth is zero on ST. */
        !          1040:                /* On STE, the Shifter skips the given amount of words. */
        !          1041:                pVideoRaster += LineWidth*2;
        !          1042: 
        !          1043:                /* On STE, handle modifications of the video counter address $ff8205/07/09 */
        !          1044:                /* that occurred while the display was already ON */
        !          1045:                if ( NewVideoHi >= 0 )
        !          1046:                {
        !          1047:                        addr = ( ( pVideoRaster - STRam ) & 0x00ffff ) | ( NewVideoHi << 16 );
        !          1048:                        pVideoRaster = &STRam[addr & ~1];
        !          1049:                        NewVideoHi = -1;
        !          1050:                }
        !          1051:                if ( NewVideoMed >= 0 )
        !          1052:                {
        !          1053:                        addr = ( ( pVideoRaster - STRam ) & 0xff00ff ) | ( NewVideoMed << 8 );
        !          1054:                        pVideoRaster = &STRam[addr & ~1];
        !          1055:                        NewVideoMed = -1;
        !          1056:                }
        !          1057:                if ( NewVideoLo >= 0 )
        !          1058:                {
        !          1059:                        addr = ( ( pVideoRaster - STRam ) & 0xffff00 ) | ( NewVideoLo );
        !          1060:                        pVideoRaster = &STRam[addr & ~1];
        !          1061:                        NewVideoLo = -1;
        !          1062:                }
        !          1063: 
        !          1064:                /* On STE, if we wrote to the hwscroll register, we set the */
        !          1065:                /* new value here, once the current line was processed */
        !          1066:                if ( NewHWScrollCount >= 0 )
        !          1067:                {
        !          1068:                        HWScrollCount = NewHWScrollCount;
        !          1069:                        NewHWScrollCount = -1;
        !          1070:                }
        !          1071: 
        !          1072:                /* On STE, if we wrote to the linewidth register, we set the */
        !          1073:                /* new value here, once the current line was processed */
        !          1074:                if ( NewLineWidth >= 0 )
        !          1075:                {
        !          1076:                        LineWidth = NewLineWidth;
        !          1077:                        NewLineWidth = -1;
        !          1078:                }
        !          1079:        }
        !          1080: 
        !          1081:        /* Each screen line copied to buffer is always same length */
        !          1082:        pSTScreen += SCREENBYTES_LINE;
        !          1083: }
        !          1084: 
        !          1085: 
        !          1086: /*-----------------------------------------------------------------------*/
        !          1087: /**
        !          1088:  * Copy extended GEM resolution screen
        !          1089:  */
1.1.1.9   root     1090: static void Video_CopyVDIScreen(void)
1.1       root     1091: {
1.1.1.11! root     1092:        /* Copy whole screen, don't care about being exact as for GEM only */
        !          1093:        memcpy(pSTScreen, pVideoRaster, ((VDIWidth*VDIPlanes)/8)*VDIHeight);
1.1       root     1094: }
                   1095: 
1.1.1.2   root     1096: 
                   1097: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1098: /**
        !          1099:  * Check at end of each HBL to see if any Sync/Shifter hardware tricks have been attempted
        !          1100:  * This is the place to check if top/bottom border were removed.
        !          1101:  * NOTE : the tests must be made with nHBL in ascending order.
        !          1102:  */
1.1.1.9   root     1103: static void Video_EndHBL(void)
1.1       root     1104: {
1.1.1.11! root     1105:        Uint8 SyncByte = IoMem_ReadByte(0xff820a) & 2;  /* only keep bit 1 (50/60 Hz) */
        !          1106: 
        !          1107:        // fprintf(stderr,"video_endhbl %d last60 %d last 50 %d\n", nHBL, LastCycleSync60, LastCycleSync50);
        !          1108: 
        !          1109:        /* Remove top border if the switch to 60 Hz was made during this vbl before cycle       */
        !          1110:        /* 33*512+LINE_REMOVE_TOP_CYCLE and if the switch to 50 Hz has not yet occured or       */
        !          1111:        /* occured before the 60 Hz or occured after cycle 33*512+LINE_REMOVE_TOP_CYCLE.        */
        !          1112:        if (( nHBL == SCREEN_START_HBL_60HZ-1)
        !          1113:            && ((LastCycleSync60 >= 0) && (LastCycleSync60 <= (SCREEN_START_HBL_60HZ-1) * nCyclesPerLine + LINE_REMOVE_TOP_CYCLE))
        !          1114:            && ((LastCycleSync50 < LastCycleSync60) || (LastCycleSync50 > (SCREEN_START_HBL_60HZ-1) * nCyclesPerLine + LINE_REMOVE_TOP_CYCLE)))
        !          1115:        {
        !          1116:                /* Top border */
        !          1117:                HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_V , "detect remove top\n" );
        !          1118:                OverscanMode |= OVERSCANMODE_TOP;               /* Set overscan bit */
        !          1119:                nStartHBL = SCREEN_START_HBL_60HZ;      /* New start screen line */
        !          1120:                pHBLPaletteMasks -= OVERSCAN_TOP;       // FIXME useless ?
        !          1121:                pHBLPalettes -= OVERSCAN_TOP;   // FIXME useless ?
        !          1122:        }
        !          1123: 
        !          1124:        /* Remove bottom border for a 60 Hz screen */
        !          1125:        else if ((nHBL == SCREEN_END_HBL_60HZ-1)        /* last displayed line in 60 Hz */
        !          1126:                 && (SyncByte == 0x02)                  /* current freq is 50 Hz */
        !          1127:                 && (LastCycleSync50 >= 0)                      /* change occurred during this VBL */
        !          1128:                 && (nStartHBL == SCREEN_START_HBL_60HZ)        /* screen starts in 60 Hz */
        !          1129:                 && ((OverscanMode & OVERSCANMODE_TOP) == 0))   /* and top border was not removed : this screen is only 60 Hz */
        !          1130:        {
        !          1131:                HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_V , "detect remove bottom 60Hz\n" );
        !          1132:                OverscanMode |= OVERSCANMODE_BOTTOM;
        !          1133:                nEndHBL = SCANLINES_PER_FRAME_60HZ;     /* new end for a 60 Hz screen */
        !          1134:        }
        !          1135: 
        !          1136:        /* Remove bottom border for a 50 Hz screen (similar method to the one for top border) */
        !          1137:        else if ((nHBL == SCREEN_END_HBL_50HZ-1)        /* last displayed line in 50 Hz */
        !          1138:                  && ((LastCycleSync60 >= 0) && (LastCycleSync60 <= (SCREEN_END_HBL_50HZ-1) * nCyclesPerLine + LINE_REMOVE_BOTTOM_CYCLE))
        !          1139:                  && ((LastCycleSync50 < LastCycleSync60) || (LastCycleSync50 > (SCREEN_END_HBL_50HZ-1) * nCyclesPerLine + LINE_REMOVE_BOTTOM_CYCLE))
        !          1140:                  && ((OverscanMode & OVERSCANMODE_BOTTOM) == 0))       /* border was not already removed at line SCREEN_END_HBL_60HZ */
        !          1141:        {
        !          1142:                HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_V , "detect remove bottom\n" );
        !          1143:                OverscanMode |= OVERSCANMODE_BOTTOM;
        !          1144:                nEndHBL = SCREEN_END_HBL_50HZ+OVERSCAN_BOTTOM;  /* new end for a 50 Hz screen */
        !          1145: 
        !          1146:                /* Some programs turn to 60 Hz during the active display of the last line to */
        !          1147:                /* remove the bottom border (FNIL by TNT), in that case, we should also remove */
        !          1148:                /* 2 bytes to this line (this is wrong practice as it can distort the display on a real ST) */
        !          1149:                if (LastCycleSync60 <= (SCREEN_END_HBL_50HZ-1) * nCyclesPerLine + LINE_END_CYCLE_60)
        !          1150:                {
        !          1151:                        HATARI_TRACE ( HATARI_TRACE_VIDEO_BORDER_H , "detect right-2\n" );
        !          1152:                        LeftRightBorder |= BORDERMASK_MIDDLE;           /* Program tries to shorten line by 2 bytes */
        !          1153:                        ScreenBorderMask[ nHBL ] |= BORDERMASK_RIGHT_MINUS_2;
        !          1154:                        LineEndCycle = LINE_END_CYCLE_60;
        !          1155:                }
        !          1156:        }
        !          1157: 
        !          1158:        /* Store palette for very first line on screen - HBLPalettes[0] */
        !          1159:        if (nHBL == nFirstVisibleHbl)
        !          1160:        {
        !          1161:                /* Store ALL palette for this line into raster table for datum */
        !          1162:                Video_StoreFirstLinePalette();
        !          1163:        }
        !          1164: 
        !          1165:        if (!bUseVDIRes)
        !          1166:        {
        !          1167:                if (bUseHighRes)
        !          1168:                {
        !          1169:                        /* Copy for hi-res (no overscan) */
        !          1170:                        if (nHBL >= nFirstVisibleHbl && nHBL < nFirstVisibleHbl+SCREEN_HEIGHT_HBL_MONO)
        !          1171:                                Video_CopyScreenLineMono();
        !          1172:                }
        !          1173:                /* Are we in possible visible color display (including borders)? */
        !          1174:                else if (nHBL >= nFirstVisibleHbl && nHBL < nFirstVisibleHbl+NUM_VISIBLE_LINES)
        !          1175:                {
        !          1176:                        /* Copy line of screen to buffer to simulate TV raster trace
        !          1177:                         * - required for mouse cursor display/game updates
        !          1178:                         * Eg, Lemmings and The Killing Game Show are good examples */
        !          1179:                        Video_CopyScreenLineColor();
        !          1180: 
        !          1181:                        /* Store resolution for every line so can check for mix low/med screens */
        !          1182:                        Video_StoreResolution(nHBL-nFirstVisibleHbl);
        !          1183:                }
        !          1184:        }
        !          1185: 
        !          1186:        /* Finally increase HBL count */
        !          1187:        nHBL++;
        !          1188: 
        !          1189:        Video_StartHBL();                  /* Setup next one */
        !          1190: }
        !          1191: 
        !          1192: 
        !          1193: /*-----------------------------------------------------------------------*/
        !          1194: /**
        !          1195:  * HBL interrupt : this occurs at the end of every line, on cycle 512 (in 50 Hz)
        !          1196:  * It takes 56 cycles to handle the 68000's exception.
        !          1197:  */
        !          1198: void Video_InterruptHandler_HBL(void)
        !          1199: {
        !          1200:        HATARI_TRACE ( HATARI_TRACE_VIDEO_HBL , "HBL %d video_cyc=%d pending_int_cnt=%d\n" ,
        !          1201:                       nHBL , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE ) );
1.1.1.10  root     1202: 
1.1.1.11! root     1203:        /* Remove this interrupt from list and re-order */
        !          1204:        Int_AcknowledgeInterrupt();
        !          1205: 
        !          1206:        /* Generate new HBL, if need to - there are 313 HBLs per frame in 50 Hz */
        !          1207:        if (nHBL < nScanlinesPerFrame-1)
        !          1208:                Int_AddAbsoluteInterrupt(nCyclesPerLine, INT_CPU_CYCLE, INTERRUPT_VIDEO_HBL);
        !          1209: 
        !          1210:        M68000_Exception ( EXCEPTION_HBLANK , M68000_INT_VIDEO );       /* Horizontal blank interrupt, level 2! */
        !          1211: 
        !          1212:        Video_EndHBL();              /* Increase HBL count, copy line to display buffer and do any video trickery */
1.1       root     1213: }
                   1214: 
1.1.1.2   root     1215: 
1.1.1.9   root     1216: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1217: /**
        !          1218:  * End Of Line interrupt
        !          1219:  *  As this occurs at the end of a line we cannot get timing for START of first
        !          1220:  * line (as in Spectrum 512)
        !          1221:  */
1.1.1.9   root     1222: void Video_InterruptHandler_EndLine(void)
                   1223: {
1.1.1.11! root     1224:        /* Remove this interrupt from list and re-order */
        !          1225:        Int_AcknowledgeInterrupt();
        !          1226:        /* Generate new Endline, if need to - there are 313 HBLs per frame */
        !          1227:        if (nHBL < nScanlinesPerFrame-1)
        !          1228:                Int_AddAbsoluteInterrupt(nCyclesPerLine, INT_CPU_CYCLE, INTERRUPT_VIDEO_ENDLINE);
        !          1229: 
        !          1230:        /* Is this a good place to send the keyboard packets? Done once per frame */
        !          1231:        if (nHBL == nStartHBL)
        !          1232:        {
        !          1233:                /* On each VBL send automatic keyboard packets for mouse, joysticks etc... */
        !          1234:                IKBD_SendAutoKeyboardCommands();
        !          1235:        }
        !          1236: 
        !          1237:        /* Timer B occurs at END of first visible screen line in Event Count mode */
        !          1238:        if (nHBL >= nStartHBL && nHBL < nEndHBL)
        !          1239:        {
        !          1240:                /* Handle Timer B when using Event Count mode */
        !          1241:                if (MFP_TBCR == 0x08)      /* Is timer in Event Count mode? */
        !          1242:                        MFP_TimerB_EventCount_Interrupt();
        !          1243:        }
        !          1244: 
        !          1245:        //Video_EndHBL();  /* now done in Video_InterruptHandler_HBL */
        !          1246: 
        !          1247:        /* If we don't often pump data into the event queue, the SDL misses events... grr... */
        !          1248:        if (!(nHBL & 63))
        !          1249:        {
        !          1250:                Main_EventHandler();
        !          1251:        }
1.1.1.9   root     1252: }
                   1253: 
                   1254: 
                   1255: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1256: /**
        !          1257:  * Clear raster line table to store changes in palette/resolution on a line
        !          1258:  * basic. Called once on VBL interrupt.
        !          1259:  */
1.1       root     1260: void Video_SetScreenRasters(void)
                   1261: {
1.1.1.11! root     1262:        pHBLPaletteMasks = HBLPaletteMasks;
        !          1263:        pHBLPalettes = HBLPalettes;
        !          1264:        memset(pHBLPaletteMasks, 0, sizeof(Uint32)*NUM_VISIBLE_LINES);  /* Clear array */
1.1       root     1265: }
                   1266: 
1.1.1.2   root     1267: 
                   1268: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1269: /**
        !          1270:  * Set pointers to HBLPalette tables to store correct colours/resolutions
        !          1271:  */
1.1.1.9   root     1272: static void Video_SetHBLPaletteMaskPointers(void)
1.1       root     1273: {
1.1.1.11! root     1274:        int FrameCycles;
        !          1275:        int Line;
        !          1276:        int Cycle;
        !          1277: 
        !          1278:        /* FIXME [NP] We should use Cycles_GetCounterOnWriteAccess, but it wouldn't     */
        !          1279:        /* work when using multiple accesses instructions like move.l or movem  */
        !          1280:        /* To correct this, assume a delay of 8 cycles (should give a good approximation */
        !          1281:        /* of a move.w or movem.l for example) */
        !          1282:        //  FrameCycles = Cycles_GetCounterOnWriteAccess(CYCLES_COUNTER_VIDEO);
        !          1283:        FrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO) + 8;
        !          1284: 
        !          1285:        /* Find 'line' into palette - screen starts 63 lines down, less 29 for top overscan */
        !          1286:        Line = (FrameCycles-(nFirstVisibleHbl*nCyclesPerLine)+SCREEN_START_CYCLE)/nCyclesPerLine;
        !          1287: //     Line = ( FrameCycles / nCyclesPerLine ) - nFirstVisibleHbl;
        !          1288:        Cycle = FrameCycles % nCyclesPerLine;
        !          1289: 
        !          1290:        /* FIXME [NP] if the color change occurs after the last visible pixel of a line */
        !          1291:        /* we consider the palette should be modified on the next line. This is quite */
        !          1292:        /* a hack, we should handle all color changes through spec512.c to have cycle */
        !          1293:        /* accuracy all the time. */
        !          1294: //     if ( Cycle >= LINE_END_CYCLE_NO_RIGHT-8 );
        !          1295: //             Line++;
        !          1296: 
        !          1297:        if (Line < 0)        /* Limit to top/bottom of possible visible screen */
        !          1298:                Line = 0;
        !          1299:        if (Line >= NUM_VISIBLE_LINES)
        !          1300:                Line = NUM_VISIBLE_LINES-1;
        !          1301: 
        !          1302:        /* Store pointers */
        !          1303:        pHBLPaletteMasks = &HBLPaletteMasks[Line];  /* Next mask entry */
        !          1304:        pHBLPalettes = &HBLPalettes[16*Line];       /* Next colour raster list x16 colours */
1.1       root     1305: }
1.1.1.8   root     1306: 
                   1307: 
1.1.1.9   root     1308: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1309: /**
        !          1310:  * Set video shifter timing variables according to screen refresh rate.
        !          1311:  * Note: The following equation must be satisfied for correct timings:
        !          1312:  *
        !          1313:  *   nCyclesPerLine * nScanlinesPerFrame * nScreenRefreshRate = 8 MHz
        !          1314:  */
1.1.1.10  root     1315: static void Video_ResetShifterTimings(void)
                   1316: {
1.1.1.11! root     1317:        Uint8 nSyncByte;
1.1.1.10  root     1318: 
1.1.1.11! root     1319:        nSyncByte = IoMem_ReadByte(0xff820a);
1.1.1.10  root     1320: 
1.1.1.11! root     1321:        if (bUseHighRes)
        !          1322:        {
        !          1323:                /* 71 Hz, monochrome */
        !          1324:                nScreenRefreshRate = 71;
        !          1325:                nScanlinesPerFrame = SCANLINES_PER_FRAME_71HZ;
        !          1326:                nCyclesPerLine = CYCLES_PER_LINE_71HZ;
        !          1327:                nStartHBL = SCREEN_START_HBL_71HZ;
        !          1328:                nFirstVisibleHbl = FIRST_VISIBLE_HBL_71HZ;
        !          1329:        }
        !          1330:        else if (nSyncByte & 2)  /* Check if running in 50 Hz or in 60 Hz */
        !          1331:        {
        !          1332:                /* 50 Hz */
        !          1333:                nScreenRefreshRate = 50;
        !          1334:                nScanlinesPerFrame = SCANLINES_PER_FRAME_50HZ;
        !          1335:                nCyclesPerLine = CYCLES_PER_LINE_50HZ;
        !          1336:                nStartHBL = SCREEN_START_HBL_50HZ;
        !          1337:                nFirstVisibleHbl = FIRST_VISIBLE_HBL_50HZ;
        !          1338:        }
        !          1339:        else
        !          1340:        {
        !          1341:                /* 60 Hz */
        !          1342:                nScreenRefreshRate = 60;
        !          1343:                nScanlinesPerFrame = SCANLINES_PER_FRAME_60HZ;
        !          1344:                nCyclesPerLine = CYCLES_PER_LINE_60HZ;
        !          1345:                nStartHBL = SCREEN_START_HBL_60HZ;
        !          1346:                nFirstVisibleHbl = FIRST_VISIBLE_HBL_60HZ;
        !          1347:        }
        !          1348: 
        !          1349:        if (bUseHighRes)
        !          1350:        {
        !          1351:                nEndHBL = nStartHBL + SCREEN_HEIGHT_HBL_MONO;
        !          1352:        }
        !          1353:        else
        !          1354:        {
        !          1355:                nEndHBL = nStartHBL + SCREEN_HEIGHT_HBL_COLOR;
        !          1356:        }
        !          1357: 
        !          1358:        /* Reset freq changes position for the next VBL to come */
        !          1359:        LastCycleSync50 = -1;
        !          1360:        LastCycleSync60 = -1;
        !          1361: }
1.1.1.10  root     1362: 
                   1363: 
1.1.1.11! root     1364: /*-----------------------------------------------------------------------*/
        !          1365: /**
        !          1366:  * Clear the array indicating the border state of each line
        !          1367:  */
        !          1368: static void Video_ClearScreenBorder(void)
        !          1369: {
        !          1370:        memset(ScreenBorderMask, 0, sizeof(int)*MAX_SCANLINES_PER_FRAME);
1.1.1.10  root     1371: }
                   1372: 
                   1373: 
                   1374: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1375: /**
        !          1376:  * Called on VBL, set registers ready for frame
        !          1377:  */
1.1.1.9   root     1378: static void Video_ClearOnVBL(void)
                   1379: {
1.1.1.11! root     1380:        /* New screen, so first HBL */
        !          1381:        nHBL = 0;
        !          1382:        OverscanMode = OVERSCANMODE_NONE;
        !          1383: 
        !          1384:        Video_ResetShifterTimings();
        !          1385: 
        !          1386:        /* Get screen address pointer, aligned to 256 bytes on ST (ie ignore lowest byte) */
        !          1387:        VideoBase = (Uint32)IoMem_ReadByte(0xff8201)<<16 | (Uint32)IoMem_ReadByte(0xff8203)<<8;
        !          1388:        if (ConfigureParams.System.nMachineType != MACHINE_ST)
        !          1389:        {
        !          1390:                /* on STe 2 aligned, on Falcon 4 aligned, on TT 8 aligned. We do STe. */
        !          1391:                VideoBase |= IoMem_ReadByte(0xff820d) & ~1;
        !          1392:        }
        !          1393:        pVideoRaster = &STRam[VideoBase];
        !          1394:        pSTScreen = pFrameBuffer->pSTScreen;
        !          1395: 
        !          1396:        Video_StartHBL();
        !          1397:        Video_SetScreenRasters();
        !          1398:        Video_ClearScreenBorder();
        !          1399:        Spec512_StartVBL();
        !          1400: }
        !          1401: 
        !          1402: 
        !          1403: /*-----------------------------------------------------------------------*/
        !          1404: /**
        !          1405:  * Get width, height and bpp according to TT-Resolution
        !          1406:  */
        !          1407: void Video_GetTTRes(int *width, int *height, int *bpp)
        !          1408: {
        !          1409:        switch (TTRes)
        !          1410:        {
        !          1411:         case ST_LOW_RES:   *width = 320;  *height = 200; *bpp = 4; break;
        !          1412:         case ST_MEDIUM_RES:*width = 640;  *height = 200; *bpp = 2; break;
        !          1413:         case ST_HIGH_RES:  *width = 640;  *height = 400; *bpp = 1; break;
        !          1414:         case TT_LOW_RES:   *width = 320;  *height = 480; *bpp = 8; break;
        !          1415:         case TT_MEDIUM_RES:*width = 640;  *height = 480; *bpp = 4; break;
        !          1416:         case TT_HIGH_RES:  *width = 1280; *height = 960; *bpp = 1; break;
        !          1417:         default:
        !          1418:                fprintf(stderr, "TT res error!\n");
        !          1419:                *width = 320; *height = 200; *bpp = 4;
        !          1420:                break;
        !          1421:        }
        !          1422: }
        !          1423: 
        !          1424: 
        !          1425: /*-----------------------------------------------------------------------*/
        !          1426: /**
        !          1427:  * Convert TT palette to SDL palette
        !          1428:  */
        !          1429: static void Video_UpdateTTPalette(int bpp)
        !          1430: {
        !          1431:        Uint32 ttpalette, src, dst;
        !          1432:        Uint8 r,g,b, lowbyte, highbyte;
        !          1433:        Uint16 stcolor, ttcolor;
        !          1434:        int i, offset, colors;
        !          1435: 
        !          1436:        ttpalette = 0xff8400;
        !          1437: 
        !          1438:        if (!bTTColorsSTSync)
        !          1439:        {
        !          1440:                /* sync TT ST-palette to TT-palette */
        !          1441:                src = 0xff8240; /* ST-palette */
        !          1442:                offset = (IoMem_ReadWord(0xff8262) & 0x0f);
        !          1443:                /*fprintf(stdout, "offset: %d\n", offset);*/
        !          1444:                dst = ttpalette + offset * 16*SIZE_WORD;
        !          1445: 
        !          1446:                for (i = 0; i < 16; i++)
        !          1447:                {
        !          1448:                        stcolor = IoMem_ReadWord(src);
        !          1449:                        ttcolor = ((stcolor&0x700) << 1) | ((stcolor&0x70) << 1) | ((stcolor&0x7) << 1);
        !          1450:                        IoMem_WriteWord(dst, ttcolor);
        !          1451:                        src += SIZE_WORD;
        !          1452:                        dst += SIZE_WORD;
        !          1453:                }
        !          1454:                bTTColorsSTSync = TRUE;
        !          1455:        }
        !          1456: 
        !          1457:        colors = 1 << bpp;
        !          1458:        if (bpp == 1)
        !          1459:        {
        !          1460:                /* Monochrome mode... palette is hardwired (?) */
        !          1461:                HostScreen_setPaletteColor(0, 255, 255, 255);
        !          1462:                HostScreen_setPaletteColor(1, 0, 0, 0);
        !          1463:        }
        !          1464:        else
        !          1465:        {
        !          1466:                for (i = 0; i < colors; i++)
        !          1467:                {
        !          1468:                        lowbyte = IoMem_ReadByte(ttpalette++);
        !          1469:                        highbyte = IoMem_ReadByte(ttpalette++);
        !          1470:                        r = (lowbyte  & 0x0f) << 4;
        !          1471:                        g = (highbyte & 0xf0);
        !          1472:                        b = (highbyte & 0x0f) << 4;
        !          1473:                        //printf("%d: (%d,%d,%d)\n", i,r,g,b);
        !          1474:                        HostScreen_setPaletteColor(i, r,g,b);
        !          1475:                }
        !          1476:        }
        !          1477: 
        !          1478:        HostScreen_updatePalette(colors);
        !          1479:        bTTColorsSync = TRUE;
        !          1480: }
        !          1481: 
        !          1482: 
        !          1483: /*-----------------------------------------------------------------------*/
        !          1484: /**
        !          1485:  * Update TT palette and blit TT screen using VIDEL code
        !          1486:  */
        !          1487: static void Video_RenderTTScreen(void)
        !          1488: {
        !          1489:        static int nPrevTTRes = -1;
        !          1490:        int width, height, bpp;
        !          1491: 
        !          1492:        Video_GetTTRes(&width, &height, &bpp);
        !          1493:        if (TTRes != nPrevTTRes)
        !          1494:        {
        !          1495:                HostScreen_setWindowSize(width, height, 8);
        !          1496:                nPrevTTRes = TTRes;
        !          1497:                if (bpp == 1)   /* Assert that mono palette will be used in mono mode */
        !          1498:                        bTTColorsSync = FALSE;
        !          1499:        }
        !          1500: 
        !          1501:        /* colors need synching? */
        !          1502:        if (!(bTTColorsSync && bTTColorsSTSync))
        !          1503:        {
        !          1504:                Video_UpdateTTPalette(bpp);
        !          1505:        }
        !          1506: 
        !          1507:        /* Yes, we are abusing the Videl routines for rendering the TT modes! */
        !          1508:        if (!HostScreen_renderBegin())
        !          1509:                return;
        !          1510:        if (ConfigureParams.Screen.bZoomLowRes)
        !          1511:                VIDEL_ConvertScreenZoom(width, height, bpp, width * bpp / 16);
        !          1512:        else
        !          1513:                VIDEL_ConvertScreenNoZoom(width, height, bpp, width * bpp / 16);
        !          1514:        HostScreen_renderEnd();
        !          1515:        HostScreen_update1(FALSE);
        !          1516: }
        !          1517: 
        !          1518: 
        !          1519: /*-----------------------------------------------------------------------*/
        !          1520: /**
        !          1521:  * Draw screen (either with ST/STE shifter drawing functions or with
        !          1522:  * Videl drawing functions)
        !          1523:  */
        !          1524: static void Video_DrawScreen(void)
        !          1525: {
        !          1526:        /* Skip frame if need to */
        !          1527:        if (nVBLs % (ConfigureParams.Screen.FrameSkips+1))
        !          1528:                return;
        !          1529: 
        !          1530:        /* Use extended VDI resolution?
        !          1531:         * If so, just copy whole screen on VBL rather than per HBL */
        !          1532:        if (bUseVDIRes)
        !          1533:                Video_CopyVDIScreen();
        !          1534: 
        !          1535:        /* Now draw the screen! */
        !          1536:        if (ConfigureParams.System.nMachineType == MACHINE_FALCON && !bUseVDIRes)
        !          1537:        {
        !          1538:                VIDEL_renderScreen();
        !          1539:        }
        !          1540:        else if (ConfigureParams.System.nMachineType == MACHINE_TT && !bUseVDIRes)
        !          1541:        {
        !          1542:                Video_RenderTTScreen();
        !          1543:        }
        !          1544:        else
        !          1545:                Screen_Draw();
        !          1546: }
        !          1547: 
        !          1548: 
        !          1549: /*-----------------------------------------------------------------------*/
        !          1550: /**
        !          1551:  * Start HBL and VBL interrupts.
        !          1552:  */
        !          1553: void Video_StartInterrupts(void)
        !          1554: {
        !          1555:        Int_AddAbsoluteInterrupt(nCyclesPerLine - TIMERB_VIDEO_CYCLE_OFFSET - VBL_VIDEO_CYCLE_OFFSET,
        !          1556:                                 INT_CPU_CYCLE, INTERRUPT_VIDEO_ENDLINE);
        !          1557:        Int_AddAbsoluteInterrupt(nCyclesPerLine + HBL_VIDEO_CYCLE_OFFSET - VBL_VIDEO_CYCLE_OFFSET,
        !          1558:                                 INT_CPU_CYCLE, INTERRUPT_VIDEO_HBL);
        !          1559:        Int_AddAbsoluteInterrupt(CYCLES_PER_FRAME, INT_CPU_CYCLE, INTERRUPT_VIDEO_VBL);
        !          1560: }
        !          1561: 
        !          1562: 
        !          1563: /*-----------------------------------------------------------------------*/
        !          1564: /**
        !          1565:  * VBL interrupt, draw screen and reset counters
        !          1566:  */
        !          1567: void Video_InterruptHandler_VBL(void)
        !          1568: {
        !          1569:        int PendingCyclesOver;
1.1.1.9   root     1570: 
1.1.1.11! root     1571:        /* Store cycles we went over for this frame(this is our inital count) */
        !          1572:        PendingCyclesOver = -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE );    /* +ve */
1.1.1.10  root     1573: 
1.1.1.11! root     1574:        /* Remove this interrupt from list and re-order */
        !          1575:        Int_AcknowledgeInterrupt();
1.1.1.9   root     1576: 
1.1.1.11! root     1577:        /* Start VBL & HBL interrupts */
        !          1578:        Video_StartInterrupts();
1.1.1.9   root     1579: 
1.1.1.11! root     1580:        /* Set frame cycles, used for Video Address */
        !          1581:        Cycles_SetCounter(CYCLES_COUNTER_VIDEO, PendingCyclesOver + VBL_VIDEO_CYCLE_OFFSET);
1.1.1.9   root     1582: 
1.1.1.11! root     1583:        /* Clear any key presses which are due to be de-bounced (held for one ST frame) */
        !          1584:        Keymap_DebounceAllKeys();
        !          1585:        /* Act on shortcut keys */
        !          1586:        ShortCut_ActKey();
1.1.1.9   root     1587: 
1.1.1.11! root     1588:        Video_DrawScreen();
1.1.1.9   root     1589: 
1.1.1.11! root     1590:        /* Check printer status */
        !          1591:        Printer_CheckIdleStatus();
        !          1592: 
        !          1593:        /* Update counter for number of screen refreshes per second */
        !          1594:        nVBLs++;
        !          1595:        /* Set video registers for frame */
        !          1596:        Video_ClearOnVBL();
        !          1597:        /* Store off PSG registers for YM file, is enabled */
        !          1598:        YMFormat_UpdateRecording();
        !          1599:        /* Generate 1/50th second of sound sample data, to be played by sound thread */
        !          1600:        Sound_Update_VBL();
        !          1601: 
        !          1602:        HATARI_TRACE ( HATARI_TRACE_VIDEO_VBL , "VBL %d video_cyc=%d pending_cyc=%d\n" ,
        !          1603:                       nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , PendingCyclesOver );
        !          1604: 
        !          1605:        M68000_Exception ( EXCEPTION_VBLANK , M68000_INT_VIDEO );       /* Vertical blank interrupt, level 4! */
        !          1606: 
        !          1607:        /* And handle any messages, check for quit message */
        !          1608:        Main_EventHandler();         /* Process messages, set 'bQuitProgram' if user tries to quit */
        !          1609:        if (bQuitProgram)
        !          1610:        {
        !          1611:                /* Pass NULL interrupt function to quit cleanly */
        !          1612:                Int_AddAbsoluteInterrupt(4, INT_CPU_CYCLE, INTERRUPT_NULL);
        !          1613:                M68000_SetSpecial(SPCFLAG_BRK);   /* Assure that CPU core shuts down */
        !          1614:        }
        !          1615: 
        !          1616:        Main_WaitOnVbl();
1.1.1.9   root     1617: }
                   1618: 
                   1619: 
                   1620: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1621: /**
        !          1622:  * Reset video chip
        !          1623:  */
1.1.1.9   root     1624: void Video_Reset(void)
                   1625: {
1.1.1.11! root     1626:        /* NOTE! Must reset all of these register type things here!!!! */
1.1.1.9   root     1627: 
1.1.1.11! root     1628:        /* Are we in high-res? */
        !          1629:        if (bUseHighRes)
        !          1630:                VideoShifterByte = ST_HIGH_RES;    /* Boot up for mono monitor */
        !          1631:        else
        !          1632:                VideoShifterByte = ST_LOW_RES;
        !          1633:        if (bUseVDIRes)
        !          1634:                VideoShifterByte = VDIRes;
        !          1635: 
        !          1636:        /* Reset VBL counter */
        !          1637:        nVBLs = 0;
        !          1638:        /* Reset addresses */
        !          1639:        VideoBase = 0L;
        !          1640:        /* Reset STe screen variables */
        !          1641:        LineWidth = 0;
        !          1642:        HWScrollCount = 0;
        !          1643:        bSteBorderFlag = FALSE;
        !          1644: 
        !          1645:        NewLineWidth = -1;                      /* cancel pending modifications set before the reset */
        !          1646:        NewHWScrollCount = -1;
        !          1647: 
        !          1648:        /* Clear ready for new VBL */
        !          1649:        Video_ClearOnVBL();
1.1.1.9   root     1650: }
                   1651: 
                   1652: 
                   1653: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1654: /**
        !          1655:  * Write to video address base high and med register (0xff8201 and 0xff8203).
        !          1656:  * When a program writes to these registers, some other video registers
        !          1657:  * are reset to zero.
        !          1658:  */
1.1.1.9   root     1659: void Video_ScreenBaseSTE_WriteByte(void)
                   1660: {
1.1.1.11! root     1661:        IoMem[0xff820d] = 0;          /* Reset screen base low register */
1.1.1.8   root     1662: 
1.1.1.11! root     1663:        if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_VIDEO_STE ) )
        !          1664:        {
        !          1665:                int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);;
        !          1666:                int nLineCycles = nFrameCycles % nCyclesPerLine;
        !          1667:                HATARI_TRACE_PRINT ( "write ste video base=%x video_cyc=%d %d@%d pc=%x instr_cyc=%d\n" , (IoMem[0xff8201]<<16)+(IoMem[0xff8203]<<8) ,
        !          1668:                                     nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
        !          1669:        }
1.1.1.8   root     1670: }
                   1671: 
                   1672: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1673: /**
        !          1674:  * Read video address counter and update ff8205/07/09
        !          1675:  */
        !          1676: void Video_ScreenCounter_ReadByte(void)
1.1.1.8   root     1677: {
1.1.1.11! root     1678:        Uint32 addr;
1.1.1.8   root     1679: 
1.1.1.11! root     1680:        addr = Video_CalculateAddress();                /* get current video address */
        !          1681:        IoMem[0xff8205] = ( addr >> 16 ) & 0xff;
        !          1682:        IoMem[0xff8207] = ( addr >> 8 ) & 0xff;
        !          1683:        IoMem[0xff8209] = addr & 0xff;
1.1.1.8   root     1684: }
                   1685: 
1.1.1.9   root     1686: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1687: /**
        !          1688:  * Write to video address counter (0xff8205, 0xff8207 and 0xff8209).
        !          1689:  * Called on STE only and like with base address, you cannot set lowest bit.
        !          1690:  * If display has not started yet for this line, we can change pVideoRaster now.
        !          1691:  * Else we store the new value of the Hi/Med/Lo address to change it at the end
        !          1692:  * of the current line when Video_CopyScreenLineColor is called.
        !          1693:  * We must change only the byte that was modified and keep the two others ones.
        !          1694:  */
1.1.1.9   root     1695: void Video_ScreenCounter_WriteByte(void)
                   1696: {
1.1.1.11! root     1697:        Uint8 AddrByte;
        !          1698:        Uint32 addr;
        !          1699:        int nFrameCycles;
        !          1700:        int nLineCycles;
        !          1701:        int HblCounterVideo;
        !          1702: 
        !          1703:        nFrameCycles = Cycles_GetCounterOnWriteAccess(CYCLES_COUNTER_VIDEO);;
        !          1704:        nLineCycles = nFrameCycles % nCyclesPerLine;
        !          1705: 
        !          1706:        /* Get real video line count (can be different from nHBL) */
        !          1707:        HblCounterVideo = nFrameCycles / nCyclesPerLine;
        !          1708: 
        !          1709:        AddrByte = IoMem[ IoAccessCurrentAddress ];
        !          1710: 
        !          1711:        /* If display has not started, we can still modify pVideoRaster */
        !          1712:        /* We must also check the write does not overlap the end of the line */
        !          1713:        if ( ( ( nLineCycles <= LINE_START_CYCLE_50 ) && ( nHBL == HblCounterVideo ) )
        !          1714:                || ( nHBL < nStartHBL ) || ( nHBL >= nEndHBL ) )
        !          1715:        {
        !          1716:                addr = Video_CalculateAddress();                /* get current video address */
        !          1717:                if ( IoAccessCurrentAddress == 0xff8205 )
        !          1718:                        addr = ( addr & 0x00ffff ) | ( AddrByte << 16 );
        !          1719:                else if ( IoAccessCurrentAddress == 0xff8207 )
        !          1720:                        addr = ( addr & 0xff00ff ) | ( AddrByte << 8 );
        !          1721:                else if ( IoAccessCurrentAddress == 0xff8209 )
        !          1722:                        addr = ( addr & 0xffff00 ) | ( AddrByte );
        !          1723: 
        !          1724:                pVideoRaster = &STRam[addr & ~1];               /* set new video address */
        !          1725:        }
        !          1726: 
        !          1727:        /* Can't change pVideoRaster now, store the modified byte for Video_CopyScreenLineColor */
        !          1728:        else
        !          1729:        {
        !          1730:                if ( IoAccessCurrentAddress == 0xff8205 )
        !          1731:                        NewVideoHi = AddrByte;
        !          1732:                else if ( IoAccessCurrentAddress == 0xff8207 )
        !          1733:                        NewVideoMed = AddrByte;
        !          1734:                else if ( IoAccessCurrentAddress == 0xff8209 )
        !          1735:                        NewVideoLo = AddrByte;
        !          1736:        }
        !          1737: 
        !          1738:        HATARI_TRACE ( HATARI_TRACE_VIDEO_STE , "write ste video %x val=0x%x video_cyc_w=%d line_cyc_w=%d @ nHBL=%d/video_hbl_w=%d pc=%x instr_cyc=%d\n" ,
        !          1739:                                IoAccessCurrentAddress, AddrByte,
        !          1740:                                nFrameCycles, nLineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
1.1.1.9   root     1741: }
1.1.1.8   root     1742: 
                   1743: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1744: /**
        !          1745:  * Read video sync register (0xff820a)
        !          1746:  */
1.1.1.8   root     1747: void Video_Sync_ReadByte(void)
                   1748: {
1.1.1.11! root     1749:        /* Nothing... */
1.1.1.8   root     1750: }
                   1751: 
                   1752: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1753: /**
        !          1754:  * Read video base address low byte (0xff820d). A plain ST can only store
        !          1755:  * screen addresses rounded to 256 bytes (i.e. no lower byte).
        !          1756:  */
1.1.1.8   root     1757: void Video_BaseLow_ReadByte(void)
                   1758: {
1.1.1.11! root     1759:        if (ConfigureParams.System.nMachineType == MACHINE_ST)
        !          1760:                IoMem[0xff820d] = 0;        /* On ST this is always 0 */
1.1.1.9   root     1761: 
1.1.1.11! root     1762:        /* Note that you should not do anything here for STe because
        !          1763:         * VideoBase address is set in an interrupt and would be wrong
        !          1764:         * here.   It's fine like this.
        !          1765:         */
1.1.1.8   root     1766: }
                   1767: 
                   1768: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1769: /**
        !          1770:  * Read video line width register (0xff820f)
        !          1771:  */
1.1.1.8   root     1772: void Video_LineWidth_ReadByte(void)
                   1773: {
1.1.1.11! root     1774:        if (ConfigureParams.System.nMachineType == MACHINE_ST)
        !          1775:                IoMem[0xff820f] = 0;        /* On ST this is always 0 */
        !          1776:        else
        !          1777:                IoMem[0xff820f] = LineWidth;
1.1.1.8   root     1778: }
                   1779: 
                   1780: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1781: /**
        !          1782:  * Read video shifter mode register (0xff8260)
        !          1783:  */
1.1.1.8   root     1784: void Video_ShifterMode_ReadByte(void)
                   1785: {
1.1.1.11! root     1786:        if (bUseHighRes)
        !          1787:                IoMem[0xff8260] = 2;                  /* If mono monitor, force to high resolution */
        !          1788:        else
        !          1789:                IoMem[0xff8260] = VideoShifterByte;   /* Read shifter register */
1.1.1.8   root     1790: }
                   1791: 
1.1.1.10  root     1792: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1793: /**
        !          1794:  * Read horizontal scroll register (0xff8265)
        !          1795:  */
1.1.1.10  root     1796: void Video_HorScroll_Read(void)
                   1797: {
1.1.1.11! root     1798:        IoMem[0xff8265] = HWScrollCount;
1.1.1.10  root     1799: }
1.1.1.8   root     1800: 
                   1801: 
                   1802: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1803: /**
        !          1804:  * Write video line width register (0xff820f) - STE only.
        !          1805:  * Content of LineWidth is added to the shifter counter when display is
        !          1806:  * turned off (start of the right border, usually at cycle 376)
        !          1807:  */
1.1.1.10  root     1808: void Video_LineWidth_WriteByte(void)
                   1809: {
1.1.1.11! root     1810:        Uint8 NewWidth;
        !          1811:        int nFrameCycles;
        !          1812:        int nLineCycles;
        !          1813:        int HblCounterVideo;
        !          1814: 
        !          1815:        nFrameCycles = Cycles_GetCounterOnWriteAccess(CYCLES_COUNTER_VIDEO);;
        !          1816:        nLineCycles = nFrameCycles % nCyclesPerLine;
        !          1817: 
        !          1818:        /* Get real video line count (can be different from nHBL) */
        !          1819:        HblCounterVideo = nFrameCycles / nCyclesPerLine;
        !          1820: 
        !          1821:        NewWidth = IoMem_ReadByte(0xff820f);
        !          1822: 
        !          1823:        /* We must also check the write does not overlap the end of the line */
        !          1824:        if ( ( ( nLineCycles <= LineEndCycle ) && ( nHBL == HblCounterVideo ) )
        !          1825:                || ( nHBL < nStartHBL ) || ( nHBL >= nEndHBL ) )
        !          1826:                LineWidth = NewWidth;           /* display is on, we can still change */
        !          1827:        else
        !          1828:                NewLineWidth = NewWidth;        /* display is off, can't change LineWidth once in right border */
        !          1829: 
        !          1830:        HATARI_TRACE ( HATARI_TRACE_VIDEO_STE , "write ste linewidth=0x%x video_cyc_w=%d line_cyc_w=%d @ nHBL=%d/video_hbl_w=%d pc=%x instr_cyc=%d\n" , NewWidth,
        !          1831:                                        nFrameCycles, nLineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
1.1.1.10  root     1832: }
                   1833: 
                   1834: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1835: /**
        !          1836:  * Write to video shifter palette registers (0xff8240-0xff825e)
        !          1837:  */
1.1.1.8   root     1838: static void Video_ColorReg_WriteWord(Uint32 addr)
                   1839: {
1.1.1.11! root     1840:        if (!bUseHighRes)                          /* Don't store if hi-res */
        !          1841:        {
        !          1842:                int idx;
        !          1843:                Uint16 col;
        !          1844:                Video_SetHBLPaletteMaskPointers();     /* Set 'pHBLPalettes' etc.. according cycles into frame */
        !          1845:                col = IoMem_ReadWord(addr);
        !          1846:                if (ConfigureParams.System.nMachineType == MACHINE_ST)
        !          1847:                        col &= 0x777;                      /* Mask off to ST 512 palette */
        !          1848:                else
        !          1849:                        col &= 0xfff;                      /* Mask off to STe 4096 palette */
        !          1850:                IoMem_WriteWord(addr, col);            /* (some games write 0xFFFF and read back to see if STe) */
        !          1851:                Spec512_StoreCyclePalette(col, addr);  /* Store colour into CyclePalettes[] */
        !          1852:                idx = (addr-0xff8240)/2;               /* words */
        !          1853:                pHBLPalettes[idx] = col;               /* Set colour x */
        !          1854:                *pHBLPaletteMasks |= 1 << idx;         /* And mask */
        !          1855: 
        !          1856:                if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_VIDEO_COLOR ) )
        !          1857:                {
        !          1858:                        int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);;
        !          1859:                        int nLineCycles = nFrameCycles % nCyclesPerLine;
        !          1860:                        HATARI_TRACE_PRINT ( "write col addr=%x col=%x video_cyc=%d %d@%d pc=%x instr_cyc=%d\n" , addr, col,
        !          1861:                                             nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
        !          1862:                }
        !          1863: 
        !          1864:        }
1.1.1.8   root     1865: }
                   1866: 
                   1867: void Video_Color0_WriteWord(void)
                   1868: {
1.1.1.11! root     1869:        Video_ColorReg_WriteWord(0xff8240);
1.1.1.8   root     1870: }
                   1871: 
                   1872: void Video_Color1_WriteWord(void)
                   1873: {
1.1.1.11! root     1874:        Video_ColorReg_WriteWord(0xff8242);
1.1.1.8   root     1875: }
                   1876: 
                   1877: void Video_Color2_WriteWord(void)
                   1878: {
1.1.1.11! root     1879:        Video_ColorReg_WriteWord(0xff8244);
1.1.1.8   root     1880: }
                   1881: 
                   1882: void Video_Color3_WriteWord(void)
                   1883: {
1.1.1.11! root     1884:        Video_ColorReg_WriteWord(0xff8246);
1.1.1.8   root     1885: }
                   1886: 
                   1887: void Video_Color4_WriteWord(void)
                   1888: {
1.1.1.11! root     1889:        Video_ColorReg_WriteWord(0xff8248);
1.1.1.8   root     1890: }
                   1891: 
                   1892: void Video_Color5_WriteWord(void)
                   1893: {
1.1.1.11! root     1894:        Video_ColorReg_WriteWord(0xff824a);
1.1.1.8   root     1895: }
                   1896: 
                   1897: void Video_Color6_WriteWord(void)
                   1898: {
1.1.1.11! root     1899:        Video_ColorReg_WriteWord(0xff824c);
1.1.1.8   root     1900: }
                   1901: 
                   1902: void Video_Color7_WriteWord(void)
                   1903: {
1.1.1.11! root     1904:        Video_ColorReg_WriteWord(0xff824e);
1.1.1.8   root     1905: }
                   1906: 
                   1907: void Video_Color8_WriteWord(void)
                   1908: {
1.1.1.11! root     1909:        Video_ColorReg_WriteWord(0xff8250);
1.1.1.8   root     1910: }
                   1911: 
                   1912: void Video_Color9_WriteWord(void)
                   1913: {
1.1.1.11! root     1914:        Video_ColorReg_WriteWord(0xff8252);
1.1.1.8   root     1915: }
                   1916: 
                   1917: void Video_Color10_WriteWord(void)
                   1918: {
1.1.1.11! root     1919:        Video_ColorReg_WriteWord(0xff8254);
1.1.1.8   root     1920: }
                   1921: 
                   1922: void Video_Color11_WriteWord(void)
                   1923: {
1.1.1.11! root     1924:        Video_ColorReg_WriteWord(0xff8256);
1.1.1.8   root     1925: }
                   1926: 
                   1927: void Video_Color12_WriteWord(void)
                   1928: {
1.1.1.11! root     1929:        Video_ColorReg_WriteWord(0xff8258);
1.1.1.8   root     1930: }
                   1931: 
                   1932: void Video_Color13_WriteWord(void)
                   1933: {
1.1.1.11! root     1934:        Video_ColorReg_WriteWord(0xff825a);
1.1.1.8   root     1935: }
                   1936: 
                   1937: void Video_Color14_WriteWord(void)
                   1938: {
1.1.1.11! root     1939:        Video_ColorReg_WriteWord(0xff825c);
1.1.1.8   root     1940: }
                   1941: 
                   1942: void Video_Color15_WriteWord(void)
                   1943: {
1.1.1.11! root     1944:        Video_ColorReg_WriteWord(0xff825e);
1.1.1.8   root     1945: }
                   1946: 
                   1947: 
                   1948: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1949: /**
        !          1950:  * Write video shifter mode register (0xff8260)
        !          1951:  */
1.1.1.8   root     1952: void Video_ShifterMode_WriteByte(void)
                   1953: {
1.1.1.11! root     1954:        if (ConfigureParams.System.nMachineType == MACHINE_TT)
        !          1955:        {
        !          1956:                TTRes = IoMem_ReadByte(0xff8260) & 7;
        !          1957:                IoMem_WriteByte(0xff8262, TTRes);           /* Copy to TT shifter mode register */
        !          1958:        }
        !          1959:        if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
        !          1960:        {
        !          1961:                /* - activate STE palette
        !          1962:                 * - TODO: set line width ($8210)
        !          1963:                 * - TODO: sets paramaters in $82c2 (double lines/interlace & cycles/pixel)
        !          1964:                 */
        !          1965:                bUseSTShifter = TRUE;
        !          1966:        }
        !          1967:        if (!bUseHighRes && !bUseVDIRes)                    /* Don't store if hi-res and don't store if VDI resolution */
        !          1968:        {
        !          1969:                VideoShifterByte = IoMem[0xff8260] & 3;     /* We only care for lower 2-bits */
        !          1970:                Video_WriteToShifter(VideoShifterByte);
        !          1971:                Video_SetHBLPaletteMaskPointers();
        !          1972:                *pHBLPaletteMasks &= 0xff00ffff;
        !          1973:                /* Store resolution after palette mask and set resolution write bit: */
        !          1974:                *pHBLPaletteMasks |= (((Uint32)VideoShifterByte|0x04)<<16);
        !          1975:        }
1.1.1.10  root     1976: }
                   1977: 
                   1978: /*-----------------------------------------------------------------------*/
1.1.1.11! root     1979: /**
        !          1980:  * Write to horizontal scroll register (0xff8265).
        !          1981:  * Note: The STE shifter has a funny "bug"  that allows to increase the
        !          1982:  * resolution to 336x200 instead of 320x200. It occurs when a program writes
        !          1983:  * certain values to 0xff8264:
        !          1984:  *     move.w  #1,$ffff8264      ; Word access!
        !          1985:  *     clr.b   $ffff8264         ; Byte access!
        !          1986:  * Some games (Obsession, Skulls) and demos (Pacemaker by Paradox) use this
        !          1987:  * feature to increase the resolution, so we have to emulate this bug, too!
        !          1988:  */
1.1.1.10  root     1989: void Video_HorScroll_Write(void)
                   1990: {
1.1.1.11! root     1991:        static BOOL bFirstSteAccess = FALSE;
        !          1992:        Uint8 ScrollCount;
        !          1993:        int nFrameCycles;
        !          1994:        int nLineCycles;
        !          1995:        int HblCounterVideo;
        !          1996: 
        !          1997:        nFrameCycles = Cycles_GetCounterOnWriteAccess(CYCLES_COUNTER_VIDEO);;
        !          1998:        nLineCycles = nFrameCycles % nCyclesPerLine;
1.1.1.10  root     1999: 
1.1.1.11! root     2000:        /* Get real video line count (can be different from nHBL) */
        !          2001:        HblCounterVideo = nFrameCycles / nCyclesPerLine;
1.1.1.10  root     2002: 
1.1.1.11! root     2003:        ScrollCount = IoMem[0xff8265];
        !          2004:        ScrollCount &= 0x0f;
1.1.1.10  root     2005: 
1.1.1.11! root     2006:        /* We must also check the write does not overlap the end of the line */
        !          2007:        if ( ( ( nLineCycles <= LINE_START_CYCLE_50 ) && ( nHBL == HblCounterVideo ) )
        !          2008:                || ( nHBL < nStartHBL ) || ( nHBL >= nEndHBL ) )
        !          2009:                HWScrollCount = ScrollCount;            /* display has not started, we can still change */
        !          2010:        else
        !          2011:                NewHWScrollCount = ScrollCount;         /* display has started, can't change HWScrollCount now */
1.1.1.10  root     2012: 
1.1.1.11! root     2013:        HATARI_TRACE ( HATARI_TRACE_VIDEO_STE , "write ste hwscroll=%x video_cyc_w=%d line_cyc_w=%d @ nHBL=%d/video_hbl_w=%d pc=%x instr_cyc=%d\n" , ScrollCount,
        !          2014:                                     nFrameCycles, nLineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
        !          2015: 
        !          2016:        /*fprintf(stderr, "Write to 0x%x (0x%x, 0x%x, %i)\n", IoAccessBaseAddress,
        !          2017:                IoMem[0xff8264], ScrollCount, nIoMemAccessSize);*/
        !          2018: 
        !          2019:        if (IoAccessBaseAddress == 0xff8264 && nIoMemAccessSize == SIZE_WORD
        !          2020:                && ScrollCount == 1)
        !          2021:        {
        !          2022:                /*fprintf(stderr, "STE border removal - access 1\n");*/
        !          2023:                bFirstSteAccess = TRUE;
        !          2024:        }
        !          2025:        else if (bFirstSteAccess && ScrollCount == 1 &&
        !          2026:                 IoAccessBaseAddress == 0xff8264 && nIoMemAccessSize == SIZE_BYTE)
        !          2027:        {
        !          2028:                /*fprintf(stderr, "STE border removal - access 2\n");*/
        !          2029:                bSteBorderFlag = TRUE;
        !          2030:        }
        !          2031:        else
        !          2032:        {
        !          2033:                bFirstSteAccess = bSteBorderFlag = FALSE;
        !          2034:        }
        !          2035: }
        !          2036: 
        !          2037: 
        !          2038: /*-----------------------------------------------------------------------*/
        !          2039: /**
        !          2040:  * Write to TT shifter mode register (0xff8262)
        !          2041:  */
        !          2042: void Video_TTShiftMode_WriteWord(void)
        !          2043: {
        !          2044:        TTRes = IoMem_ReadByte(0xff8262) & 7;
        !          2045: 
        !          2046:        /*fprintf(stderr, "Write to FF8262: %x, res=%i\n", IoMem_ReadWord(0xff8262), TTRes);*/
        !          2047: 
        !          2048:        /* Is it an ST compatible resolution? */
        !          2049:        if (TTRes <= 2)
        !          2050:        {
        !          2051:                IoMem_WriteByte(0xff8260, TTRes);
        !          2052:                Video_ShifterMode_WriteByte();
        !          2053:        }
        !          2054: }
        !          2055: 
        !          2056: /*-----------------------------------------------------------------------*/
        !          2057: /**
        !          2058:  * Write to TT color register (0xff8400)
        !          2059:  */
        !          2060: void Video_TTColorRegs_WriteWord(void)
        !          2061: {
        !          2062:        bTTColorsSync = FALSE;
        !          2063: }
        !          2064: 
        !          2065: /*-----------------------------------------------------------------------*/
        !          2066: /**
        !          2067:  * Write to ST color register on TT (0xff8400)
        !          2068:  */
        !          2069: void Video_TTColorSTRegs_WriteWord(void)
        !          2070: {
        !          2071:        bTTColorsSTSync = FALSE;
1.1.1.8   root     2072: }

unix.superglobalmegacorp.com

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