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

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.8 ! root       12: char Video_rcsid[] = "Hatari $Id: video.c,v 1.28 2005/04/05 14:41:32 thothy Exp $";
1.1       root       13: 
1.1.1.4   root       14: #include <SDL.h>
1.1.1.7   root       15: #include <SDL_endian.h>
1.1.1.4   root       16: 
1.1       root       17: #include "main.h"
1.1.1.6   root       18: #include "configuration.h"
1.1       root       19: #include "fdc.h"
                     20: #include "int.h"
                     21: #include "ikbd.h"
1.1.1.8 ! root       22: #include "ioMem.h"
1.1.1.4   root       23: #include "keymap.h"
1.1       root       24: #include "m68000.h"
                     25: #include "memorySnapShot.h"
                     26: #include "mfp.h"
                     27: #include "screen.h"
                     28: #include "shortcut.h"
                     29: #include "sound.h"
                     30: #include "spec512.h"
                     31: #include "stMemory.h"
                     32: #include "vdi.h"
                     33: #include "video.h"
                     34: #include "ymFormat.h"
1.1.1.4   root       35: 
                     36: 
1.1.1.2   root       37: BOOL bUseHighRes = FALSE;                       /* Use hi-res (ie Mono monitor) */
1.1       root       38: int nVBLs, nHBL;                                /* VBL Counter, HBL line */
1.1.1.8 ! root       39: int nStartHBL, nEndHBL;                         /* Start/End HBL for visible screen(64 lines in Top border) */
1.1       root       40: int OverscanMode;                               /* OVERSCANMODE_xxxx for current display frame */
1.1.1.8 ! root       41: Uint16 HBLPalettes[(NUM_VISIBLE_LINES+1)*16];   /* 1x16 colour palette per screen line, +1 line just incase write after line 200 */
        !            42: Uint16 *pHBLPalettes;                           /* Pointer to current palette lists, one per HBL */
1.1       root       43: unsigned long HBLPaletteMasks[NUM_VISIBLE_LINES+1];  /* Bit mask of palette colours changes, top bit set is resolution change */
                     44: unsigned long *pHBLPaletteMasks;
1.1.1.6   root       45: int VBLCounter;                                 /* VBL counter */
                     46: int nScreenRefreshRate = 50;                    /* 50 or 60 Hz in color, 70 Hz in mono */
1.1.1.8 ! root       47: Uint32 VideoBase;                               /* Base address in ST Ram for screen (read on each VBL) */
        !            48: static Uint8 *pVideoRaster;                     /* Pointer to Video raster, after VideoBase in PC address space. Use to copy data on HBL */
        !            49: static Uint8 VideoShifterByte;                  /* VideoShifter (0xff8260) value store in video chip */
        !            50: static int LeftRightBorder;                     /* BORDERMASK_xxxx used to simulate left/right border removal */
1.1       root       51: 
                     52: 
                     53: /*-----------------------------------------------------------------------*/
                     54: /*
                     55:   Reset video chip
                     56: */
                     57: void Video_Reset(void)
                     58: {
                     59:   /* NOTE! Must reset all of these register type things here!!!! */
1.1.1.7   root       60: 
1.1       root       61:   /* Are we in high-res? */
                     62:   if (bUseHighRes)
                     63:     VideoShifterByte = ST_HIGH_RES;    /* Boot up for mono monitor */
                     64:   else
                     65:     VideoShifterByte = ST_LOW_RES;
1.1.1.4   root       66:   if(bUseVDIRes)
                     67:     VideoShifterByte = VDIRes;
1.1       root       68: 
                     69:   /* Reset VBL counter */
                     70:   nVBLs = 0;
                     71:   /* Reset addresses */
                     72:   VideoBase = 0L;
                     73:   /* Clear ready for new VBL */
                     74:   Video_ClearOnVBL();
                     75: }
                     76: 
                     77: /*-----------------------------------------------------------------------*/
                     78: /*
                     79:   Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                     80: */
                     81: void Video_MemorySnapShot_Capture(BOOL bSave)
                     82: {
                     83:   /* Save/Restore details */
                     84:   MemorySnapShot_Store(&VideoShifterByte,sizeof(VideoShifterByte));
                     85:   MemorySnapShot_Store(&bUseHighRes,sizeof(bUseHighRes));
                     86:   MemorySnapShot_Store(&nVBLs,sizeof(nVBLs));
                     87:   MemorySnapShot_Store(&nHBL,sizeof(nHBL));
                     88:   MemorySnapShot_Store(&nStartHBL,sizeof(nStartHBL));
                     89:   MemorySnapShot_Store(&nEndHBL,sizeof(nEndHBL));
                     90:   MemorySnapShot_Store(&OverscanMode,sizeof(OverscanMode));
                     91:   MemorySnapShot_Store(HBLPalettes,sizeof(HBLPalettes));
                     92:   MemorySnapShot_Store(HBLPaletteMasks,sizeof(HBLPaletteMasks));
                     93:   MemorySnapShot_Store(&VideoBase,sizeof(VideoBase));
1.1.1.8 ! root       94:   MemorySnapShot_Store(&pVideoRaster,sizeof(pVideoRaster));
1.1       root       95: }
                     96: 
                     97: /*-----------------------------------------------------------------------*/
                     98: /*
                     99:   Called on VBL, set registers ready for frame
                    100: */
                    101: void Video_ClearOnVBL(void)
                    102: {
                    103:   /* New screen, so first HBL */
                    104:   nHBL = 0;
                    105:   nStartHBL = SCREEN_START_HBL;
                    106:   nEndHBL = SCREEN_START_HBL+SCREEN_HEIGHT_HBL;
                    107:   OverscanMode = OVERSCANMODE_NONE;
                    108: 
1.1.1.8 ! root      109:   /* Get screen address pointer, aligned to 256 bytes on ST (ie ignore lowest byte) */
        !           110:   VideoBase = (Uint32)STMemory_ReadByte(0xff8201)<<16 | (Uint32)STMemory_ReadByte(0xff8203)<<8;
        !           111:   if (ConfigureParams.System.nMachineType != MACHINE_ST)
        !           112:     VideoBase |= STMemory_ReadByte(0xff820d);
        !           113: 
        !           114:   pVideoRaster = &STRam[VideoBase];
1.1       root      115:   pSTScreen = pFrameBuffer->pSTScreen;
                    116: 
                    117:   Video_StartHBL();
                    118:   Video_SetScreenRasters();
                    119:   Spec512_StartVBL();
                    120: }
                    121: 
1.1.1.8 ! root      122: 
1.1       root      123: /*-----------------------------------------------------------------------*/
                    124: /*
1.1.1.8 ! root      125:   Calculate and return video address pointer.
1.1       root      126: */
1.1.1.8 ! root      127: static Uint32 Video_CalculateAddress(void)
1.1       root      128: {
                    129:   int X,Y,FrameCycles,nPixelsIn;
1.1.1.8 ! root      130:   Uint32 VideoAddress;                          /* Address of video display in ST screen space */
1.1       root      131: 
                    132:   /* Find number of cycles passed during frame */
                    133:   FrameCycles = Int_FindFrameCycles();
                    134: 
                    135:   /* Top of screen is usually 64 lines from VBL(64x512=32768 cycles) */
                    136:   if (FrameCycles<(nStartHBL*CYCLES_PER_LINE))
1.1.1.8 ! root      137:   {
1.1       root      138:     VideoAddress = 0;
1.1.1.8 ! root      139:   }
        !           140:   else
        !           141:   {
1.1       root      142:     /* Now find which pixel we are on(ignore left/right borders) */
                    143:     /* 96 + 320 + 96 = 512 pixels per scan line(each pixel is one cycle) */
                    144:     nPixelsIn = FrameCycles-(nStartHBL*CYCLES_PER_LINE);
                    145:     /* Convert this to an X,Y pixel on screen */
                    146:     Y = nPixelsIn/512;
                    147:     X = nPixelsIn - (Y*512);
                    148:     if (X<SCREEN_START_CYCLE)       /* Limit if in NULL area outside screen */
                    149:       X = SCREEN_START_CYCLE;
                    150:     if (X>(512-SCREEN_START_CYCLE))
                    151:       X = (512-SCREEN_START_CYCLE);
                    152:     /* X is now from 96 to 416(320 pixels), subtract 96 to give X pixel across screen! */
                    153:     X = ((X-SCREEN_START_CYCLE)>>1)&(~1);
1.1.1.6   root      154: 
1.1       root      155:     if (Y<(nEndHBL-nStartHBL))      /* Limit to end of screen */
                    156:       VideoAddress = (Y*160) + X;
                    157:     else
                    158:       VideoAddress = ((nEndHBL-nStartHBL)*160);
                    159:   }
                    160: 
                    161:   /* Offset from start of screen(MUST use address loading into video display) */
                    162:   VideoAddress += VideoBase;
                    163: 
1.1.1.8 ! root      164:   return VideoAddress;
1.1       root      165: }
                    166: 
1.1.1.7   root      167: 
1.1       root      168: /*-----------------------------------------------------------------------*/
                    169: /*
                    170:   VBL interrupt, draw screen and reset counters
                    171: */
                    172: void Video_InterruptHandler_VBL(void)
                    173: {
                    174:   int PendingCyclesOver;
1.1.1.6   root      175:   int nNewMilliTicks;
                    176:   static int nOldMilliTicks = 0;
                    177:   signed int nDelay;
1.1       root      178: 
                    179:   /* Store cycles we went over for this frame(this is our inital count) */
                    180:   PendingCyclesOver = -PendingInterruptCount;    /* +ve */
                    181: 
                    182:   /* Remove this interrupt from list and re-order */
                    183:   Int_AcknowledgeInterrupt();
1.1.1.6   root      184:   /* Start HBL interrupts - MUST do before add in cycles */
1.1       root      185:   Int_AddAbsoluteInterrupt(CYCLES_ENDLINE,INTERRUPT_VIDEO_ENDLINE);
                    186:   Int_AddAbsoluteInterrupt(CYCLES_HBL,INTERRUPT_VIDEO_HBL);
                    187:   Int_AddAbsoluteInterrupt(CYCLES_PER_FRAME,INTERRUPT_VIDEO_VBL);
                    188: 
                    189:   /* Set frame cycles, used for Video Address */
                    190:   nFrameCyclesOver = PendingCyclesOver;      /* Number of cycles into frame */
                    191: 
1.1.1.6   root      192:   /* Set the screen refresh rate */
                    193: #if 0
                    194:   if(bUseHighRes)
                    195:     nScreenRefreshRate = 70;
1.1.1.8 ! root      196:   else if(IoMem[0xff820a] & 2)               /* Is it 50Hz or is it 60Hz? */
1.1.1.6   root      197:     nScreenRefreshRate = 50;
                    198:   else
                    199:     nScreenRefreshRate = 60;
                    200: #endif
                    201: 
                    202:   VBLCounter += 1;
1.1.1.2   root      203: 
1.1.1.3   root      204:   /* Clear any key presses which are due to be de-bounced (held for one ST frame) */
                    205:   Keymap_DebounceAllKeys();
1.1.1.7   root      206:   /* Check shortcut keys */
1.1       root      207:   ShortCut_CheckKeys();
1.1.1.7   root      208: 
1.1       root      209:   /* Use extended VDI resolution? If so, just copy whole screen on VBL rather than per HBL */
                    210:   if (bUseVDIRes)
                    211:     Video_CopyVDIScreen();
1.1.1.5   root      212: 
1.1       root      213:   /* Draw screen, skip frame if need to */
1.1.1.6   root      214:   if (ConfigureParams.Screen.bFrameSkip)
1.1.1.5   root      215:   {
1.1       root      216:     if (nVBLs&1)
                    217:       Screen_Draw();
                    218:   }
                    219:   else
                    220:     Screen_Draw();
1.1.1.5   root      221: 
1.1       root      222:   /* Update counter for number of screen refreshes per second(for debugging) */
                    223:   nVBLs++;
                    224:   /* Set video registers for frame */
                    225:   Video_ClearOnVBL();
                    226:   /* Store off PSG registers for YM file, is enabled */
                    227:   YMFormat_UpdateRecording();
1.1.1.4   root      228:   /* Generate 1/50th second of sound sample data, to be played by sound thread */
1.1       root      229:   Sound_Update_VBL();
                    230: 
1.1.1.7   root      231:   M68000_Exception(EXCEPTION_VBLANK);   /* Vertical blank interrupt, level 4! */
1.1       root      232: 
1.1.1.5   root      233:   /* And handle any messages, check for quit message */
1.1       root      234:   Main_EventHandler();         /* Process messages, set 'bQuitProgram' if user tries to quit */
1.1.1.7   root      235:   if (bQuitProgram)
                    236:   {
1.1       root      237:     Int_AddAbsoluteInterrupt(4, 0L);  /* Pass NULL interrupt function to quit cleanly */
1.1.1.7   root      238:     set_special(SPCFLAG_BRK);         /* Assure that CPU core shuts down */
                    239:   }
1.1.1.6   root      240: 
1.1.1.7   root      241:   if (ConfigureParams.System.nMinMaxSpeed != MINMAXSPEED_MAX)
1.1.1.6   root      242:   {
1.1.1.7   root      243:     /* Wait, so we stay in sync with the sound */
                    244:     do
1.1.1.6   root      245:     {
1.1.1.7   root      246:       nNewMilliTicks = SDL_GetTicks();
                    247:       nDelay = 1000/nScreenRefreshRate - (nNewMilliTicks-nOldMilliTicks);
                    248:       if(nDelay > 2)
                    249:       {
                    250:         /* SDL_Delay seems to be quite inaccurate, so we don't wait the whole time */
                    251:         SDL_Delay(nDelay - 1);
                    252:       }
1.1.1.6   root      253:     }
1.1.1.7   root      254:     while(nDelay > 0);
                    255:     nOldMilliTicks = nNewMilliTicks;
1.1.1.6   root      256:   }
1.1       root      257: }
                    258: 
                    259: 
                    260: /*-----------------------------------------------------------------------*/
                    261: /*
                    262:   End Of Line interrupt
1.1.1.5   root      263:   As this occurs at the end of a line we cannot get timing for START of first
                    264:   line (as in Spectrum 512)
1.1       root      265: */
                    266: void Video_InterruptHandler_EndLine(void)
                    267: {
                    268:   /* Remove this interrupt from list and re-order */
                    269:   Int_AcknowledgeInterrupt();
                    270:   /* Generate new HBL, if need to - there are 313 HBLs per frame */
                    271:   if (nHBL<(SCANLINES_PER_FRAME-1))
                    272:     Int_AddAbsoluteInterrupt(CYCLES_PER_LINE,INTERRUPT_VIDEO_ENDLINE);
                    273: 
1.1.1.5   root      274:   /* Is this a good place to send the keyboard packets? Done once per frame */
                    275:   if(nHBL == nStartHBL)
                    276:   {
                    277:     /* On each VBL send automatic keyboard packets for mouse, joysticks etc... */
                    278:     IKBD_SendAutoKeyboardCommands();
                    279:   }
                    280: 
1.1       root      281:   /* Timer A/B occur at END of first visible screen line in Event Count mode */
                    282:   if ( (nHBL>=nStartHBL) && (nHBL<nEndHBL) )
                    283:    {
                    284:     /* Handle Timers A and B when using Event Count mode(timer taken from HBL) */
1.1.1.2   root      285:     if (MFP_TACR==0x08)        /* Is timer in Event Count mode? */
1.1       root      286:       MFP_TimerA_EventCount_Interrupt();
1.1.1.2   root      287:     if (MFP_TBCR==0x08)        /* Is timer in Event Count mode? */
1.1       root      288:       MFP_TimerB_EventCount_Interrupt();
                    289:    }
                    290: 
1.1.1.2   root      291:   FDC_UpdateHBL();             /* Update FDC motion */
                    292:   Video_EndHBL();              /* Increase HBL count, copy line to display buffer and do any video trickery */
1.1       root      293: 
                    294:   /* If we don't often pump data into the event queue, the SDL misses events... grr... */
                    295:   if( !(nHBL&63) )
1.1.1.5   root      296:   {
1.1       root      297:     Main_EventHandler();
1.1.1.5   root      298:   }
1.1       root      299: }
                    300: 
                    301: 
1.1.1.2   root      302: /*-----------------------------------------------------------------------*/
1.1       root      303: /*
                    304:   HBL interrupt - this is very inaccurate on ST and appears to occur around 1/3rd way into
                    305:   the display!
                    306: */
                    307: void Video_InterruptHandler_HBL(void)
                    308: {
1.1.1.2   root      309:   /* Remove this interrupt from list and re-order */
1.1       root      310:   Int_AcknowledgeInterrupt();
1.1.1.7   root      311: 
1.1.1.2   root      312:   /* Generate new Timer AB, if need to - there are 313 HBLs per frame */
1.1.1.7   root      313:   if(nHBL < (SCANLINES_PER_FRAME-1))
1.1       root      314:     Int_AddAbsoluteInterrupt(CYCLES_PER_LINE,INTERRUPT_VIDEO_HBL);
                    315: 
1.1.1.7   root      316:   M68000_Exception(EXCEPTION_HBLANK);   /* Horizontal blank interrupt, level 2! */
1.1       root      317: }
                    318: 
                    319: 
1.1.1.2   root      320: /*-----------------------------------------------------------------------*/
1.1       root      321: /*
1.1.1.7   root      322:   Write to VideoShifter (0xff8260), resolution bits
1.1       root      323: */
1.1.1.7   root      324: void Video_WriteToShifter(Uint8 Byte)
1.1       root      325: {
1.1.1.7   root      326:   static int nLastHBL = -1, LastByte, nLastCycles;
                    327:   int nFrameCycles, nLineCycles;
                    328:   
                    329:   nFrameCycles = Int_FindFrameCycles();
1.1       root      330: 
1.1.1.7   root      331:   /* We only care for cycle position in the actual screen line */
                    332:   nLineCycles = nFrameCycles % CYCLES_PER_LINE;
1.1       root      333: 
1.1.1.7   root      334:   /*fprintf(stderr,"Shifter=0x%2.2X %d (%d) @ %d\n",
                    335:           Byte, nFrameCycles, nLineCycles, nHBL);*/
1.1       root      336: 
1.1.1.7   root      337:   /* Check if program tries to open left border.
                    338:    * FIXME: This is a very inaccurate test that should be improved,
                    339:    * but we probably need better CPU cycles emulation first. There's
                    340:    * also no support for sync-scrolling yet :-( */
                    341:   if (nHBL == nLastHBL && LastByte == 0x02 && Byte == 0x00
                    342:       && nLineCycles <= 48 && nLineCycles-nLastCycles <= 16)
                    343:   {
                    344:     LeftRightBorder |= BORDERMASK_LEFT;
                    345:   }
1.1.1.2   root      346: 
1.1.1.7   root      347:   nLastHBL = nHBL;
                    348:   LastByte = Byte;
                    349:   nLastCycles = nLineCycles;
1.1       root      350: }
                    351: 
1.1.1.2   root      352: 
                    353: /*-----------------------------------------------------------------------*/
1.1       root      354: /*
1.1.1.7   root      355:   Write to VideoSync (0xff820a), Hz setting
1.1       root      356: */
1.1.1.8 ! root      357: void Video_Sync_WriteByte(void)
1.1       root      358: {
1.1.1.7   root      359:   static int nLastHBL = -1, LastByte, nLastCycles;
                    360:   int nFrameCycles, nLineCycles;
1.1.1.8 ! root      361:   Uint8 Byte;
        !           362: 
        !           363:   Byte = IoMem[0xff820a] & 3;           /* Note: We're only interested in lower 2 bits (50/60Hz) */
        !           364: 
1.1.1.7   root      365:   nFrameCycles = Int_FindFrameCycles();
1.1       root      366: 
1.1.1.7   root      367:   /* We only care for cycle position in the actual screen line */
                    368:   nLineCycles = nFrameCycles % CYCLES_PER_LINE;
1.1.1.2   root      369: 
1.1.1.7   root      370:   /*fprintf(stderr,"Sync=0x%2.2X %d (%d) @ %d\n",
                    371:           Byte, nFrameCycles, nLineCycles, nHBL);*/
1.1       root      372: 
1.1.1.7   root      373:   /* Check if program tries to open a border.
                    374:    * FIXME: These are very inaccurate tests that should be improved,
                    375:    * but we probably need better CPU cycles emulation first. There's
                    376:    * also no support for sync-scrolling yet :-( */
                    377:   if (LastByte == 0x00 && Byte == 0x02)   /* switched from 50 Hz to 60 Hz and back to 50 Hz? */
                    378:   {
                    379:     if (nHBL >= OVERSCAN_TOP && nHBL <= 39 && nStartHBL > FIRST_VISIBLE_HBL)
                    380:     {
                    381:       /* Top border */
                    382:       OverscanMode |= OVERSCANMODE_TOP;       /* Set overscan bit */
                    383:       nStartHBL = FIRST_VISIBLE_HBL;          /* New start screen line */
                    384:       pHBLPaletteMasks -= OVERSCAN_TOP;
                    385:       pHBLPalettes -= OVERSCAN_TOP;
1.1       root      386:     }
1.1.1.7   root      387:     else if (nHBL == SCREEN_START_HBL+SCREEN_HEIGHT_HBL)
                    388:     {
                    389:       /* Bottom border */
                    390:       OverscanMode |= OVERSCANMODE_BOTTOM;    /* Set overscan bit */
                    391:       nEndHBL = SCREEN_START_HBL+SCREEN_HEIGHT_HBL+OVERSCAN_BOTTOM;  /* New end screen line */
1.1       root      392:     }
                    393: 
1.1.1.7   root      394:     if (nHBL == nLastHBL && nLineCycles >= 400 && nLineCycles <= 480
                    395:         && nLineCycles-nLastCycles <= 16)
                    396:     {
                    397:       /* Right border */
                    398:       LeftRightBorder |= BORDERMASK_RIGHT;
                    399:     }
1.1       root      400:   }
                    401: 
1.1.1.7   root      402:   nLastHBL = nHBL;
                    403:   LastByte = Byte;
                    404:   nLastCycles = nLineCycles;
1.1       root      405: }
                    406: 
1.1.1.2   root      407: 
                    408: /*-----------------------------------------------------------------------*/
1.1       root      409: /*
                    410:   Reset Sync/Shifter table at start of each HBL
                    411: */
                    412: void Video_StartHBL(void)
                    413: {
                    414:   LeftRightBorder = 0;
                    415: }
                    416: 
1.1.1.2   root      417: 
                    418: /*-----------------------------------------------------------------------*/
1.1       root      419: /*
                    420:   Store whole palette on first line so have reference to work from
                    421: */
1.1.1.7   root      422: static void Video_StoreFirstLinePalette(void)
1.1       root      423: {
1.1.1.8 ! root      424:   Uint16 *pp2;
1.1       root      425:   int i;
                    426: 
1.1.1.8 ! root      427:   pp2 = (Uint16 *)&IoMem[0xff8240];
1.1       root      428:   for(i=0; i<16; i++)
1.1.1.7   root      429:     HBLPalettes[i] = SDL_SwapBE16(*pp2++);
1.1.1.2   root      430:   /* And set mask flag with palette and resolution */
1.1.1.8 ! root      431:   HBLPaletteMasks[0] = (PALETTEMASK_RESOLUTION|PALETTEMASK_PALETTE) | (((unsigned long)IoMem_ReadByte(0xff8260)&0x3)<<16);
1.1       root      432: }
                    433: 
1.1.1.2   root      434: 
                    435: /*-----------------------------------------------------------------------*/
1.1       root      436: /*
                    437:   Store resolution on each line(used to test if mixed low/medium resolutions)
                    438: */
1.1.1.7   root      439: static void Video_StoreResolution(int y)
1.1       root      440: {
1.1.1.2   root      441:   /* Clear resolution, and set with current value */
1.1.1.8 ! root      442:   if (!(bUseHighRes || bUseVDIRes))
        !           443:   {
1.1       root      444:     HBLPaletteMasks[y] &= ~(0x3<<16);
1.1.1.8 ! root      445:     HBLPaletteMasks[y] |= ((unsigned long)IoMem_ReadByte(0xff8260)&0x3)<<16;
1.1       root      446:   }
                    447: }
                    448: 
1.1.1.2   root      449: 
                    450: /*-----------------------------------------------------------------------*/
1.1       root      451: /*
                    452:   Copy line of screen into buffer for conversion later.
                    453:   Possible lines may be top/bottom border, and/or left/right borders
                    454: */
1.1.1.7   root      455: static void Video_CopyScreenLine(int BorderMask)
1.1       root      456: {
1.1.1.2   root      457:   /* Only copy screen line if not doing high VDI resolution */
1.1       root      458:   if (!bUseVDIRes) {
                    459:     BorderMask |= LeftRightBorder;
                    460: 
                    461:     if (bUseHighRes) {
1.1.1.2   root      462:       /* Copy for hi-res (no overscan) */
1.1.1.8 ! root      463:       memcpy(pSTScreen, pVideoRaster, SCREENBYTES_MIDDLE);
        !           464:       pVideoRaster += SCREENBYTES_MIDDLE;
1.1.1.2   root      465:       /* Each screen line copied to buffer is always same length */
1.1       root      466:       pSTScreen += SCREENBYTES_MIDDLE;
                    467:     }
                    468:     else {
1.1.1.2   root      469:       /* Is total blank line? Ie top/bottom border? */
1.1       root      470:       if (BorderMask&(BORDERMASK_TOP|BORDERMASK_BOTTOM)) {
1.1.1.2   root      471:         /* Clear line to colour '0' */
1.1       root      472:         memset(pSTScreen,0,SCREENBYTES_LINE);
                    473:       }
                    474:       else {
1.1.1.2   root      475:         /* Does have left border? If not, clear to colour '0' */
1.1       root      476:         if (BorderMask&BORDERMASK_LEFT) {
1.1.1.8 ! root      477:           pVideoRaster += 24-SCREENBYTES_LEFT;
        !           478:           memcpy(pSTScreen, pVideoRaster, SCREENBYTES_LEFT);
        !           479:           pVideoRaster += SCREENBYTES_LEFT;
1.1       root      480:         }
                    481:         else
                    482:           memset(pSTScreen,0,SCREENBYTES_LEFT);
1.1.1.2   root      483:         /* Copy middle - always present */
1.1.1.8 ! root      484:         memcpy(pSTScreen+SCREENBYTES_LEFT, pVideoRaster, SCREENBYTES_MIDDLE);
        !           485:         pVideoRaster += SCREENBYTES_MIDDLE;
1.1.1.2   root      486:         /* Does have right border? If not, clear to colour '0' */
1.1       root      487:         if (BorderMask&BORDERMASK_RIGHT) {
1.1.1.8 ! root      488:           memcpy(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE, pVideoRaster, SCREENBYTES_RIGHT);
        !           489:           pVideoRaster += 46-SCREENBYTES_RIGHT;
        !           490:           pVideoRaster += SCREENBYTES_RIGHT;
1.1       root      491:         }
                    492:         else
                    493:           memset(pSTScreen+SCREENBYTES_LEFT+SCREENBYTES_MIDDLE,0,SCREENBYTES_RIGHT);
                    494:       }
1.1.1.6   root      495: 
1.1.1.2   root      496:       /* Each screen line copied to buffer is always same length */
1.1       root      497:       pSTScreen += SCREENBYTES_LINE;
                    498:     }
                    499:   }
                    500: }
                    501: 
1.1.1.2   root      502: 
                    503: /*-----------------------------------------------------------------------*/
1.1       root      504: /*
                    505:   Copy extended GEM resolution screen
                    506: */
                    507: void Video_CopyVDIScreen(void)
                    508: {
1.1.1.2   root      509:   /* Copy whole screen, don't care about being exact as for GEM only */
1.1.1.8 ! root      510:   memcpy(pSTScreen, pVideoRaster, ((VDIWidth*VDIPlanes)/8)*VDIHeight);  /* 640x400x16colour */
1.1       root      511: }
                    512: 
1.1.1.2   root      513: 
                    514: /*-----------------------------------------------------------------------*/
1.1       root      515: /*
                    516:   Check at end of each HBL to see if any Sync/Shifter hardware tricks have been attempted
                    517: */
                    518: void Video_EndHBL(void)
                    519: {
1.1.1.2   root      520:   /* Are we in possible visible display (including borders)? */
1.1       root      521:   if ( (nHBL>=FIRST_VISIBLE_HBL) && (nHBL<(FIRST_VISIBLE_HBL+NUM_VISIBLE_LINES)) ) {
1.1.1.2   root      522:     /* Copy line of screen to buffer to simulate TV raster trace - required for mouse cursor display/game updates */
                    523:     /* Eg, Lemmings and The Killing Game Show are good examples */
1.1       root      524: 
1.1.1.2   root      525:     if (nHBL<nStartHBL)                /* Are we in top border blank (ie no top overscan enabled) */
1.1       root      526:       Video_CopyScreenLine(BORDERMASK_TOP);
1.1.1.2   root      527:     else if (nHBL>=nEndHBL)            /* Are we in bottom border blank */
1.1       root      528:       Video_CopyScreenLine(BORDERMASK_BOTTOM);
1.1.1.2   root      529:     else                               /* Must be in visible screen(including overscan), ignore left/right borders for now */
1.1       root      530:       Video_CopyScreenLine(BORDERMASK_NONE);
                    531: 
1.1.1.2   root      532:     if (nHBL==FIRST_VISIBLE_HBL) {    /* Very first line on screen - HBLPalettes[0] */
                    533:       /* Store ALL palette for this line into raster table for datum */
1.1       root      534:       Video_StoreFirstLinePalette();
                    535:     }
1.1.1.2   root      536:     /* Store resolution for every line so can check for mix low/medium screens */
1.1       root      537:     Video_StoreResolution(nHBL-FIRST_VISIBLE_HBL);
                    538:   }
                    539: 
1.1.1.2   root      540:   /* Finally increase HBL count */
1.1       root      541:   nHBL++;
                    542: 
1.1.1.2   root      543:   Video_StartHBL();                  /* Setup next one */
1.1       root      544: }
                    545: 
1.1.1.2   root      546: 
                    547: /* Clear raster line table to store changes in palette/resolution on a line basic */
                    548: /* Call once on VBL interrupt */
1.1       root      549: void Video_SetScreenRasters(void)
                    550: {
                    551:   pHBLPaletteMasks = HBLPaletteMasks;
                    552:   pHBLPalettes = HBLPalettes;
1.1.1.8 ! root      553:   memset(pHBLPaletteMasks, 0, sizeof(unsigned long)*NUM_VISIBLE_LINES);  /* Clear array */
1.1       root      554: }
                    555: 
1.1.1.2   root      556: 
                    557: /*-----------------------------------------------------------------------*/
1.1       root      558: /*
                    559:   Set pointers to HBLPalette tables to store correct colours/resolutions
                    560: */
                    561: void Video_SetHBLPaletteMaskPointers(void)
                    562: {
                    563:   int FrameCycles;
                    564:   int Line;
                    565: 
                    566:   /* Top of standard screen is 64 lines from VBL(64x512=32768 cycles) */
                    567:   /* Each line is 64+320+64+64(Blank) = 512 pixels per scan line      */
                    568:   /* Timer occurs at end of 64+320+64; Display Enable(DE)=Low         */
                    569:   /* HBL is incorrect on machine and occurs around 96+ cycles in      */
                    570: 
                    571:   /* Top of standard screen is 64 lines from VBL(64x512=32768 cycles) */
                    572:   /* Each line is 96 + 320 + 96 = 512 pixels per scan line(each pixel is one cycle) */
                    573:   FrameCycles = Int_FindFrameCycles();
                    574: 
                    575:   /* Find 'line' into palette - screen starts 64 lines down, less 28 for top overscan */
                    576:   /* And if write to last 96 cycle of line it will count as the NEXT line(needed else games may flicker) */
                    577:   Line = (FrameCycles-(FIRST_VISIBLE_HBL*CYCLES_PER_LINE)+SCREEN_START_CYCLE)/CYCLES_PER_LINE;
                    578:   if (Line<0)          /* Limit to top/bottom of possible visible screen */
                    579:     Line = 0;
                    580:   if (Line>=NUM_VISIBLE_LINES)
                    581:     Line = NUM_VISIBLE_LINES-1;
                    582: 
1.1.1.2   root      583:   /* Store pointers */
1.1       root      584:   pHBLPaletteMasks = &HBLPaletteMasks[Line];  /* Next mask entry */
                    585:   pHBLPalettes = &HBLPalettes[16*Line];       /* Next colour raster list x16 colours */
                    586: }
1.1.1.8 ! root      587: 
        !           588: 
        !           589: 
        !           590: /*-----------------------------------------------------------------------*/
        !           591: /*
        !           592:   Read video address counter high byte (0xff8205)
        !           593: */
        !           594: void Video_ScreenCounterHigh_ReadByte(void)
        !           595: {
        !           596:   IoMem[0xff8205] = Video_CalculateAddress() >> 16;   /* Get video address counter high byte */
        !           597: }
        !           598: 
        !           599: /*-----------------------------------------------------------------------*/
        !           600: /*
        !           601:   Read video address counter med byte (0xff8207)
        !           602: */
        !           603: void Video_ScreenCounterMed_ReadByte(void)
        !           604: {
        !           605:   IoMem[0xff8207] = Video_CalculateAddress() >> 8;    /* Get video address counter med byte */
        !           606: }
        !           607: 
        !           608: /*-----------------------------------------------------------------------*/
        !           609: /*
        !           610:   Read video address counter low byte (0xff8209)
        !           611: */
        !           612: void Video_ScreenCounterLow_ReadByte(void)
        !           613: {
        !           614:   IoMem[0xff8209] = Video_CalculateAddress();         /* Get video address counter low byte */
        !           615: }
        !           616: 
        !           617: 
        !           618: /*-----------------------------------------------------------------------*/
        !           619: /*
        !           620:   Read video sync register (0xff820a)
        !           621: */
        !           622: void Video_Sync_ReadByte(void)
        !           623: {
        !           624:   /* Nothing... */
        !           625: }
        !           626: 
        !           627: /*-----------------------------------------------------------------------*/
        !           628: /*
        !           629:   Read video base address low byte (0xff820d). A plain ST can only store
        !           630:   screen addresses rounded to 256 bytes (i.e. no lower byte).
        !           631: */
        !           632: void Video_BaseLow_ReadByte(void)
        !           633: {
        !           634:   if (ConfigureParams.System.nMachineType == MACHINE_ST)
        !           635:     IoMem[0xff820d] = 0;
        !           636: }
        !           637: 
        !           638: /*-----------------------------------------------------------------------*/
        !           639: /*
        !           640:   Read video line width register (0xff820f)
        !           641: */
        !           642: void Video_LineWidth_ReadByte(void)
        !           643: {
        !           644:   IoMem[0xff820f] = 0;        /* On ST this is always 0 */
        !           645: }
        !           646: 
        !           647: /*-----------------------------------------------------------------------*/
        !           648: /*
        !           649:   Read video shifter mode register (0xff8260)
        !           650: */
        !           651: void Video_ShifterMode_ReadByte(void)
        !           652: {
        !           653:   if (bUseHighRes)
        !           654:     IoMem[0xff8260] = 2;                  /* If mono monitor, force to high resolution */
        !           655:   else
        !           656:     IoMem[0xff8260] = VideoShifterByte;   /* Read shifter register */
        !           657: }
        !           658: 
        !           659: 
        !           660: 
        !           661: /*-----------------------------------------------------------------------*/
        !           662: /*
        !           663:   Write to video shifter palette registers (0xff8240-0xff825e)
        !           664: */
        !           665: static void Video_ColorReg_WriteWord(Uint32 addr)
        !           666: {
        !           667:   if (!bUseHighRes)                                 /* Don't store if hi-res */
        !           668:   {
        !           669:     Uint16 col;
        !           670:     Video_SetHBLPaletteMaskPointers();              /* Set 'pHBLPalettes' etc.. according cycles into frame */
        !           671:     col = IoMem_ReadWord(addr);
        !           672:     col &= 0x777;                                   /* Mask off to 512 palette */
        !           673:     IoMem_WriteWord(addr, col);                     /* (some games write 0xFFFF and read back to see if STe) */
        !           674:     Spec512_StoreCyclePalette(col, addr);           /* Store colour into CyclePalettes[] */
        !           675:     pHBLPalettes[(addr-0xff8240)/2] = col;          /* Set colour x */
        !           676:     *pHBLPaletteMasks |= 1 << ((addr-0xff8240)/2);  /* And mask */
        !           677:   }
        !           678: }
        !           679: 
        !           680: void Video_Color0_WriteWord(void)
        !           681: {
        !           682:   Video_ColorReg_WriteWord(0xff8240);
        !           683: }
        !           684: 
        !           685: void Video_Color1_WriteWord(void)
        !           686: {
        !           687:   Video_ColorReg_WriteWord(0xff8242);
        !           688: }
        !           689: 
        !           690: void Video_Color2_WriteWord(void)
        !           691: {
        !           692:   Video_ColorReg_WriteWord(0xff8244);
        !           693: }
        !           694: 
        !           695: void Video_Color3_WriteWord(void)
        !           696: {
        !           697:   Video_ColorReg_WriteWord(0xff8246);
        !           698: }
        !           699: 
        !           700: void Video_Color4_WriteWord(void)
        !           701: {
        !           702:   Video_ColorReg_WriteWord(0xff8248);
        !           703: }
        !           704: 
        !           705: void Video_Color5_WriteWord(void)
        !           706: {
        !           707:   Video_ColorReg_WriteWord(0xff824a);
        !           708: }
        !           709: 
        !           710: void Video_Color6_WriteWord(void)
        !           711: {
        !           712:   Video_ColorReg_WriteWord(0xff824c);
        !           713: }
        !           714: 
        !           715: void Video_Color7_WriteWord(void)
        !           716: {
        !           717:   Video_ColorReg_WriteWord(0xff824e);
        !           718: }
        !           719: 
        !           720: void Video_Color8_WriteWord(void)
        !           721: {
        !           722:   Video_ColorReg_WriteWord(0xff8250);
        !           723: }
        !           724: 
        !           725: void Video_Color9_WriteWord(void)
        !           726: {
        !           727:   Video_ColorReg_WriteWord(0xff8252);
        !           728: }
        !           729: 
        !           730: void Video_Color10_WriteWord(void)
        !           731: {
        !           732:   Video_ColorReg_WriteWord(0xff8254);
        !           733: }
        !           734: 
        !           735: void Video_Color11_WriteWord(void)
        !           736: {
        !           737:   Video_ColorReg_WriteWord(0xff8256);
        !           738: }
        !           739: 
        !           740: void Video_Color12_WriteWord(void)
        !           741: {
        !           742:   Video_ColorReg_WriteWord(0xff8258);
        !           743: }
        !           744: 
        !           745: void Video_Color13_WriteWord(void)
        !           746: {
        !           747:   Video_ColorReg_WriteWord(0xff825a);
        !           748: }
        !           749: 
        !           750: void Video_Color14_WriteWord(void)
        !           751: {
        !           752:   Video_ColorReg_WriteWord(0xff825c);
        !           753: }
        !           754: 
        !           755: void Video_Color15_WriteWord(void)
        !           756: {
        !           757:   Video_ColorReg_WriteWord(0xff825e);
        !           758: }
        !           759: 
        !           760: 
        !           761: /*-----------------------------------------------------------------------*/
        !           762: /*
        !           763:   Write video shifter mode register (0xff860)
        !           764: */
        !           765: void Video_ShifterMode_WriteByte(void)
        !           766: {
        !           767:   if (!bUseHighRes && !bUseVDIRes)                    /* Don't store if hi-res and don't store if VDI resolution */
        !           768:   {
        !           769:     VideoShifterByte = IoMem[0xff8260] & 3;           /* We only care for lower 2-bits */
        !           770:     Video_WriteToShifter(VideoShifterByte);
        !           771:     Video_SetHBLPaletteMaskPointers();
        !           772:     *pHBLPaletteMasks &= 0xff00ffff;
        !           773:     /* Store resolution after palette mask and set resolution write bit: */
        !           774:     *pHBLPaletteMasks |= (((unsigned long)VideoShifterByte|0x04)<<16);
        !           775:   }
        !           776: }

unix.superglobalmegacorp.com

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