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

1.1       root        1: /*
1.1.1.7   root        2:   Hatari - spec512.c
1.1       root        3: 
1.1.1.7   root        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:   Handle storing of writes to ST palette using clock-cycle counts. We can use
                      8:   this to accurately any form of Spectrum512 style images - even down to the
                      9:   way the screen colours change on decompression routines in menus!
                     10: 
                     11:   As the 68000 has a 4-clock cycle increment we can only change palette every
                     12:   4 cycles. This means that on one scanline (512 cycles in 50Hz) we have just
                     13:   512/4=128 places where palette writes can take place. We keep track of this
                     14:   in a table (storing on each scanline and color writes and the cycles on the
                     15:   scanline where they happen). When we draw the screen we simply keep a
                     16:   cycle-count on the line and check this with our table and update the 16-color
                     17:   palette with each change. As the table is already ordered this makes things
                     18:   very simple. Speed is a problem, though, as the palette can change once every
                     19:   4 pixels - that's a lot of processing.
1.1       root       20: */
1.1.1.8 ! root       21: char Spec512_rcsid[] = "Hatari $Id: spec512.c,v 1.10 2005/07/30 09:07:18 eerot Exp $";
1.1       root       22: 
1.1.1.4   root       23: #include <SDL_byteorder.h>
                     24: 
1.1       root       25: #include "main.h"
                     26: #include "int.h"
                     27: #include "screen.h"
                     28: #include "spec512.h"
                     29: #include "video.h"
                     30: 
1.1.1.2   root       31: 
1.1.1.8 ! root       32: /* 314k; 1024-bytes per line */
        !            33: CYCLEPALETTE CyclePalettes[(SCANLINES_PER_FRAME+1)*MAX_CYCLEPALETTES_PERLINE];
1.1       root       34: CYCLEPALETTE *pCyclePalette;
1.1.1.8 ! root       35: int nCyclePalettes[(SCANLINES_PER_FRAME+1)];  /* Number of entries in above table for each scanline */
        !            36: int nPalettesAccess[(SCANLINES_PER_FRAME+1)]; /* Number of times accessed palette register 'x' in this scan line */
        !            37: static Uint16 CycleColour;
        !            38: static int CycleColourIndex;
        !            39: static int nScanLine, ScanLineCycleCount;
        !            40: static BOOL bIsSpec512Display;
        !            41: static int nb_spc512lines, last_spc512line;
1.1       root       42: 
1.1.1.4   root       43: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
                     44: static const int STRGBPalEndianTable[16] = {0,2,1,3,8,10,9,11,4,6,5,7,12,14,13,15};
                     45: #endif
                     46: 
1.1.1.2   root       47: 
                     48: /*-----------------------------------------------------------------------*/
1.1       root       49: /*
                     50:   Return TRUE if this frame is a Spectrum 512 style image(MUST be low res/non-mix)
                     51: */
                     52: BOOL Spec512_IsImage(void)
                     53: {
1.1.1.2   root       54:   /* Normal Low res screen? */
1.1       root       55:   if ( (STRes==ST_LOW_RES) && (bIsSpec512Display) )
                     56:     return(TRUE);
                     57: 
                     58:   return(FALSE);
                     59: }
                     60: 
1.1.1.2   root       61: 
                     62: /*-----------------------------------------------------------------------*/
1.1       root       63: /*
                     64:   We store every palette access in a table to perform Spectrum 512 colour effects
                     65:   This is cleared on each VBL
                     66: */
                     67: void Spec512_StartVBL(void)
                     68: {
1.1.1.2   root       69:   /* Clear number of cycle palettes on each frame */
1.1       root       70:   memset(nCyclePalettes,0x0,(SCANLINES_PER_FRAME+1)*sizeof(int));
1.1.1.2   root       71:   /* Clear number of times accessed on entry in palette (used to check if is true Spectrum 512 image) */
1.1.1.5   root       72:   memset(nPalettesAccess,0x0,(SCANLINES_PER_FRAME+1)*sizeof(int));
1.1.1.2   root       73:   /* Set as not Spectrum 512 displayed image */
1.1       root       74:   bIsSpec512Display = FALSE;
1.1.1.5   root       75:   last_spc512line = -1;
                     76:   nb_spc512lines = 0;
1.1       root       77: }
                     78: 
1.1.1.2   root       79: 
                     80: /*-----------------------------------------------------------------------*/
1.1       root       81: /*
1.1.1.4   root       82:   Store color into table 'CyclePalettes[]' for screen conversion according
                     83:   to cycles into frame.
1.1       root       84: */
1.1.1.8 ! root       85: void Spec512_StoreCyclePalette(Uint16 col, Uint32 addr)
1.1       root       86: {
1.1.1.7   root       87:   CYCLEPALETTE *pTmpCyclePalette;
                     88:   int FrameCycles, ScanLine;
1.1       root       89: 
1.1.1.4   root       90:   CycleColour = col;
                     91:   CycleColourIndex = (addr-0xff8240)>>1;
                     92: 
1.1.1.2   root       93:   /* Find number of cycles into frame */
1.1       root       94:   FrameCycles = Int_FindFrameCycles();
                     95: 
1.1.1.2   root       96:   /* Find scan line we are currently on and get index into cycle-palette table */
1.1       root       97:   ScanLine = (FrameCycles/CYCLES_PER_LINE);
1.1.1.7   root       98:   pTmpCyclePalette = &CyclePalettes[ (ScanLine*MAX_CYCLEPALETTES_PERLINE) + nCyclePalettes[ScanLine] ];
1.1.1.2   root       99:   /* Do we have a previous entry at the same cycles? If so, 68000 have used a 'move.l' instruction so stagger writes */
1.1.1.7   root      100:   if (nCyclePalettes[ScanLine]>0)
                    101:   {
                    102:     if ((pTmpCyclePalette-1)->LineCycles == (FrameCycles % CYCLES_PER_LINE))
                    103:       FrameCycles += 4;              /* Colors are staggered by [4,20] when writing a long word! */
1.1       root      104:   }
                    105: 
1.1.1.2   root      106:   /* Store palette access */
1.1.1.7   root      107:   pTmpCyclePalette->LineCycles = FrameCycles % CYCLES_PER_LINE;  /* Cycles into scanline */
1.1.1.8 ! root      108:   pTmpCyclePalette->Colour = CycleColour;                        /* Store ST/STe colour RGB */
1.1.1.7   root      109:   pTmpCyclePalette->Index = CycleColourIndex;                    /* And Index (0...15) */
1.1.1.2   root      110:   /* Increment count(this can never overflow as you cannot write to the palette more than 'MAX_CYCLEPALETTES_PERLINE' times per scanline) */
1.1       root      111:   nCyclePalettes[ScanLine]++;
                    112: 
1.1.1.2   root      113:   /* Check if program wrote to certain palette entry multiple times on a single scan-line  */
                    114:   /* If we did then we must be using a Spectrum512 image or some kind of colour cycling... */
1.1       root      115:   nPalettesAccess[ScanLine]++;
1.1.1.7   root      116:   if (nPalettesAccess[ScanLine]>=32)
                    117:   {
1.1.1.5   root      118:     /* This code has obviously something wrong. It detects the grav44 disk
1.1.1.7   root      119:        demo as a spec512 image because the scroller at the bottom of the screen
1.1.1.5   root      120:        uses more than 1 palette... But doing so, it ruins the colours of the
                    121:        rest of the screen. I should review all this code, but later.
1.1.1.7   root      122:        For now, I just make sure it chooses this mode only when most of the
                    123:        screen is a spec512 screen (at least 80 lines) ! */
                    124:     if (last_spc512line != ScanLine)
                    125:     {
1.1.1.5   root      126:       last_spc512line = ScanLine;
                    127:       nb_spc512lines++;
1.1.1.7   root      128:       if (nb_spc512lines >= 80)
                    129:         bIsSpec512Display = TRUE;
1.1.1.5   root      130:     }
                    131:   }
1.1       root      132: }
                    133: 
1.1.1.2   root      134: 
                    135: /*-----------------------------------------------------------------------*/
1.1       root      136: /*
1.1.1.5   root      137:   Begin palette calculation for Spectrum 512 style images,
1.1       root      138: */
                    139: void Spec512_StartFrame(void)
                    140: {
                    141:   int i;
                    142: 
1.1.1.2   root      143:   /* Set so screen gets full-update when returns from Spectrum 512 display */
1.1       root      144:   Screen_SetFullUpdate();
                    145: 
1.1.1.2   root      146:   /* Set terminators on each line, so when scan during conversion we know when to stop */
1.1.1.4   root      147:   for(i=0; i<(SCANLINES_PER_FRAME+1); i++)
                    148:   {
1.1       root      149:     pCyclePalette = &CyclePalettes[ (i*MAX_CYCLEPALETTES_PERLINE) + nCyclePalettes[i] ];
1.1.1.2   root      150:     pCyclePalette->LineCycles = -1;          /* Term */
1.1       root      151:   }
                    152: 
1.1.1.2   root      153:   /* Copy first line palette, kept in 'HBLPalettes' and store to 'STRGBPalette' */
1.1       root      154:   for(i=0; i<16; i++)
1.1.1.4   root      155:   {
                    156: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1.1.1.8 ! root      157:     STRGBPalette[STRGBPalEndianTable[i]] = ST2RGB[pHBLPalettes[i]];
1.1.1.4   root      158: #else
1.1.1.8 ! root      159:     STRGBPalette[i] = ST2RGB[pHBLPalettes[i]];
1.1.1.4   root      160: #endif
                    161:   }
1.1       root      162: 
1.1.1.2   root      163:   /* Ready for first call to 'Spec512_ScanLine' */
1.1       root      164:   nScanLine = 0;
1.1.1.5   root      165:   if (OverscanMode & OVERSCANMODE_TOP)
                    166:     nScanLine += OVERSCAN_TOP;
1.1       root      167: 
1.1.1.2   root      168:   /* Skip to first line(where start to draw screen from) */
1.1       root      169:   for (i=0; i<(STScreenStartHorizLine+(nStartHBL-OVERSCAN_TOP)); i++)
                    170:     Spec512_ScanWholeLine();
                    171: }
                    172: 
1.1.1.2   root      173: 
                    174: /*-----------------------------------------------------------------------*/
1.1       root      175: /*
                    176:   Scan whole line and build up palette - need to do this so when get to screen line we have
                    177:   the correct 16 colours set
                    178: */
                    179: void Spec512_ScanWholeLine(void)
                    180: {
1.1.1.2   root      181:   /* Store pointer to line of palette cycle writes */
1.1       root      182:   pCyclePalette = &CyclePalettes[nScanLine*MAX_CYCLEPALETTES_PERLINE];
1.1.1.2   root      183:   /* Ready for next scan line */
1.1       root      184:   nScanLine++;
                    185: 
1.1.1.2   root      186:   /* Update palette entries until we reach start of displayed screen */
1.1       root      187:   ScanLineCycleCount = 0;
1.1.1.2   root      188:   Spec512_EndScanLine();        /* Read whole line of palettes and update 'STRGBPalette' */
1.1       root      189: }
                    190: 
1.1.1.2   root      191: 
                    192: /*-----------------------------------------------------------------------*/
1.1       root      193: /*
                    194:   Build up palette for this scan line and store in 'ScanLinePalettes'
                    195: */
                    196: void Spec512_StartScanLine(void)
                    197: {
                    198:   int i;
                    199: 
1.1.1.2   root      200:   /* Store pointer to line of palette cycle writes */
1.1       root      201:   pCyclePalette = &CyclePalettes[nScanLine*MAX_CYCLEPALETTES_PERLINE];
1.1.1.2   root      202:   /* Ready for next scan line */
1.1       root      203:   nScanLine++;
                    204: 
1.1.1.2   root      205:   /* Update palette entries until we reach start of displayed screen */
1.1       root      206:   ScanLineCycleCount = 0;
1.1.1.2   root      207:   for(i=0; i<((SCREEN_START_CYCLE-8)/4); i++)   /* This '8' is as we've already added in the 'move' instruction timing */
                    208:     Spec512_UpdatePaletteSpan();                /* Update palette for this 4-cycle period */
                    209:   /* And skip for left border is not using overscan display to user */
                    210:   for (i=0; i<(STScreenLeftSkipBytes/2); i++)   /* Eg, 16 bytes = 32 pixels or 8 palette periods */
1.1       root      211:     Spec512_UpdatePaletteSpan();
                    212: }
                    213: 
1.1.1.2   root      214: 
                    215: /*-----------------------------------------------------------------------*/
1.1       root      216: /*
                    217:   Run to end of scan line looking up palettes so 'STRGBPalette' is up-to-date
                    218: */
                    219: void Spec512_EndScanLine(void)
                    220: {
1.1.1.2   root      221:   /* Continue to reads palette until complete so have correct version for next line */
1.1       root      222:   while(ScanLineCycleCount<CYCLES_PER_LINE)
                    223:     Spec512_UpdatePaletteSpan();
                    224: }
                    225: 
1.1.1.2   root      226: 
                    227: /*-----------------------------------------------------------------------*/
1.1       root      228: /*
                    229:   Update palette for 4-pixels span, storing to 'STRGBPalette'
                    230: */
                    231: void Spec512_UpdatePaletteSpan(void)
                    232: {
1.1.1.2   root      233:   if( pCyclePalette->LineCycles == ScanLineCycleCount )
                    234:    {
                    235:     /* Need to update palette with new entry */
1.1.1.4   root      236: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
1.1.1.8 ! root      237:     STRGBPalette[STRGBPalEndianTable[pCyclePalette->Index]] = ST2RGB[pCyclePalette->Colour];
1.1.1.4   root      238: #else
1.1.1.8 ! root      239:     STRGBPalette[pCyclePalette->Index] = ST2RGB[pCyclePalette->Colour];
1.1.1.4   root      240: #endif
1.1.1.2   root      241:     pCyclePalette += 1;
                    242:    }
                    243:   ScanLineCycleCount += 4;      /* Next 4 cycles */
1.1       root      244: }

unix.superglobalmegacorp.com

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