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

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

unix.superglobalmegacorp.com

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