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

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: 
                     15: #include "main.h"
                     16: #include "debug.h"
                     17: #include "decode.h"
                     18: #include "int.h"
                     19: #include "screen.h"
                     20: #include "spec512.h"
                     21: #include "video.h"
                     22: 
1.1.1.2 ! root       23: 
        !            24: CYCLEPALETTE CyclePalettes[(SCANLINES_PER_FRAME+1)*MAX_CYCLEPALETTES_PERLINE];  /* 314k; 1024-bytes per line */
1.1       root       25: CYCLEPALETTE *pCyclePalette;
1.1.1.2 ! root       26: int nCyclePalettes[(SCANLINES_PER_FRAME+1)];                  /* Number of entries in above table for each scanline */
        !            27: int nPalettesAccess[(SCANLINES_PER_FRAME+1)];                 /* Number of times accessed palette register 'x' in this scan line */
1.1       root       28: unsigned short int CycleColour;
                     29: int CycleColourIndex;
                     30: int nScanLine, ScanLineCycleCount;
                     31: BOOL bIsSpec512Display;
                     32: 
1.1.1.2 ! root       33: 
        !            34: /*-----------------------------------------------------------------------*/
1.1       root       35: /*
                     36:   Return TRUE if this frame is a Spectrum 512 style image(MUST be low res/non-mix)
                     37: */
                     38: BOOL Spec512_IsImage(void)
                     39: {
1.1.1.2 ! root       40:   /* Normal Low res screen? */
1.1       root       41:   if ( (STRes==ST_LOW_RES) && (bIsSpec512Display) )
                     42:     return(TRUE);
                     43: 
                     44:   return(FALSE);
                     45: }
                     46: 
1.1.1.2 ! root       47: 
        !            48: /*-----------------------------------------------------------------------*/
1.1       root       49: /*
                     50:   We store every palette access in a table to perform Spectrum 512 colour effects
                     51:   This is cleared on each VBL
                     52: */
                     53: void Spec512_StartVBL(void)
                     54: {
1.1.1.2 ! root       55:   /* Clear number of cycle palettes on each frame */
1.1       root       56:   memset(nCyclePalettes,0x0,(SCANLINES_PER_FRAME+1)*sizeof(int));
1.1.1.2 ! root       57:   /* Clear number of times accessed on entry in palette (used to check if is true Spectrum 512 image) */
1.1       root       58:   memset(nPalettesAccess,0x0,(SCANLINES_PER_FRAME+1)*sizeof(int));  
1.1.1.2 ! root       59:   /* Set as not Spectrum 512 displayed image */
1.1       root       60:   bIsSpec512Display = FALSE;
                     61: }
                     62: 
1.1.1.2 ! root       63: 
        !            64: /*-----------------------------------------------------------------------*/
1.1       root       65: /*
                     66:   Store 'bx' colour into 'CyclePalettes[]' according to cycles into frame
                     67:   Address is passed in 'ecx', eg 0xff8240
                     68: */
                     69: void Spec512_StoreCyclePalette_Execute(void)
                     70: {
                     71:   CYCLEPALETTE *pCyclePalette;
                     72:   int FrameCycles,ScanLine;
                     73: 
1.1.1.2 ! root       74:   /* Find number of cycles into frame */
1.1       root       75:   FrameCycles = Int_FindFrameCycles();
                     76: 
1.1.1.2 ! root       77:   /* Find scan line we are currently on and get index into cycle-palette table */
1.1       root       78:   ScanLine = (FrameCycles/CYCLES_PER_LINE);
                     79:   pCyclePalette = &CyclePalettes[ (ScanLine*MAX_CYCLEPALETTES_PERLINE) + nCyclePalettes[ScanLine] ];
1.1.1.2 ! root       80:   /* 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       81:   if (nCyclePalettes[ScanLine]>0) {
                     82:     if ((pCyclePalette-1)->LineCycles==(FrameCycles&511))
1.1.1.2 ! root       83:       FrameCycles += 4;              /* Colours are staggered by [4,20] when writing a long word! */
1.1       root       84:   }
                     85: 
1.1.1.2 ! root       86:   /* Store palette access */
        !            87:   pCyclePalette->LineCycles = FrameCycles&511;    /* Cycles into scanline */
        !            88:   pCyclePalette->Colour = CycleColour&0x777;      /* Store ST colour RGB */
        !            89:   pCyclePalette->Index = CycleColourIndex;        /* And Index (0...15) */
        !            90:   /* Increment count(this can never overflow as you cannot write to the palette more than 'MAX_CYCLEPALETTES_PERLINE' times per scanline) */
1.1       root       91:   nCyclePalettes[ScanLine]++;
                     92: 
1.1.1.2 ! root       93:   /* Check if program wrote to certain palette entry multiple times on a single scan-line  */
        !            94:   /* If we did then we must be using a Spectrum512 image or some kind of colour cycling... */
1.1       root       95:   nPalettesAccess[ScanLine]++;
                     96:   if (nPalettesAccess[ScanLine]>=32)
                     97:     bIsSpec512Display = TRUE;
                     98: }
                     99: 
                    100: void Spec512_StoreCyclePalette(unsigned short col, unsigned long addr)
                    101: {
                    102:   CycleColour = col;
                    103:   CycleColourIndex = (addr-0xff8240)>>1;
                    104:   Spec512_StoreCyclePalette_Execute();    /* Store it in table for screen conversion */
                    105: }
                    106: 
1.1.1.2 ! root      107: 
        !           108: /*-----------------------------------------------------------------------*/
1.1       root      109: /*
                    110:   Begin palette calculation for Spectrum 512 style images, 
                    111: */
                    112: void Spec512_StartFrame(void)
                    113: {
                    114:   int i;
                    115: 
1.1.1.2 ! root      116:   /* Set so screen gets full-update when returns from Spectrum 512 display */
1.1       root      117:   Screen_SetFullUpdate();
                    118: 
1.1.1.2 ! root      119:   /* Set terminators on each line, so when scan during conversion we know when to stop */
1.1       root      120:   for(i=0; i<(SCANLINES_PER_FRAME+1); i++) {
                    121:     pCyclePalette = &CyclePalettes[ (i*MAX_CYCLEPALETTES_PERLINE) + nCyclePalettes[i] ];
1.1.1.2 ! root      122:     pCyclePalette->LineCycles = -1;          /* Term */
1.1       root      123:   }
                    124: 
1.1.1.2 ! root      125:   /* Copy first line palette, kept in 'HBLPalettes' and store to 'STRGBPalette' */
1.1       root      126:   for(i=0; i<16; i++)
                    127:     STRGBPalette[i] = ST2RGB[HBLPalettes[i]&0x777];
                    128: 
1.1.1.2 ! root      129:   /* Ready for first call to 'Spec512_ScanLine' */
1.1       root      130:   nScanLine = 0;
                    131: 
1.1.1.2 ! root      132:   /* Skip to first line(where start to draw screen from) */
1.1       root      133:   for (i=0; i<(STScreenStartHorizLine+(nStartHBL-OVERSCAN_TOP)); i++)
                    134:     Spec512_ScanWholeLine();
                    135: }
                    136: 
1.1.1.2 ! root      137: 
        !           138: /*-----------------------------------------------------------------------*/
1.1       root      139: /*
                    140:   Scan whole line and build up palette - need to do this so when get to screen line we have
                    141:   the correct 16 colours set
                    142: */
                    143: void Spec512_ScanWholeLine(void)
                    144: {
1.1.1.2 ! root      145:   /* Store pointer to line of palette cycle writes */
1.1       root      146:   pCyclePalette = &CyclePalettes[nScanLine*MAX_CYCLEPALETTES_PERLINE];
1.1.1.2 ! root      147:   /* Ready for next scan line */
1.1       root      148:   nScanLine++;
                    149: 
1.1.1.2 ! root      150:   /* Update palette entries until we reach start of displayed screen */
1.1       root      151:   ScanLineCycleCount = 0;
1.1.1.2 ! root      152:   Spec512_EndScanLine();        /* Read whole line of palettes and update 'STRGBPalette' */
1.1       root      153: }
                    154: 
1.1.1.2 ! root      155: 
        !           156: /*-----------------------------------------------------------------------*/
1.1       root      157: /*
                    158:   Build up palette for this scan line and store in 'ScanLinePalettes'
                    159: */
                    160: void Spec512_StartScanLine(void)
                    161: {
                    162:   int i;
                    163: 
1.1.1.2 ! root      164:   /* Store pointer to line of palette cycle writes */
1.1       root      165:   pCyclePalette = &CyclePalettes[nScanLine*MAX_CYCLEPALETTES_PERLINE];
1.1.1.2 ! root      166:   /* Ready for next scan line */
1.1       root      167:   nScanLine++;
                    168: 
1.1.1.2 ! root      169:   /* Update palette entries until we reach start of displayed screen */
1.1       root      170:   ScanLineCycleCount = 0;
1.1.1.2 ! root      171:   for(i=0; i<((SCREEN_START_CYCLE-8)/4); i++)   /* This '8' is as we've already added in the 'move' instruction timing */
        !           172:     Spec512_UpdatePaletteSpan();                /* Update palette for this 4-cycle period */
        !           173:   /* And skip for left border is not using overscan display to user */
        !           174:   for (i=0; i<(STScreenLeftSkipBytes/2); i++)   /* Eg, 16 bytes = 32 pixels or 8 palette periods */
1.1       root      175:     Spec512_UpdatePaletteSpan();
                    176: }
                    177: 
1.1.1.2 ! root      178: 
        !           179: /*-----------------------------------------------------------------------*/
1.1       root      180: /*
                    181:   Run to end of scan line looking up palettes so 'STRGBPalette' is up-to-date
                    182: */
                    183: void Spec512_EndScanLine(void)
                    184: {
1.1.1.2 ! root      185:   /* Continue to reads palette until complete so have correct version for next line */
1.1       root      186:   while(ScanLineCycleCount<CYCLES_PER_LINE)
                    187:     Spec512_UpdatePaletteSpan();
                    188: }
                    189: 
1.1.1.2 ! root      190: 
        !           191: /*-----------------------------------------------------------------------*/
1.1       root      192: /*
                    193:   Update palette for 4-pixels span, storing to 'STRGBPalette'
                    194: */
                    195: void Spec512_UpdatePaletteSpan(void)
                    196: {
1.1.1.2 ! root      197:   if( pCyclePalette->LineCycles == ScanLineCycleCount )
        !           198:    {
        !           199:     /* Need to update palette with new entry */
        !           200:     STRGBPalette[pCyclePalette->Index] = ST2RGB[pCyclePalette->Colour&0x777];
        !           201:     pCyclePalette += 1;
        !           202:    }
1.1       root      203: /*
                    204:     mov    ebx,[pCyclePalette]
                    205:     mov    eax,[ebx]        // pCyclePalette->LineCycles
                    206:     cmp    eax,[ScanLineCycleCount]    // == ScanLineCycleCount?
                    207:     jne    no_cycle_match
                    208: 
                    209:     // Need to update palette with new entry
                    210:     mov    eax,4[ebx]        // pCyclePalette->Colour
                    211:     and    eax,0x777        // Colour&0x777
                    212:     mov    eax,ST2RGB[eax*4]      // Convert to PC's RGB
                    213:     movzx  ebx,WORD PTR 6[ebx]        // pCyclePalette->Index
                    214:     shl    ebx,2          // as 'long' index
                    215:     add    ebx,OFFSET [STRGBPalette]
                    216:     mov    [ebx],eax        // Store as long's for speed
                    217: 
                    218:     add    [pCyclePalette],8      // sizeof(CYCLEPALETTE)
                    219: 
                    220: no_cycle_match:
                    221:     add    [ScanLineCycleCount],4      // Next 4 cycles
                    222: */
1.1.1.2 ! root      223:   ScanLineCycleCount += 4;      /* Next 4 cycles */
1.1       root      224: }

unix.superglobalmegacorp.com

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