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

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

unix.superglobalmegacorp.com

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