a1842c04f9
With LCD driver all calculation will be performed on RGB888 and the hardware/OS can display from our 24bit framebuffer. It is not yet as performance optimized as the existing drivers but should be good enough.The vast number of small changes is due to the fact that fb_data can be a struct type now, while most of the code expected a scalar type. lcd-as-memframe ASM code does not work with 24bit currently so the with 24bit it enforces the generic C code. All plugins are ported over. Except for rockpaint. It uses so much memory that it wouldnt fit into the 512k plugin buffer anymore (patches welcome). Change-Id: Ibb1964545028ce0d8ff9833ccc3ab66be3ee0754
1257 lines
32 KiB
C
1257 lines
32 KiB
C
#include "rockmacros.h"
|
|
#include "defs.h"
|
|
#include "regs.h"
|
|
#include "hw.h"
|
|
#include "mem.h"
|
|
#include "lcd-gb.h"
|
|
#include "fb.h"
|
|
#ifdef HAVE_LCD_COLOR
|
|
#include "palette-presets.h"
|
|
#endif
|
|
#ifdef USE_ASM
|
|
#include "asm.h"
|
|
#endif
|
|
|
|
struct lcd lcd;
|
|
|
|
struct scan scan IBSS_ATTR;
|
|
|
|
#define BG (scan.bg)
|
|
#define WND (scan.wnd)
|
|
|
|
#if LCD_DEPTH >= 16
|
|
#define BUF (scan.buf)
|
|
#else
|
|
#define BUF (scan.buf[scanline_ind])
|
|
#endif
|
|
|
|
#define PRI (scan.pri)
|
|
|
|
#define PAL (scan.pal)
|
|
|
|
#define VS (scan.vs) /* vissprites */
|
|
#define NS (scan.ns)
|
|
|
|
#define L (scan.l) /* line */
|
|
#define X (scan.x) /* screen position */
|
|
#define Y (scan.y)
|
|
#define S (scan.s) /* tilemap position */
|
|
#define T (scan.t)
|
|
#define U (scan.u) /* position within tile */
|
|
#define V (scan.v)
|
|
#define WX (scan.wx)
|
|
#define WY (scan.wy)
|
|
#define WT (scan.wt)
|
|
#define WV (scan.wv)
|
|
|
|
byte patpix[4096][8][8]
|
|
#if defined(CPU_COLDFIRE)
|
|
__attribute__ ((aligned(16))) /* to profit from burst mode */
|
|
#endif
|
|
;
|
|
byte patdirty[1024];
|
|
byte anydirty;
|
|
|
|
#if LCD_DEPTH < 16
|
|
static int scanline_ind=0;
|
|
#endif
|
|
|
|
static int dmg_pal[4][4];
|
|
|
|
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
|
|
unsigned char *vdest;
|
|
#else
|
|
fb_data *vdest;
|
|
#endif
|
|
|
|
#ifndef ASM_UPDATEPATPIX
|
|
static void updatepatpix(void) ICODE_ATTR;
|
|
static void updatepatpix(void)
|
|
{
|
|
int i, j;
|
|
#if ((CONFIG_CPU != SH7034) && !defined(CPU_COLDFIRE))
|
|
int k, a, c;
|
|
#endif
|
|
byte *vram = lcd.vbank[0];
|
|
|
|
if (!anydirty) return;
|
|
for (i = 0; i < 1024; i++)
|
|
{
|
|
if (i == 384) i = 512;
|
|
if (i == 896) break;
|
|
if (!patdirty[i]) continue;
|
|
patdirty[i] = 0;
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
#if CONFIG_CPU == SH7034
|
|
asm volatile (
|
|
"mov.w @%2,r1 \n"
|
|
"swap.b r1,r2 \n"
|
|
|
|
"mov #0,r0 \n"
|
|
"shlr r1 \n"
|
|
"rotcl r0 \n"
|
|
"shlr r2 \n"
|
|
"rotcl r0 \n"
|
|
"mov.b r0,@%0 \n"
|
|
"mov.b r0,@(7,%1) \n"
|
|
"mov #0,r0 \n"
|
|
"shlr r1 \n"
|
|
"rotcl r0 \n"
|
|
"shlr r2 \n"
|
|
"rotcl r0 \n"
|
|
"mov.b r0,@(1,%0) \n"
|
|
"mov.b r0,@(6,%1) \n"
|
|
"mov #0,r0 \n"
|
|
"shlr r1 \n"
|
|
"rotcl r0 \n"
|
|
"shlr r2 \n"
|
|
"rotcl r0 \n"
|
|
"mov.b r0,@(2,%0) \n"
|
|
"mov.b r0,@(5,%1) \n"
|
|
"mov #0,r0 \n"
|
|
"shlr r1 \n"
|
|
"rotcl r0 \n"
|
|
"shlr r2 \n"
|
|
"rotcl r0 \n"
|
|
"mov.b r0,@(3,%0) \n"
|
|
"mov.b r0,@(4,%1) \n"
|
|
"mov #0,r0 \n"
|
|
"shlr r1 \n"
|
|
"rotcl r0 \n"
|
|
"shlr r2 \n"
|
|
"rotcl r0 \n"
|
|
"mov.b r0,@(4,%0) \n"
|
|
"mov.b r0,@(3,%1) \n"
|
|
"mov #0,r0 \n"
|
|
"shlr r1 \n"
|
|
"rotcl r0 \n"
|
|
"shlr r2 \n"
|
|
"rotcl r0 \n"
|
|
"mov.b r0,@(5,%0) \n"
|
|
"mov.b r0,@(2,%1) \n"
|
|
"mov #0,r0 \n"
|
|
"shlr r1 \n"
|
|
"rotcl r0 \n"
|
|
"shlr r2 \n"
|
|
"rotcl r0 \n"
|
|
"mov.b r0,@(6,%0) \n"
|
|
"mov.b r0,@(1,%1) \n"
|
|
"mov #0,r0 \n"
|
|
"shlr r1 \n"
|
|
"rotcl r0 \n"
|
|
"shlr r2 \n"
|
|
"rotcl r0 \n"
|
|
"mov.b r0,@(7,%0) \n"
|
|
"mov.b r0,@%1 \n"
|
|
: /* outputs */
|
|
: /* inputs */
|
|
/* %0 */ "r"(patpix[i+1024][j]),
|
|
/* %1 */ "r"(patpix[i][j]),
|
|
/* %2 */ "r"(&vram[(i<<4)|(j<<1)])
|
|
: /* clobbers */
|
|
"r0", "r1", "r2"
|
|
);
|
|
#elif defined(CPU_COLDFIRE)
|
|
asm volatile (
|
|
"move.b (%2),%%d2 \n"
|
|
"move.b (1,%2),%%d1 \n"
|
|
|
|
"addq.l #8,%1 \n"
|
|
"clr.l %%d0 \n"
|
|
"lsr.l #1,%%d1 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"lsr.l #1,%%d2 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"move.b %%d0,-(%1) \n"
|
|
"lsl.l #6,%%d0 \n"
|
|
"lsr.l #1,%%d1 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"lsr.l #1,%%d2 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"move.b %%d0,-(%1) \n"
|
|
"lsl.l #6,%%d0 \n"
|
|
"lsr.l #1,%%d1 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"lsr.l #1,%%d2 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"move.b %%d0,-(%1) \n"
|
|
"lsl.l #6,%%d0 \n"
|
|
"lsr.l #1,%%d1 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"lsr.l #1,%%d2 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"move.l %%d0,(%0) \n"
|
|
"move.b %%d0,-(%1) \n"
|
|
"clr.l %%d0 \n"
|
|
"lsr.l #1,%%d1 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"lsr.l #1,%%d2 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"move.b %%d0,-(%1) \n"
|
|
"lsl.l #6,%%d0 \n"
|
|
"lsr.l #1,%%d1 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"lsr.l #1,%%d2 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"move.b %%d0,-(%1) \n"
|
|
"lsl.l #6,%%d0 \n"
|
|
"lsr.l #1,%%d1 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"lsr.l #1,%%d2 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"move.b %%d0,-(%1) \n"
|
|
"lsl.l #6,%%d0 \n"
|
|
"lsr.l #1,%%d1 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"lsr.l #1,%%d2 \n"
|
|
"addx.l %%d0,%%d0 \n"
|
|
"move.l %%d0,(4,%0) \n"
|
|
"move.b %%d0,-(%1) \n"
|
|
: /* outputs */
|
|
: /* inputs */
|
|
/* %0 */ "a"(patpix[i+1024][j]),
|
|
/* %1 */ "a"(patpix[i][j]),
|
|
/* %2 */ "a"(&vram[(i<<4)|(j<<1)])
|
|
: /* clobbers */
|
|
"d0", "d1", "d2"
|
|
);
|
|
#else
|
|
a = ((i<<4) | (j<<1));
|
|
for (k = 0; k < 8; k++)
|
|
{
|
|
c = vram[a] & BIT_N(k) ? 1 : 0;
|
|
c |= vram[a+1] & BIT_N(k) ? 2 : 0;
|
|
patpix[i+1024][j][k] = c;
|
|
}
|
|
for (k = 0; k < 8; k++)
|
|
patpix[i][j][k] =
|
|
patpix[i+1024][j][7-k];
|
|
#endif
|
|
}
|
|
#if CONFIG_CPU == SH7034
|
|
asm volatile (
|
|
"mov.l @%0,r0 \n"
|
|
"mov.l @(4,%0),r1 \n"
|
|
"mov.l r0,@(56,%1) \n"
|
|
"mov.l r1,@(60,%1) \n"
|
|
"mov.l @(8,%0),r0 \n"
|
|
"mov.l @(12,%0),r1 \n"
|
|
"mov.l r0,@(48,%1) \n"
|
|
"mov.l r1,@(52,%1) \n"
|
|
"mov.l @(16,%0),r0 \n"
|
|
"mov.l @(20,%0),r1 \n"
|
|
"mov.l r0,@(40,%1) \n"
|
|
"mov.l r1,@(44,%1) \n"
|
|
"mov.l @(24,%0),r0 \n"
|
|
"mov.l @(28,%0),r1 \n"
|
|
"mov.l r0,@(32,%1) \n"
|
|
"mov.l r1,@(36,%1) \n"
|
|
"mov.l @(32,%0),r0 \n"
|
|
"mov.l @(36,%0),r1 \n"
|
|
"mov.l r0,@(24,%1) \n"
|
|
"mov.l r1,@(28,%1) \n"
|
|
"mov.l @(40,%0),r0 \n"
|
|
"mov.l @(44,%0),r1 \n"
|
|
"mov.l r0,@(16,%1) \n"
|
|
"mov.l r1,@(20,%1) \n"
|
|
"mov.l @(48,%0),r0 \n"
|
|
"mov.l @(52,%0),r1 \n"
|
|
"mov.l r0,@(8,%1) \n"
|
|
"mov.l r1,@(12,%1) \n"
|
|
"mov.l @(56,%0),r0 \n"
|
|
"mov.l @(60,%0),r1 \n"
|
|
"mov.l r0,@%1 \n"
|
|
"mov.l r1,@(4,%1) \n"
|
|
|
|
"add %2,%0 \n"
|
|
"add %2,%1 \n"
|
|
|
|
"mov.l @%0,r0 \n"
|
|
"mov.l @(4,%0),r1 \n"
|
|
"mov.l r0,@(56,%1) \n"
|
|
"mov.l r1,@(60,%1) \n"
|
|
"mov.l @(8,%0),r0 \n"
|
|
"mov.l @(12,%0),r1 \n"
|
|
"mov.l r0,@(48,%1) \n"
|
|
"mov.l r1,@(52,%1) \n"
|
|
"mov.l @(16,%0),r0 \n"
|
|
"mov.l @(20,%0),r1 \n"
|
|
"mov.l r0,@(40,%1) \n"
|
|
"mov.l r1,@(44,%1) \n"
|
|
"mov.l @(24,%0),r0 \n"
|
|
"mov.l @(28,%0),r1 \n"
|
|
"mov.l r0,@(32,%1) \n"
|
|
"mov.l r1,@(36,%1) \n"
|
|
"mov.l @(32,%0),r0 \n"
|
|
"mov.l @(36,%0),r1 \n"
|
|
"mov.l r0,@(24,%1) \n"
|
|
"mov.l r1,@(28,%1) \n"
|
|
"mov.l @(40,%0),r0 \n"
|
|
"mov.l @(44,%0),r1 \n"
|
|
"mov.l r0,@(16,%1) \n"
|
|
"mov.l r1,@(20,%1) \n"
|
|
"mov.l @(48,%0),r0 \n"
|
|
"mov.l @(52,%0),r1 \n"
|
|
"mov.l r0,@(8,%1) \n"
|
|
"mov.l r1,@(12,%1) \n"
|
|
"mov.l @(56,%0),r0 \n"
|
|
"mov.l @(60,%0),r1 \n"
|
|
"mov.l r0,@%1 \n"
|
|
"mov.l r1,@(4,%1) \n"
|
|
: /* outputs */
|
|
: /* inputs */
|
|
/* %0 */ "r"(patpix[i][0]),
|
|
/* %1 */ "r"(patpix[i+2048][0]),
|
|
/* %2 */ "r"(1024*64)
|
|
: /* clobbers */
|
|
"r0", "r1"
|
|
);
|
|
#elif defined(CPU_COLDFIRE)
|
|
asm volatile (
|
|
"movem.l (%0),%%d0-%%d3 \n"
|
|
"move.l %%d0,%%d4 \n"
|
|
"move.l %%d1,%%d5 \n"
|
|
"movem.l %%d2-%%d5,(48,%1) \n"
|
|
"movem.l (16,%0),%%d0-%%d3 \n"
|
|
"move.l %%d0,%%d4 \n"
|
|
"move.l %%d1,%%d5 \n"
|
|
"movem.l %%d2-%%d5,(32,%1) \n"
|
|
"movem.l (32,%0),%%d0-%%d3 \n"
|
|
"move.l %%d0,%%d4 \n"
|
|
"move.l %%d1,%%d5 \n"
|
|
"movem.l %%d2-%%d5,(16,%1) \n"
|
|
"movem.l (48,%0),%%d0-%%d3 \n"
|
|
"move.l %%d0,%%d4 \n"
|
|
"move.l %%d1,%%d5 \n"
|
|
"movem.l %%d2-%%d5,(%1) \n"
|
|
|
|
"move.l %2,%%d0 \n"
|
|
"add.l %%d0,%0 \n"
|
|
"add.l %%d0,%1 \n"
|
|
|
|
"movem.l (%0),%%d0-%%d3 \n"
|
|
"move.l %%d0,%%d4 \n"
|
|
"move.l %%d1,%%d5 \n"
|
|
"movem.l %%d2-%%d5,(48,%1) \n"
|
|
"movem.l (16,%0),%%d0-%%d3 \n"
|
|
"move.l %%d0,%%d4 \n"
|
|
"move.l %%d1,%%d5 \n"
|
|
"movem.l %%d2-%%d5,(32,%1) \n"
|
|
"movem.l (32,%0),%%d0-%%d3 \n"
|
|
"move.l %%d0,%%d4 \n"
|
|
"move.l %%d1,%%d5 \n"
|
|
"movem.l %%d2-%%d5,(16,%1) \n"
|
|
"movem.l (48,%0),%%d0-%%d3 \n"
|
|
"move.l %%d0,%%d4 \n"
|
|
"move.l %%d1,%%d5 \n"
|
|
"movem.l %%d2-%%d5,(%1) \n"
|
|
: /* outputs */
|
|
: /* inputs */
|
|
/* %0 */ "a"(patpix[i][0]),
|
|
/* %1 */ "a"(patpix[i+2048][0]),
|
|
/* %2 */ "i"(1024*64)
|
|
: /* clobbers */
|
|
"d0", "d1", "d2", "d3", "d4", "d5"
|
|
);
|
|
#else
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
for (k = 0; k < 8; k++)
|
|
{
|
|
patpix[i+2048][j][k] =
|
|
patpix[i][7-j][k];
|
|
patpix[i+3072][j][k] =
|
|
patpix[i+1024][7-j][k];
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
anydirty = 0;
|
|
}
|
|
#endif /* ASM_UPDATEPATPIX */
|
|
|
|
|
|
|
|
static void tilebuf(void) ICODE_ATTR;
|
|
static void tilebuf(void)
|
|
{
|
|
int i, cnt;
|
|
int base;
|
|
byte *tilemap, *attrmap;
|
|
int *tilebuf;
|
|
int *wrap;
|
|
static int wraptable[64] =
|
|
{
|
|
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,-32
|
|
};
|
|
|
|
base = ((R_LCDC&0x08)?0x1C00:0x1800) + (T<<5) + S;
|
|
tilemap = lcd.vbank[0] + base;
|
|
attrmap = lcd.vbank[1] + base;
|
|
tilebuf = BG;
|
|
wrap = wraptable + S;
|
|
cnt = ((WX + 7) >> 3) + 1;
|
|
|
|
if (hw.cgb) {
|
|
if (R_LCDC & 0x10)
|
|
for (i = cnt; i > 0; i--)
|
|
{
|
|
*(tilebuf++) = *tilemap
|
|
| (((int)*attrmap & 0x08) << 6)
|
|
| (((int)*attrmap & 0x60) << 5);
|
|
*(tilebuf++) = (((int)*attrmap & 0x07) << 2);
|
|
attrmap += *wrap + 1;
|
|
tilemap += *(wrap++) + 1;
|
|
}
|
|
else
|
|
for (i = cnt; i > 0; i--)
|
|
{
|
|
*(tilebuf++) = (256 + ((n8)*tilemap))
|
|
| (((int)*attrmap & 0x08) << 6)
|
|
| (((int)*attrmap & 0x60) << 5);
|
|
*(tilebuf++) = (((int)*attrmap & 0x07) << 2);
|
|
attrmap += *wrap + 1;
|
|
tilemap += *(wrap++) + 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (R_LCDC & 0x10)
|
|
for (i = cnt; i > 0; i--)
|
|
{
|
|
*(tilebuf++) = *(tilemap++);
|
|
tilemap += *(wrap++);
|
|
}
|
|
else
|
|
for (i = cnt; i > 0; i--)
|
|
{
|
|
*(tilebuf++) = (256 + ((n8)*(tilemap++)));
|
|
tilemap += *(wrap++);
|
|
}
|
|
}
|
|
|
|
if (WX >= 160) return;
|
|
|
|
base = ((R_LCDC&0x40)?0x1C00:0x1800) + (WT<<5);
|
|
tilemap = lcd.vbank[0] + base;
|
|
attrmap = lcd.vbank[1] + base;
|
|
tilebuf = WND;
|
|
cnt = ((160 - WX) >> 3) + 1;
|
|
|
|
if (hw.cgb)
|
|
{
|
|
if (R_LCDC & 0x10)
|
|
for (i = cnt; i > 0; i--)
|
|
{
|
|
*(tilebuf++) = *(tilemap++)
|
|
| (((int)*attrmap & 0x08) << 6)
|
|
| (((int)*attrmap & 0x60) << 5);
|
|
*(tilebuf++) = (((int)*(attrmap++)&7) << 2);
|
|
}
|
|
else
|
|
for (i = cnt; i > 0; i--)
|
|
{
|
|
*(tilebuf++) = (256 + ((n8)*(tilemap++)))
|
|
| (((int)*attrmap & 0x08) << 6)
|
|
| (((int)*attrmap & 0x60) << 5);
|
|
*(tilebuf++) = (((int)*(attrmap++)&7) << 2);
|
|
}
|
|
}
|
|
else
|
|
|
|
{
|
|
if (R_LCDC & 0x10)
|
|
for (i = cnt; i > 0; i--)
|
|
*(tilebuf++) = *(tilemap++);
|
|
else
|
|
for (i = cnt; i > 0; i--)
|
|
*(tilebuf++) = (256 + ((n8)*(tilemap++)));
|
|
}
|
|
}
|
|
|
|
|
|
/* V = vertical line
|
|
* WX = WND start (if 0, no need to do anything) -> WY
|
|
* U = start...something...thingy... 7 at most
|
|
*/
|
|
static void bg_scan(void) ICODE_ATTR;
|
|
static void bg_scan(void)
|
|
{
|
|
int cnt;
|
|
byte *src, *dest;
|
|
int *tile;
|
|
|
|
if (WX <= 0) return;
|
|
cnt = WX;
|
|
tile = BG;
|
|
dest = BUF;
|
|
|
|
src = patpix[*(tile++)][V] + U;
|
|
memcpy(dest, src, 8-U);
|
|
dest += 8-U;
|
|
cnt -= 8-U;
|
|
if (cnt <= 0) return;
|
|
while (cnt >= 8)
|
|
{
|
|
#if defined(CPU_COLDFIRE)
|
|
asm volatile (
|
|
"move.l (%1)+,(%0)+ \n"
|
|
"move.l (%1)+,(%0)+ \n"
|
|
: /*outputs*/
|
|
: /*inputs*/
|
|
/* %0 */ "a" (dest),
|
|
/* %1 */ "a" (patpix[*(tile++)][V])
|
|
//: /* clobbers */
|
|
);
|
|
#else
|
|
src = patpix[*(tile++)][V];
|
|
memcpy(dest,src,8);
|
|
dest += 8;
|
|
#endif
|
|
cnt -= 8;
|
|
}
|
|
src = patpix[*tile][V];
|
|
while (cnt--)
|
|
*(dest++) = *(src++);
|
|
}
|
|
|
|
static void wnd_scan(void) ICODE_ATTR;
|
|
static void wnd_scan(void)
|
|
{
|
|
int cnt;
|
|
byte *src, *dest;
|
|
int *tile;
|
|
|
|
if (WX >= 160) return;
|
|
cnt = 160 - WX;
|
|
tile = WND;
|
|
dest = BUF + WX;
|
|
|
|
while (cnt >= 8)
|
|
{
|
|
#if defined(CPU_COLDFIRE)
|
|
asm volatile (
|
|
"move.l (%1)+,(%0)+ \n"
|
|
"move.l (%1)+,(%0)+ \n"
|
|
: /*outputs*/
|
|
: /*inputs*/
|
|
/* %0 */ "a" (dest),
|
|
/* %1 */ "a" (patpix[*(tile++)][WV])
|
|
//: /* clobbers */
|
|
);
|
|
#else
|
|
src = patpix[*(tile++)][WV];
|
|
memcpy(dest,src,8);
|
|
dest += 8;
|
|
#endif
|
|
cnt -= 8;
|
|
}
|
|
src = patpix[*tile][WV];
|
|
while (cnt--)
|
|
*(dest++) = *(src++);
|
|
}
|
|
|
|
static void blendcpy(byte *dest, byte *src, byte b, int cnt)
|
|
{
|
|
while (cnt--) *(dest++) = *(src++) | b;
|
|
}
|
|
|
|
static int priused(void *attr)
|
|
{
|
|
un32 *a = attr;
|
|
return (int)((a[0]|a[1]|a[2]|a[3]|a[4]|a[5]|a[6]|a[7])&0x80808080);
|
|
}
|
|
|
|
static void bg_scan_pri(void) ICODE_ATTR;
|
|
static void bg_scan_pri(void)
|
|
{
|
|
int cnt, i;
|
|
byte *src, *dest;
|
|
|
|
if (WX <= 0) return;
|
|
i = S;
|
|
cnt = WX;
|
|
dest = PRI;
|
|
src = lcd.vbank[1] + ((R_LCDC&0x08)?0x1C00:0x1800) + (T<<5);
|
|
|
|
if (!priused(src))
|
|
{
|
|
memset(dest, 0, cnt);
|
|
return;
|
|
}
|
|
|
|
memset(dest, src[i++&31]&128, 8-U);
|
|
dest += 8-U;
|
|
cnt -= 8-U;
|
|
if (cnt <= 0) return;
|
|
while (cnt >= 8)
|
|
{
|
|
memset(dest, src[i++&31]&128, 8);
|
|
dest += 8;
|
|
cnt -= 8;
|
|
}
|
|
memset(dest, src[i&31]&128, cnt);
|
|
}
|
|
|
|
static void wnd_scan_pri(void) ICODE_ATTR;
|
|
static void wnd_scan_pri(void)
|
|
{
|
|
int cnt, i;
|
|
byte *src, *dest;
|
|
|
|
if (WX >= 160) return;
|
|
i = 0;
|
|
cnt = 160 - WX;
|
|
dest = PRI + WX;
|
|
src = lcd.vbank[1] + ((R_LCDC&0x40)?0x1C00:0x1800) + (WT<<5);
|
|
|
|
if (!priused(src))
|
|
{
|
|
memset(dest, 0, cnt);
|
|
return;
|
|
}
|
|
|
|
while (cnt >= 8)
|
|
{
|
|
memset(dest, src[i++]&128, 8);
|
|
dest += 8;
|
|
cnt -= 8;
|
|
}
|
|
memset(dest, src[i]&128, cnt);
|
|
}
|
|
|
|
static void bg_scan_color(void)
|
|
{
|
|
int cnt;
|
|
byte *src, *dest;
|
|
int *tile;
|
|
|
|
if (WX <= 0) return;
|
|
cnt = WX;
|
|
tile = BG;
|
|
dest = BUF;
|
|
|
|
src = patpix[*(tile++)][V] + U;
|
|
blendcpy(dest, src, *(tile++), 8-U);
|
|
dest += 8-U;
|
|
cnt -= 8-U;
|
|
if (cnt <= 0) return;
|
|
while (cnt >= 8)
|
|
{
|
|
src = patpix[*(tile++)][V];
|
|
#if defined(CPU_COLDFIRE)
|
|
asm volatile (
|
|
"move.l (%2)+,%%d1 \n"
|
|
|
|
"move.b %%d1,%%d2 \n"
|
|
|
|
"move.b (%1)+,%%d0 \n"
|
|
"or.l %%d2,%%d0 \n"
|
|
"move.b %%d0,(%0)+ \n"
|
|
|
|
"move.b (%1)+,%%d0 \n"
|
|
"or.l %%d1,%%d0 \n"
|
|
"move.b %%d0,(%0)+ \n"
|
|
|
|
"move.b (%1)+,%%d0 \n"
|
|
"or.l %%d2,%%d0 \n"
|
|
"move.b %%d0,(%0)+ \n"
|
|
|
|
"move.b (%1)+,%%d0 \n"
|
|
"or.l %%d2,%%d0 \n"
|
|
"move.b %%d0,(%0)+ \n"
|
|
|
|
"move.b (%1)+,%%d0 \n"
|
|
"or.l %%d2,%%d0 \n"
|
|
"move.b %%d0,(%0)+ \n"
|
|
|
|
"move.b (%1)+,%%d0 \n"
|
|
"or.l %%d2,%%d0 \n"
|
|
"move.b %%d0,(%0)+ \n"
|
|
|
|
"move.b (%1)+,%%d0 \n"
|
|
"or.l %%d2,%%d0 \n"
|
|
"move.b %%d0,(%0)+ \n"
|
|
|
|
"move.b (%1)+,%%d0 \n"
|
|
"or.l %%d2,%%d0 \n"
|
|
"move.b %%d0,(%0)+ \n"
|
|
: /*outputs*/
|
|
: /*inputs*/
|
|
/* %0 */ "a" (dest),
|
|
/* %1 */ "a" (src),
|
|
/* %2 */ "a" (tile)
|
|
: /* clobbers */
|
|
"d0", "d1", "d2"
|
|
);
|
|
#else
|
|
blendcpy(dest, src, *(tile++), 8);
|
|
dest += 8;
|
|
#endif
|
|
cnt -= 8;
|
|
}
|
|
src = patpix[*(tile++)][V];
|
|
blendcpy(dest, src, *(tile++), cnt);
|
|
}
|
|
|
|
static void wnd_scan_color(void)
|
|
{
|
|
int cnt;
|
|
byte *src, *dest;
|
|
int *tile;
|
|
|
|
if (WX >= 160) return;
|
|
cnt = 160 - WX;
|
|
tile = WND;
|
|
dest = BUF + WX;
|
|
|
|
while (cnt >= 8)
|
|
{
|
|
src = patpix[*(tile++)][WV];
|
|
blendcpy(dest, src, *(tile++), 8);
|
|
dest += 8;
|
|
cnt -= 8;
|
|
}
|
|
src = patpix[*(tile++)][WV];
|
|
blendcpy(dest, src, *(tile++), cnt);
|
|
}
|
|
|
|
static void spr_enum(void) ICODE_ATTR;
|
|
static void spr_enum(void)
|
|
{
|
|
int i, j;
|
|
struct obj *o;
|
|
struct vissprite ts;
|
|
int v, pat;
|
|
|
|
NS = 0;
|
|
if (!(R_LCDC & 0x02)) return;
|
|
|
|
o = lcd.oam.obj;
|
|
|
|
for (i = 40; i; i--, o++)
|
|
{
|
|
if (L >= o->y || L + 16 < o->y)
|
|
continue;
|
|
if (L + 8 >= o->y && !(R_LCDC & 0x04))
|
|
continue;
|
|
VS[NS].x = (int)o->x - 8;
|
|
v = L - (int)o->y + 16;
|
|
if (hw.cgb)
|
|
{
|
|
pat = o->pat | (((int)o->flags & 0x60) << 5)
|
|
| (((int)o->flags & 0x08) << 6);
|
|
VS[NS].pal = 32 + ((o->flags & 0x07) << 2);
|
|
}
|
|
else
|
|
{
|
|
pat = o->pat | (((int)o->flags & 0x60) << 5);
|
|
VS[NS].pal = 32 + ((o->flags & 0x10) >> 2);
|
|
}
|
|
VS[NS].pri = (o->flags & 0x80) >> 7;
|
|
if ((R_LCDC & 0x04))
|
|
{
|
|
pat &= ~1;
|
|
if (v >= 8)
|
|
{
|
|
v -= 8;
|
|
pat++;
|
|
}
|
|
if (o->flags & 0x40) pat ^= 1;
|
|
}
|
|
VS[NS].buf = patpix[pat][v];
|
|
if (++NS == 10) break;
|
|
}
|
|
if (hw.cgb) return;
|
|
for (i = 0; i < NS; i++)
|
|
{
|
|
for (j = i + 1; j < NS; j++)
|
|
{
|
|
if (VS[i].x > VS[j].x)
|
|
{
|
|
ts = VS[i];
|
|
VS[i] = VS[j];
|
|
VS[j] = ts;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void spr_scan(void) ICODE_ATTR;
|
|
static void spr_scan(void)
|
|
{
|
|
int i, x;
|
|
byte pal, b, ns = NS;
|
|
byte *src, *dest, *bg, *pri;
|
|
struct vissprite *vs;
|
|
static byte bgdup[256];
|
|
|
|
if (!ns) return;
|
|
|
|
memcpy(bgdup, BUF, 256);
|
|
vs = &VS[ns-1];
|
|
|
|
for (; ns; ns--, vs--)
|
|
{
|
|
x = vs->x;
|
|
if (x > 159) continue;
|
|
if (x < -7) continue;
|
|
if (x < 0)
|
|
{
|
|
src = vs->buf - x;
|
|
dest = BUF;
|
|
i = 8 + x;
|
|
}
|
|
else
|
|
{
|
|
src = vs->buf;
|
|
dest = BUF + x;
|
|
if (x > 152) i = 160 - x;
|
|
else i = 8;
|
|
}
|
|
pal = vs->pal;
|
|
if (vs->pri)
|
|
{
|
|
bg = bgdup + (dest - BUF);
|
|
while (i--)
|
|
{
|
|
b = src[i];
|
|
if (b && !(bg[i]&3)) dest[i] = pal|b;
|
|
}
|
|
}
|
|
else if (hw.cgb)
|
|
{
|
|
bg = bgdup + (dest - BUF);
|
|
pri = PRI + (dest - BUF);
|
|
while (i--)
|
|
{
|
|
b = src[i];
|
|
if (b && (!pri[i] || !(bg[i]&3)))
|
|
dest[i] = pal|b;
|
|
}
|
|
}
|
|
else while (i--) if (src[i]) dest[i] = pal|src[i];
|
|
}
|
|
}
|
|
|
|
/* Scaling defines */
|
|
#define DX ((LCD_WIDTH<<16) / 160)
|
|
#define DXI ((160<<16) / LCD_WIDTH)
|
|
#define DY ((LCD_HEIGHT<<16) / 144)
|
|
#define DYI ((144<<16) / LCD_HEIGHT)
|
|
|
|
#define DXR ((LCD_WIDTH<<16) / 144)
|
|
#define DXIR ((144<<16) / LCD_WIDTH)
|
|
#define DYR ((LCD_HEIGHT<<16) / 160)
|
|
#define DYIR ((160<<16) / LCD_HEIGHT)
|
|
|
|
/* Defines for scale offsets:
|
|
* S2 is for scaled
|
|
* S3 if scaled and maintain ratio
|
|
* S1 is unscaled
|
|
* R's are the rotated defines
|
|
*/
|
|
#if (LCD_WIDTH>=160) && (LCD_HEIGHT>=144)
|
|
#define S1 ((LCD_HEIGHT-144)/2)*LCD_WIDTH + ((LCD_WIDTH-160)/2)
|
|
#define S2 0
|
|
#define S1R ((LCD_HEIGHT-160)/2)*LCD_WIDTH + ((LCD_WIDTH-144)/2)+144
|
|
#define S2R (LCD_WIDTH-1)
|
|
|
|
#elif (LCD_WIDTH>=160) && (LCD_HEIGHT<=144)
|
|
#define S1 0
|
|
#define S2 0
|
|
#define S1R LCD_WIDTH-1
|
|
#define S2R LCD_WIDTH-1
|
|
|
|
#elif (LCD_WIDTH<=160) && (LCD_HEIGHT>=144)
|
|
#define S1 ((LCD_HEIGHT-144)/2)*LCD_WIDTH
|
|
#define S2 ((LCD_HEIGHT-144)/2)*LCD_WIDTH
|
|
#define S1R LCD_WIDTH-1
|
|
#define S2R LCD_WIDTH-1
|
|
|
|
#else
|
|
#define S1 0
|
|
#define S2 0
|
|
#define S1R LCD_WIDTH-1
|
|
#define S2R LCD_WIDTH-1
|
|
#endif
|
|
|
|
#if (LCD_WIDTH>LCD_HEIGHT)
|
|
#define S3 ((LCD_WIDTH-((160*DY)>>16))/2)
|
|
#define S3R LCD_WIDTH-1
|
|
#else
|
|
#define S3 ((LCD_HEIGHT-((144*DX)>>16))/2)*LCD_WIDTH
|
|
#define S3R ((LCD_HEIGHT-((160*DXR)>>16))/2)*LCD_WIDTH+LCD_WIDTH-1
|
|
#endif
|
|
|
|
void lcd_begin(void)
|
|
{
|
|
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
|
|
vdest=(unsigned char*)rb->lcd_framebuffer;
|
|
#else
|
|
vdest=rb->lcd_framebuffer;
|
|
#endif
|
|
|
|
#ifdef HAVE_LCD_COLOR
|
|
|
|
if(options.rotate==1) {
|
|
if(options.scaling == 0)
|
|
vdest+=S2R;
|
|
else if (options.scaling == 1)
|
|
vdest+=S3R;
|
|
else
|
|
vdest+=S1R;
|
|
} else if(options.rotate==2) {
|
|
if(options.scaling == 0)
|
|
vdest+=(LCD_WIDTH*LCD_HEIGHT)-S2R;
|
|
else if (options.scaling == 1)
|
|
vdest+=(LCD_WIDTH*LCD_HEIGHT)-S3R;
|
|
else
|
|
vdest+=(LCD_WIDTH*LCD_HEIGHT)-S1R-144;
|
|
} else {
|
|
if(options.scaling == 0)
|
|
vdest+=S2;
|
|
else if (options.scaling == 1)
|
|
vdest+=S3;
|
|
else
|
|
vdest+=S1;
|
|
}
|
|
#endif
|
|
WY = R_WY;
|
|
}
|
|
|
|
#ifdef HAVE_LCD_COLOR
|
|
int SCALEWL IDATA_ATTR=1<<16;
|
|
int SCALEWS IDATA_ATTR=1<<16;
|
|
int SCALEHL IDATA_ATTR=1<<16;
|
|
int SCALEHS IDATA_ATTR=1<<16;
|
|
int swidth IDATA_ATTR=160;
|
|
int sremain IDATA_ATTR=LCD_WIDTH-160;
|
|
#endif
|
|
|
|
void setvidmode(void)
|
|
{
|
|
|
|
#ifdef HAVE_LCD_COLOR
|
|
switch(options.scaling)
|
|
{
|
|
case 0:
|
|
if(options.rotate)
|
|
{
|
|
SCALEWL=DYR;
|
|
SCALEWS=DYIR;
|
|
SCALEHL=DXR;
|
|
SCALEHS=DXIR;
|
|
}
|
|
else
|
|
{
|
|
SCALEWL=DX;
|
|
SCALEWS=DXI;
|
|
SCALEHL=DY;
|
|
SCALEHS=DYI;
|
|
}
|
|
break;
|
|
case 1: /* Maintain Ratio */
|
|
if(options.rotate)
|
|
{
|
|
if (DYR<DXR)
|
|
{
|
|
SCALEWL=DYR;
|
|
SCALEWS=DYIR;
|
|
SCALEHL=DYR;
|
|
SCALEHS=DYIR;
|
|
}
|
|
else
|
|
{
|
|
SCALEWL=DXR;
|
|
SCALEWS=DXIR;
|
|
SCALEHL=DXR;
|
|
SCALEHS=DXIR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (DY<DX)
|
|
{
|
|
SCALEWL=DY;
|
|
SCALEWS=DYI;
|
|
SCALEHL=DY;
|
|
SCALEHS=DYI;
|
|
}
|
|
else
|
|
{
|
|
SCALEWL=DX;
|
|
SCALEWS=DXI;
|
|
SCALEHL=DX;
|
|
SCALEHS=DXI;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
SCALEWL=1<<16;
|
|
SCALEWS=1<<16;
|
|
SCALEHL=1<<16;
|
|
SCALEHS=1<<16;
|
|
}
|
|
swidth=((160*SCALEWL)>>16);
|
|
|
|
if(options.rotate==1) {
|
|
sremain=-(((160*SCALEWL)>>16)*LCD_WIDTH+1);
|
|
} else if(options.rotate==2) {
|
|
sremain=(((160*SCALEWL)>>16)*LCD_WIDTH+1);
|
|
} else {
|
|
sremain=LCD_WIDTH-swidth;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void lcd_refreshline(void)
|
|
{
|
|
if (!(R_LCDC & 0x80))
|
|
return; /* should not happen... */
|
|
|
|
#if (LCD_HEIGHT <= 128) && !defined(HAVE_LCD_COLOR)
|
|
if ( (fb.mode==0&&(R_LY >= 128)) ||
|
|
(fb.mode==1&&(R_LY < 16)) ||
|
|
(fb.mode==2&&(R_LY<8||R_LY>=136)) ||
|
|
(fb.mode==3&&((R_LY%9)==8))
|
|
|
|
#if LCD_HEIGHT == 64
|
|
|| (R_LY & 1) /* calculate only even lines */
|
|
#endif
|
|
)
|
|
return;
|
|
#endif
|
|
|
|
updatepatpix();
|
|
|
|
L = R_LY;
|
|
X = R_SCX;
|
|
Y = (R_SCY + L) & 0xff;
|
|
S = X >> 3;
|
|
T = Y >> 3;
|
|
U = X & 7;
|
|
V = Y & 7;
|
|
|
|
WX = R_WX - 7;
|
|
if (WY>L || WY<0 || WY>143 || WX<-7 || WX>159 || !(R_LCDC&0x20))
|
|
WX = 160;
|
|
WT = (L - WY) >> 3;
|
|
WV = (L - WY) & 7;
|
|
|
|
spr_enum();
|
|
|
|
tilebuf();
|
|
if (hw.cgb)
|
|
{
|
|
bg_scan_color();
|
|
wnd_scan_color();
|
|
if (NS)
|
|
{
|
|
bg_scan_pri();
|
|
wnd_scan_pri();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
bg_scan();
|
|
wnd_scan();
|
|
}
|
|
spr_scan();
|
|
|
|
#if !defined(HAVE_LCD_COLOR)
|
|
#if LCD_DEPTH == 1
|
|
if (scanline_ind == 7)
|
|
#elif LCD_DEPTH == 2
|
|
if (scanline_ind == 3)
|
|
#endif
|
|
{
|
|
if(fb.mode!=3)
|
|
vid_update(L);
|
|
else
|
|
vid_update(L-((int)(L/9)));
|
|
#else
|
|
{
|
|
/* Universal Scaling pulled from PrBoom and modified for rockboy */
|
|
|
|
static int hpt IDATA_ATTR=0x8000;
|
|
|
|
while((hpt>>16)<L+1)
|
|
{
|
|
hpt+=SCALEHS;
|
|
register unsigned int srcpt=0x8000;
|
|
register unsigned int wcount=swidth;
|
|
while(wcount--)
|
|
{
|
|
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
|
|
*vdest = BUF[srcpt>>16];
|
|
#else
|
|
*vdest = PAL[BUF[srcpt>>16]];
|
|
#endif
|
|
if (options.rotate == 1) {
|
|
vdest+=LCD_WIDTH;
|
|
} else if (options.rotate == 2) {
|
|
vdest-=LCD_WIDTH;
|
|
} else {
|
|
vdest++;
|
|
}
|
|
|
|
srcpt+=SCALEWS;
|
|
}
|
|
vdest+=sremain;
|
|
}
|
|
|
|
if(L==143)
|
|
{
|
|
if(options.showstats)
|
|
{
|
|
if(options.showstats==1) {
|
|
rb->lcd_putsxyf(0,LCD_HEIGHT-10," %d %d ",
|
|
options.fps, options.frameskip);
|
|
} else {
|
|
rb->lcd_putsxyf(0,LCD_HEIGHT-10," FPS: %d Frameskip: %d ",
|
|
options.fps, options.frameskip);
|
|
}
|
|
rb->lcd_update_rect(0,LCD_HEIGHT-10, LCD_WIDTH, 10);
|
|
}
|
|
|
|
hpt=0x8000;
|
|
|
|
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
|
|
if(options.scaling==3) {
|
|
rb->lcd_blit_pal256((unsigned char*)rb->lcd_framebuffer,(LCD_WIDTH-160)/2, (LCD_HEIGHT-144)/2, (LCD_WIDTH-160)/2, (LCD_HEIGHT-144)/2, 160, 144);
|
|
} else {
|
|
rb->lcd_blit_pal256((unsigned char*)rb->lcd_framebuffer,0,0,0,0,LCD_WIDTH,LCD_HEIGHT);
|
|
}
|
|
#else
|
|
if(options.scaling==3) {
|
|
rb->lcd_update_rect( (LCD_WIDTH-160)/2, (LCD_HEIGHT-144)/2, 160, 144);
|
|
} else {
|
|
rb->lcd_update();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
}
|
|
#if LCD_DEPTH == 1
|
|
scanline_ind = (scanline_ind+1) % 8;
|
|
#elif LCD_DEPTH == 2
|
|
scanline_ind = (scanline_ind+1) % 4;
|
|
#endif
|
|
}
|
|
|
|
#ifdef HAVE_LCD_COLOR
|
|
void set_pal(void)
|
|
{
|
|
memcpy(dmg_pal,palettes[options.pal], sizeof(dmg_pal));
|
|
pal_dirty();
|
|
}
|
|
|
|
static void updatepalette(int i)
|
|
{
|
|
int c, r, g, b;
|
|
fb_data px;
|
|
|
|
c = (lcd.pal[i<<1] | ((int)lcd.pal[(i<<1)|1] << 8)) & 0x7FFF;
|
|
r = (c & 0x001F) << 3;
|
|
g = (c & 0x03E0) >> 2;
|
|
b = (c & 0x7C00) >> 7;
|
|
r |= (r >> 5);
|
|
g |= (g >> 5);
|
|
b |= (b >> 5);
|
|
|
|
r = (r >> fb.cc[0].r) << fb.cc[0].l;
|
|
g = (g >> fb.cc[1].r) << fb.cc[1].l;
|
|
b = (b >> fb.cc[2].r) << fb.cc[2].l;
|
|
|
|
c = r|g|b;
|
|
|
|
px = FB_SCALARPACK_LCD(c);
|
|
|
|
/* updatepalette might get called, but the pallete does not necessarily
|
|
* need to be updated.
|
|
*/
|
|
if(memcmp(&PAL[i], &px, sizeof(fb_data)))
|
|
{
|
|
PAL[i] = px;
|
|
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
|
|
rb->lcd_pal256_update_pal(PAL);
|
|
#endif
|
|
}
|
|
}
|
|
#endif /* HAVE_LCD_COLOR */
|
|
|
|
void pal_write(int i, byte b)
|
|
{
|
|
if (lcd.pal[i] == b) return;
|
|
lcd.pal[i] = b;
|
|
#ifdef HAVE_LCD_COLOR
|
|
updatepalette(i>>1);
|
|
#endif
|
|
}
|
|
|
|
void pal_write_dmg(int i, int mapnum, byte d)
|
|
{
|
|
int j;
|
|
int *cmap = dmg_pal[mapnum];
|
|
int c, r, g, b;
|
|
|
|
if (hw.cgb) return;
|
|
|
|
for (j = 0; j < 8; j += 2)
|
|
{
|
|
c = cmap[(d >> j) & 3];
|
|
r = (c & 0xf8) >> 3;
|
|
g = (c & 0xf800) >> 6;
|
|
b = (c & 0xf80000) >> 9;
|
|
c = r|g|b;
|
|
/* FIXME - handle directly without faking cgb */
|
|
pal_write(i+j, c & 0xff);
|
|
pal_write(i+j+1, c >> 8);
|
|
}
|
|
}
|
|
|
|
void vram_write(addr a, byte b)
|
|
{
|
|
lcd.vbank[R_VBK&1][a] = b;
|
|
if (a >= 0x1800) return;
|
|
patdirty[((R_VBK&1)<<9)+(a>>4)] = 1;
|
|
anydirty = 1;
|
|
pal_dirty();
|
|
}
|
|
|
|
void vram_dirty(void)
|
|
{
|
|
anydirty = 1;
|
|
memset(patdirty, 1, sizeof patdirty);
|
|
}
|
|
|
|
void pal_dirty(void)
|
|
{
|
|
#ifdef HAVE_LCD_COLOR
|
|
int i;
|
|
#endif
|
|
if (!hw.cgb)
|
|
{
|
|
|
|
pal_write_dmg(0, 0, R_BGP);
|
|
pal_write_dmg(8, 1, R_BGP);
|
|
pal_write_dmg(64, 2, R_OBP0);
|
|
pal_write_dmg(72, 3, R_OBP1);
|
|
}
|
|
#ifdef HAVE_LCD_COLOR
|
|
for (i = 0; i < 64; i++)
|
|
updatepalette(i);
|
|
#endif
|
|
}
|
|
|
|
void lcd_reset(void)
|
|
{
|
|
memset(&lcd, 0, sizeof lcd);
|
|
lcd_begin();
|
|
vram_dirty();
|
|
}
|