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

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.                            */
1.1.1.15! root       30: /* 2007/05/11  [NP]    Add support for med res overscan (No Cooper Greetings).                 */
1.1.1.11  root       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 */
1.1.1.15! root       34: /*                     depending on line (med/lo and borders).                                 */
1.1.1.11  root       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).                        */
1.1.1.15! root       39: /* 2007/10/31  [NP]    Use BORDERMASK_LEFT_OFF_MED when left border is removed with hi/med     */
1.1.1.11  root       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).                                         */
1.1.1.15! root       43: /* 2007/11/05  [NP]    Depending on the position of the med res switch, the planes will be     */
        !            44: /*                     shifted when doing med res overscan (Best Part Of the Creation in PYM   */
1.1.1.11  root       45: /*                     or No Cooper Greetings).                                                */
1.1.1.15! root       46: /* 2007/11/30  [NP]    A hi/med 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 med res    */
1.1.1.11  root       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       */
1.1.1.13  root       55: /*                     HBL/VBL/MFP exception).                                                 */
1.1.1.11  root       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.13  root      139: /* 2008/04/02  [NP]    Correct a rare case in Video_Sync_WriteByte at the end of line 33 :     */
                    140: /*                     nStartHBL was set to 33 instead of 64, which gave a wrong address in    */
                    141: /*                     Video_CalculateAddress.                                                 */
                    142: /* 2008/04/04  [NP]    The value of RestartVideoCounterCycle is slightly different between     */
                    143: /*                     an STF and an STE.                                                      */
                    144: /* 2008/04/05  [NP]    The value of VblVideoCycleOffset is different of 4 cycles between       */
                    145: /*                     STF and STE (fix end part in Pacemaker by Paradox).                     */
                    146: /* 2008/04/09  [NP]    Preliminary support for lines using different frequencies in the same   */
                    147: /*                     screen. In Video_InterruptHandler_EndLine, if the current freq is 50 Hz,*/
                    148: /*                     then next int should be scheduled in 512 cycles ; if freq is 60 Hz,     */
                    149: /*                     next int should be in 508 cycles (used by timer B event count mode).    */
                    150: /* 2008/04/10  [NP]    Update LineEndCycle after changing freq to 50 or 60 Hz.                 */
                    151: /*                     Set EndLine interrupt to happen 28 cycles after LineEndCycle. This way  */
                    152: /*                     Timer B occurs at cycle 404 in 50 Hz, or cycle 400 in 60 Hz (improve    */
                    153: /*                     flickering bottom border in B.I.G. Demo screen 1).                      */
                    154: /* 2008/04/12  [NP]    In the case of a 'right-2' line, we should not change the EndLine's int */
                    155: /*                     position when switching back to 50 Hz ; the int should happen at        */
                    156: /*                     position LINE_END_CYCLE_60 + 28 (Anomaly Demo main menu).               */
                    157: /* 2008/05/31  [NP]    Ignore consecutives writes of the same value in the freq/res register.  */
                    158: /*                     Only the 1st write matters, else this could confuse the code to remove  */
                    159: /*                     top/bottom border (fix OSZI.PRG demo by ULM).                           */
                    160: /* 2008/06/07  [NP]    In Video_SetHBLPaletteMaskPointers, use LineStartCycle instead of the   */
                    161: /*                     50 Hz constant SCREEN_START_CYCLE.                                      */
                    162: /*                     Rename SCREEN_START_HBL_xxx to VIDEO_START_HBL_xxx.                     */
                    163: /*                     Rename SCREEN_END_HBL_xxx to VIDEO_END_HBL_xxx.                         */
                    164: /*                     Rename SCREEN_HEIGHT_HBL_xxx to VIDEO_HEIGHT_HBL_xxx.                   */
                    165: /*                     Use VIDEO_HEIGHT_BOTTOM_50HZ instead of OVERSCAN_BOTTOM.                */
                    166: /* 2008/06/16  [NP]    When Hatari is configured to display the screen's borders, 274 lines    */
                    167: /*                     will be rendered on screen, but if the shifter is in 60 Hz, the last    */
                    168: /*                     16 lines will never be used, which can leave some bad pixels on         */
                    169: /*                     screen. We clear the remaining lines before calling 'Screen_Draw'.      */
                    170: /*                     (in FNIL by Delta Force, fix flickering gfx in the bottom border of the */
                    171: /*                     F2 screen : last 16 lines were the ones from the menu where bottom      */
                    172: /*                     border was removed ).                                                   */
                    173: /* 2008/06/26  [NP]    Improve STE scrolling : handle $ff8264 (no prefetch) and $ff8265        */
                    174: /*                     (prefetch). See Video_HorScroll_Write for details on both registers.    */
                    175: /*                     More generic support for starting display 16 pixels earlier on STE      */
                    176: /*                     by writing to $ff8265 and settting $ff8264=0 just after.                */
                    177: /*                     (fix Digiworld 2 by ICE, which uses $ff8264 for horizontal scroll).     */
                    178: /* 2008/07/07  [NP]    Ignore other 50/60 Hz switches once the right border was removed, keep  */
                    179: /*                     the timer B to occur at pos 460+28 (fix Oxygene screen in Transbeauce 2)*/
                    180: /* 2008/07/14  [NP]    When removing only left border in 60Hz, line size is 26+158 bytes       */
                    181: /*                     instead of 26+160 bytes in 50 Hz (HigResMode demo by Paradox).          */
                    182: /* 2008/07/19  [NP]    If $ff8260==3 (which is not a valid resolution mode), we use 0 instead  */
                    183: /*                     (low res) (fix Omegakul screen in old Omega Demo from 1988).            */
                    184: /* 2008/09/05  [NP]    No need to test 60/50 switch if HblCounterVideo < nStartHBL (display    */
                    185: /*                     has not started yet).                                                   */
                    186: /* 2008/09/25  [NP]    Use nLastVisibleHbl to store the number of the last hbl line that should*/
                    187: /*                     be copied to the emulator's screen buffer.                              */
                    188: /*                     On STE, allow to change immediatly video address, hw scroll and         */
                    189: /*                     linewidth when nHBL>=nLastVisibleHbl instead of nHBL>=nEndHBL           */
                    190: /*                     (fix Power Rise / Xtrem D demo).                                        */
                    191: /* 2008/11/15  [NP]    For STE registers, add in the TRACE call if the write is delayed or     */
                    192: /*                     not (linewidth, hwscroll, video address).                               */
                    193: /*                     On STE, allow to change linewdith, hwscroll and video address with no   */
                    194: /*                     delay as soon as nHBL >= nEndHBL (revert previous changes). Power Rise  */
                    195: /*                     is still working due to NewHWScrollCount=-1 when setting immediate      */
                    196: /*                     hwscroll. Fix regression in Braindamage.                                */
1.1.1.14  root      197: /* 2008/11/29  [NP]    Increment jitter's index for HBL and VBL each time a possible interrupt */
                    198: /*                     occurs. Each interrupt can have a jitter between 0, 4 and 8 cycles ; the*/
                    199: /*                     jitter follows a predefined pattern of 5 values. The HBL and the VBL    */
                    200: /*                     have their own pattern. See InterruptAddJitter() in uae-cpu/newcpu.c    */
                    201: /*                     (fix Fullscreen tunnel in Suretrip 49% by Checkpoint and digi sound in  */
                    202: /*                     Swedish New Year's TCB screen).                                         */
                    203: /* 2008/12/10  [NP]    Enhance support for 0 byte line. The 60/50 Hz switch can happen at      */
                    204: /*                     cycles 56/64, but also at 58/66 (because access to $ff820a doesn't      */
                    205: /*                     require to be on a 4 cycles boundary). As hatari doesn't handle         */
                    206: /*                     multiple of 2 cycles, we allow cycles 56/64 and 60/68 (fix nosync.tos   */
                    207: /*                     that uses the STOP instruction to produce a 0 byte line on the first    */
                    208: /*                     displayed line (found on atari-forum.com)).                             */
                    209: /* 2008/12/26  [NP]    When reading $ff8260 on ST/STE, set unused bits to 1 instead of 0       */
                    210: /*                     (fix wrong TOS resolution in Awesome Menu Disk 16).                     */
                    211: /*                     Set unused bit to 1 when reading $ff820a too.                           */
                    212: /* 2009/01/16  [NP]    Handle special case when writing only in upper byte of a color reg.     */
                    213: /* 2009/01/21  [NP]    Implement STE horizontal scroll for medium res (fixes cool_ste.prg).    */
                    214: /*                     Take the current res into account in Video_CopyScreenLineColor to       */
1.1.1.15! root      215: /*                     allow mixing low/med res with horizontal scroll on STE.                 */      
        !           216: /* 2009/01/24  [NP]    Better detection of 'right-2' when freq is changed to 60 Hz and         */
        !           217: /*                     restored to 50 after the end of the current line (fixes games menu on   */
        !           218: /*                     BBC compil 10).                                                         */
        !           219: /* 2009/01/31  [NP]    Handle a rare case where 'move.b #8,$fffa1f' to start the timer B is    */
        !           220: /*                     done just a few cycles before the actual signal for end of line. In that*/
        !           221: /*                     case we must ensure that the write was really effective before the end  */
        !           222: /*                     of line (else no interrupt should be made) (fix Pompey Pirate Menu #57).*/
        !           223: /* 2009/02/08  [NP]    Handle special case for simultaneous HBL exceptions (fixes flickering in*/
        !           224: /*                     Monster Business and Super Monaco GP).                                  */
        !           225: /* 2009/02/25  [NP]    Ignore other 50/60 Hz switches after display was stopped in the middle  */
        !           226: /*                     of the line with a hi/lo switch. Correct missing end of line timer B    */
        !           227: /*                     interrupt in that case (fix flickering Dragon Ball part in Blood disk 2 */
        !           228: /*                     by Holocaust).                                                          */
        !           229: /* 2008/02/02  [NP]    Added 0 byte line detection in STE mode when switching hi/lo res        */
        !           230: /*                     at position 32 (Lemmings screen in Nostalgic-o-demo).                   */
        !           231: /* 2009/03/28  [NP]    Depending on bit 3 of MFP's AER, timer B will count end of line events  */
        !           232: /*                     (bit=0) or start of line events (bit=1) (fix Seven Gates Of Jambala).   */
        !           233: /* 2009/04/02  [NP]    Add another method to obtain a 0 byte line, by switching to hi/lo res   */
        !           234: /*                     at position 500/508 (fix the game No Buddies Land).                     */
        !           235: /* 2009/04/xx  [NP]    Rewrite of many parts : add SHIFTER_FRAME structure, better accuracy    */
        !           236: /*                     when mixing 50/60 Hz lines and reading $ff8209, better emulation of     */
        !           237: /*                     HBL and Timer B position when changing freq/res, better emulation of    */
        !           238: /*                     freq changes for top/bottom/right borders.                              */
        !           239: /* 2009/07/16  [NP]    In Video_SetHBLPaletteMaskPointers, if LineCycle>460 we consider the    */
        !           240: /*                     color's change should be applied to next line (used when spec512 mode   */
        !           241: /*                     if off).                                                                */
1.1.1.11  root      242: 
                    243: 
1.1.1.12  root      244: 
1.1.1.15! root      245: const char Video_fileid[] = "Hatari video.c : " __DATE__ " " __TIME__;
1.1       root      246: 
1.1.1.7   root      247: #include <SDL_endian.h>
1.1.1.4   root      248: 
1.1       root      249: #include "main.h"
1.1.1.6   root      250: #include "configuration.h"
1.1.1.10  root      251: #include "cycles.h"
1.1       root      252: #include "fdc.h"
                    253: #include "int.h"
1.1.1.8   root      254: #include "ioMem.h"
1.1.1.4   root      255: #include "keymap.h"
1.1       root      256: #include "m68000.h"
                    257: #include "memorySnapShot.h"
                    258: #include "mfp.h"
1.1.1.11  root      259: #include "printer.h"
1.1       root      260: #include "screen.h"
1.1.1.13  root      261: #include "screenSnapShot.h"
1.1       root      262: #include "shortcut.h"
                    263: #include "sound.h"
                    264: #include "spec512.h"
                    265: #include "stMemory.h"
                    266: #include "vdi.h"
                    267: #include "video.h"
                    268: #include "ymFormat.h"
1.1.1.11  root      269: #include "falcon/videl.h"
                    270: #include "falcon/hostscreen.h"
1.1.1.4   root      271: 
                    272: 
1.1.1.11  root      273: /* The border's mask allows to keep track of all the border tricks             */
                    274: /* applied to one video line. The masks for all lines are stored in the array  */
                    275: /* ScreenBorderMask[].                                                         */
                    276: /* - bits 0-15 are used to describe the border tricks.                         */
                    277: /* - bits 20-23 are used to store the bytes offset to apply for some particular        */
1.1.1.15! root      278: /*   tricks (for example med res overscan can shift display by 0 or 2 bytes    */
        !           279: /*   depending on when the switch to med res is done after removing the left   */
1.1.1.11  root      280: /*   border).                                                                  */
                    281: 
1.1.1.14  root      282: #define BORDERMASK_NONE                        0x00    /* no effect on this line */
1.1.1.11  root      283: #define BORDERMASK_LEFT_OFF            0x01    /* removal of left border with hi/lo res switch -> +26 bytes */
                    284: #define BORDERMASK_LEFT_PLUS_2         0x02    /* line starts earlier in 60 Hz -> +2 bytes */
                    285: #define BORDERMASK_STOP_MIDDLE         0x04    /* line ends in hires at cycle 160 -> -106 bytes */
                    286: #define BORDERMASK_RIGHT_MINUS_2       0x08    /* line ends earlier in 60 Hz -> -2 bytes */
                    287: #define BORDERMASK_RIGHT_OFF           0x10    /* removal of right border -> +44 bytes */
                    288: #define BORDERMASK_RIGHT_OFF_FULL      0x20    /* full removal of right border and next left border -> +22 bytes */
1.1.1.15! root      289: #define BORDERMASK_OVERSCAN_MED_RES    0x40    /* some borders were removed and the line is in med res instead of low res */
1.1.1.11  root      290: #define BORDERMASK_EMPTY_LINE          0x80    /* 60/50 Hz switch prevents the line to start, video counter is not incremented */
1.1.1.15! root      291: #define BORDERMASK_LEFT_OFF_MED                0x100   /* removal of left border with hi/med res switch -> +26 bytes (for 4 pixels hardware scrolling) */
1.1.1.11  root      292: 
                    293: 
                    294: int STRes = ST_LOW_RES;                         /* current ST resolution */
                    295: int TTRes;                                      /* TT shifter resolution mode */
1.1.1.13  root      296: int nFrameSkips;                                /* speed up by skipping video frames */
1.1.1.9   root      297: 
1.1.1.13  root      298: bool bUseSTShifter;                             /* Falcon: whether to use ST palette */
                    299: bool bUseHighRes;                               /* Use hi-res (ie Mono monitor) */
1.1       root      300: int OverscanMode;                               /* OVERSCANMODE_xxxx for current display frame */
1.1.1.8   root      301: Uint16 HBLPalettes[(NUM_VISIBLE_LINES+1)*16];   /* 1x16 colour palette per screen line, +1 line just incase write after line 200 */
                    302: Uint16 *pHBLPalettes;                           /* Pointer to current palette lists, one per HBL */
1.1.1.9   root      303: Uint32 HBLPaletteMasks[NUM_VISIBLE_LINES+1];    /* Bit mask of palette colours changes, top bit set is resolution change */
                    304: Uint32 *pHBLPaletteMasks;
1.1.1.15! root      305: int nScreenRefreshRate = 50;                    /* 50 or 60 Hz in color, 71 Hz in mono */
1.1.1.8   root      306: Uint32 VideoBase;                               /* Base address in ST Ram for screen (read on each VBL) */
1.1.1.9   root      307: 
1.1.1.11  root      308: int nVBLs;                                      /* VBL Counter */
                    309: int nHBL;                                       /* HBL line */
                    310: int nStartHBL;                                  /* Start HBL for visible screen */
                    311: int nEndHBL;                                    /* End HBL for visible screen */
1.1.1.10  root      312: int nScanlinesPerFrame = 313;                   /* Number of scan lines per frame */
                    313: int nCyclesPerLine = 512;                       /* Cycles per horizontal line scan */
1.1.1.13  root      314: static int nFirstVisibleHbl = FIRST_VISIBLE_HBL_50HZ;                  /* The first line of the ST screen that is copied to the PC screen buffer */
                    315: static int nLastVisibleHbl = FIRST_VISIBLE_HBL_50HZ+NUM_VISIBLE_LINES; /* The last line of the ST screen that is copied to the PC screen buffer */
1.1.1.10  root      316: 
1.1.1.13  root      317: static Uint8 HWScrollCount;                    /* HW scroll pixel offset, STE only (0...15) */
                    318: static int NewHWScrollCount = -1;              /* Used in STE mode when writing to the scrolling registers $ff8264/65 */
                    319: static Uint8 HWScrollPrefetch;                 /* 0 when scrolling with $ff8264, 1 when scrolling with $ff8265 */
                    320: static int NewHWScrollPrefetch = -1;           /* Used in STE mode when writing to the scrolling registers $ff8264/65 */
                    321: static Uint8 LineWidth;                                /* Scan line width add, STe only (words, minus 1) */
                    322: static int NewLineWidth = -1;                  /* Used in STE mode when writing to the line width register $ff820f */
                    323: static Uint8 *pVideoRaster;                    /* Pointer to Video raster, after VideoBase in PC address space. Use to copy data on HBL */
                    324: static Uint8 VideoShifterByte;                 /* VideoShifter (0xff8260) value store in video chip */
1.1.1.15! root      325: static bool bSteBorderFlag;                    /* true when screen width has been switched to 336 (e.g. in Obsession) */
1.1.1.13  root      326: static int NewSteBorderFlag = -1;              /* New value for next line */
                    327: static bool bTTColorsSync, bTTColorsSTSync;    /* whether TT colors need convertion to SDL */
1.1       root      328: 
1.1.1.13  root      329: int    LastCycleScroll8264;                    /* value of Cycles_GetCounterOnWriteAccess last time ff8264 was set for the current VBL */
                    330: int    LastCycleScroll8265;                    /* value of Cycles_GetCounterOnWriteAccess last time ff8265 was set for the current VBL */
                    331: 
1.1.1.15! root      332: int    LastCycleHblException;                  /* value of Cycles_GetCounter last time a level 2 interrupt was executed by the CPU */
        !           333: 
1.1.1.11  root      334: int    NewVideoHi = -1;                        /* new value for $ff8205 on STE */
                    335: int    NewVideoMed = -1;                       /* new value for $ff8207 on STE */
                    336: int    NewVideoLo = -1;                        /* new value for $ff8209 on STE */
1.1.1.15! root      337: 
1.1.1.13  root      338: int    LineTimerBCycle = LINE_END_CYCLE_50 + TIMERB_VIDEO_CYCLE_OFFSET;        /* position of the Timer B interrupt on active lines */
1.1.1.15! root      339: int    TimerBEventCountCycleStart = -1;        /* value of Cycles_GetCounterOnWriteAccess last time timer B was started for the current VBL */
1.1       root      340: 
1.1.1.12  root      341: int    LineRemoveTopCycle = LINE_REMOVE_TOP_CYCLE_STF;
                    342: int    LineRemoveBottomCycle = LINE_REMOVE_BOTTOM_CYCLE_STF;
1.1.1.13  root      343: int    RestartVideoCounterCycle = RESTART_VIDEO_COUNTER_CYCLE_STF;
                    344: int    VblVideoCycleOffset = VBL_VIDEO_CYCLE_OFFSET_STF;
1.1.1.12  root      345: 
1.1.1.14  root      346: #define HBL_JITTER_MAX_POS 5
                    347: int    HblJitterIndex = 0;
                    348: int    HblJitterArray[] =              { 8,4,4,0,0 };          /* measured on STF */
                    349: int    HblJitterArrayPending[] =       { 4,4,4,4,4 };  // { 8,8,12,8,12 };     /* measured on STF, not always accurate */
                    350: #define VBL_JITTER_MAX_POS 5
                    351: int    VblJitterIndex = 0;
                    352: int    VblJitterArray[] =              { 8,0,4,0,4 };          /* measured on STF */
                    353: int    VblJitterArrayPending[] =       { 8,8,12,8,12 };        /* not verified on STF, use the same as HBL */
                    354: 
1.1.1.12  root      355: 
1.1.1.15! root      356: 
        !           357: typedef struct
        !           358: {
        !           359:        int     VBL;                            /* VBL for this Pos (or -1 if Pos not defined for now) */
        !           360:        int     FrameCycles;                    /* Number of cycles since this VBL */
        !           361:        int     HBL;                            /* HBL in the VBL */
        !           362:        int     LineCycles;                     /* cycles in the HBL */
        !           363: } SHIFTER_POS;
        !           364: 
        !           365: 
        !           366: typedef struct 
        !           367: {
        !           368:        int     StartCycle;                     /* first cycle of this line, as returned by Cycles_GetCounter */
        !           369: 
        !           370:        Uint32  BorderMask;                     /* borders' states for this line */
        !           371:        int     DisplayPixelShift;              /* number of pixels to shift the whole line (<0 shift to the left, >0 shift to the right) */
        !           372:                                                /* On STF, this is obtained when switching hi/med for a variable number of cycles, */
        !           373:                                                /* but just removing left border will shift the line too. */
        !           374: 
        !           375:        int     DisplayStartCycle;              /* cycle where display starts for this line (0-512) : 0, 52 or 56 */
        !           376:        int     DisplayEndCycle;                /* cycle where display ends for this line (0-512) : 0, 160, 372, 376, 460 or 512 */
        !           377:        int     DisplayBytes;                   /* how many bytes to display for this line */
        !           378: 
        !           379: } SHIFTER_LINE;
        !           380: 
        !           381: 
        !           382: typedef struct
        !           383: {
        !           384:        int     HBL_CyclePos;                   /* cycle position for the HBL int (depends on freq/res) */
        !           385:        int     TimerB_CyclePos;                /* cycle position for the Timer B int (depends on freq/res) */
        !           386: 
        !           387:        int     Freq;                           /* value of ff820a & 2, or -1 if not set */
        !           388:        int     Res;                            /* value of ff8260 & 3, or -1 if not set */
        !           389:        SHIFTER_POS     FreqPos50;              /* position of latest freq change to 50 Hz*/
        !           390:        SHIFTER_POS     FreqPos60;              /* position of latest freq change to 60 Hz*/
        !           391:        SHIFTER_POS     ResPosLo;               /* position of latest change to low res */
        !           392:        SHIFTER_POS     ResPosMed;              /* position of latest change to med res */
        !           393:        SHIFTER_POS     ResPosHi;               /* position of latest change to high res */
        !           394: 
        !           395:        SHIFTER_POS     Scroll8264Pos;          /* position of latest write to $ff8264 */
        !           396:        SHIFTER_POS     Scroll8265Pos;          /* position of latest write to $ff8265 */
        !           397: 
        !           398:        SHIFTER_LINE    ShifterLines[ MAX_SCANLINES_PER_FRAME ];
        !           399: } SHIFTER_FRAME;
        !           400: 
        !           401: 
        !           402: SHIFTER_FRAME  ShifterFrame;
        !           403: 
        !           404: 
        !           405: 
        !           406: /*--------------------------------------------------------------*/
        !           407: /* Local functions prototypes                                   */
        !           408: /*--------------------------------------------------------------*/
        !           409: 
        !           410: static void    Video_SetSystemTimings ( void );
        !           411: 
        !           412: static Uint32  Video_CalculateAddress ( void );
        !           413: static void    Video_WriteToShifter ( Uint8 Res );
        !           414: static void    Video_Sync_SetDefaultStartEnd ( Uint8 Freq , int HblCounterVideo , int LineCycles );
        !           415: 
        !           416: static int     Video_HBL_GetPos ( void );
        !           417: static void    Video_EndHBL ( void );
        !           418: static void    Video_StartHBL ( void );
        !           419: 
        !           420: static void    Video_StoreFirstLinePalette(void);
        !           421: static void    Video_StoreResolution(int y);
        !           422: static void    Video_CopyScreenLineMono(void);
        !           423: static void    Video_CopyScreenLineColor(void);
        !           424: static void    Video_CopyVDIScreen(void);
        !           425: static void    Video_SetHBLPaletteMaskPointers(void);
        !           426: 
        !           427: static void    Video_UpdateTTPalette(int bpp);
        !           428: static bool    Video_RenderTTScreen(void);
        !           429: static void    Video_DrawScreen(void);
        !           430: 
        !           431: static void    Video_ResetShifterTimings(void);
        !           432: static void    Video_InitShifterLines(void);
        !           433: static void    Video_ClearOnVBL(void);
        !           434: 
        !           435: static void    Video_AddInterrupt ( int Pos , interrupt_id Handler );
        !           436: static void    Video_AddInterruptHBL ( int Pos );
        !           437: 
        !           438: static void    Video_ColorReg_WriteWord(Uint32 addr);
        !           439: 
        !           440: 
1.1       root      441: /*-----------------------------------------------------------------------*/
1.1.1.11  root      442: /**
                    443:  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                    444:  */
1.1.1.13  root      445: void Video_MemorySnapShot_Capture(bool bSave)
1.1       root      446: {
1.1.1.11  root      447:        /* Save/Restore details */
                    448:        MemorySnapShot_Store(&VideoShifterByte, sizeof(VideoShifterByte));
                    449:        MemorySnapShot_Store(&TTRes, sizeof(TTRes));
                    450:        MemorySnapShot_Store(&bUseSTShifter, sizeof(bUseSTShifter));
                    451:        MemorySnapShot_Store(&bUseHighRes, sizeof(bUseHighRes));
                    452:        MemorySnapShot_Store(&nVBLs, sizeof(nVBLs));
                    453:        MemorySnapShot_Store(&nHBL, sizeof(nHBL));
                    454:        MemorySnapShot_Store(&nStartHBL, sizeof(nStartHBL));
                    455:        MemorySnapShot_Store(&nEndHBL, sizeof(nEndHBL));
                    456:        MemorySnapShot_Store(&OverscanMode, sizeof(OverscanMode));
                    457:        MemorySnapShot_Store(HBLPalettes, sizeof(HBLPalettes));
                    458:        MemorySnapShot_Store(HBLPaletteMasks, sizeof(HBLPaletteMasks));
                    459:        MemorySnapShot_Store(&VideoBase, sizeof(VideoBase));
                    460:        MemorySnapShot_Store(&LineWidth, sizeof(LineWidth));
                    461:        MemorySnapShot_Store(&HWScrollCount, sizeof(HWScrollCount));
                    462:        MemorySnapShot_Store(&pVideoRaster, sizeof(pVideoRaster));
                    463:        MemorySnapShot_Store(&nScanlinesPerFrame, sizeof(nScanlinesPerFrame));
                    464:        MemorySnapShot_Store(&nCyclesPerLine, sizeof(nCyclesPerLine));
                    465:        MemorySnapShot_Store(&nFirstVisibleHbl, sizeof(nFirstVisibleHbl));
                    466:        MemorySnapShot_Store(&bSteBorderFlag, sizeof(bSteBorderFlag));
1.1.1.14  root      467:        MemorySnapShot_Store(&HblJitterIndex, sizeof(HblJitterIndex));
                    468:        MemorySnapShot_Store(&VblJitterIndex, sizeof(VblJitterIndex));
1.1.1.15! root      469:        MemorySnapShot_Store(&ShifterFrame, sizeof(ShifterFrame));
        !           470: }
        !           471: 
        !           472: 
        !           473: /*-----------------------------------------------------------------------*/
        !           474: /**
        !           475:  * Reset video chip
        !           476:  */
        !           477: void Video_Reset(void)
        !           478: {
        !           479:        /* NOTE! Must reset all of these register type things here!!!! */
        !           480: 
        !           481:        /* Are we in high-res? */
        !           482:        if (bUseHighRes)
        !           483:                VideoShifterByte = ST_HIGH_RES;    /* Boot up for mono monitor */
        !           484:        else
        !           485:                VideoShifterByte = ST_LOW_RES;
        !           486:        if (bUseVDIRes)
        !           487:                VideoShifterByte = VDIRes;
        !           488: 
        !           489:        /* Set system specific timings */
        !           490:        Video_SetSystemTimings();
        !           491: 
        !           492:        /* Reset VBL counter */
        !           493:        nVBLs = 0;
        !           494:        /* Reset addresses */
        !           495:        VideoBase = 0L;
        !           496: 
        !           497:        /* Reset shifter's state variables */
        !           498:        ShifterFrame.Freq = -1;
        !           499:        ShifterFrame.Res = -1;
        !           500:        ShifterFrame.FreqPos50.VBL = -1;
        !           501:        ShifterFrame.FreqPos60.VBL = -1;
        !           502:        ShifterFrame.ResPosLo.VBL = -1;
        !           503:        ShifterFrame.ResPosMed.VBL = -1;
        !           504:        ShifterFrame.ResPosHi.VBL = -1;
        !           505:        ShifterFrame.Scroll8264Pos.VBL = -1;
        !           506:        ShifterFrame.Scroll8265Pos.VBL = -1;
        !           507: 
        !           508:        Video_InitShifterLines ();
        !           509: 
        !           510:        /* Reset STE screen variables */
        !           511:        LineWidth = 0;
        !           512:        HWScrollCount = 0;
        !           513:        bSteBorderFlag = false;
        !           514: 
        !           515:        NewLineWidth = -1;                      /* cancel pending modifications set before the reset */
        !           516:        NewHWScrollCount = -1;
        !           517: 
        !           518:        /* Reset jitter indexes */
        !           519:        HblJitterIndex = 0;
        !           520:        VblJitterIndex = 0;
        !           521: 
        !           522:        /* Clear framecycles counter */
        !           523:        Cycles_SetCounter(CYCLES_COUNTER_VIDEO, 0);
        !           524: 
        !           525:        /* Clear ready for new VBL */
        !           526:        Video_ClearOnVBL();
        !           527: }
        !           528: 
        !           529: 
        !           530: /*-----------------------------------------------------------------------*/
        !           531: /**
        !           532:  * Reset the GLUE chip responsible for generating the H/V sync signals.
        !           533:  * When the 68000 RESET instruction is called, frequency and resolution
        !           534:  * should be reset to 0.
        !           535:  */
        !           536: void Video_Reset_Glue(void)
        !           537: {
        !           538:        IoMem_WriteByte(0xff820a,0);            /* video freq */
        !           539:        IoMem_WriteByte(0xff8260,0);            /* video res */
1.1       root      540: }
                    541: 
1.1.1.8   root      542: 
1.1       root      543: /*-----------------------------------------------------------------------*/
1.1.1.12  root      544: /*
                    545:  * Set specific video timings, depending on the system being emulated.
                    546:  */
1.1.1.15! root      547: static void    Video_SetSystemTimings(void)
1.1.1.12  root      548: {
                    549:   if ( ConfigureParams.System.nMachineType == MACHINE_ST )
                    550:     {
                    551:       LineRemoveTopCycle = LINE_REMOVE_TOP_CYCLE_STF;
                    552:       LineRemoveBottomCycle = LINE_REMOVE_BOTTOM_CYCLE_STF;
1.1.1.13  root      553:       RestartVideoCounterCycle = RESTART_VIDEO_COUNTER_CYCLE_STF;
                    554:       VblVideoCycleOffset = VBL_VIDEO_CYCLE_OFFSET_STF;
1.1.1.12  root      555:     }
                    556: 
                    557:   else                                 /* STE, Falcon, TT */
                    558:     {
                    559:       LineRemoveTopCycle = LINE_REMOVE_TOP_CYCLE_STE;
                    560:       LineRemoveBottomCycle = LINE_REMOVE_BOTTOM_CYCLE_STE;
1.1.1.13  root      561:       RestartVideoCounterCycle = RESTART_VIDEO_COUNTER_CYCLE_STE;
                    562:       VblVideoCycleOffset = VBL_VIDEO_CYCLE_OFFSET_STE;
1.1.1.12  root      563:     }
                    564: }
                    565: 
                    566: 
                    567: /*-----------------------------------------------------------------------*/
1.1.1.11  root      568: /**
1.1.1.15! root      569:  * Convert the elapsed number of cycles since the start of the VBL
        !           570:  * into the corresponding HBL number and the cycle position in the current
        !           571:  * HBL. We use the starting cycle position of the closest HBL to compute
        !           572:  * the cycle position on the line (this allows to mix lines with different
        !           573:  * values for nCyclesPerLine).
        !           574:  * We can have 2 cases on the limit where the real video line count can be
        !           575:  * different from nHBL :
        !           576:  * - when reading video address between cycle 0 and 12, LineCycle will be <0,
        !           577:  *   so we need to use the data from line nHBL-1
        !           578:  * - if LineCycle >= nCyclesPerLine, this means the HBL int was not processed
        !           579:  *   yet, so the video line number is in fact nHBL+1
        !           580:  */
        !           581: 
        !           582: void   Video_ConvertPosition ( int FrameCycles , int *pHBL , int *pLineCycles )
        !           583: {
        !           584:        *pHBL = nHBL;
        !           585:        *pLineCycles = FrameCycles - ShifterFrame.ShifterLines[ nHBL ].StartCycle;
        !           586: 
        !           587:        if ( *pLineCycles < 0 )                                 /* reading from the previous video line */
        !           588:        {
        !           589:                *pHBL = nHBL-1;
        !           590:                *pLineCycles = FrameCycles - ShifterFrame.ShifterLines[ nHBL-1 ].StartCycle;
        !           591:        }
        !           592:        
        !           593:        else if ( *pLineCycles >= nCyclesPerLine )              /* reading on the next line, but HBL int was delayed */
        !           594:        {
        !           595:                *pHBL = nHBL+1;
        !           596:                *pLineCycles -= nCyclesPerLine;
        !           597:        }
        !           598: 
        !           599: 
        !           600: if ( *pLineCycles < 0 )
        !           601:        fprintf ( stderr , "bug nHBL=%d %d %d\n" , nHBL , *pHBL , *pLineCycles );
        !           602: 
        !           603: //if ( ( *pHBL != FrameCycles / nCyclesPerLine ) || ( *pLineCycles != FrameCycles % nCyclesPerLine ) )
        !           604: //  LOG_TRACE ( TRACE_VIDEO_ADDR , "conv pos %d %d - %d %d\n" , *pHBL , FrameCycles / nCyclesPerLine , *pLineCycles , FrameCycles % nCyclesPerLine );
        !           605: //  LOG_TRACE ( TRACE_VIDEO_ADDR , "conv pos %d %d %d\n" , FrameCycles , *pHBL , *pLineCycles );
        !           606: }
        !           607: 
        !           608: 
        !           609: void   Video_GetPosition ( int *pFrameCycles , int *pHBL , int *pLineCycles )
        !           610: {
        !           611:        *pFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
        !           612:        Video_ConvertPosition ( *pFrameCycles , pHBL , pLineCycles );
        !           613: }
        !           614: 
        !           615: 
        !           616: void   Video_GetPosition_OnWriteAccess ( int *pFrameCycles , int *pHBL , int *pLineCycles )
        !           617: {
        !           618:        *pFrameCycles = Cycles_GetCounterOnWriteAccess(CYCLES_COUNTER_VIDEO);
        !           619:        Video_ConvertPosition ( *pFrameCycles , pHBL , pLineCycles );
        !           620: }
        !           621: 
        !           622: 
        !           623: void   Video_GetPosition_OnReadAccess ( int *pFrameCycles , int *pHBL , int *pLineCycles )
        !           624: {
        !           625:        *pFrameCycles = Cycles_GetCounterOnReadAccess(CYCLES_COUNTER_VIDEO);
        !           626:        Video_ConvertPosition ( *pFrameCycles , pHBL , pLineCycles );
        !           627: }
        !           628: 
        !           629: 
        !           630: /*-----------------------------------------------------------------------*/
        !           631: /**
1.1.1.11  root      632:  * Calculate and return video address pointer.
                    633:  */
1.1.1.15! root      634: static Uint32 Video_CalculateAddress ( void )
1.1       root      635: {
1.1.1.15! root      636:        int FrameCycles, HblCounterVideo, LineCycles;
        !           637:        int X, NbBytes;
1.1.1.11  root      638:        Uint32 VideoAddress;      /* Address of video display in ST screen space */
                    639:        int nSyncByte;
                    640:        int LineBorderMask;
                    641:        int PrevSize;
                    642:        int CurSize;
1.1.1.15! root      643:        int LineStartCycle , LineEndCycle;
        !           644:        
1.1.1.11  root      645: 
                    646:        /* Find number of cycles passed during frame */
                    647:        /* We need to substract '12' for correct video address calculation */
1.1.1.15! root      648:        FrameCycles = Cycles_GetCounterOnReadAccess(CYCLES_COUNTER_VIDEO) - 12;
1.1.1.11  root      649: 
                    650:        /* Now find which pixel we are on (ignore left/right borders) */
1.1.1.15! root      651:        Video_ConvertPosition ( FrameCycles , &HblCounterVideo , &LineCycles );
        !           652:        X = LineCycles;
1.1.1.11  root      653: 
                    654:        nSyncByte = IoMem_ReadByte(0xff820a) & 2;       /* only keep bit 1 */
                    655:        if (nSyncByte)                          /* 50 Hz */
                    656:        {
                    657:                LineStartCycle = LINE_START_CYCLE_50;
                    658:                LineEndCycle = LINE_END_CYCLE_50;
                    659:        }
                    660:        else                                            /* 60 Hz */
                    661:        {
                    662:                LineStartCycle = LINE_START_CYCLE_60;
                    663:                LineEndCycle = LINE_END_CYCLE_60;
                    664:        }
                    665: 
                    666: 
                    667:        /* Top of screen is usually 63 lines from VBL in 50 Hz */
1.1.1.15! root      668:        if ( HblCounterVideo < nStartHBL )
1.1.1.11  root      669:        {
                    670:                /* pVideoRaster was set during Video_ClearOnVBL using VideoBase */
                    671:                /* and it could also have been modified on STE by writing to ff8205/07/09 */
1.1.1.15! root      672:                /* So, we should not use ff8201/ff8203 which are reloaded in ff8205/ff8207 only once per VBL */
        !           673:                /* but use pVideoRaster - STRam instead to get current shifter video address */
1.1.1.11  root      674:                VideoAddress = pVideoRaster - STRam;
                    675:        }
                    676: 
1.1.1.15! root      677:        else if (FrameCycles > RestartVideoCounterCycle)
1.1.1.11  root      678:        {
                    679:                /* This is where ff8205/ff8207 are reloaded with the content of ff8201/ff8203 on a real ST */
                    680:                /* (used in ULM DSOTS demos). VideoBase is also reloaded in Video_ClearOnVBL to be sure */
                    681:                VideoBase = (Uint32)IoMem_ReadByte(0xff8201)<<16 | (Uint32)IoMem_ReadByte(0xff8203)<<8;
                    682:                if (ConfigureParams.System.nMachineType != MACHINE_ST)
                    683:                {
                    684:                        /* on STe 2 aligned, on Falcon 4 aligned, on TT 8 aligned. We do STe. */
                    685:                        VideoBase |= IoMem_ReadByte(0xff820d) & ~1;
                    686:                }
                    687: 
                    688:                VideoAddress = VideoBase;
                    689:        }
                    690: 
                    691:        else
                    692:        {
                    693:                VideoAddress = pVideoRaster - STRam;            /* pVideoRaster is updated by Video_CopyScreenLineColor */
                    694: 
                    695:                /* Now find which pixel we are on (ignore left/right borders) */
1.1.1.15! root      696: //             X = ( Cycles_GetCounterOnReadAccess(CYCLES_COUNTER_VIDEO) - 12 ) % nCyclesPerLine;
1.1.1.11  root      697: 
                    698:                /* Get real video line count (can be different from nHBL) */
1.1.1.15! root      699: //             HblCounterVideo = ( Cycles_GetCounterOnReadAccess(CYCLES_COUNTER_VIDEO) - 12 ) / nCyclesPerLine;
1.1.1.11  root      700: 
                    701:                /* Correct the case when read overlaps end of line / start of next line */
                    702:                /* Video_CopyScreenLineColor was not called yet to update VideoAddress */
                    703:                /* so we need to determine the size of the previous line to get the */
                    704:                /* correct value of VideoAddress. */
                    705:                PrevSize = 0;
                    706:                if ( HblCounterVideo < nHBL )
                    707:                        X = 0;
                    708:                else if ( ( HblCounterVideo > nHBL )            /* HblCounterVideo = nHBL+1 */
                    709:                          &&  ( nHBL >= nStartHBL ) )           /* if nHBL was not visible, PrevSize = 0 */
                    710:                {
1.1.1.15! root      711:                        LineBorderMask = ShifterFrame.ShifterLines[ HblCounterVideo-1 ].BorderMask; /* get border mask for nHBL */
1.1.1.11  root      712:                        PrevSize = BORDERBYTES_NORMAL;          /* normal line */
                    713: 
                    714:                        if (LineBorderMask & BORDERMASK_LEFT_OFF)
                    715:                                PrevSize += BORDERBYTES_LEFT;
                    716:                        else if (LineBorderMask & BORDERMASK_LEFT_PLUS_2)
                    717:                                PrevSize += 2;
                    718: 
                    719:                        if (LineBorderMask & BORDERMASK_STOP_MIDDLE)
                    720:                                PrevSize -= 106;
                    721:                        else if (LineBorderMask & BORDERMASK_RIGHT_MINUS_2)
                    722:                                PrevSize -= 2;
                    723:                        else if (LineBorderMask & BORDERMASK_RIGHT_OFF)
                    724:                                PrevSize += BORDERBYTES_RIGHT;
                    725: 
                    726:                        if (LineBorderMask & BORDERMASK_EMPTY_LINE)
                    727:                                PrevSize = 0;
                    728:                }
                    729: 
                    730: 
1.1.1.15! root      731:                LineBorderMask = ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask;
1.1.1.11  root      732: 
                    733:                CurSize = BORDERBYTES_NORMAL;                   /* normal line */
                    734: 
                    735:                if (LineBorderMask & BORDERMASK_LEFT_OFF)
                    736:                        CurSize += BORDERBYTES_LEFT;
                    737:                else if (LineBorderMask & BORDERMASK_LEFT_PLUS_2)
                    738:                        CurSize += 2;
                    739: 
                    740:                if (LineBorderMask & BORDERMASK_STOP_MIDDLE)
                    741:                        CurSize -= 106;
                    742:                else if (LineBorderMask & BORDERMASK_RIGHT_MINUS_2)
                    743:                        CurSize -= 2;
                    744:                else if (LineBorderMask & BORDERMASK_RIGHT_OFF)
                    745:                        CurSize += BORDERBYTES_RIGHT;
                    746:                if (LineBorderMask & BORDERMASK_RIGHT_OFF_FULL)
                    747:                        CurSize += BORDERBYTES_RIGHT_FULL;
                    748: 
                    749:                if ( LineBorderMask & BORDERMASK_LEFT_PLUS_2)
                    750:                        LineStartCycle = LINE_START_CYCLE_60;
                    751:                else if ( LineBorderMask & BORDERMASK_LEFT_OFF )
1.1.1.15! root      752:                        LineStartCycle = LINE_START_CYCLE_71;
1.1.1.11  root      753: 
                    754:                LineEndCycle = LineStartCycle + CurSize*2;
                    755: 
                    756: 
                    757:                if ( X < LineStartCycle )
                    758:                        X = LineStartCycle;                             /* display is disabled in the left border */
                    759:                else if ( X > LineEndCycle )
                    760:                        X = LineEndCycle;                               /* display is disabled in the right border */
                    761: 
                    762:                NbBytes = ( (X-LineStartCycle)>>1 ) & (~1);     /* 2 cycles per byte */
                    763: 
                    764: 
                    765:                /* when left border is open, we have 2 bytes less than theorical value */
                    766:                /* (26 bytes in left border, which is not a multiple of 4 cycles) */
                    767:                if ( LineBorderMask & BORDERMASK_LEFT_OFF )
                    768:                        NbBytes -= 2;
                    769: 
                    770:                if ( LineBorderMask & BORDERMASK_EMPTY_LINE )
                    771:                        NbBytes = 0;
                    772: 
                    773:                /* Add line cycles if we have not reached end of screen yet: */
1.1.1.15! root      774:                if ( HblCounterVideo < nEndHBL )
1.1.1.11  root      775:                        VideoAddress += PrevSize + NbBytes;
                    776:        }
                    777: 
1.1.1.15! root      778:        LOG_TRACE(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",
1.1.1.11  root      779:                       VideoBase, pVideoRaster - STRam, VideoAddress, Cycles_GetCounter(CYCLES_COUNTER_VIDEO),
1.1.1.15! root      780:                       LineCycles, X,
1.1.1.11  root      781:                       nHBL, HblCounterVideo, LineStartCycle, LineEndCycle, M68000_GetPC(), CurrentInstrCycles );
                    782: 
                    783:        return VideoAddress;
                    784: }
                    785: 
                    786: 
                    787: /*-----------------------------------------------------------------------*/
                    788: /**
                    789:  * Write to VideoShifter (0xff8260), resolution bits
                    790:  */
1.1.1.15! root      791: static void Video_WriteToShifter ( Uint8 Res )
1.1       root      792: {
1.1.1.15! root      793:        int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.11  root      794: 
1.1.1.15! root      795:        Video_GetPosition_OnWriteAccess ( &FrameCycles , &HblCounterVideo , &LineCycles );
1.1.1.11  root      796: 
1.1.1.15! root      797:        LOG_TRACE(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",
        !           798:                       Res, FrameCycles, LineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
1.1.1.11  root      799: 
                    800: 
1.1.1.13  root      801:        /* Ignore consecutive writes of the same value */
1.1.1.15! root      802:        if ( Res == ShifterFrame.Res )
1.1.1.13  root      803:                return;                                         /* do nothing */
                    804: 
1.1.1.15! root      805: 
        !           806:        if ( Res == 0x02 )                                      /* switch to high res */
        !           807:        {
        !           808:                if ( LineCycles < ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle )      /* start could be 0,52,56 */
        !           809:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle = LINE_START_CYCLE_71;
        !           810: 
        !           811:                if ( ( LineCycles < ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle )      /* end could be 160,372,376,460 */
        !           812:                  && ( LineCycles < LINE_END_CYCLE_71 ) )
        !           813:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle = LINE_END_CYCLE_71;
        !           814:        }
        !           815:        else                                                    /* switch to lo/med res */
        !           816:        {
        !           817:                /* In lo/med res, display start/end depends on the freq register in $ff820a */
        !           818:                Video_Sync_SetDefaultStartEnd ( IoMem[0xff820a] & 2 , HblCounterVideo , LineCycles );
        !           819:        }
        !           820: 
        !           821: 
1.1.1.11  root      822:        /* Remove left border : +26 bytes */
1.1.1.15! root      823:        /* This can be done with a hi/lo res switch or a hi/med res switch */
        !           824:        if ( ( ShifterFrame.Res == 0x02 ) && ( Res == 0x00 )    /* switched from hi res to lo res */
        !           825:                && ( LineCycles <= (LINE_START_CYCLE_71+28) )
        !           826:                && ( FrameCycles - ShifterFrame.ResPosHi.FrameCycles <= 30 ) )
        !           827:        {
        !           828:                ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_LEFT_OFF;
        !           829:                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle = LINE_START_CYCLE_71;
        !           830:                LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect remove left %d<->%d\n" ,
        !           831:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
        !           832:        }
        !           833: 
        !           834:        if ( ( ShifterFrame.Res == 0x02 ) && ( Res == 0x01 )    /* switched from hi res to med res */
        !           835:                && ( LineCycles <= (LINE_START_CYCLE_71+20) )
        !           836:                && ( FrameCycles - ShifterFrame.ResPosHi.FrameCycles <= 30 ) )
        !           837:        {
        !           838:                ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_LEFT_OFF_MED;     /* a later switch to low res might gives right scrolling */
        !           839:                /* By default, this line will be in med res, except if we detect hardware scrolling later */
        !           840:                ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_OVERSCAN_MED_RES | ( 2 << 20 );
        !           841:                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle = LINE_START_CYCLE_71;
        !           842:                LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect remove left med %d<->%d\n" ,
        !           843:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
        !           844:        }
        !           845: 
        !           846:        /* Empty line switching res on STF : switch to hi res on cycle 28, then go back to med/lo res */
        !           847:        /* This creates a 0 byte line, the video counter won't change for this line */
        !           848:        else if ( ( ShifterFrame.Res == 0x02 )                  /* switched from hi res */
        !           849:                  && ( FrameCycles - ShifterFrame.ResPosHi.FrameCycles <= 16 )
        !           850:                  && ( ShifterFrame.ResPosHi.LineCycles == LINE_EMPTY_CYCLE_71_STF )
        !           851:                  && ( ConfigureParams.System.nMachineType == MACHINE_ST ) )
        !           852:        {
        !           853:                ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_EMPTY_LINE;
        !           854:                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle = 0;
        !           855:                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle = 0;
        !           856:                LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect empty line res %d<->%d\n" ,
        !           857:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
        !           858:        }
        !           859: 
        !           860:        /* Empty line switching res on STE (switch is 4 cycles later than on STF) */
        !           861:        else if ( ( ShifterFrame.Res == 0x02 )                  /* switched from hi res */
        !           862:                  && ( FrameCycles - ShifterFrame.ResPosHi.FrameCycles <= 16 )
        !           863:                  && ( ShifterFrame.ResPosHi.LineCycles == LINE_EMPTY_CYCLE_71_STE )
        !           864:                  && ( ConfigureParams.System.nMachineType == MACHINE_STE ) )
        !           865:        {
        !           866:                ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_EMPTY_LINE;
        !           867:                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle = 0;
        !           868:                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle = 0;
        !           869:                LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect empty line res %d<->%d\n" ,
        !           870:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
        !           871:        }
        !           872: 
        !           873:        /* Empty line switching res on STF : switch to hi res just before the HBL then go back to lo/med res */
        !           874:        else if ( ( ShifterFrame.Res == 0x02 )                  /* switched from hi res */
        !           875:                  && ( ShifterFrame.ResPosHi.LineCycles == 500 )
        !           876:                  && ( LineCycles == 508 ) )
        !           877:        {
        !           878:                ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_EMPTY_LINE;
        !           879:                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle = 0;
        !           880:                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle = 0;
        !           881:                LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect empty line res 2 %d<->%d\n" ,
        !           882:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
        !           883:        }
        !           884: 
        !           885:        /* Start right border near middle of the line : -106 bytes */ 
        !           886:        /* Switch to hi res just before the start of the right border in hi res, then go back to lo/mid res */
        !           887:        if ( ( ShifterFrame.Res == 0x02 )                               /* switched from hi res */
        !           888:                && ( ShifterFrame.ResPosHi.HBL == HblCounterVideo )     /* switch during the same line */
        !           889:                && ( ShifterFrame.ResPosHi.LineCycles <= LINE_END_CYCLE_71+4 )  /* switched to hi res before cycle 164 */
        !           890:                && ( LineCycles >= LINE_END_CYCLE_71+4 ) )              /* switch to lo res after cycle 164 */
        !           891:        {
        !           892:                ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_STOP_MIDDLE;
        !           893:                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle = LINE_END_CYCLE_71;
        !           894:                LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect stop middle %d<->%d\n" ,
        !           895:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
        !           896:        }
        !           897: 
        !           898:        /* Remove right border a second time after removing it a first time. Display will */
        !           899:        /* stop at cycle 512 instead of 460. */
        !           900:        /* This removes left border on next line too (used in 'Enchanted Lands') */
        !           901:        if ( ( ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask & BORDERMASK_RIGHT_OFF )
        !           902:                && ( ShifterFrame.Res == 0x02 )                         /* switched from hi res */
        !           903:                && ( FrameCycles - ShifterFrame.ResPosHi.FrameCycles <= 20 )
        !           904:                && ( ShifterFrame.ResPosHi.LineCycles == LINE_END_CYCLE_50_2 ) )        /* switch at end of right border */
        !           905:        {
        !           906:                ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_RIGHT_OFF_FULL;
        !           907:                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle = LINE_END_CYCLE_FULL;
        !           908:                ShifterFrame.ShifterLines[ HblCounterVideo+1 ].BorderMask |= BORDERMASK_LEFT_OFF;       /* no left border on next line */
        !           909:                ShifterFrame.ShifterLines[ HblCounterVideo+1 ].DisplayStartCycle = LINE_START_CYCLE_71;
        !           910:                LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect remove right full %d<->%d\n" ,
        !           911:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
        !           912:        }
        !           913: 
        !           914:        /* If left border is opened and we switch to medium resolution during the next cycles, */
        !           915:        /* then we assume a med res overscan line instead of a low res overscan line. */
        !           916:        /* Note that in that case, the switch to med res can shift the display by 0-3 words */
1.1.1.11  root      917:        /* Used in 'No Cooper' greetings by 1984 and 'Punish Your Machine' by Delta Force */
1.1.1.15! root      918:        if ( ( ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask & BORDERMASK_LEFT_OFF )
        !           919:                && ( Res == 0x01 ) )
1.1.1.11  root      920:        {
1.1.1.15! root      921:                if ( LineCycles == LINE_LEFT_MED_CYCLE_1 )              /* 'No Cooper' timing */
1.1.1.11  root      922:                {
1.1.1.15! root      923:                        LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect med res overscan offset 0 byte\n" );
        !           924:                        ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_OVERSCAN_MED_RES | ( 0 << 20 );
1.1.1.11  root      925:                }
1.1.1.15! root      926:                else if ( LineCycles == LINE_LEFT_MED_CYCLE_2 )         /* 'Best Part Of The Creation / PYM' timing */
1.1.1.11  root      927:                {
1.1.1.15! root      928:                        LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect med res overscan offset 2 bytes\n" );
        !           929:                        ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_OVERSCAN_MED_RES | ( 2 << 20 );
1.1.1.11  root      930:                }
                    931:        }
                    932: 
1.1.1.15! root      933:        /* If left border was opened with a hi/med res switch we need to check */
        !           934:        /* if the switch to low res can trigger a right hardware scrolling. */
        !           935:        /* We store the pixels count in DisplayPixelShift */
        !           936:        if ( ( ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask & BORDERMASK_LEFT_OFF_MED )
        !           937:                && ( Res == 0x00 ) && ( LineCycles <= LINE_SCROLL_1_CYCLE_50 ) )
1.1.1.11  root      938:        {
1.1.1.15! root      939:                /* The hi/med switch was a switch to do low res hardware scrolling, */
        !           940:                /* so we must cancel the med res overscan bit. */
        !           941:                ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask &= (~BORDERMASK_OVERSCAN_MED_RES);
1.1.1.11  root      942: 
1.1.1.15! root      943:                if ( LineCycles == LINE_SCROLL_13_CYCLE_50 )            /* cycle 20 */
1.1.1.11  root      944:                {
1.1.1.15! root      945:                        LOG_TRACE(TRACE_VIDEO_BORDER_H , "detect 13 pixels right scroll\n" );
        !           946:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayPixelShift = 13;
1.1.1.11  root      947:                }
1.1.1.15! root      948:                else if ( LineCycles == LINE_SCROLL_9_CYCLE_50 )        /* cycle 24 */
1.1.1.11  root      949:                {
1.1.1.15! root      950:                        LOG_TRACE(TRACE_VIDEO_BORDER_H , "detect 9 pixels right scroll\n" );
        !           951:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayPixelShift = 9;
1.1.1.11  root      952:                }
1.1.1.15! root      953:                else if ( LineCycles == LINE_SCROLL_5_CYCLE_50 )        /* cycle 28 */
1.1.1.11  root      954:                {
1.1.1.15! root      955:                        LOG_TRACE(TRACE_VIDEO_BORDER_H , "detect 5 pixels right scroll\n" );
        !           956:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayPixelShift = 5;
1.1.1.11  root      957:                }
1.1.1.15! root      958:                else if ( LineCycles == LINE_SCROLL_1_CYCLE_50 )        /* cycle 32 */
1.1.1.11  root      959:                {
1.1.1.15! root      960:                        LOG_TRACE(TRACE_VIDEO_BORDER_H , "detect 1 pixel right scroll\n" );
        !           961:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayPixelShift = 1;
1.1.1.11  root      962:                }
                    963:        }
                    964: 
1.1.1.15! root      965: 
        !           966:        /* Update HBL's position only if display has not reached pos LINE_START_CYCLE_50 */
        !           967:        /* and HBL interrupt was already handled at the beginning of this line. */
        !           968:        /* This also changes the number of cycles per line. */
        !           969:        if ( ( LineCycles <= LINE_START_CYCLE_50 ) && ( HblCounterVideo == nHBL ) )
        !           970:        {
        !           971:                nCyclesPerLine = Video_HBL_GetPos();
        !           972:                Video_AddInterruptHBL ( nCyclesPerLine );
        !           973:        }
        !           974: 
        !           975: 
        !           976:        /* Update Timer B's position */
        !           977:        LineTimerBCycle = Video_TimerB_GetPos ( HblCounterVideo );
        !           978:        Video_AddInterruptTimerB ( LineTimerBCycle );
        !           979: 
        !           980: 
        !           981:        ShifterFrame.Res = Res;
        !           982:        if ( Res == 0x02 )                                              /* high res */
        !           983:        {
        !           984:                ShifterFrame.ResPosHi.VBL = nVBLs;
        !           985:                ShifterFrame.ResPosHi.FrameCycles = FrameCycles;
        !           986:                ShifterFrame.ResPosHi.HBL = HblCounterVideo;
        !           987:                ShifterFrame.ResPosHi.LineCycles = LineCycles;
        !           988:        }
        !           989:        else if ( Res == 0x01 )                                         /* med res */
        !           990:        {
        !           991:                ShifterFrame.ResPosMed.VBL = nVBLs;
        !           992:                ShifterFrame.ResPosMed.FrameCycles = FrameCycles;
        !           993:                ShifterFrame.ResPosMed.HBL = HblCounterVideo;
        !           994:                ShifterFrame.ResPosMed.LineCycles = LineCycles;
        !           995:        }
        !           996:        else                                                            /* low res */
        !           997:        {
        !           998:                ShifterFrame.ResPosLo.VBL = nVBLs;
        !           999:                ShifterFrame.ResPosLo.FrameCycles = FrameCycles;
        !          1000:                ShifterFrame.ResPosLo.HBL = HblCounterVideo;
        !          1001:                ShifterFrame.ResPosLo.LineCycles = LineCycles;
        !          1002:        }
        !          1003: }
        !          1004: 
        !          1005: 
        !          1006: 
        !          1007: /*-----------------------------------------------------------------------*/
        !          1008: /**
        !          1009:  * Set some default values for DisplayStartCycle/DisplayEndCycle
        !          1010:  * when changing frequency in lo/med res (testing orders are important
        !          1011:  * because the line can already have some borders changed).
        !          1012:  * This is necessary as some freq changes can modify start/end
        !          1013:  * even if they're not made at the exact borders' positions.
        !          1014:  * These values will be modified later if some borders are changed.
        !          1015:  */
        !          1016: static void    Video_Sync_SetDefaultStartEnd ( Uint8 Freq , int HblCounterVideo , int LineCycles )
        !          1017: {
        !          1018:        if ( Freq == 0x02 )                                     /* switch to 50 Hz */
        !          1019:        {
        !          1020:                if ( ( LineCycles <= ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle )   /* start could be 0,52,56 */
        !          1021:                  && ( ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle == LINE_START_CYCLE_60 ) )
        !          1022:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle = LINE_START_CYCLE_50;
        !          1023: 
        !          1024:                if ( ( LineCycles <= ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle )     /* end could be 160,372,376,460 */
        !          1025:                  && ( ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle < LINE_END_CYCLE_50 ) )
        !          1026:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle = LINE_END_CYCLE_50;
        !          1027:        }
        !          1028: 
        !          1029:        else                                                    /* switch to 60 Hz */
        !          1030:        {
        !          1031:                if ( LineCycles < ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle )      /* start could be 0,52,56 */
        !          1032:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle = LINE_START_CYCLE_60;
        !          1033: 
        !          1034:                if ( ( LineCycles < ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle )      /* end could be 160,372,376,460 */
        !          1035:                  && ( ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle <= LINE_END_CYCLE_50 ) )
        !          1036:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle = LINE_END_CYCLE_60;
        !          1037:        }
        !          1038: 
        !          1039: //fprintf ( stderr , "sync default pos %d %d\n", ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
1.1.1.11  root     1040: }
                   1041: 
                   1042: 
                   1043: /*-----------------------------------------------------------------------*/
                   1044: /**
                   1045:  * Write to VideoSync (0xff820a), Hz setting
                   1046:  */
1.1.1.15! root     1047: void Video_Sync_WriteByte ( void )
1.1       root     1048: {
1.1.1.15! root     1049:        int FrameCycles, HblCounterVideo, LineCycles;
        !          1050:        Uint8 Freq;
1.1.1.11  root     1051: 
                   1052: 
1.1.1.15! root     1053:        if ( bUseVDIRes )
        !          1054:                return;                                         /* no 50/60 Hz freq in VDI mode */
1.1.1.11  root     1055: 
                   1056: 
1.1.1.15! root     1057:        /* We're only interested in bit 1 (50/60Hz) */
        !          1058:        Freq = IoMem[0xff820a] & 2;
1.1.1.11  root     1059: 
1.1.1.15! root     1060:        Video_GetPosition_OnWriteAccess ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !          1061: 
        !          1062:        LOG_TRACE(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",
        !          1063:                       Freq, FrameCycles, LineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
1.1.1.11  root     1064: 
1.1.1.13  root     1065:        /* Ignore consecutive writes of the same value */
1.1.1.15! root     1066:        if ( Freq == ShifterFrame.Freq )
1.1.1.13  root     1067:                return;                                         /* do nothing */
                   1068: 
1.1.1.15! root     1069:        /* Ignore freq changes if we are in high res */
        !          1070:        /* 2009/04/26 : don't ignore for now (see ST Cnx in Punish Your Machine) */
        !          1071: //     if ( ShifterFrame.Res == 0x02 )
        !          1072: //             return;                                         /* do nothing */
        !          1073: 
        !          1074:        /* Set some default values for DisplayStartCycle/DisplayEndCycle before checking for border removal */
        !          1075:        Video_Sync_SetDefaultStartEnd ( Freq , HblCounterVideo , LineCycles );
        !          1076: 
        !          1077: 
        !          1078:        if ( ( ShifterFrame.Freq == 0x00 ) && ( Freq == 0x02 )  /* switched from 60 Hz to 50 Hz ? */
        !          1079: //             && ( ShifterFrame.FreqPos60.VBL == nVBLs )      /* switched during the same VBL */
        !          1080:                && ( HblCounterVideo >= nStartHBL )             /* only if display is on */
        !          1081:                && ( HblCounterVideo < nEndHBL ) )              /* only if display is on */
        !          1082:        {
        !          1083:                /* Add 2 bytes to left border : switch to 60 Hz before LINE_START_CYCLE_60 to force an early start */
        !          1084:                /* of the DE signal, then go back to 50 Hz. Note that depending on where the 50 Hz switch is made */
        !          1085:                /* the HBL signal will be at position 508 (60 Hz line) or 512 (50 Hz line) */
        !          1086:                /* Obtaining a +2 line with 512 cycles requires a 2 cycles precision and is "wake up" state dependant */
        !          1087:                if ( ( ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle == LINE_START_CYCLE_60 )
        !          1088:                        && ( LineCycles >= LINE_START_CYCLE_50 )        /* The line started in 60 Hz and continues in 50 Hz */
        !          1089:                        && ( LineCycles <= ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle ) )     /* change when line is active */
1.1.1.11  root     1090:                {
1.1.1.15! root     1091:                        ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_LEFT_PLUS_2;
        !          1092:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle = LINE_END_CYCLE_50;
        !          1093:                        LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect left+2 %d<->%d\n" ,
        !          1094:                                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
1.1.1.11  root     1095:                }
                   1096: 
1.1.1.15! root     1097:                /* Empty line switching freq : start the line in 50 Hz, change to 60 Hz at the exact place */
        !          1098:                /* where display is enabled in 50 Hz, then go back to 50 Hz. */
        !          1099:                /* Due to 4 cycles precision instead of 2, we must accept a 60 Hz switch at pos 56 or 56+4 */
        !          1100:                else if ( ( FrameCycles - ShifterFrame.FreqPos60.FrameCycles <= 24 )
        !          1101:                        && ( ( ShifterFrame.FreqPos60.LineCycles == LINE_START_CYCLE_50 ) || ( ShifterFrame.FreqPos60.LineCycles == LINE_START_CYCLE_50+4 ) )
        !          1102:                        && ( LineCycles > LINE_START_CYCLE_50 ) )
        !          1103:                {
        !          1104:                        ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_EMPTY_LINE;
        !          1105:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle = 0;
        !          1106:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle = 0;
        !          1107:                        LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect empty line freq %d<->%d\n" ,
        !          1108:                                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
1.1.1.11  root     1109:                }
1.1.1.15! root     1110: 
        !          1111:                /* Remove 2 bytes to the right : start the line in 50 Hz (pos 0 or 56), change to 60 Hz before the position */
        !          1112:                /* where display is disabled in 60 Hz, then go back to 50 Hz */
        !          1113:                if ( ( LineCycles > LINE_END_CYCLE_60 )                                 /* back to 50 Hz after end of 60 Hz line */
        !          1114:                        && ( ShifterFrame.ShifterLines[ nHBL ].DisplayStartCycle != LINE_START_CYCLE_60 )       /* start could be 0 or 56 */
        !          1115:                        && ( ShifterFrame.ShifterLines[ nHBL ].DisplayEndCycle == LINE_END_CYCLE_60 ) )
        !          1116:                {
        !          1117:                        ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_RIGHT_MINUS_2;
        !          1118:                        LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect right-2 %d<->%d\n" ,
        !          1119:                                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
        !          1120:                }
        !          1121: 
1.1.1.11  root     1122:        }
                   1123: 
1.1.1.15! root     1124: 
        !          1125:        if ( ( ShifterFrame.Freq == 0x02 && Freq == 0x00 )      /* switched from 50 Hz to 60 Hz ? */
        !          1126:                && ( HblCounterVideo >= nStartHBL )             /* only if display is on */
        !          1127:                && ( HblCounterVideo < nEndHBL ) )              /* only if display is on */
        !          1128:        {
        !          1129:                /* remove right border, display 44 bytes more : switch to 60 Hz at the position where */
        !          1130:                /* the line ends in 50 Hz. Some programs don't switch back to 50 Hz immediatly */
        !          1131:                /* (sync screen in SNY II), so we just check if freq changes to 60 Hz at the position where line should end in 50 Hz */
        !          1132:                if ( ( LineCycles == LINE_END_CYCLE_50 )
        !          1133:                        && ( ShifterFrame.ShifterLines[ nHBL ].DisplayEndCycle == LINE_END_CYCLE_50 ) )
        !          1134:                {
        !          1135:                        ShifterFrame.ShifterLines[ HblCounterVideo ].BorderMask |= BORDERMASK_RIGHT_OFF;
        !          1136:                        ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle = LINE_END_CYCLE_50;
        !          1137:                        LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect remove right %d<->%d\n" ,
        !          1138:                                ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayStartCycle , ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle );
1.1.1.11  root     1139:                }
                   1140:        }
                   1141: 
                   1142: 
                   1143:        /* Store cycle position of freq 50/60 to check for top/bottom border removal in Video_EndHBL. */
1.1.1.15! root     1144:        if ( Freq == 0x02 )                                             /* switch to 50 Hz */
1.1.1.11  root     1145:        {
1.1.1.13  root     1146:                if ( ( HblCounterVideo < VIDEO_START_HBL_50HZ )         /* nStartHBL can change only if display is not ON yet */
                   1147:                        && ( OverscanMode & OVERSCANMODE_TOP ) == 0 )   /* update only if top was not removed */
                   1148:                        nStartHBL = VIDEO_START_HBL_50HZ;
1.1.1.11  root     1149: 
1.1.1.13  root     1150:                if ( ( HblCounterVideo < VIDEO_END_HBL_50HZ )           /* nEndHBL can change only if display is not OFF yet */
1.1.1.11  root     1151:                        && ( OverscanMode & OVERSCANMODE_BOTTOM ) == 0 )        /* update only if bottom was not removed */
1.1.1.13  root     1152:                        nEndHBL = VIDEO_END_HBL_50HZ;                           /* 263 */
1.1.1.11  root     1153:        }
1.1.1.15! root     1154:        else if ( Freq == 0x00 )                                        /* switch to 60 Hz */
1.1.1.11  root     1155:        {
1.1.1.13  root     1156:                if ( ( HblCounterVideo < VIDEO_START_HBL_60HZ-1 )       /* nStartHBL can change only if display is not ON yet */
1.1.1.15! root     1157:                        || ( ( HblCounterVideo == VIDEO_START_HBL_60HZ-1 ) && ( LineCycles <= LineRemoveTopCycle ) ) )
1.1.1.13  root     1158:                        nStartHBL = VIDEO_START_HBL_60HZ;
1.1.1.11  root     1159: 
1.1.1.13  root     1160:                if ( ( HblCounterVideo < VIDEO_END_HBL_60HZ )           /* nEndHBL can change only if display is not OFF yet */
1.1.1.11  root     1161:                        && ( OverscanMode & OVERSCANMODE_BOTTOM ) == 0 )        /* update only if bottom was not removed */
1.1.1.13  root     1162:                        nEndHBL = VIDEO_END_HBL_60HZ;                           /* 234 */
                   1163:        }
                   1164: 
1.1.1.15! root     1165: 
1.1.1.13  root     1166:        /* If the frequence changed, we need to update the EndLine interrupt */
1.1.1.15! root     1167:        /* so that it happens 28 cycles after the current DisplayEndCycle.*/
1.1.1.13  root     1168:        /* We check if the change affects the current line or the next one. */
1.1.1.15! root     1169:        /* We also need to check if the HBL interrupt and nCyclesPerLine need */
        !          1170:        /* to be updated first. */
        !          1171:        if ( Freq != ShifterFrame.Freq )
        !          1172:        {
        !          1173:                /* Update HBL's position only if display has not reached pos LINE_START_CYCLE_50 */
        !          1174:                /* and HBL interrupt was already handled at the beginning of this line. */
        !          1175:                /* This also changes the number of cycles per line. */
        !          1176:                if ( ( LineCycles <= LINE_START_CYCLE_50 ) && ( HblCounterVideo == nHBL ) )
        !          1177:                {
        !          1178:                        nCyclesPerLine = Video_HBL_GetPos();
        !          1179:                        Video_AddInterruptHBL ( nCyclesPerLine );
        !          1180:                }
        !          1181: 
        !          1182:                /* Update Timer B's position */
        !          1183:                LineTimerBCycle = Video_TimerB_GetPos ( HblCounterVideo );
        !          1184:                Video_AddInterruptTimerB ( LineTimerBCycle );
        !          1185:        }
        !          1186: 
        !          1187: 
        !          1188:        ShifterFrame.Freq = Freq;
        !          1189:        if ( Freq == 0x02 )                                             /* 50 Hz */
        !          1190:        {
        !          1191:                ShifterFrame.FreqPos50.VBL = nVBLs;
        !          1192:                ShifterFrame.FreqPos50.FrameCycles = FrameCycles;
        !          1193:                ShifterFrame.FreqPos50.HBL = HblCounterVideo;
        !          1194:                ShifterFrame.FreqPos50.LineCycles = LineCycles;
        !          1195:        }
        !          1196:        else
        !          1197:        {
        !          1198:                ShifterFrame.FreqPos60.VBL = nVBLs;
        !          1199:                ShifterFrame.FreqPos60.FrameCycles = FrameCycles;
        !          1200:                ShifterFrame.FreqPos60.HBL = HblCounterVideo;
        !          1201:                ShifterFrame.FreqPos60.LineCycles = LineCycles;
        !          1202:        }
        !          1203: }
        !          1204: 
        !          1205: 
        !          1206: /*-----------------------------------------------------------------------*/
        !          1207: /**
        !          1208:  * Compute the cycle position where the HBL should happen on each line.
        !          1209:  * In low/med res, the position depends on the video frequency (50/60 Hz)
        !          1210:  * In high res, the position is always the same.
        !          1211:  * This position also gives the number of CPU cycles per video line.
        !          1212:  */
        !          1213: static int Video_HBL_GetPos ( void )
        !          1214: {
        !          1215:        int Pos;
        !          1216: 
        !          1217:        if ( ( IoMem_ReadByte ( 0xff8260 ) & 3 ) == 2 )         /* hi res */
        !          1218:                Pos = CYCLES_PER_LINE_71HZ;
        !          1219: 
        !          1220:        else                                                    /* low res or med res */
        !          1221:        {
        !          1222:                if ( IoMem_ReadByte ( 0xff820a ) & 2 )          /* 50 Hz, pos 512 */
        !          1223:                        Pos = CYCLES_PER_LINE_50HZ;
        !          1224:                else                                            /* 60 Hz, pos 508 */
        !          1225:                        Pos = CYCLES_PER_LINE_60HZ;
        !          1226:        }
        !          1227: 
        !          1228:        return Pos;
        !          1229: }
        !          1230: 
        !          1231: 
        !          1232: /*-----------------------------------------------------------------------*/
        !          1233: /**
        !          1234:  * Compute the cycle position where the timer B should happen on each
        !          1235:  * visible line.
        !          1236:  * We compute Timer B position for the given LineNumber, using start/end
        !          1237:  * display cycles from ShifterLines[ LineNumber ].
        !          1238:  * The position depends on the start of line / end of line positions
        !          1239:  * (which depend on the current frequency / border tricks) and
        !          1240:  * on the value of the bit 3 in the MFP's AER.
        !          1241:  * If bit is 0, timer B will count end of line events (usual case),
        !          1242:  * but if bit is 1, timer B will count start of line events (eg Seven Gates Of Jambala)
        !          1243:  */
        !          1244: int Video_TimerB_GetPos ( int LineNumber )
        !          1245: {
        !          1246:        int Pos;
        !          1247: 
        !          1248:        if ( ( IoMem[0xfffa03] & ( 1 << 3 ) ) == 0 )                    /* we're counting end of line events */
        !          1249:        {
        !          1250:                Pos = ShifterFrame.ShifterLines[ LineNumber ].DisplayEndCycle + TIMERB_VIDEO_CYCLE_OFFSET;
        !          1251:        }
        !          1252:        else                                                            /* we're counting start of line events */
        !          1253:        {
        !          1254:                Pos = ShifterFrame.ShifterLines[ LineNumber ].DisplayStartCycle + TIMERB_VIDEO_CYCLE_OFFSET;
        !          1255:        }
        !          1256: 
        !          1257:        return Pos;
        !          1258: }
        !          1259: 
        !          1260: 
        !          1261: /*-----------------------------------------------------------------------*/
        !          1262: /**
        !          1263:  * HBL interrupt : this occurs at the end of every line, on cycle 512 (in 50 Hz)
        !          1264:  * It takes 56 cycles to handle the 68000's exception.
        !          1265:  */
        !          1266: void Video_InterruptHandler_HBL ( void )
        !          1267: {
        !          1268:        int FrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
        !          1269:        int PendingCyclesOver;
        !          1270:        int NewHBLPos;
        !          1271: 
        !          1272:        /* How many cycle was this HBL delayed (>= 0) */
        !          1273:        PendingCyclesOver = -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE );
        !          1274: 
        !          1275:        /* Remove this interrupt from list and re-order */
        !          1276:        Int_AcknowledgeInterrupt();
        !          1277: 
        !          1278:        /* Increment the hbl jitter index */
        !          1279:        HblJitterIndex++;
        !          1280:        if ( HblJitterIndex == HBL_JITTER_MAX_POS )
        !          1281:                HblJitterIndex = 0;
        !          1282:        
        !          1283:        LOG_TRACE ( TRACE_VIDEO_HBL , "HBL %d video_cyc=%d pending_cyc=%d jitter=%d\n" ,
        !          1284:                       nHBL , FrameCycles , PendingCyclesOver , HblJitterArray[ HblJitterIndex ] );
        !          1285: 
        !          1286:        /* Default cycle position for next HBL */
        !          1287:        NewHBLPos = Video_HBL_GetPos();
        !          1288: 
        !          1289:        /* Generate new HBL, if need to - there are 313 HBLs per frame in 50 Hz */
        !          1290:        if (nHBL < nScanlinesPerFrame-1)
        !          1291:                Video_AddInterruptHBL ( NewHBLPos );
        !          1292: 
        !          1293: 
        !          1294:        /* We must handle a very special case : if we had a pending HBL that becomes active */
        !          1295:        /* because SR is now <= $2100, then we must process an exception for this pending HBL. */
        !          1296:        /* But if a "real" (non pending) HBL occurs during the first 56 cycles needed by the */
        !          1297:        /* CPU to prepare the exception, we must ignore this HBL signal (instead of considering */
        !          1298:        /* this new HBL should be put in pending state to be processed later) */
        !          1299:         /* -> any HBL occuring between LastCycleHblException and LastCycleHblException+56 should be ignored */
        !          1300:        if ( ( LastCycleHblException != -1 )
        !          1301:          && ( ( FrameCycles - PendingCyclesOver - HblJitterArray[ HblJitterIndex ] ) - LastCycleHblException <= 56 ) )
        !          1302:        {
        !          1303:                /* simultaneous case, don't call M68000_Exception */
        !          1304:                LOG_TRACE ( TRACE_VIDEO_HBL , "HBL %d video_cyc=%d signal ignored during pending hbl exception at cycle %d\n" ,
        !          1305:                        nHBL , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , LastCycleHblException );
        !          1306:                LastCycleHblException = -1;
        !          1307:        }
        !          1308:        else
        !          1309:        {
        !          1310:                /* "normal" case, this HBL doesn't occur during the processing of a pending HBL */
        !          1311:                M68000_Exception ( EXCEPTION_HBLANK , M68000_EXCEPTION_SRC_INT_VIDEO ); /* Horizontal blank interrupt, level 2! */
        !          1312:        }
        !          1313: 
        !          1314: 
        !          1315:        Video_EndHBL();                                 /* Check some borders removal and copy line to display buffer */
        !          1316: 
        !          1317:        nHBL++;                                         /* Increase HBL count */
        !          1318: 
        !          1319:        if (nHBL < nScanlinesPerFrame)
        !          1320:        {
        !          1321:                /* Update start cycle for next HBL */
        !          1322:                ShifterFrame.ShifterLines[ nHBL ].StartCycle = FrameCycles - PendingCyclesOver;
        !          1323:                LOG_TRACE(TRACE_VIDEO_HBL, "HBL %d start=%d %x\n", nHBL,
        !          1324:                          ShifterFrame.ShifterLines[nHBL].StartCycle, ShifterFrame.ShifterLines[nHBL].StartCycle);
        !          1325: 
        !          1326:                /* Setup next HBL */
        !          1327:                Video_StartHBL();
        !          1328:        }
        !          1329: }
        !          1330: 
        !          1331: 
        !          1332: /*-----------------------------------------------------------------------*/
        !          1333: /**
        !          1334:  * Check at end of each HBL to see if any Shifter hardware tricks have been attempted
        !          1335:  * and copy the line to the screen buffer.
        !          1336:  * This is the place to check if top/bottom border were removed, as well as if some
        !          1337:  * left/right border changes were not validated before.
        !          1338:  * NOTE : the tests must be made with nHBL in ascending order.
        !          1339:  */
        !          1340: static void Video_EndHBL(void)
        !          1341: {
        !          1342:        //
        !          1343:        // Handle top/bottom borders removal when switching freq
        !          1344:        //
        !          1345: 
        !          1346:        /* Remove top border if the switch to 60 Hz was made during this vbl before cycle       */
        !          1347:        /* LineRemoveTopCycle on line 33 and if the switch to 50 Hz has not yet occured or      */
        !          1348:        /* occured before the 60 Hz or occured after cycle LineRemoveTopCycle on line 33.       */
        !          1349:        if ( ( nHBL == VIDEO_START_HBL_60HZ-1 )                         /* last HBL before first line of a 60 Hz screen */
        !          1350:                && ( ShifterFrame.FreqPos60.VBL == nVBLs )              /* switch to 60 Hz during this VBL */
        !          1351:                && ( ( ShifterFrame.FreqPos60.HBL < nHBL ) || ( ShifterFrame.FreqPos60.LineCycles <= LineRemoveTopCycle ) )
        !          1352:                && (   ( ShifterFrame.FreqPos50.VBL < nVBLs )
        !          1353:                    || ( ShifterFrame.FreqPos50.FrameCycles < ShifterFrame.FreqPos60.FrameCycles )
        !          1354:                    || ( ShifterFrame.FreqPos50.HBL > nHBL )
        !          1355:                    || ( ( ShifterFrame.FreqPos50.HBL == nHBL ) && ( ShifterFrame.FreqPos50.LineCycles > LineRemoveTopCycle ) ) ) )
        !          1356:        {
        !          1357:                /* Top border */
        !          1358:                LOG_TRACE ( TRACE_VIDEO_BORDER_V , "detect remove top\n" );
        !          1359:                OverscanMode |= OVERSCANMODE_TOP;       /* Set overscan bit */
        !          1360:                nStartHBL = VIDEO_START_HBL_60HZ;       /* New start screen line */
        !          1361:                pHBLPaletteMasks -= OVERSCAN_TOP;       // FIXME useless ?
        !          1362:                pHBLPalettes -= OVERSCAN_TOP;   // FIXME useless ?
        !          1363:        }
        !          1364: 
        !          1365:        /* Remove bottom border for a 60 Hz screen (tests are similar to the ones for top border) */
        !          1366:        else if ( ( nHBL == VIDEO_END_HBL_60HZ-1 )                      /* last displayed line in 60 Hz */
        !          1367:                && ( nStartHBL == VIDEO_START_HBL_60HZ )                /* screen started in 60 Hz */
        !          1368:                && ( ( OverscanMode & OVERSCANMODE_TOP ) == 0 )         /* and top border was not removed : this screen is only 60 Hz */
        !          1369:                && ( ShifterFrame.FreqPos50.VBL == nVBLs )              /* switch to 50 Hz during this VBL */
        !          1370:                && ( ( ShifterFrame.FreqPos50.HBL < nHBL ) || ( ShifterFrame.FreqPos50.LineCycles <= LineRemoveBottomCycle ) )
        !          1371:                && (   ( ShifterFrame.FreqPos60.VBL < nVBLs )
        !          1372:                    || ( ShifterFrame.FreqPos60.FrameCycles < ShifterFrame.FreqPos50.FrameCycles )
        !          1373:                    || ( ShifterFrame.FreqPos60.HBL > nHBL )
        !          1374:                    || ( ( ShifterFrame.FreqPos60.HBL == nHBL ) && ( ShifterFrame.FreqPos60.LineCycles > LineRemoveBottomCycle ) ) ) )
        !          1375:        {
        !          1376:                LOG_TRACE ( TRACE_VIDEO_BORDER_V , "detect remove bottom 60Hz\n" );
        !          1377:                OverscanMode |= OVERSCANMODE_BOTTOM;
        !          1378:                nEndHBL = SCANLINES_PER_FRAME_60HZ;     /* new end for a 60 Hz screen */
        !          1379:        }
        !          1380: 
        !          1381:        /* Remove bottom border for a 50 Hz screen (tests are similar to the ones for top border) */
        !          1382:        else if ( ( nHBL == VIDEO_END_HBL_50HZ-1 )                      /* last displayed line in 50 Hz */
        !          1383:                && ( ( OverscanMode & OVERSCANMODE_BOTTOM ) == 0 )      /* border was not already removed at line VIDEO_END_HBL_60HZ-1 */
        !          1384:                && ( ShifterFrame.FreqPos60.VBL == nVBLs )              /* switch to 60 Hz during this VBL */
        !          1385:                && ( ( ShifterFrame.FreqPos60.HBL < nHBL ) || ( ShifterFrame.FreqPos60.LineCycles <= LineRemoveBottomCycle ) )
        !          1386:                && (   ( ShifterFrame.FreqPos50.VBL < nVBLs )
        !          1387:                    || ( ShifterFrame.FreqPos50.FrameCycles < ShifterFrame.FreqPos60.FrameCycles )
        !          1388:                    || ( ShifterFrame.FreqPos50.HBL > nHBL )
        !          1389:                    || ( ( ShifterFrame.FreqPos50.HBL == nHBL ) && ( ShifterFrame.FreqPos50.LineCycles > LineRemoveBottomCycle ) ) ) )
1.1.1.13  root     1390:        {
1.1.1.15! root     1391:                LOG_TRACE ( TRACE_VIDEO_BORDER_V , "detect remove bottom\n" );
        !          1392:                OverscanMode |= OVERSCANMODE_BOTTOM;
        !          1393:                nEndHBL = VIDEO_END_HBL_50HZ+VIDEO_HEIGHT_BOTTOM_50HZ;  /* new end for a 50 Hz screen */
        !          1394:        }
        !          1395: 
        !          1396: 
        !          1397:        //
        !          1398:        // Check some left/right borders effects that were not detected earlier
        !          1399:        // (this is usually due to staying in 60 Hz for too long, which is often a bad
        !          1400:        // coding practice as it can distort the display on a real ST)
        !          1401:        //
        !          1402: 
        !          1403:        /* Special case when the line was not started in 60 Hz, then switched to 60 Hz */
        !          1404:        /* and was not restored to 50 Hz before the end of the line. In that case, the */
        !          1405:        /* line ends 2 bytes earlier on the right (line can start at LINE_START_CYCLE_71/50) */
        !          1406:        /* Some programs also turn to 60 Hz too early during the active display of the last */
        !          1407:        /* line to remove the bottom border (FNIL by TNT), in that case, we should also remove */
        !          1408:        /* 2 bytes to this line */
        !          1409:        if ( ( ( ShifterFrame.ShifterLines[ nHBL ].BorderMask & BORDERMASK_RIGHT_MINUS_2 ) == 0 )
        !          1410:          && ( ShifterFrame.ShifterLines[ nHBL ].DisplayStartCycle != LINE_START_CYCLE_60 )             /* start could be 0 or 56 */
        !          1411:          && ( ShifterFrame.ShifterLines[ nHBL ].DisplayEndCycle == LINE_END_CYCLE_60 ) )
        !          1412:        {
        !          1413:                ShifterFrame.ShifterLines[ nHBL ].BorderMask |= BORDERMASK_RIGHT_MINUS_2;
        !          1414:                LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect late right-2 %d<->%d\n" ,
        !          1415:                        ShifterFrame.ShifterLines[ nHBL ].DisplayStartCycle , ShifterFrame.ShifterLines[ nHBL ].DisplayEndCycle );
        !          1416:        }
        !          1417: 
        !          1418: 
        !          1419:        /* Similar case when line started in 60 Hz but did not end at the usual LINE_END_CYCLE_60 position */
        !          1420:        /* (line can end at LINE_END_CYCLE_71/50 or have right border removed) */
        !          1421:        /* This means left border had 2 bytes more to display */
        !          1422:        if ( ( ( ShifterFrame.ShifterLines[ nHBL ].BorderMask & BORDERMASK_LEFT_PLUS_2 ) == 0 )
        !          1423:          && ( ShifterFrame.ShifterLines[ nHBL ].DisplayStartCycle == LINE_START_CYCLE_60 )
        !          1424:          && ( ShifterFrame.ShifterLines[ nHBL ].DisplayEndCycle != LINE_END_CYCLE_60 ) )               /* end could be 160, 372 or 460 */
        !          1425:        {
        !          1426:                ShifterFrame.ShifterLines[ nHBL ].BorderMask |= BORDERMASK_LEFT_PLUS_2;
        !          1427:                LOG_TRACE ( TRACE_VIDEO_BORDER_H , "detect late left+2 %d<->%d\n" ,
        !          1428:                        ShifterFrame.ShifterLines[ nHBL ].DisplayStartCycle , ShifterFrame.ShifterLines[ nHBL ].DisplayEndCycle );
        !          1429:        }
        !          1430: 
        !          1431: 
        !          1432:        /* Although a 'left+2' was detected earlier, the freq was switched back to 60 Hz during DE, so the line is just */
        !          1433:        /* a normal 60 Hz line ; we must cancel the 'left+2' flag */
        !          1434:        else if ( ( ShifterFrame.ShifterLines[ nHBL ].BorderMask & BORDERMASK_LEFT_PLUS_2 )
        !          1435:          && ( ShifterFrame.ShifterLines[ nHBL ].DisplayEndCycle == LINE_END_CYCLE_60 ) )
        !          1436:        {
        !          1437:                ShifterFrame.ShifterLines[ nHBL ].BorderMask &= ~BORDERMASK_LEFT_PLUS_2;
        !          1438:                LOG_TRACE ( TRACE_VIDEO_BORDER_H , "cancel late left+2 %d<->%d\n" ,
        !          1439:                        ShifterFrame.ShifterLines[ nHBL ].DisplayStartCycle , ShifterFrame.ShifterLines[ nHBL ].DisplayEndCycle );
        !          1440:        }
        !          1441: 
        !          1442: 
1.1.1.13  root     1443: 
1.1.1.15! root     1444:        /* Store palette for very first line on screen - HBLPalettes[0] */
        !          1445:        if (nHBL == nFirstVisibleHbl-1)
        !          1446:        {
        !          1447:                /* Store ALL palette for this line into raster table for datum */
        !          1448:                Video_StoreFirstLinePalette();
        !          1449:        }
        !          1450: 
        !          1451:        if (bUseHighRes)
        !          1452:        {
        !          1453:                /* Copy for hi-res (no overscan) */
        !          1454:                if (nHBL >= nFirstVisibleHbl && nHBL < nLastVisibleHbl)
        !          1455:                        Video_CopyScreenLineMono();
        !          1456:        }
        !          1457:        /* Are we in possible visible color display (including borders)? */
        !          1458:        else if (nHBL >= nFirstVisibleHbl && nHBL < nLastVisibleHbl)
        !          1459:        {
        !          1460:                /* Store resolution for every line so can check for mix low/med screens */
        !          1461:                Video_StoreResolution(nHBL-nFirstVisibleHbl);
        !          1462: 
        !          1463:                /* Copy line of screen to buffer to simulate TV raster trace
        !          1464:                 * - required for mouse cursor display/game updates
        !          1465:                 * Eg, Lemmings and The Killing Game Show are good examples */
        !          1466:                Video_CopyScreenLineColor();
        !          1467:        }
        !          1468: }
        !          1469: 
        !          1470: 
        !          1471: /*-----------------------------------------------------------------------*/
        !          1472: /**
        !          1473:  * Set default values for the next HBL, depending on the current res/freq.
        !          1474:  * We set the number of cycles per line, as well as some default values
        !          1475:  * for display start/end cycle.
        !          1476:  */
        !          1477: static void Video_StartHBL(void)
        !          1478: {
        !          1479:        if ( ( IoMem_ReadByte( 0xff8260 ) & 3 ) == 2 )          /* hi res */
        !          1480:        {
        !          1481:                nCyclesPerLine = CYCLES_PER_LINE_71HZ;
        !          1482:                ShifterFrame.ShifterLines[ nHBL ].DisplayStartCycle = LINE_START_CYCLE_71;
        !          1483:                ShifterFrame.ShifterLines[ nHBL ].DisplayEndCycle = LINE_END_CYCLE_71;
        !          1484:        }
        !          1485: 
        !          1486:        else
        !          1487:        {
        !          1488:                if ( IoMem_ReadByte ( 0xff820a ) & 2 )          /* 50 Hz */
        !          1489:                {
        !          1490:                        nCyclesPerLine = CYCLES_PER_LINE_50HZ;
        !          1491:                        if ( ShifterFrame.ShifterLines[ nHBL ].DisplayStartCycle == -1 )        /* start not set yet */
        !          1492:                                ShifterFrame.ShifterLines[ nHBL ].DisplayStartCycle = LINE_START_CYCLE_50;
        !          1493:                        ShifterFrame.ShifterLines[ nHBL ].DisplayEndCycle = LINE_END_CYCLE_50;
        !          1494:                }
        !          1495:                else                                            /* 60 Hz */
        !          1496:                {
        !          1497:                        nCyclesPerLine = CYCLES_PER_LINE_60HZ;
        !          1498:                        if ( ShifterFrame.ShifterLines[ nHBL ].DisplayStartCycle == -1 )        /* start not set yet */
        !          1499:                                ShifterFrame.ShifterLines[ nHBL ].DisplayStartCycle = LINE_START_CYCLE_60;
        !          1500:                        ShifterFrame.ShifterLines[ nHBL ].DisplayEndCycle = LINE_END_CYCLE_60;
        !          1501:                }
        !          1502:        }
        !          1503: }
        !          1504: 
        !          1505: 
        !          1506: /*-----------------------------------------------------------------------*/
        !          1507: /**
        !          1508:  * End Of Line interrupt
        !          1509:  * This interrupt is started on cycle position 404 in 50 Hz and on cycle
        !          1510:  * position 400 in 60 Hz. 50 Hz display ends at cycle 376 and 60 Hz displays
        !          1511:  * ends at cycle 372. This means the EndLine interrupt happens 28 cycles
        !          1512:  * after DisplayEndCycle.
        !          1513:  * Note that if bit 3 of MFP AER is 1, then timer B will count start of line
        !          1514:  * instead of end of line (at cycle 52+28 or 56+28)
        !          1515:  */
        !          1516: void Video_InterruptHandler_EndLine(void)
        !          1517: {
        !          1518:        int FrameCycles, HblCounterVideo, LineCycles;
        !          1519:        int PendingCycles = -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE );
        !          1520: 
        !          1521:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !          1522: 
        !          1523:        LOG_TRACE ( TRACE_VIDEO_HBL , "EndLine TB %d video_cyc=%d line_cyc=%d pending_int_cnt=%d\n" ,
        !          1524:                       nHBL , FrameCycles , LineCycles , PendingCycles );
        !          1525: 
        !          1526:        /* Remove this interrupt from list and re-order */
        !          1527:        Int_AcknowledgeInterrupt();
        !          1528: 
        !          1529:        /* Ignore HBLs in VDI mode */
        !          1530:        if (bUseVDIRes)
        !          1531:                return;
        !          1532: 
        !          1533:        /* Generate new Endline, if need to - there are 313 HBLs per frame */
        !          1534:        if (nHBL < nScanlinesPerFrame-1)
        !          1535:        {
        !          1536:                /* By default, next EndLine's int will be on line nHBL+1 at pos 376+28 or 372+28 */
        !          1537:                if ( ( IoMem[0xfffa03] & ( 1 << 3 ) ) == 0 )            /* count end of line */
1.1.1.13  root     1538:                {
1.1.1.15! root     1539:                        /* If EndLine int is delayed too much (more than 100 cycles), nLineCycles will */
        !          1540:                        /* be in the range 0..xxx instead of 400..512. In that case, we need to add */
        !          1541:                        /* nCyclesPerLine to be in the range 512..x+512 */
        !          1542:                        /* Maximum possible delay should be around 160 cycles on STF (DIVS) */
        !          1543:                        /* In that case, HBL int will be delayed too, so we will have HblCounterVideo == nHBL+1 */
        !          1544:                        if ( HblCounterVideo == nHBL+1 )                /* int happened in fact on the next line nHBL+1 */
        !          1545:                                LineCycles += nCyclesPerLine;
1.1.1.13  root     1546: 
1.1.1.15! root     1547:                        LineTimerBCycle = Video_TimerB_GetPos( HblCounterVideo );
1.1.1.13  root     1548:                }
                   1549: 
1.1.1.15! root     1550:                else                                                    /* count start of line, no possible delay to handle */
1.1.1.13  root     1551:                {
1.1.1.15! root     1552:                        LineTimerBCycle = Video_TimerB_GetPos( HblCounterVideo );
1.1.1.13  root     1553:                }
                   1554: 
1.1.1.15! root     1555: //fprintf ( stderr , "new tb %d %d %d\n" , LineTimerBCycle , nCyclesPerLine , LineTimerBCycle - LineCycles + nCyclesPerLine );
        !          1556:                Int_AddRelativeInterrupt ( LineTimerBCycle - LineCycles + nCyclesPerLine,
        !          1557:                                         INT_CPU_CYCLE, INTERRUPT_VIDEO_ENDLINE );
1.1.1.11  root     1558:        }
                   1559: 
1.1.1.15! root     1560:        /* Timer B occurs at END of first visible screen line in Event Count mode */
        !          1561:        if (nHBL >= nStartHBL && nHBL < nEndHBL)
1.1.1.11  root     1562:        {
1.1.1.15! root     1563:                /* Handle Timer B when using Event Count mode */
        !          1564:                /* We must ensure that the write to fffa1b to activate timer B was */
        !          1565:                /* completed before the point where the end of line signal was generated */
        !          1566:                /* (in the case of a move.b #8,$fffa1b that would happen 4 cycles */
        !          1567:                /* before end of line, the interrupt should not be generated) */
        !          1568:                if ( (MFP_TBCR == 0x08)                                         /* Is timer in Event Count mode ? */
        !          1569:                        && ( ( TimerBEventCountCycleStart == -1 )               /* timer B was started during a previous VBL */
        !          1570:                          || ( TimerBEventCountCycleStart < FrameCycles-PendingCycles ) ) )     /* timer B was started before this possible interrupt */
        !          1571:                        MFP_TimerB_EventCount_Interrupt();                      /* we have a valid timer B interrupt */
1.1.1.11  root     1572:        }
1.1       root     1573: }
                   1574: 
1.1.1.2   root     1575: 
1.1.1.15! root     1576: 
        !          1577: 
1.1.1.2   root     1578: /*-----------------------------------------------------------------------*/
1.1.1.11  root     1579: /**
                   1580:  * Store whole palette on first line so have reference to work from
                   1581:  */
1.1.1.7   root     1582: static void Video_StoreFirstLinePalette(void)
1.1       root     1583: {
1.1.1.11  root     1584:        Uint16 *pp2;
                   1585:        int i;
                   1586: 
                   1587:        pp2 = (Uint16 *)&IoMem[0xff8240];
                   1588:        for (i = 0; i < 16; i++)
                   1589:                HBLPalettes[i] = SDL_SwapBE16(*pp2++);
1.1       root     1590: 
1.1.1.11  root     1591:        /* And set mask flag with palette and resolution */
                   1592: //     FIXME ; enlever PALETTEMASK_RESOLUTION
                   1593: 
1.1.1.15! root     1594: //     if ( ShifterFrame.ShifterLines[ nFirstVisibleHbl ].BorderMask == BORDERMASK_NONE )      // no border trick, store the current res
1.1.1.11  root     1595:        HBLPaletteMasks[0] = (PALETTEMASK_RESOLUTION|PALETTEMASK_PALETTE) | (((Uint32)IoMem_ReadByte(0xff8260)&0x3)<<16);
                   1596: //     else                                            // border removal, assume low res for the whole line
                   1597: //             HBLPaletteMasks[0] = (PALETTEMASK_RESOLUTION|PALETTEMASK_PALETTE) | (0<<16);
1.1       root     1598: }
                   1599: 
1.1.1.2   root     1600: 
                   1601: /*-----------------------------------------------------------------------*/
1.1.1.11  root     1602: /**
                   1603:  * Store resolution on each line (used to test if mixed low/medium resolutions)
                   1604:  */
1.1.1.7   root     1605: static void Video_StoreResolution(int y)
1.1       root     1606: {
1.1.1.11  root     1607:        Uint8 res;
                   1608:        int Mask;
1.1       root     1609: 
1.1.1.11  root     1610:        /* Clear resolution, and set with current value */
                   1611:        if (!(bUseHighRes || bUseVDIRes))
                   1612:        {
                   1613:                HBLPaletteMasks[y] &= ~(0x3<<16);
                   1614:                res = IoMem_ReadByte(0xff8260)&0x3;
                   1615: 
1.1.1.15! root     1616:                Mask = ShifterFrame.ShifterLines[ y+nFirstVisibleHbl ].BorderMask;
1.1.1.11  root     1617: 
1.1.1.15! root     1618:                if ( Mask & BORDERMASK_OVERSCAN_MED_RES )               /* special case for med res to render the overscan line */
        !          1619:                        res = 1;                                        /* med res instead of low res */
1.1.1.11  root     1620:                else if ( Mask != BORDERMASK_NONE )                     /* border removal : assume low res for the whole line */
                   1621:                        res = 0;
1.1.1.2   root     1622: 
1.1.1.11  root     1623:                HBLPaletteMasks[y] |= PALETTEMASK_RESOLUTION|((Uint32)res)<<16;
                   1624: 
                   1625: #if 0
                   1626:                if ( ( Mask == BORDERMASK_NONE )                        /* no border trick, store the current res */
                   1627:                        || ( res == 0 ) || ( res == 1 ) )                       /* if border trick, ignore passage to hi res */
                   1628:                        HBLPaletteMasks[y] |= PALETTEMASK_RESOLUTION|((Uint32)res)<<16;
                   1629:                else                                            /* border removal or hi res : assume low res for the whole line */
                   1630:                        HBLPaletteMasks[y] |= (0)<<16;
                   1631: 
1.1.1.15! root     1632:                /* special case for med res to render the overscan line */
        !          1633:                if ( Mask & BORDERMASK_OVERSCAN_MED_RES )
        !          1634:                        HBLPaletteMasks[y] |= PALETTEMASK_RESOLUTION|((Uint32)1)<<16;   /* med res instead of low res */
1.1.1.11  root     1635: #endif
1.1       root     1636: 
1.1.1.11  root     1637: //   fprintf ( stderr , "store res %d line %d %x %x\n" , res , y , Mask , HBLPaletteMasks[y] );
                   1638:        }
1.1.1.9   root     1639: }
                   1640: 
                   1641: 
                   1642: /*-----------------------------------------------------------------------*/
1.1.1.11  root     1643: /**
                   1644:  * Copy one line of monochrome screen into buffer for conversion later.
                   1645:  */
                   1646: static void Video_CopyScreenLineMono(void)
                   1647: {
                   1648:        Uint32 addr;
                   1649: 
                   1650:        /* Copy one line - 80 bytes in ST high resolution */
                   1651:        memcpy(pSTScreen, pVideoRaster, SCREENBYTES_MONOLINE);
                   1652:        pVideoRaster += SCREENBYTES_MONOLINE;
                   1653: 
                   1654:        /* Handle STE fine scrolling (HWScrollCount is zero on ST). */
                   1655:        if (HWScrollCount)
                   1656:        {
                   1657:                Uint16 *pScrollAdj;
                   1658:                int nNegScrollCnt;
                   1659: 
                   1660:                pScrollAdj = (Uint16 *)pSTScreen;
                   1661:                nNegScrollCnt = 16 - HWScrollCount;
                   1662: 
                   1663:                /* Shift the whole line by the given scroll count */
                   1664:                while ((Uint8*)pScrollAdj < pSTScreen + SCREENBYTES_MONOLINE-2)
                   1665:                {
                   1666:                        do_put_mem_word(pScrollAdj, (do_get_mem_word(pScrollAdj) << HWScrollCount)
                   1667:                                        | (do_get_mem_word(pScrollAdj+1) >> nNegScrollCnt));
                   1668:                        ++pScrollAdj;
                   1669:                }
                   1670: 
                   1671:                /* Handle the last 16 pixels of the line */
                   1672:                do_put_mem_word(pScrollAdj, (do_get_mem_word(pScrollAdj) << HWScrollCount)
                   1673:                                | (do_get_mem_word(pVideoRaster) >> nNegScrollCnt));
                   1674: 
                   1675:                /* HW scrolling advances Shifter video counter by one */
                   1676:                pVideoRaster += 1 * 2;
                   1677:        }
                   1678: 
                   1679:        /* LineWidth is zero on ST. */
                   1680:        /* On STE, the Shifter skips the given amount of words. */
                   1681:        pVideoRaster += LineWidth*2;
                   1682: 
                   1683:        /* On STE, handle modifications of the video counter address $ff8205/07/09 */
                   1684:        /* that occurred while the display was already ON */
                   1685:        if ( NewVideoHi >= 0 )
                   1686:        {
                   1687:                addr = ( ( pVideoRaster - STRam ) & 0x00ffff ) | ( NewVideoHi << 16 );
                   1688:                pVideoRaster = &STRam[addr & ~1];
                   1689:                NewVideoHi = -1;
                   1690:        }
                   1691:        if ( NewVideoMed >= 0 )
                   1692:        {
                   1693:                addr = ( ( pVideoRaster - STRam ) & 0xff00ff ) | ( NewVideoMed << 8 );
                   1694:                pVideoRaster = &STRam[addr & ~1];
                   1695:                NewVideoMed = -1;
                   1696:        }
                   1697:        if ( NewVideoLo >= 0 )
                   1698:        {
                   1699:                addr = ( ( pVideoRaster - STRam ) & 0xffff00 ) | ( NewVideoLo );
                   1700:                pVideoRaster = &STRam[addr & ~1];
                   1701:                NewVideoLo = -1;
                   1702:        }
                   1703: 
                   1704:        /* On STE, if we wrote to the hwscroll register, we set the */
                   1705:        /* new value here, once the current line was processed */
                   1706:        if ( NewHWScrollCount >= 0 )
                   1707:        {
                   1708:                HWScrollCount = NewHWScrollCount;
                   1709:                NewHWScrollCount = -1;
                   1710:        }
                   1711: 
                   1712:        /* On STE, if we wrote to the linewidth register, we set the */
                   1713:        /* new value here, once the current line was processed */
                   1714:        if ( NewLineWidth >= 0 )
                   1715:        {
                   1716:                LineWidth = NewLineWidth;
                   1717:                NewLineWidth = -1;
                   1718:        }
                   1719: 
                   1720:        /* Each screen line copied to buffer is always same length */
                   1721:        pSTScreen += SCREENBYTES_MONOLINE;
                   1722: }
                   1723: 
                   1724: 
                   1725: /*-----------------------------------------------------------------------*/
                   1726: /**
                   1727:  * Copy one line of color screen into buffer for conversion later.
                   1728:  * Possible lines may be top/bottom border, and/or left/right borders.
                   1729:  */
1.1.1.9   root     1730: static void Video_CopyScreenLineColor(void)
                   1731: {
1.1.1.15! root     1732:        int LineBorderMask;
1.1.1.11  root     1733:        int VideoOffset = 0;
                   1734:        int STF_PixelScroll = 0;
                   1735:        Uint32 addr;
1.1.1.14  root     1736:        int LineRes;
                   1737: 
                   1738: 
1.1.1.15! root     1739:        LineBorderMask = ShifterFrame.ShifterLines[ nHBL ].BorderMask;
        !          1740: 
        !          1741:        /* Get resolution for this line (in case of mixed low/med screen) */
        !          1742:        LineRes = ( HBLPaletteMasks[nHBL-nFirstVisibleHbl] >> 16 ) & 1;         /* 0=low res  1=med res */
1.1.1.11  root     1743: 
                   1744:        //fprintf(stderr , "copy line %d start %d end %d %d %x\n" , nHBL, nStartHBL, nEndHBL, LineBorderMask, pVideoRaster - STRam);
                   1745: 
                   1746:        /* If left border is opened, we need to compensate one missing word in low res (1 plan) */
1.1.1.15! root     1747:        /* If overscan is in med res, the offset is variable */
        !          1748:        if ( LineBorderMask & BORDERMASK_OVERSCAN_MED_RES )
        !          1749:                VideoOffset = - ( ( LineBorderMask >> 20 ) & 0x0f );            /* No Cooper=0  PYM=-2 in med res overscan */
1.1.1.11  root     1750: 
                   1751:        else if ( LineBorderMask & BORDERMASK_LEFT_OFF )
1.1.1.14  root     1752:                VideoOffset = -2;                                               /* always 2 bytes in low res overscan */
1.1.1.11  root     1753: 
                   1754:        /* Handle 4 pixels hardware scrolling ('ST Cnx' demo in 'Punish Your Machine') */
                   1755:        /* Depending on the number of pixels, we need to compensate for some skipped words */
1.1.1.15! root     1756:        else if ( LineBorderMask & BORDERMASK_LEFT_OFF_MED )
1.1.1.11  root     1757:        {
1.1.1.15! root     1758:                STF_PixelScroll = ShifterFrame.ShifterLines[ nHBL ].DisplayPixelShift;
1.1.1.11  root     1759: 
                   1760:                if      ( STF_PixelScroll == 13 )       VideoOffset = 2+8;
                   1761:                else if ( STF_PixelScroll == 9 )        VideoOffset = 0+8;
                   1762:                else if ( STF_PixelScroll == 5 )        VideoOffset = -2+8;
                   1763:                else if ( STF_PixelScroll == 1 )        VideoOffset = -4+8;
                   1764:                else                                    VideoOffset = 0;        /* never used ? */
                   1765: 
                   1766:                // fprintf(stderr , "scr off %d %d\n" , STF_PixelScroll , VideoOffset);
                   1767:        }
                   1768: 
1.1.1.13  root     1769: 
1.1.1.11  root     1770:        /* Is total blank line? I.e. top/bottom border? */
                   1771:        if ((nHBL < nStartHBL) || (nHBL >= nEndHBL)
1.1.1.15! root     1772:            || (LineBorderMask & BORDERMASK_EMPTY_LINE))
1.1.1.11  root     1773:        {
                   1774:                /* Clear line to color '0' */
                   1775:                memset(pSTScreen, 0, SCREENBYTES_LINE);
                   1776:        }
                   1777:        else
                   1778:        {
                   1779:                /* Does have left border? If not, clear to color '0' */
1.1.1.15! root     1780:                if ( LineBorderMask & ( BORDERMASK_LEFT_OFF | BORDERMASK_LEFT_OFF_MED ) )
1.1.1.11  root     1781:                {
                   1782:                        /* The "-2" in the following line is needed so that the offset is a multiple of 8 */
                   1783:                        pVideoRaster += BORDERBYTES_LEFT-SCREENBYTES_LEFT+VideoOffset;
                   1784:                        memcpy(pSTScreen, pVideoRaster, SCREENBYTES_LEFT);
                   1785:                        pVideoRaster += SCREENBYTES_LEFT;
                   1786:                }
                   1787:                else if (LineBorderMask & BORDERMASK_LEFT_PLUS_2)
                   1788:                {
1.1.1.12  root     1789:                        /* bigger line by 2 bytes on the left */
                   1790:                        memset(pSTScreen,0,SCREENBYTES_LEFT-2);         /* clear unused pixels */
1.1.1.11  root     1791:                        memcpy(pSTScreen+SCREENBYTES_LEFT-2, pVideoRaster, 2);
                   1792:                        pVideoRaster += 2;
                   1793:                }
1.1.1.12  root     1794:                else if (bSteBorderFlag)                                /* STE specific */
                   1795:                {
                   1796:                        /* bigger line by 8 bytes on the left */
                   1797:                        memset(pSTScreen,0,SCREENBYTES_LEFT-4*2);       /* clear unused pixels */
                   1798:                        memcpy(pSTScreen+SCREENBYTES_LEFT-4*2, pVideoRaster, 4*2);
                   1799:                        pVideoRaster += 4*2;
                   1800:                }
1.1.1.11  root     1801:                else
                   1802:                        memset(pSTScreen,0,SCREENBYTES_LEFT);
                   1803: 
                   1804:                /* Short line due to hires in the middle ? */
                   1805:                if (LineBorderMask & BORDERMASK_STOP_MIDDLE)
                   1806:                {
                   1807:                        /* 106 bytes less in the line */
                   1808:                        memcpy(pSTScreen+SCREENBYTES_LEFT, pVideoRaster, SCREENBYTES_MIDDLE-106);
1.1.1.12  root     1809:                        memset(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE-106, 0, 106);      /* clear unused pixels */
1.1.1.11  root     1810:                        pVideoRaster += (SCREENBYTES_MIDDLE-106);
                   1811:                }
                   1812:                else
                   1813:                {
                   1814:                        /* normal middle part (160 bytes) */
                   1815:                        memcpy(pSTScreen+SCREENBYTES_LEFT, pVideoRaster, SCREENBYTES_MIDDLE);
                   1816:                        pVideoRaster += SCREENBYTES_MIDDLE;
                   1817:                }
                   1818: 
                   1819:                /* Does have right border ? */
                   1820:                if (LineBorderMask & BORDERMASK_RIGHT_OFF)
                   1821:                {
                   1822:                        memcpy(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE, pVideoRaster, SCREENBYTES_RIGHT);
                   1823:                        pVideoRaster += BORDERBYTES_RIGHT-SCREENBYTES_RIGHT;
                   1824:                        pVideoRaster += SCREENBYTES_RIGHT;
                   1825:                }
                   1826:                else if (LineBorderMask & BORDERMASK_RIGHT_MINUS_2)
                   1827:                {
                   1828:                        /* Shortened line by 2 bytes */
                   1829:                        memset(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE-2, 0, SCREENBYTES_RIGHT+2);
                   1830:                        pVideoRaster -= 2;
                   1831:                }
                   1832:                else
                   1833:                {
                   1834:                        /* Simply clear right border to '0' */
                   1835:                        memset(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE,0,SCREENBYTES_RIGHT);
                   1836:                }
                   1837: 
                   1838:                /* Full right border removal up to the end of the line (cycle 512) */
                   1839:                if (LineBorderMask & BORDERMASK_RIGHT_OFF_FULL)
                   1840:                        pVideoRaster += BORDERBYTES_RIGHT_FULL;
                   1841: 
                   1842:                /* Correct the offset for pVideoRaster from BORDERMASK_LEFT_OFF above if needed */
                   1843:                pVideoRaster -= VideoOffset;            /* VideoOffset is 0 or -2 */
                   1844: 
                   1845: 
                   1846:                /* Handle 4 pixels hardware scrolling ('ST Cnx' demo in 'Punish Your Machine') */
                   1847:                /* Shift the line by STF_PixelScroll pixels to the right (we don't need to scroll */
                   1848:                /* the first 16 pixels / 8 bytes). */
                   1849:                if (STF_PixelScroll != 0)
                   1850:                {
                   1851:                        Uint16 *pScreenLineEnd;
                   1852:                        int count;
                   1853: 
                   1854:                        pScreenLineEnd = (Uint16 *) ( pSTScreen + SCREENBYTES_LINE - 2 );
                   1855:                        for ( count = 0 ; count < ( SCREENBYTES_LINE - 8 ) / 2 ; count++ , pScreenLineEnd-- )
                   1856:                                do_put_mem_word ( pScreenLineEnd , ( ( do_get_mem_word ( pScreenLineEnd - 4 ) << 16 ) | ( do_get_mem_word ( pScreenLineEnd ) ) ) >> STF_PixelScroll );
                   1857:                }
                   1858: 
                   1859: 
                   1860:                /* STE specific */
1.1.1.13  root     1861:                if (!bSteBorderFlag && HWScrollCount)           /* Handle STE fine scrolling (HWScrollCount is zero on ST) */
1.1.1.11  root     1862:                {
1.1.1.13  root     1863:                        Uint16 *pScrollAdj;     /* Pointer to actual position in line */
1.1.1.11  root     1864:                        int nNegScrollCnt;
1.1.1.13  root     1865:                        Uint16 *pScrollEndAddr; /* Pointer to end of the line */
1.1.1.11  root     1866: 
                   1867:                        nNegScrollCnt = 16 - HWScrollCount;
                   1868:                        if (LineBorderMask & BORDERMASK_LEFT_OFF)
                   1869:                                pScrollAdj = (Uint16 *)pSTScreen;
                   1870:                        else
                   1871:                                pScrollAdj = (Uint16 *)(pSTScreen + SCREENBYTES_LEFT);
                   1872:                        if (LineBorderMask & BORDERMASK_RIGHT_OFF)
                   1873:                                pScrollEndAddr = (Uint16 *)(pSTScreen + SCREENBYTES_LINE - 8);
                   1874:                        else
                   1875:                                pScrollEndAddr = (Uint16 *)(pSTScreen + SCREENBYTES_LEFT + SCREENBYTES_MIDDLE - 8);
                   1876: 
1.1.1.15! root     1877:                        if ( LineRes == 1 )                     /* med res */
1.1.1.11  root     1878:                        {
1.1.1.15! root     1879:                                /* in med res, 16 pixels are 4 bytes, not 8 as in low res, so only the last 4 bytes need a special case */
1.1.1.14  root     1880:                                pScrollEndAddr += 2;                            /* 2 Uint16 -> 4 bytes */
                   1881: 
                   1882:                                /* Shift the whole line to the left by the given scroll count */
                   1883:                                while (pScrollAdj < pScrollEndAddr)
                   1884:                                {
                   1885:                                        do_put_mem_word(pScrollAdj, (do_get_mem_word(pScrollAdj) << HWScrollCount)
                   1886:                                                        | (do_get_mem_word(pScrollAdj+2) >> nNegScrollCnt));
                   1887:                                        ++pScrollAdj;
                   1888:                                }
                   1889:                                /* Handle the last 16 pixels of the line */
1.1.1.15! root     1890:                                if (LineBorderMask & BORDERMASK_RIGHT_OFF)      /* FIXME : med + right off should be tested on a real STE */
1.1.1.14  root     1891:                                {
                   1892:                                        Uint16 *pVideoLineEnd = (Uint16 *)(pVideoRaster - (46 - SCREENBYTES_RIGHT));
                   1893:                                        do_put_mem_word(pScrollAdj+0, (do_get_mem_word(pScrollAdj+0) << HWScrollCount)
                   1894:                                                        | (do_get_mem_word(pVideoLineEnd++) >> nNegScrollCnt));
                   1895:                                        do_put_mem_word(pScrollAdj+1, (do_get_mem_word(pScrollAdj+1) << HWScrollCount)
                   1896:                                                        | (do_get_mem_word(pVideoLineEnd++) >> nNegScrollCnt));
                   1897:                                }
                   1898:                                else
                   1899:                                {
                   1900:                                        do_put_mem_word(pScrollAdj+0, (do_get_mem_word(pScrollAdj+0) << HWScrollCount)
                   1901:                                                        | (do_get_mem_word(pVideoRaster+0) >> nNegScrollCnt));
                   1902:                                        do_put_mem_word(pScrollAdj+1, (do_get_mem_word(pScrollAdj+1) << HWScrollCount)
                   1903:                                                        | (do_get_mem_word(pVideoRaster+2) >> nNegScrollCnt));
                   1904:                                }
                   1905: 
                   1906:                                /* Depending on whether $ff8264 or $ff8265 was used to scroll, */
                   1907:                                /* we prefetched 16 pixel (4 bytes) */
1.1.1.13  root     1908:                                if ( HWScrollPrefetch == 1 )            /* $ff8265 prefetches 16 pixels */
                   1909:                                        pVideoRaster += 2 * 2;          /* 2 bitplans */
1.1.1.14  root     1910: 
                   1911:                                /* If scrolling with $ff8264, there's no prefetch, which means display starts */
                   1912:                                /* 16 pixels later but still stops at the normal point (eg we display */
                   1913:                                /* (320-16) pixels in low res). We shift the whole line 4 bytes to the right to */
                   1914:                                /* get the correct result (using memmove, as src/dest are overlapping). */
                   1915:                                else
                   1916:                                {
                   1917:                                        if (LineBorderMask & BORDERMASK_RIGHT_OFF)
                   1918:                                                memmove ( pSTScreen+4 , pSTScreen , SCREENBYTES_LINE - 4 );
                   1919:                                        else
                   1920:                                                memmove ( pSTScreen+4 , pSTScreen , SCREENBYTES_LEFT + SCREENBYTES_MIDDLE - 4 );
                   1921: 
                   1922:                                        memset ( pSTScreen , 0 , 4 );   /* first 16 pixels are color '0' */
                   1923:                                }
1.1.1.11  root     1924:                        }
1.1.1.14  root     1925: 
                   1926:                        else                                    /* low res */
1.1.1.11  root     1927:                        {
                   1928:                                /* Shift the whole line to the left by the given scroll count */
                   1929:                                while (pScrollAdj < pScrollEndAddr)
                   1930:                                {
                   1931:                                        do_put_mem_word(pScrollAdj, (do_get_mem_word(pScrollAdj) << HWScrollCount)
                   1932:                                                        | (do_get_mem_word(pScrollAdj+4) >> nNegScrollCnt));
                   1933:                                        ++pScrollAdj;
                   1934:                                }
                   1935:                                /* Handle the last 16 pixels of the line */
                   1936:                                if (LineBorderMask & BORDERMASK_RIGHT_OFF)
                   1937:                                {
                   1938:                                        /* When right border is open, we have to deal with this ugly offset
                   1939:                                         * of 46-SCREENBYTES_RIGHT - The demo "Mind rewind" is a good example */
                   1940:                                        Uint16 *pVideoLineEnd = (Uint16 *)(pVideoRaster - (46 - SCREENBYTES_RIGHT));
                   1941:                                        do_put_mem_word(pScrollAdj+0, (do_get_mem_word(pScrollAdj+0) << HWScrollCount)
                   1942:                                                        | (do_get_mem_word(pVideoLineEnd++) >> nNegScrollCnt));
                   1943:                                        do_put_mem_word(pScrollAdj+1, (do_get_mem_word(pScrollAdj+1) << HWScrollCount)
                   1944:                                                        | (do_get_mem_word(pVideoLineEnd++) >> nNegScrollCnt));
                   1945:                                        do_put_mem_word(pScrollAdj+2, (do_get_mem_word(pScrollAdj+2) << HWScrollCount)
                   1946:                                                        | (do_get_mem_word(pVideoLineEnd++) >> nNegScrollCnt));
                   1947:                                        do_put_mem_word(pScrollAdj+3, (do_get_mem_word(pScrollAdj+3) << HWScrollCount)
                   1948:                                                        | (do_get_mem_word(pVideoLineEnd++) >> nNegScrollCnt));
                   1949:                                }
                   1950:                                else
                   1951:                                {
                   1952:                                        do_put_mem_word(pScrollAdj+0, (do_get_mem_word(pScrollAdj+0) << HWScrollCount)
                   1953:                                                        | (do_get_mem_word(pVideoRaster+0) >> nNegScrollCnt));
                   1954:                                        do_put_mem_word(pScrollAdj+1, (do_get_mem_word(pScrollAdj+1) << HWScrollCount)
                   1955:                                                        | (do_get_mem_word(pVideoRaster+2) >> nNegScrollCnt));
                   1956:                                        do_put_mem_word(pScrollAdj+2, (do_get_mem_word(pScrollAdj+2) << HWScrollCount)
                   1957:                                                        | (do_get_mem_word(pVideoRaster+4) >> nNegScrollCnt));
                   1958:                                        do_put_mem_word(pScrollAdj+3, (do_get_mem_word(pScrollAdj+3) << HWScrollCount)
                   1959:                                                        | (do_get_mem_word(pVideoRaster+6) >> nNegScrollCnt));
                   1960:                                }
1.1.1.13  root     1961: 
                   1962:                                /* Depending on whether $ff8264 or $ff8265 was used to scroll, */
                   1963:                                /* we prefetched 16 pixel (8 bytes) */
                   1964:                                if ( HWScrollPrefetch == 1 )            /* $ff8265 prefetches 16 pixels */
                   1965:                                        pVideoRaster += 4 * 2;          /* 4 bitplans */
                   1966: 
                   1967:                                /* If scrolling with $ff8264, there's no prefetch, which means display starts */
                   1968:                                /* 16 pixels later but still stops at the normal point (eg we display */
                   1969:                                /* (320-16) pixels in low res). We shift the whole line 8 bytes to the right to */
                   1970:                                /* get the correct result (using memmove, as src/dest are overlapping). */
                   1971:                                else
                   1972:                                {
                   1973:                                        if (LineBorderMask & BORDERMASK_RIGHT_OFF)
                   1974:                                                memmove ( pSTScreen+8 , pSTScreen , SCREENBYTES_LINE - 8 );
                   1975:                                        else
                   1976:                                                memmove ( pSTScreen+8 , pSTScreen , SCREENBYTES_LEFT + SCREENBYTES_MIDDLE - 8 );
                   1977: 
                   1978:                                        memset ( pSTScreen , 0 , 8 );   /* first 16 pixels are color '0' */
                   1979:                                }
1.1.1.11  root     1980: 
                   1981:                                /* On STE, when we have a 230 bytes overscan line and HWScrollCount > 0 */
                   1982:                                /* we must read 6 bytes less than expected */
                   1983:                                if ( (LineBorderMask & BORDERMASK_LEFT_OFF) && (LineBorderMask & BORDERMASK_RIGHT_OFF) )
                   1984:                                        pVideoRaster -= 6;              /* we don't add 8 bytes, but 2 */
                   1985: 
                   1986:                        }
                   1987:                }
                   1988: 
                   1989:                /* LineWidth is zero on ST. */
                   1990:                /* On STE, the Shifter skips the given amount of words. */
                   1991:                pVideoRaster += LineWidth*2;
                   1992: 
                   1993:                /* On STE, handle modifications of the video counter address $ff8205/07/09 */
                   1994:                /* that occurred while the display was already ON */
                   1995:                if ( NewVideoHi >= 0 )
                   1996:                {
                   1997:                        addr = ( ( pVideoRaster - STRam ) & 0x00ffff ) | ( NewVideoHi << 16 );
                   1998:                        pVideoRaster = &STRam[addr & ~1];
                   1999:                        NewVideoHi = -1;
                   2000:                }
                   2001:                if ( NewVideoMed >= 0 )
                   2002:                {
                   2003:                        addr = ( ( pVideoRaster - STRam ) & 0xff00ff ) | ( NewVideoMed << 8 );
                   2004:                        pVideoRaster = &STRam[addr & ~1];
                   2005:                        NewVideoMed = -1;
                   2006:                }
                   2007:                if ( NewVideoLo >= 0 )
                   2008:                {
                   2009:                        addr = ( ( pVideoRaster - STRam ) & 0xffff00 ) | ( NewVideoLo );
                   2010:                        pVideoRaster = &STRam[addr & ~1];
                   2011:                        NewVideoLo = -1;
                   2012:                }
                   2013: 
                   2014:                /* On STE, if we wrote to the hwscroll register, we set the */
                   2015:                /* new value here, once the current line was processed */
                   2016:                if ( NewHWScrollCount >= 0 )
                   2017:                {
                   2018:                        HWScrollCount = NewHWScrollCount;
1.1.1.13  root     2019:                        HWScrollPrefetch = NewHWScrollPrefetch;
1.1.1.11  root     2020:                        NewHWScrollCount = -1;
1.1.1.13  root     2021:                        NewHWScrollPrefetch = -1;
                   2022:                }
                   2023: 
                   2024:                /* On STE, if we trigger the left border + 16 pixels trick, we set the */
                   2025:                /* new value here, once the current line was processed */
                   2026:                if ( NewSteBorderFlag >= 0 )
                   2027:                {
                   2028:                        if ( NewSteBorderFlag == 0 )
1.1.1.15! root     2029:                                bSteBorderFlag = false;
1.1.1.13  root     2030:                        else
1.1.1.15! root     2031:                                bSteBorderFlag = true;
1.1.1.13  root     2032:                        NewSteBorderFlag = -1;
1.1.1.11  root     2033:                }
                   2034: 
                   2035:                /* On STE, if we wrote to the linewidth register, we set the */
                   2036:                /* new value here, once the current line was processed */
                   2037:                if ( NewLineWidth >= 0 )
                   2038:                {
                   2039:                        LineWidth = NewLineWidth;
                   2040:                        NewLineWidth = -1;
                   2041:                }
                   2042:        }
                   2043: 
                   2044:        /* Each screen line copied to buffer is always same length */
                   2045:        pSTScreen += SCREENBYTES_LINE;
                   2046: }
                   2047: 
                   2048: 
                   2049: /*-----------------------------------------------------------------------*/
                   2050: /**
                   2051:  * Copy extended GEM resolution screen
                   2052:  */
1.1.1.9   root     2053: static void Video_CopyVDIScreen(void)
1.1       root     2054: {
1.1.1.11  root     2055:        /* Copy whole screen, don't care about being exact as for GEM only */
                   2056:        memcpy(pSTScreen, pVideoRaster, ((VDIWidth*VDIPlanes)/8)*VDIHeight);
1.1       root     2057: }
                   2058: 
1.1.1.2   root     2059: 
                   2060: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2061: /**
                   2062:  * Clear raster line table to store changes in palette/resolution on a line
                   2063:  * basic. Called once on VBL interrupt.
                   2064:  */
1.1       root     2065: void Video_SetScreenRasters(void)
                   2066: {
1.1.1.11  root     2067:        pHBLPaletteMasks = HBLPaletteMasks;
                   2068:        pHBLPalettes = HBLPalettes;
                   2069:        memset(pHBLPaletteMasks, 0, sizeof(Uint32)*NUM_VISIBLE_LINES);  /* Clear array */
1.1       root     2070: }
                   2071: 
1.1.1.2   root     2072: 
                   2073: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2074: /**
                   2075:  * Set pointers to HBLPalette tables to store correct colours/resolutions
                   2076:  */
1.1.1.9   root     2077: static void Video_SetHBLPaletteMaskPointers(void)
1.1       root     2078: {
1.1.1.15! root     2079:        int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.11  root     2080:        int Line;
                   2081: 
                   2082:        /* FIXME [NP] We should use Cycles_GetCounterOnWriteAccess, but it wouldn't     */
                   2083:        /* work when using multiple accesses instructions like move.l or movem  */
1.1.1.15! root     2084:        /* To correct this, we assume a delay of 8 cycles (should give a good approximation */
1.1.1.11  root     2085:        /* of a move.w or movem.l for example) */
                   2086:        //  FrameCycles = Cycles_GetCounterOnWriteAccess(CYCLES_COUNTER_VIDEO);
                   2087:        FrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO) + 8;
                   2088: 
                   2089:        /* Find 'line' into palette - screen starts 63 lines down, less 29 for top overscan */
1.1.1.15! root     2090:        Video_ConvertPosition ( FrameCycles , &HblCounterVideo , &LineCycles );
        !          2091:        Line = HblCounterVideo - nFirstVisibleHbl;
1.1.1.11  root     2092: 
                   2093:        /* FIXME [NP] if the color change occurs after the last visible pixel of a line */
                   2094:        /* we consider the palette should be modified on the next line. This is quite */
                   2095:        /* a hack, we should handle all color changes through spec512.c to have cycle */
                   2096:        /* accuracy all the time. */
1.1.1.15! root     2097:        if ( LineCycles >= LINE_END_CYCLE_NO_RIGHT )
        !          2098:                Line++;
1.1.1.11  root     2099: 
                   2100:        if (Line < 0)        /* Limit to top/bottom of possible visible screen */
                   2101:                Line = 0;
                   2102:        if (Line >= NUM_VISIBLE_LINES)
                   2103:                Line = NUM_VISIBLE_LINES-1;
                   2104: 
                   2105:        /* Store pointers */
                   2106:        pHBLPaletteMasks = &HBLPaletteMasks[Line];  /* Next mask entry */
                   2107:        pHBLPalettes = &HBLPalettes[16*Line];       /* Next colour raster list x16 colours */
1.1       root     2108: }
1.1.1.8   root     2109: 
                   2110: 
1.1.1.9   root     2111: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2112: /**
                   2113:  * Set video shifter timing variables according to screen refresh rate.
                   2114:  * Note: The following equation must be satisfied for correct timings:
                   2115:  *
                   2116:  *   nCyclesPerLine * nScanlinesPerFrame * nScreenRefreshRate = 8 MHz
                   2117:  */
1.1.1.10  root     2118: static void Video_ResetShifterTimings(void)
                   2119: {
1.1.1.11  root     2120:        Uint8 nSyncByte;
1.1.1.10  root     2121: 
1.1.1.11  root     2122:        nSyncByte = IoMem_ReadByte(0xff820a);
1.1.1.10  root     2123: 
1.1.1.11  root     2124:        if (bUseHighRes)
                   2125:        {
                   2126:                /* 71 Hz, monochrome */
                   2127:                nScreenRefreshRate = 71;
                   2128:                nScanlinesPerFrame = SCANLINES_PER_FRAME_71HZ;
                   2129:                nCyclesPerLine = CYCLES_PER_LINE_71HZ;
1.1.1.13  root     2130:                nStartHBL = VIDEO_START_HBL_71HZ;
1.1.1.11  root     2131:                nFirstVisibleHbl = FIRST_VISIBLE_HBL_71HZ;
1.1.1.13  root     2132:                nLastVisibleHbl = FIRST_VISIBLE_HBL_71HZ + VIDEO_HEIGHT_HBL_MONO;
1.1.1.11  root     2133:        }
                   2134:        else if (nSyncByte & 2)  /* Check if running in 50 Hz or in 60 Hz */
                   2135:        {
                   2136:                /* 50 Hz */
                   2137:                nScreenRefreshRate = 50;
                   2138:                nScanlinesPerFrame = SCANLINES_PER_FRAME_50HZ;
                   2139:                nCyclesPerLine = CYCLES_PER_LINE_50HZ;
1.1.1.13  root     2140:                nStartHBL = VIDEO_START_HBL_50HZ;
1.1.1.11  root     2141:                nFirstVisibleHbl = FIRST_VISIBLE_HBL_50HZ;
1.1.1.13  root     2142:                nLastVisibleHbl = FIRST_VISIBLE_HBL_50HZ + NUM_VISIBLE_LINES;
1.1.1.11  root     2143:        }
                   2144:        else
                   2145:        {
                   2146:                /* 60 Hz */
                   2147:                nScreenRefreshRate = 60;
                   2148:                nScanlinesPerFrame = SCANLINES_PER_FRAME_60HZ;
                   2149:                nCyclesPerLine = CYCLES_PER_LINE_60HZ;
1.1.1.13  root     2150:                nStartHBL = VIDEO_START_HBL_60HZ;
1.1.1.11  root     2151:                nFirstVisibleHbl = FIRST_VISIBLE_HBL_60HZ;
1.1.1.13  root     2152:                nLastVisibleHbl = FIRST_VISIBLE_HBL_60HZ + NUM_VISIBLE_LINES;
1.1.1.11  root     2153:        }
                   2154: 
                   2155:        if (bUseHighRes)
                   2156:        {
1.1.1.13  root     2157:                nEndHBL = nStartHBL + VIDEO_HEIGHT_HBL_MONO;
1.1.1.11  root     2158:        }
                   2159:        else
                   2160:        {
1.1.1.13  root     2161:                nEndHBL = nStartHBL + VIDEO_HEIGHT_HBL_COLOR;
1.1.1.11  root     2162:        }
                   2163: 
                   2164:        /* Reset freq changes position for the next VBL to come */
1.1.1.13  root     2165:        LastCycleScroll8264 = -1;
                   2166:        LastCycleScroll8265 = -1;
1.1.1.15! root     2167: 
        !          2168:        TimerBEventCountCycleStart = -1;                /* reset timer B activation cycle for this VBL */
        !          2169: 
        !          2170:        LastCycleHblException = -1;
1.1.1.11  root     2171: }
1.1.1.10  root     2172: 
                   2173: 
1.1.1.11  root     2174: /*-----------------------------------------------------------------------*/
                   2175: /**
1.1.1.15! root     2176:  * Clear the array indicating the state of each video line.
1.1.1.11  root     2177:  */
1.1.1.15! root     2178: static void Video_InitShifterLines ( void )
1.1.1.11  root     2179: {
1.1.1.15! root     2180:        int     i;
        !          2181: 
        !          2182:        for ( i=0 ; i<MAX_SCANLINES_PER_FRAME ; i++ )
        !          2183:        {
        !          2184:                ShifterFrame.ShifterLines[i].BorderMask = 0;
        !          2185:                ShifterFrame.ShifterLines[i].DisplayPixelShift = 0;
        !          2186:                ShifterFrame.ShifterLines[i].DisplayStartCycle = -1;
        !          2187:        }
        !          2188: 
        !          2189:        ShifterFrame.ShifterLines[0].StartCycle = 0;                    /* 1st HBL starts at cycle 0 */
1.1.1.10  root     2190: }
                   2191: 
                   2192: 
                   2193: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2194: /**
                   2195:  * Called on VBL, set registers ready for frame
                   2196:  */
1.1.1.9   root     2197: static void Video_ClearOnVBL(void)
                   2198: {
1.1.1.11  root     2199:        /* New screen, so first HBL */
                   2200:        nHBL = 0;
                   2201:        OverscanMode = OVERSCANMODE_NONE;
                   2202: 
                   2203:        Video_ResetShifterTimings();
                   2204: 
                   2205:        /* Get screen address pointer, aligned to 256 bytes on ST (ie ignore lowest byte) */
                   2206:        VideoBase = (Uint32)IoMem_ReadByte(0xff8201)<<16 | (Uint32)IoMem_ReadByte(0xff8203)<<8;
                   2207:        if (ConfigureParams.System.nMachineType != MACHINE_ST)
                   2208:        {
                   2209:                /* on STe 2 aligned, on Falcon 4 aligned, on TT 8 aligned. We do STe. */
                   2210:                VideoBase |= IoMem_ReadByte(0xff820d) & ~1;
                   2211:        }
                   2212:        pVideoRaster = &STRam[VideoBase];
                   2213:        pSTScreen = pFrameBuffer->pSTScreen;
                   2214: 
                   2215:        Video_SetScreenRasters();
1.1.1.15! root     2216:        Video_InitShifterLines();
1.1.1.11  root     2217:        Spec512_StartVBL();
1.1.1.15! root     2218:        Video_StartHBL();                                       /* Init ShifterFrame.ShifterLines[0] */
1.1.1.11  root     2219: }
                   2220: 
                   2221: 
                   2222: /*-----------------------------------------------------------------------*/
                   2223: /**
                   2224:  * Get width, height and bpp according to TT-Resolution
                   2225:  */
                   2226: void Video_GetTTRes(int *width, int *height, int *bpp)
                   2227: {
                   2228:        switch (TTRes)
                   2229:        {
                   2230:         case ST_LOW_RES:   *width = 320;  *height = 200; *bpp = 4; break;
                   2231:         case ST_MEDIUM_RES:*width = 640;  *height = 200; *bpp = 2; break;
                   2232:         case ST_HIGH_RES:  *width = 640;  *height = 400; *bpp = 1; break;
                   2233:         case TT_LOW_RES:   *width = 320;  *height = 480; *bpp = 8; break;
                   2234:         case TT_MEDIUM_RES:*width = 640;  *height = 480; *bpp = 4; break;
                   2235:         case TT_HIGH_RES:  *width = 1280; *height = 960; *bpp = 1; break;
                   2236:         default:
                   2237:                fprintf(stderr, "TT res error!\n");
                   2238:                *width = 320; *height = 200; *bpp = 4;
                   2239:                break;
                   2240:        }
                   2241: }
                   2242: 
                   2243: 
                   2244: /*-----------------------------------------------------------------------*/
                   2245: /**
                   2246:  * Convert TT palette to SDL palette
                   2247:  */
                   2248: static void Video_UpdateTTPalette(int bpp)
                   2249: {
                   2250:        Uint32 ttpalette, src, dst;
                   2251:        Uint8 r,g,b, lowbyte, highbyte;
                   2252:        Uint16 stcolor, ttcolor;
                   2253:        int i, offset, colors;
                   2254: 
                   2255:        ttpalette = 0xff8400;
                   2256: 
                   2257:        if (!bTTColorsSTSync)
                   2258:        {
                   2259:                /* sync TT ST-palette to TT-palette */
                   2260:                src = 0xff8240; /* ST-palette */
                   2261:                offset = (IoMem_ReadWord(0xff8262) & 0x0f);
1.1.1.13  root     2262:                /*fprintf(stderr, "offset: %d\n", offset);*/
1.1.1.11  root     2263:                dst = ttpalette + offset * 16*SIZE_WORD;
                   2264: 
                   2265:                for (i = 0; i < 16; i++)
                   2266:                {
                   2267:                        stcolor = IoMem_ReadWord(src);
                   2268:                        ttcolor = ((stcolor&0x700) << 1) | ((stcolor&0x70) << 1) | ((stcolor&0x7) << 1);
                   2269:                        IoMem_WriteWord(dst, ttcolor);
                   2270:                        src += SIZE_WORD;
                   2271:                        dst += SIZE_WORD;
                   2272:                }
1.1.1.15! root     2273:                bTTColorsSTSync = true;
1.1.1.11  root     2274:        }
                   2275: 
                   2276:        colors = 1 << bpp;
                   2277:        if (bpp == 1)
                   2278:        {
                   2279:                /* Monochrome mode... palette is hardwired (?) */
                   2280:                HostScreen_setPaletteColor(0, 255, 255, 255);
                   2281:                HostScreen_setPaletteColor(1, 0, 0, 0);
                   2282:        }
                   2283:        else
                   2284:        {
                   2285:                for (i = 0; i < colors; i++)
                   2286:                {
                   2287:                        lowbyte = IoMem_ReadByte(ttpalette++);
                   2288:                        highbyte = IoMem_ReadByte(ttpalette++);
                   2289:                        r = (lowbyte  & 0x0f) << 4;
                   2290:                        g = (highbyte & 0xf0);
                   2291:                        b = (highbyte & 0x0f) << 4;
                   2292:                        //printf("%d: (%d,%d,%d)\n", i,r,g,b);
                   2293:                        HostScreen_setPaletteColor(i, r,g,b);
                   2294:                }
                   2295:        }
                   2296: 
                   2297:        HostScreen_updatePalette(colors);
1.1.1.15! root     2298:        bTTColorsSync = true;
1.1.1.11  root     2299: }
                   2300: 
                   2301: 
                   2302: /*-----------------------------------------------------------------------*/
                   2303: /**
1.1.1.13  root     2304:  * Update TT palette and blit TT screen using VIDEL code.
                   2305:  * @return  true if the screen contents changed
1.1.1.11  root     2306:  */
1.1.1.13  root     2307: static bool Video_RenderTTScreen(void)
1.1.1.11  root     2308: {
                   2309:        static int nPrevTTRes = -1;
                   2310:        int width, height, bpp;
                   2311: 
                   2312:        Video_GetTTRes(&width, &height, &bpp);
                   2313:        if (TTRes != nPrevTTRes)
                   2314:        {
                   2315:                HostScreen_setWindowSize(width, height, 8);
                   2316:                nPrevTTRes = TTRes;
                   2317:                if (bpp == 1)   /* Assert that mono palette will be used in mono mode */
1.1.1.15! root     2318:                        bTTColorsSync = false;
1.1.1.11  root     2319:        }
                   2320: 
                   2321:        /* colors need synching? */
                   2322:        if (!(bTTColorsSync && bTTColorsSTSync))
                   2323:        {
                   2324:                Video_UpdateTTPalette(bpp);
                   2325:        }
                   2326: 
                   2327:        /* Yes, we are abusing the Videl routines for rendering the TT modes! */
                   2328:        if (!HostScreen_renderBegin())
1.1.1.13  root     2329:                return false;
1.1.1.11  root     2330:        if (ConfigureParams.Screen.bZoomLowRes)
                   2331:                VIDEL_ConvertScreenZoom(width, height, bpp, width * bpp / 16);
                   2332:        else
                   2333:                VIDEL_ConvertScreenNoZoom(width, height, bpp, width * bpp / 16);
                   2334:        HostScreen_renderEnd();
1.1.1.15! root     2335:        HostScreen_update1(false);
1.1.1.13  root     2336: 
                   2337:        return true;
1.1.1.11  root     2338: }
                   2339: 
                   2340: 
                   2341: /*-----------------------------------------------------------------------*/
                   2342: /**
                   2343:  * Draw screen (either with ST/STE shifter drawing functions or with
                   2344:  * Videl drawing functions)
                   2345:  */
                   2346: static void Video_DrawScreen(void)
                   2347: {
1.1.1.13  root     2348:        bool bScreenChanged;
                   2349: 
1.1.1.11  root     2350:        /* Skip frame if need to */
1.1.1.13  root     2351:        if (nVBLs % (nFrameSkips+1))
1.1.1.11  root     2352:                return;
                   2353: 
                   2354:        /* Use extended VDI resolution?
                   2355:         * If so, just copy whole screen on VBL rather than per HBL */
                   2356:        if (bUseVDIRes)
                   2357:                Video_CopyVDIScreen();
                   2358: 
                   2359:        /* Now draw the screen! */
                   2360:        if (ConfigureParams.System.nMachineType == MACHINE_FALCON && !bUseVDIRes)
                   2361:        {
1.1.1.13  root     2362:                bScreenChanged = VIDEL_renderScreen();
1.1.1.11  root     2363:        }
                   2364:        else if (ConfigureParams.System.nMachineType == MACHINE_TT && !bUseVDIRes)
                   2365:        {
1.1.1.13  root     2366:                bScreenChanged = Video_RenderTTScreen();
1.1.1.11  root     2367:        }
                   2368:        else
1.1.1.13  root     2369:        {
                   2370:                /* Before drawing the screen, ensure all unused lines are cleared to color 0 */
                   2371:                /* (this can happen in 60 Hz when hatari is displaying the screen's border) */
                   2372:                /* pSTScreen was set during Video_CopyScreenLineColor */
1.1.1.14  root     2373:                if (!bUseVDIRes && nHBL < nLastVisibleHbl)
1.1.1.13  root     2374:                        memset(pSTScreen, 0, SCREENBYTES_LINE * ( nLastVisibleHbl - nHBL ) );
                   2375: 
                   2376:                bScreenChanged = Screen_Draw();
                   2377:        }
                   2378: 
                   2379:        /* Grab any animation */
                   2380:        if (bRecordingAnimation)
                   2381:                ScreenSnapShot_RecordFrame(bScreenChanged);
1.1.1.11  root     2382: }
                   2383: 
                   2384: 
                   2385: /*-----------------------------------------------------------------------*/
                   2386: /**
1.1.1.15! root     2387:  * Start HBL, Timer B and VBL interrupts.
        !          2388:  */
        !          2389: 
        !          2390: 
        !          2391: /**
        !          2392:  * Start HBL or Timer B interrupt at position Pos. If position Pos was
        !          2393:  * already reached, then the interrupt is set on the next line.
        !          2394:  */
        !          2395: 
        !          2396: static void Video_AddInterrupt ( int Pos , interrupt_id Handler )
        !          2397: {
        !          2398:        int FrameCycles , HblCounterVideo , LineCycles;
        !          2399: 
        !          2400:        if ( nHBL >= nScanlinesPerFrame )
        !          2401:          return;                               /* don't set a new hbl/timer B if we're on the last line, as the vbl will happen first */
        !          2402:        
        !          2403:        Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !          2404: 
        !          2405:        if ( LineCycles < Pos )                 /* changed before reaching the new Pos on the current line */
        !          2406:                Int_AddRelativeInterrupt ( Pos - LineCycles , INT_CPU_CYCLE, Handler );
        !          2407:        else                                    /* Pos will be applied on next line */
        !          2408:                Int_AddRelativeInterrupt ( Pos - LineCycles + nCyclesPerLine , INT_CPU_CYCLE, Handler );
        !          2409: }
        !          2410: 
        !          2411: 
        !          2412: static void Video_AddInterruptHBL ( int Pos )
        !          2413: {
        !          2414: //fprintf ( stderr , "add hbl %d\n" , Pos );
        !          2415:        if ( !bUseVDIRes )
        !          2416:                Video_AddInterrupt ( Pos , INTERRUPT_VIDEO_HBL );
        !          2417: }
        !          2418: 
        !          2419: 
        !          2420: void Video_AddInterruptTimerB ( int Pos )
        !          2421: {
        !          2422:        if ( !bUseVDIRes )
        !          2423:                Video_AddInterrupt ( Pos , INTERRUPT_VIDEO_ENDLINE );
        !          2424: }
        !          2425: 
        !          2426: 
        !          2427: /**
        !          2428:  * Add some video interrupts to handle the first HBL and the first Timer B
        !          2429:  * in a new VBL. Also add an interrupt to trigger the next VBL.
        !          2430:  * This function is called from the VBL, so we use PendingCycleOver to take into account
        !          2431:  * the possible delay occurring when the VBL was executed.
1.1.1.11  root     2432:  */
1.1.1.15! root     2433: void Video_StartInterrupts ( int PendingCyclesOver )
1.1.1.11  root     2434: {
1.1.1.15! root     2435:        /* HBL/Timer B are not emulated in VDI mode */
1.1.1.14  root     2436:        if (!bUseVDIRes)
                   2437:        {
1.1.1.15! root     2438:                /* Set Timer B interrupt for line 0 */
        !          2439:                Video_AddInterruptTimerB ( Video_TimerB_GetPos ( 0 ) );
        !          2440: 
        !          2441:                /* Set HBL interrupt */
        !          2442:                Video_AddInterruptHBL ( Video_HBL_GetPos() );
1.1.1.14  root     2443:        }
1.1.1.15! root     2444: 
        !          2445:        /* TODO replace CYCLES_PER_FRAME */
        !          2446:        Int_AddRelativeInterrupt ( CYCLES_PER_FRAME - PendingCyclesOver , INT_CPU_CYCLE , INTERRUPT_VIDEO_VBL );
1.1.1.11  root     2447: }
                   2448: 
                   2449: 
                   2450: /*-----------------------------------------------------------------------*/
                   2451: /**
1.1.1.15! root     2452:  * VBL interrupt : set new interrupts, draw screen, generate sound,
        !          2453:  * reset counters, ...
1.1.1.11  root     2454:  */
1.1.1.15! root     2455: void Video_InterruptHandler_VBL ( void )
1.1.1.11  root     2456: {
                   2457:        int PendingCyclesOver;
1.1.1.9   root     2458: 
1.1.1.11  root     2459:        /* Store cycles we went over for this frame(this is our inital count) */
                   2460:        PendingCyclesOver = -INT_CONVERT_FROM_INTERNAL ( PendingInterruptCount , INT_CPU_CYCLE );    /* +ve */
1.1.1.10  root     2461: 
1.1.1.11  root     2462:        /* Remove this interrupt from list and re-order */
                   2463:        Int_AcknowledgeInterrupt();
1.1.1.9   root     2464: 
1.1.1.14  root     2465:        /* Increment the vbl jitter index */
                   2466:        VblJitterIndex++;
                   2467:        if ( VblJitterIndex == VBL_JITTER_MAX_POS )
                   2468:                VblJitterIndex = 0;
                   2469:        
1.1.1.11  root     2470:        /* Set frame cycles, used for Video Address */
1.1.1.13  root     2471:        Cycles_SetCounter(CYCLES_COUNTER_VIDEO, PendingCyclesOver + VblVideoCycleOffset);
1.1.1.9   root     2472: 
1.1.1.11  root     2473:        /* Clear any key presses which are due to be de-bounced (held for one ST frame) */
                   2474:        Keymap_DebounceAllKeys();
1.1.1.9   root     2475: 
1.1.1.11  root     2476:        Video_DrawScreen();
1.1.1.9   root     2477: 
1.1.1.11  root     2478:        /* Check printer status */
                   2479:        Printer_CheckIdleStatus();
                   2480: 
                   2481:        /* Update counter for number of screen refreshes per second */
                   2482:        nVBLs++;
                   2483:        /* Set video registers for frame */
                   2484:        Video_ClearOnVBL();
1.1.1.15! root     2485: 
        !          2486:        /* Since we don't execute HBL functions in VDI mode, we've got to
        !          2487:         * initialize the first HBL palette here when VDI mode is enabled. */
        !          2488:        if (bUseVDIRes)
        !          2489:                Video_StoreFirstLinePalette();
        !          2490: 
        !          2491:        /* Start VBL, HBL and Timer B interrupts (this must be done after resetting
        !          2492:          * video cycle counter setting default freq values in Video_ClearOnVBL) */
        !          2493:        Video_StartInterrupts(PendingCyclesOver);
        !          2494: 
        !          2495:        /* Act on shortcut keys */
        !          2496:        ShortCut_ActKey();
        !          2497: 
1.1.1.11  root     2498:        /* Store off PSG registers for YM file, is enabled */
                   2499:        YMFormat_UpdateRecording();
                   2500:        /* Generate 1/50th second of sound sample data, to be played by sound thread */
                   2501:        Sound_Update_VBL();
                   2502: 
1.1.1.15! root     2503:        LOG_TRACE(TRACE_VIDEO_VBL , "VBL %d video_cyc=%d pending_cyc=%d jitter=%d\n" ,
1.1.1.14  root     2504:                       nVBLs , Cycles_GetCounter(CYCLES_COUNTER_VIDEO) , PendingCyclesOver , VblJitterArray[ VblJitterIndex ] );
1.1.1.11  root     2505: 
1.1.1.13  root     2506:        M68000_Exception ( EXCEPTION_VBLANK , M68000_EXCEPTION_SRC_INT_VIDEO ); /* Vertical blank interrupt, level 4! */
1.1.1.11  root     2507: 
                   2508:        Main_WaitOnVbl();
1.1.1.9   root     2509: }
                   2510: 
                   2511: 
                   2512: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2513: /**
1.1.1.13  root     2514:  * Write to video address base high, med and low register (0xff8201/03/0d).
                   2515:  * On STE, when a program writes to high or med registers, base low register
                   2516:  * is reset to zero.
1.1.1.11  root     2517:  */
1.1.1.9   root     2518: void Video_ScreenBaseSTE_WriteByte(void)
                   2519: {
1.1.1.13  root     2520:        if ( ( IoAccessCurrentAddress == 0xff8201 ) || ( IoAccessCurrentAddress == 0xff8203 ) )
                   2521:                IoMem[0xff820d] = 0;          /* Reset screen base low register */
1.1.1.8   root     2522: 
1.1.1.15! root     2523:        if (LOG_TRACE_LEVEL(TRACE_VIDEO_STE))
1.1.1.11  root     2524:        {
1.1.1.15! root     2525:                int FrameCycles, HblCounterVideo, LineCycles;
        !          2526: 
        !          2527:                Video_GetPosition_OnWriteAccess ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !          2528:                
        !          2529:                LOG_TRACE_PRINT ( "write ste video base=0x%x video_cyc_w=%d line_cyc_w=%d @ nHBL=%d/video_hbl_w=%d pc=%x instr_cyc=%d\n" ,
1.1.1.13  root     2530:                        (IoMem[0xff8201]<<16)+(IoMem[0xff8203]<<8)+IoMem[0xff820d] ,
1.1.1.15! root     2531:                        FrameCycles, LineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
1.1.1.11  root     2532:        }
1.1.1.8   root     2533: }
                   2534: 
                   2535: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2536: /**
                   2537:  * Read video address counter and update ff8205/07/09
                   2538:  */
                   2539: void Video_ScreenCounter_ReadByte(void)
1.1.1.8   root     2540: {
1.1.1.11  root     2541:        Uint32 addr;
1.1.1.8   root     2542: 
1.1.1.11  root     2543:        addr = Video_CalculateAddress();                /* get current video address */
                   2544:        IoMem[0xff8205] = ( addr >> 16 ) & 0xff;
                   2545:        IoMem[0xff8207] = ( addr >> 8 ) & 0xff;
                   2546:        IoMem[0xff8209] = addr & 0xff;
1.1.1.8   root     2547: }
                   2548: 
1.1.1.9   root     2549: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2550: /**
                   2551:  * Write to video address counter (0xff8205, 0xff8207 and 0xff8209).
                   2552:  * Called on STE only and like with base address, you cannot set lowest bit.
                   2553:  * If display has not started yet for this line, we can change pVideoRaster now.
                   2554:  * Else we store the new value of the Hi/Med/Lo address to change it at the end
                   2555:  * of the current line when Video_CopyScreenLineColor is called.
                   2556:  * We must change only the byte that was modified and keep the two others ones.
                   2557:  */
1.1.1.9   root     2558: void Video_ScreenCounter_WriteByte(void)
                   2559: {
1.1.1.11  root     2560:        Uint8 AddrByte;
                   2561:        Uint32 addr;
1.1.1.15! root     2562:        int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.13  root     2563:        int Delayed;
1.1.1.11  root     2564: 
1.1.1.15! root     2565:        Video_GetPosition_OnWriteAccess ( &FrameCycles , &HblCounterVideo , &LineCycles );
1.1.1.11  root     2566: 
                   2567:        AddrByte = IoMem[ IoAccessCurrentAddress ];
                   2568: 
                   2569:        /* If display has not started, we can still modify pVideoRaster */
                   2570:        /* We must also check the write does not overlap the end of the line */
1.1.1.15! root     2571:        if ( ( ( LineCycles <= LINE_START_CYCLE_50 ) && ( nHBL == HblCounterVideo ) )
1.1.1.11  root     2572:                || ( nHBL < nStartHBL ) || ( nHBL >= nEndHBL ) )
                   2573:        {
                   2574:                addr = Video_CalculateAddress();                /* get current video address */
                   2575:                if ( IoAccessCurrentAddress == 0xff8205 )
                   2576:                        addr = ( addr & 0x00ffff ) | ( AddrByte << 16 );
                   2577:                else if ( IoAccessCurrentAddress == 0xff8207 )
                   2578:                        addr = ( addr & 0xff00ff ) | ( AddrByte << 8 );
                   2579:                else if ( IoAccessCurrentAddress == 0xff8209 )
                   2580:                        addr = ( addr & 0xffff00 ) | ( AddrByte );
                   2581: 
                   2582:                pVideoRaster = &STRam[addr & ~1];               /* set new video address */
1.1.1.15! root     2583:                Delayed = false;
1.1.1.11  root     2584:        }
                   2585: 
                   2586:        /* Can't change pVideoRaster now, store the modified byte for Video_CopyScreenLineColor */
                   2587:        else
                   2588:        {
                   2589:                if ( IoAccessCurrentAddress == 0xff8205 )
                   2590:                        NewVideoHi = AddrByte;
                   2591:                else if ( IoAccessCurrentAddress == 0xff8207 )
                   2592:                        NewVideoMed = AddrByte;
                   2593:                else if ( IoAccessCurrentAddress == 0xff8209 )
                   2594:                        NewVideoLo = AddrByte;
1.1.1.15! root     2595:                Delayed = true;
1.1.1.11  root     2596:        }
                   2597: 
1.1.1.15! root     2598:        LOG_TRACE(TRACE_VIDEO_STE , "write ste video %x val=0x%x delayed=%s video_cyc_w=%d line_cyc_w=%d @ nHBL=%d/video_hbl_w=%d pc=%x instr_cyc=%d\n" ,
1.1.1.13  root     2599:                                IoAccessCurrentAddress, AddrByte, Delayed ? "yes" : "no" ,
1.1.1.15! root     2600:                                FrameCycles, LineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
1.1.1.9   root     2601: }
1.1.1.8   root     2602: 
                   2603: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2604: /**
                   2605:  * Read video sync register (0xff820a)
                   2606:  */
1.1.1.8   root     2607: void Video_Sync_ReadByte(void)
                   2608: {
1.1.1.14  root     2609:        if ( (ConfigureParams.System.nMachineType == MACHINE_ST) || (ConfigureParams.System.nMachineType == MACHINE_STE) )
                   2610:                IoMem[0xff820a] |= 0xfc;                /* set unused bits 2-7 to 1 */
1.1.1.8   root     2611: }
                   2612: 
                   2613: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2614: /**
                   2615:  * Read video base address low byte (0xff820d). A plain ST can only store
                   2616:  * screen addresses rounded to 256 bytes (i.e. no lower byte).
                   2617:  */
1.1.1.8   root     2618: void Video_BaseLow_ReadByte(void)
                   2619: {
1.1.1.11  root     2620:        if (ConfigureParams.System.nMachineType == MACHINE_ST)
                   2621:                IoMem[0xff820d] = 0;        /* On ST this is always 0 */
1.1.1.9   root     2622: 
1.1.1.11  root     2623:        /* Note that you should not do anything here for STe because
                   2624:         * VideoBase address is set in an interrupt and would be wrong
                   2625:         * here.   It's fine like this.
                   2626:         */
1.1.1.8   root     2627: }
                   2628: 
                   2629: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2630: /**
                   2631:  * Read video line width register (0xff820f)
                   2632:  */
1.1.1.8   root     2633: void Video_LineWidth_ReadByte(void)
                   2634: {
1.1.1.11  root     2635:        if (ConfigureParams.System.nMachineType == MACHINE_ST)
                   2636:                IoMem[0xff820f] = 0;        /* On ST this is always 0 */
                   2637:        else
                   2638:                IoMem[0xff820f] = LineWidth;
1.1.1.8   root     2639: }
                   2640: 
                   2641: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2642: /**
                   2643:  * Read video shifter mode register (0xff8260)
                   2644:  */
1.1.1.8   root     2645: void Video_ShifterMode_ReadByte(void)
                   2646: {
1.1.1.11  root     2647:        if (bUseHighRes)
1.1.1.14  root     2648:                IoMem[0xff8260] = 2;                    /* If mono monitor, force to high resolution */
1.1.1.11  root     2649:        else
1.1.1.14  root     2650:                IoMem[0xff8260] = VideoShifterByte;     /* Read shifter register, set unused bits to 1 */
                   2651: 
                   2652:        if ( (ConfigureParams.System.nMachineType == MACHINE_ST) || (ConfigureParams.System.nMachineType == MACHINE_STE) )
                   2653:                IoMem[0xff8260] |= 0xfc;                /* set unused bits 2-7 to 1 */
1.1.1.8   root     2654: }
                   2655: 
1.1.1.10  root     2656: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2657: /**
                   2658:  * Read horizontal scroll register (0xff8265)
                   2659:  */
1.1.1.10  root     2660: void Video_HorScroll_Read(void)
                   2661: {
1.1.1.11  root     2662:        IoMem[0xff8265] = HWScrollCount;
1.1.1.10  root     2663: }
1.1.1.8   root     2664: 
                   2665: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2666: /**
                   2667:  * Write video line width register (0xff820f) - STE only.
                   2668:  * Content of LineWidth is added to the shifter counter when display is
                   2669:  * turned off (start of the right border, usually at cycle 376)
                   2670:  */
1.1.1.10  root     2671: void Video_LineWidth_WriteByte(void)
                   2672: {
1.1.1.11  root     2673:        Uint8 NewWidth;
1.1.1.15! root     2674:        int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.13  root     2675:        int Delayed;
1.1.1.11  root     2676: 
1.1.1.15! root     2677:        Video_GetPosition_OnWriteAccess ( &FrameCycles , &HblCounterVideo , &LineCycles );
1.1.1.11  root     2678: 
                   2679:        NewWidth = IoMem_ReadByte(0xff820f);
                   2680: 
                   2681:        /* We must also check the write does not overlap the end of the line */
1.1.1.15! root     2682:        if ( ( ( nHBL == HblCounterVideo ) && ( LineCycles <= ShifterFrame.ShifterLines[ HblCounterVideo ].DisplayEndCycle ) )
1.1.1.11  root     2683:                || ( nHBL < nStartHBL ) || ( nHBL >= nEndHBL ) )
1.1.1.13  root     2684:        {
1.1.1.11  root     2685:                LineWidth = NewWidth;           /* display is on, we can still change */
1.1.1.13  root     2686:                NewLineWidth = -1;              /* cancel 'pending' change */
1.1.1.15! root     2687:                Delayed = false;
1.1.1.13  root     2688:        }
1.1.1.11  root     2689:        else
1.1.1.13  root     2690:        {
1.1.1.11  root     2691:                NewLineWidth = NewWidth;        /* display is off, can't change LineWidth once in right border */
1.1.1.15! root     2692:                Delayed = true;
1.1.1.13  root     2693:        }
1.1.1.11  root     2694: 
1.1.1.15! root     2695:        LOG_TRACE(TRACE_VIDEO_STE , "write ste linewidth=0x%x delayed=%s video_cyc_w=%d line_cyc_w=%d @ nHBL=%d/video_hbl_w=%d pc=%x instr_cyc=%d\n",
1.1.1.13  root     2696:                                        NewWidth, Delayed ? "yes" : "no" ,
1.1.1.15! root     2697:                                        FrameCycles, LineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
1.1.1.10  root     2698: }
                   2699: 
                   2700: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2701: /**
                   2702:  * Write to video shifter palette registers (0xff8240-0xff825e)
1.1.1.14  root     2703:  *
                   2704:  * Note that there's a special "strange" case when writing only to the upper byte
                   2705:  * of the color reg (instead of writing 16 bits at once with .W/.L).
                   2706:  * In that case, the byte written to address x is automatically written
                   2707:  * to address x+1 too (but we shouldn't copy x in x+1 after masking x ; we apply the mask at the end)
                   2708:  * So :        move.w #0,$ff8240       -> color 0 is now $000
                   2709:  *     move.b #7,$ff8240       -> color 0 is now $707 !
                   2710:  *     move.b #$55,$ff8241     -> color 0 is now $755 ($ff8240 remains unchanged)
                   2711:  *     move.b #$71,$ff8240     -> color 0 is now $171 (bytes are first copied, then masked)
1.1.1.11  root     2712:  */
1.1.1.8   root     2713: static void Video_ColorReg_WriteWord(Uint32 addr)
                   2714: {
1.1.1.15! root     2715:        if (!bUseHighRes && !bUseVDIRes)               /* Don't store if hi-res or VDI resolution */
1.1.1.11  root     2716:        {
                   2717:                int idx;
                   2718:                Uint16 col;
                   2719:                Video_SetHBLPaletteMaskPointers();     /* Set 'pHBLPalettes' etc.. according cycles into frame */
                   2720:                col = IoMem_ReadWord(addr);
1.1.1.14  root     2721: 
                   2722:                /* Handle special case when writing only to the upper byte of the color reg */
                   2723:                if ( ( nIoMemAccessSize == SIZE_BYTE ) && ( ( IoAccessCurrentAddress & 1 ) == 0 ) )
                   2724:                        col = ( IoMem_ReadByte(addr) << 8 ) + IoMem_ReadByte(addr);             /* copy upper byte into lower byte */
                   2725: 
1.1.1.11  root     2726:                if (ConfigureParams.System.nMachineType == MACHINE_ST)
                   2727:                        col &= 0x777;                      /* Mask off to ST 512 palette */
                   2728:                else
                   2729:                        col &= 0xfff;                      /* Mask off to STe 4096 palette */
                   2730:                IoMem_WriteWord(addr, col);            /* (some games write 0xFFFF and read back to see if STe) */
                   2731:                Spec512_StoreCyclePalette(col, addr);  /* Store colour into CyclePalettes[] */
                   2732:                idx = (addr-0xff8240)/2;               /* words */
                   2733:                pHBLPalettes[idx] = col;               /* Set colour x */
                   2734:                *pHBLPaletteMasks |= 1 << idx;         /* And mask */
                   2735: 
1.1.1.15! root     2736:                if (LOG_TRACE_LEVEL(TRACE_VIDEO_COLOR))
1.1.1.11  root     2737:                {
1.1.1.15! root     2738:                        int FrameCycles, HblCounterVideo, LineCycles;
        !          2739: 
        !          2740:                        Video_GetPosition_OnWriteAccess ( &FrameCycles , &HblCounterVideo , &LineCycles );
        !          2741: 
        !          2742:                        LOG_TRACE_PRINT ( "write col addr=%x col=%x video_cyc_w=%d line_cyc_w=%d @ nHBL=%d/video_hbl_w=%d pc=%x instr_cyc=%d\n" ,
        !          2743:                                addr, col,
        !          2744:                                FrameCycles, LineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
1.1.1.11  root     2745:                }
                   2746: 
                   2747:        }
1.1.1.8   root     2748: }
                   2749: 
                   2750: void Video_Color0_WriteWord(void)
                   2751: {
1.1.1.11  root     2752:        Video_ColorReg_WriteWord(0xff8240);
1.1.1.8   root     2753: }
                   2754: 
                   2755: void Video_Color1_WriteWord(void)
                   2756: {
1.1.1.11  root     2757:        Video_ColorReg_WriteWord(0xff8242);
1.1.1.8   root     2758: }
                   2759: 
                   2760: void Video_Color2_WriteWord(void)
                   2761: {
1.1.1.11  root     2762:        Video_ColorReg_WriteWord(0xff8244);
1.1.1.8   root     2763: }
                   2764: 
                   2765: void Video_Color3_WriteWord(void)
                   2766: {
1.1.1.11  root     2767:        Video_ColorReg_WriteWord(0xff8246);
1.1.1.8   root     2768: }
                   2769: 
                   2770: void Video_Color4_WriteWord(void)
                   2771: {
1.1.1.11  root     2772:        Video_ColorReg_WriteWord(0xff8248);
1.1.1.8   root     2773: }
                   2774: 
                   2775: void Video_Color5_WriteWord(void)
                   2776: {
1.1.1.11  root     2777:        Video_ColorReg_WriteWord(0xff824a);
1.1.1.8   root     2778: }
                   2779: 
                   2780: void Video_Color6_WriteWord(void)
                   2781: {
1.1.1.11  root     2782:        Video_ColorReg_WriteWord(0xff824c);
1.1.1.8   root     2783: }
                   2784: 
                   2785: void Video_Color7_WriteWord(void)
                   2786: {
1.1.1.11  root     2787:        Video_ColorReg_WriteWord(0xff824e);
1.1.1.8   root     2788: }
                   2789: 
                   2790: void Video_Color8_WriteWord(void)
                   2791: {
1.1.1.11  root     2792:        Video_ColorReg_WriteWord(0xff8250);
1.1.1.8   root     2793: }
                   2794: 
                   2795: void Video_Color9_WriteWord(void)
                   2796: {
1.1.1.11  root     2797:        Video_ColorReg_WriteWord(0xff8252);
1.1.1.8   root     2798: }
                   2799: 
                   2800: void Video_Color10_WriteWord(void)
                   2801: {
1.1.1.11  root     2802:        Video_ColorReg_WriteWord(0xff8254);
1.1.1.8   root     2803: }
                   2804: 
                   2805: void Video_Color11_WriteWord(void)
                   2806: {
1.1.1.11  root     2807:        Video_ColorReg_WriteWord(0xff8256);
1.1.1.8   root     2808: }
                   2809: 
                   2810: void Video_Color12_WriteWord(void)
                   2811: {
1.1.1.11  root     2812:        Video_ColorReg_WriteWord(0xff8258);
1.1.1.8   root     2813: }
                   2814: 
                   2815: void Video_Color13_WriteWord(void)
                   2816: {
1.1.1.11  root     2817:        Video_ColorReg_WriteWord(0xff825a);
1.1.1.8   root     2818: }
                   2819: 
                   2820: void Video_Color14_WriteWord(void)
                   2821: {
1.1.1.11  root     2822:        Video_ColorReg_WriteWord(0xff825c);
1.1.1.8   root     2823: }
                   2824: 
                   2825: void Video_Color15_WriteWord(void)
                   2826: {
1.1.1.11  root     2827:        Video_ColorReg_WriteWord(0xff825e);
1.1.1.8   root     2828: }
                   2829: 
                   2830: 
                   2831: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2832: /**
                   2833:  * Write video shifter mode register (0xff8260)
                   2834:  */
1.1.1.8   root     2835: void Video_ShifterMode_WriteByte(void)
                   2836: {
1.1.1.11  root     2837:        if (ConfigureParams.System.nMachineType == MACHINE_TT)
                   2838:        {
                   2839:                TTRes = IoMem_ReadByte(0xff8260) & 7;
                   2840:                IoMem_WriteByte(0xff8262, TTRes);           /* Copy to TT shifter mode register */
                   2841:        }
                   2842:        if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
                   2843:        {
                   2844:                /* - activate STE palette
                   2845:                 * - TODO: set line width ($8210)
                   2846:                 * - TODO: sets paramaters in $82c2 (double lines/interlace & cycles/pixel)
                   2847:                 */
1.1.1.15! root     2848:                bUseSTShifter = true;
1.1.1.11  root     2849:        }
1.1.1.15! root     2850: 
        !          2851:        if (/*!bUseHighRes &&*/ !bUseVDIRes)                /* Don't store if hi-res and don't store if VDI resolution */
1.1.1.11  root     2852:        {
1.1.1.13  root     2853:                VideoShifterByte = IoMem[0xff8260] & 3;         /* We only care for lower 2-bits */
                   2854:                if ( VideoShifterByte == 3 )                    /* 3 is not a valid resolution, use low res instead */
                   2855:                {
                   2856:                        VideoShifterByte = 0;
                   2857:                        IoMem_WriteByte(0xff8260,0);
                   2858:                }
1.1.1.11  root     2859:                Video_WriteToShifter(VideoShifterByte);
                   2860:                Video_SetHBLPaletteMaskPointers();
                   2861:                *pHBLPaletteMasks &= 0xff00ffff;
                   2862:                /* Store resolution after palette mask and set resolution write bit: */
                   2863:                *pHBLPaletteMasks |= (((Uint32)VideoShifterByte|0x04)<<16);
                   2864:        }
1.1.1.10  root     2865: }
                   2866: 
                   2867: /*-----------------------------------------------------------------------*/
1.1.1.11  root     2868: /**
1.1.1.13  root     2869:  * Handle horizontal scrolling to the left.
                   2870:  * On STE, there're 2 registers that can scroll the line :
                   2871:  *  - $ff8264 : scroll without prefetch
1.1.1.14  root     2872:  *  - $ff8265 : scroll with prefetch
1.1.1.13  root     2873:  * Both registers will scroll the line to the left by skipping the amount
                   2874:  * of pixels in $ff8264 or $ff8265 (from 0 to 15).
                   2875:  * As some pixels will be skipped, this means the shifter needs to read
                   2876:  * 16 other pixels in advance in some internal registers to have an uninterrupted flow of pixels.
                   2877:  *
1.1.1.14  root     2878:  * These 16 pixels can be prefetched before the display starts (on cycle 56 for example) when using
1.1.1.13  root     2879:  * $ff8265 to scroll the line. In that case 8 more bytes per line (low res) will be read. Most programs
                   2880:  * are using $ff8265 to scroll the line.
                   2881:  *
                   2882:  * When using $ff8264, the next 16 pixels will not be prefetched before the display
                   2883:  * starts, they will be read when the display normally starts (cycle 56). While
                   2884:  * reading these 16 pixels, the shifter won't be able to display anything, which will
                   2885:  * result in 16 pixels having the color 0. So, reading the 16 pixels will in fact delay
                   2886:  * the real start of the line, which will look as if it started 16 pixels later. As the
                   2887:  * shifter will stop the display at cycle 56+320 anyway, this means the last 16 pixels
                   2888:  * of each line won't be displayed and you get the equivalent of a shorter 304 pixels line.
                   2889:  * As a consequence, this register is rarely used to scroll the line.
                   2890:  *
                   2891:  * By writing a value > 0 in $ff8265 (to start prefetching) and immediatly after a value of 0
                   2892:  * in $ff8264 (no scroll and no prefetch), it's possible to fill the internal registers used
                   2893:  * for the scrolling even if scrolling is set to 0. In that case, the shifter will start displaying
                   2894:  * each line 16 pixels earlier (as the data are already available in the internal registers).
                   2895:  * This allows to have 336 pixels per line (instead of 320) for all the remaining lines on the screen.
                   2896:  *
                   2897:  * Although some programs are using this sequence :
                   2898:  *     move.w  #1,$ffff8264            ; Word access!
                   2899:  *     clr.b   $ffff8264               ; Byte access!
                   2900:  * It is also possible to add 16 pixels by doing :
                   2901:  *     move.b  #X,$ff8265              ; with X > 0
                   2902:  *     move.b  #0,$ff8264
1.1.1.11  root     2903:  * Some games (Obsession, Skulls) and demos (Pacemaker by Paradox) use this
                   2904:  * feature to increase the resolution, so we have to emulate this bug, too!
1.1.1.13  root     2905:  *
                   2906:  * So considering a low res line of 320 pixels (160 bytes) :
                   2907:  *     - if both $ff8264/65 are 0, no scrolling happens, the shifter reads 160 bytes and displays 320 pixels (same as STF)
                   2908:  *     - if $ff8265 > 0, line is scrolled, the shifter reads 168 bytes and displays 320 pixels.
                   2909:  *     - if $ff8264 > 0, line is scrolled, the shifter reads 160 bytes and displays 304 pixels,
                   2910:  *             the display starts 16 pixels later.
                   2911:  *     - if $ff8265 > 0 and then $ff8264 = 0, there's no scrolling, the shifter reads 168 bytes and displays 336 pixels,
                   2912:  *             the display starts 16 pixels earlier.
1.1.1.11  root     2913:  */
1.1.1.13  root     2914: 
                   2915: void Video_HorScroll_Write_8264(void)
                   2916: {
                   2917:        Video_HorScroll_Write();
                   2918: }
                   2919: 
                   2920: void Video_HorScroll_Write_8265(void)
                   2921: {
                   2922:        Video_HorScroll_Write();
                   2923: }
                   2924: 
1.1.1.10  root     2925: void Video_HorScroll_Write(void)
                   2926: {
1.1.1.13  root     2927:        Uint32 RegAddr;
1.1.1.11  root     2928:        Uint8 ScrollCount;
1.1.1.13  root     2929:        Uint8 Prefetch;
1.1.1.15! root     2930:        int FrameCycles, HblCounterVideo, LineCycles;
        !          2931:        bool Add16px = false;
1.1.1.13  root     2932:        static Uint8 LastVal8265 = 0;
                   2933:        int Delayed;
                   2934: 
1.1.1.15! root     2935:        Video_GetPosition_OnWriteAccess ( &FrameCycles , &HblCounterVideo , &LineCycles );
1.1.1.10  root     2936: 
1.1.1.13  root     2937:        RegAddr = IoAccessCurrentAddress;               /* 0xff8264 or 0xff8265 */
                   2938:        ScrollCount = IoMem[ RegAddr ];
1.1.1.11  root     2939:        ScrollCount &= 0x0f;
1.1.1.10  root     2940: 
1.1.1.13  root     2941:        if ( RegAddr == 0xff8264 )
                   2942:        {
                   2943:                Prefetch = 0;                           /* scroll without prefetch */
1.1.1.15! root     2944:                LastCycleScroll8264 = FrameCycles;
1.1.1.11  root     2945: 
1.1.1.15! root     2946:                ShifterFrame.Scroll8264Pos.VBL = nVBLs;
        !          2947:                ShifterFrame.Scroll8264Pos.FrameCycles = FrameCycles;
        !          2948:                ShifterFrame.Scroll8264Pos.HBL = HblCounterVideo;
        !          2949:                ShifterFrame.Scroll8264Pos.LineCycles = LineCycles;
        !          2950: 
        !          2951:                if ( ( ScrollCount == 0 ) && ( LastVal8265 > 0 )
        !          2952:                        && ( ShifterFrame.Scroll8265Pos.VBL > 0 )               /* a write to ff8265 has been made */
        !          2953:                        && ( ShifterFrame.Scroll8265Pos.VBL == ShifterFrame.Scroll8264Pos.VBL )         /* during the same VBL */
        !          2954:                        && ( ShifterFrame.Scroll8264Pos.FrameCycles - ShifterFrame.Scroll8265Pos.FrameCycles <= 40 ) )
1.1.1.13  root     2955:                {
1.1.1.15! root     2956:                        LOG_TRACE(TRACE_VIDEO_BORDER_H , "detect ste left+16 pixels\n" );
        !          2957:                        Add16px = true;
1.1.1.13  root     2958:                }
                   2959:        }
                   2960:        else
1.1.1.11  root     2961:        {
1.1.1.13  root     2962:                Prefetch = 1;                           /* scroll with prefetch */
1.1.1.15! root     2963:                LastCycleScroll8265 = FrameCycles;
        !          2964: 
        !          2965:                ShifterFrame.Scroll8265Pos.VBL = nVBLs;
        !          2966:                ShifterFrame.Scroll8265Pos.FrameCycles = FrameCycles;
        !          2967:                ShifterFrame.Scroll8265Pos.HBL = HblCounterVideo;
        !          2968:                ShifterFrame.Scroll8265Pos.LineCycles = LineCycles;
        !          2969: 
1.1.1.13  root     2970:                LastVal8265 = ScrollCount;
1.1.1.15! root     2971:                Add16px = false;
1.1.1.11  root     2972:        }
1.1.1.13  root     2973: 
                   2974: 
                   2975:        /* If the write was made before display starts on the current line, then */
                   2976:        /* we can still change the value now. Else, the new values will be used */
                   2977:        /* for line n+1. */
                   2978:        /* We must also check the write does not overlap the end of the line */
1.1.1.15! root     2979:        if ( ( ( LineCycles <= LINE_START_CYCLE_50 ) && ( nHBL == HblCounterVideo ) )
1.1.1.13  root     2980:                || ( nHBL < nStartHBL ) || ( nHBL >= nEndHBL ) )
1.1.1.11  root     2981:        {
1.1.1.13  root     2982:                HWScrollCount = ScrollCount;            /* display has not started, we can still change */
                   2983:                HWScrollPrefetch = Prefetch;
                   2984:                bSteBorderFlag = Add16px;
                   2985:                NewHWScrollCount = -1;                  /* cancel 'pending' change */
1.1.1.15! root     2986:                Delayed = false;
1.1.1.11  root     2987:        }
                   2988:        else
                   2989:        {
1.1.1.13  root     2990:                NewHWScrollCount = ScrollCount;         /* display has started, can't change HWScrollCount now */
                   2991:                NewHWScrollPrefetch = Prefetch;
                   2992:                if ( Add16px )
                   2993:                        NewSteBorderFlag = 1;
                   2994:                else
                   2995:                        NewSteBorderFlag = 0;
1.1.1.15! root     2996:                Delayed = true;
1.1.1.11  root     2997:        }
                   2998: 
1.1.1.15! root     2999:        LOG_TRACE(TRACE_VIDEO_STE , "write ste %x hwscroll=%x delayed=%s video_cyc_w=%d line_cyc_w=%d @ nHBL=%d/video_hbl_w=%d pc=%x instr_cyc=%d\n" ,
1.1.1.13  root     3000:                RegAddr , ScrollCount, Delayed ? "yes" : "no" ,
1.1.1.15! root     3001:                FrameCycles, LineCycles, nHBL, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles );
1.1.1.13  root     3002: }
1.1.1.11  root     3003: 
                   3004: /*-----------------------------------------------------------------------*/
                   3005: /**
                   3006:  * Write to TT shifter mode register (0xff8262)
                   3007:  */
                   3008: void Video_TTShiftMode_WriteWord(void)
                   3009: {
                   3010:        TTRes = IoMem_ReadByte(0xff8262) & 7;
                   3011: 
                   3012:        /*fprintf(stderr, "Write to FF8262: %x, res=%i\n", IoMem_ReadWord(0xff8262), TTRes);*/
                   3013: 
                   3014:        /* Is it an ST compatible resolution? */
                   3015:        if (TTRes <= 2)
                   3016:        {
                   3017:                IoMem_WriteByte(0xff8260, TTRes);
                   3018:                Video_ShifterMode_WriteByte();
                   3019:        }
                   3020: }
                   3021: 
                   3022: /*-----------------------------------------------------------------------*/
                   3023: /**
                   3024:  * Write to TT color register (0xff8400)
                   3025:  */
                   3026: void Video_TTColorRegs_WriteWord(void)
                   3027: {
1.1.1.15! root     3028:        bTTColorsSync = false;
1.1.1.11  root     3029: }
                   3030: 
                   3031: /*-----------------------------------------------------------------------*/
                   3032: /**
1.1.1.15! root     3033:  * Write to ST color register on TT (0xff8240)
1.1.1.11  root     3034:  */
                   3035: void Video_TTColorSTRegs_WriteWord(void)
                   3036: {
1.1.1.15! root     3037:        bTTColorsSTSync = false;
1.1.1.8   root     3038: }

unix.superglobalmegacorp.com

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