Subversion Repositories psp

[/] [trunk/] [smsplus/] [tms.c] - Blame information for rev 514

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 514 jack
/*
2
    tms.c --
3
    TMS9918 and legacy video mode support.
4
*/
5
#include "shared.h"
6
 
7
int text_counter;               /* Text offset counter */
8
uint8 tms_lookup[16][256][2];   /* Expand BD, PG data into 8-bit pixels (G1,G2) */
9
uint8 mc_lookup[16][256][8];    /* Expand BD, PG data into 8-bit pixels (MC) */
10
uint8 txt_lookup[256][2];       /* Expand BD, PG data into 8-bit pixels (TX) */
11
uint8 bp_expand[256][8];        /* Expand PG data into 8-bit pixels */
12
uint8 tms_obj_lut[16*256];      /* Look up priority between SG and display pixels */
13
 
14
static const uint8 diff_mask[]  = {0x07, 0x07, 0x0F, 0x0F};
15
static const uint8 name_mask[]  = {0xFF, 0xFF, 0xFC, 0xFC};
16
static const uint8 diff_shift[] = {0, 1, 0, 1};
17
static const uint8 size_tab[]   = {8, 16, 16, 32};
18
 
19
/* Internally latched sprite data in the VDP */
20
typedef struct {
21
    int xpos;
22
    uint8 attr;
23
    uint8 sg[2];
24
} tms_sprite;
25
 
26
tms_sprite sprites[4];
27
int sprites_found;
28
 
29
void parse_line(int line)
30
{
31
    int yp, i;
32
    int mode = vdp.reg[1] & 3;
33
    int size = size_tab[mode];
34
    int diff, name;
35
    uint8 *sa, *sg;
36
    tms_sprite *p;
37
 
38
    /* Reset # of sprites found */
39
    sprites_found = 0;
40
 
41
    /* Parse sprites */
42
    for(i = 0; i < 32; i++)
43
    {
44
        /* Point to current sprite in SA and our current sprite record */
45
        p = &sprites[sprites_found];
46
        sa = &vdp.vram[vdp.sa + (i << 2)];
47
 
48
        /* Fetch Y coordinate */
49
        yp = sa[0];
50
 
51
        /* Check for end marker */
52
        if(yp == 0xD0)
53
            goto parse_end;
54
 
55
        /* Wrap Y position */
56
        if(yp > 0xE0)
57
            yp -= 256;
58
 
59
        /* Check if sprite falls on following line */
60
        if(line >= yp && line < (yp + size))
61
        {
62
            /* Sprite overflow on this line */
63
            if(sprites_found == 4)
64
            {
65
                /* Set 5S and abort parsing */
66
                vdp.status |= 0x40;
67
                goto parse_end;
68
            }
69
 
70
            /* Fetch X position */
71
            p->xpos = sa[1];
72
 
73
            /* Fetch name */
74
            name = sa[2] & name_mask[mode];
75
 
76
            /* Load attribute into attribute storage */
77
            p->attr = sa[3];
78
 
79
            /* Apply early clock bit */
80
            if(p->attr & 0x80)
81
                p->xpos -= 32;
82
 
83
            /* Calculate offset in pattern */
84
            diff = ((line - yp) >> diff_shift[mode]) & diff_mask[mode];
85
 
86
            /* Insert additional name bit for 16-pixel tall sprites */
87
            if(diff & 8)
88
                name |= 1;
89
 
90
            /* Fetch SG data */
91
            sg = &vdp.vram[vdp.sg | (name << 3) | (diff & 7)];
92
            p->sg[0] = sg[0x00];
93
            p->sg[1] = sg[0x10];
94
 
95
            /* Bump found sprite count */
96
            ++sprites_found;
97
        }
98
    }
99
parse_end:
100
 
101
    /* Insert number of last sprite entry processed */
102
    vdp.status = (vdp.status & 0xE0) | (i & 0x1F);
103
}
104
 
105
void render_obj_tms(int line)
106
{
107
    int i, x = 0;
108
    int size, start, end, mode;
109
    uint8 *lb, *lut, *ex[2];
110
    tms_sprite *p;
111
 
112
    mode = vdp.reg[1] & 3;
113
    size = size_tab[mode];
114
 
115
    /* Render sprites */
116
    for(i = 0; i < sprites_found; i++)
117
    {
118
        p = &sprites[i];
119
        lb = &linebuf[p->xpos];
120
        lut = &tms_obj_lut[(p->attr & 0x0F) << 8];
121
 
122
        /* Point to expanded PG data */
123
        ex[0] = bp_expand[p->sg[0]];
124
        ex[1] = bp_expand[p->sg[1]];
125
 
126
        /* Clip left edge */
127
        if(p->xpos < 0)
128
            start = 0 - p->xpos;
129
        else
130
            start = 0;
131
 
132
        /* Clip right edge */
133
        if(p->xpos > 256 - size)
134
            end = 256 - p->xpos;
135
        else
136
            end = size;
137
 
138
        /* Render sprite line */
139
        switch(mode)
140
        {
141
            case 0: /* 8x8 */
142
                for(x = start; x < end; x++) {
143
                    if(ex[0][x])
144
                        lb[x] = lut[lb[x]];
145
                }
146
                break;
147
 
148
            case 1: /* 8x8 zoomed */
149
                for(x = start; x < end; x++) {
150
                    if(ex[0][x >> 1])
151
                        lb[x] = lut[lb[x]];
152
                }
153
                break;
154
 
155
            case 2: /* 16x16 */
156
                for(x = start; x < end; x++) {
157
                    if(ex[(x >> 3) & 1][x & 7])
158
                        lb[x] = lut[lb[x]];
159
                }
160
                break;
161
 
162
            case 3: /* 16x16 zoomed */
163
                for(x = start; x < end; x++) {
164
                    if(ex[(x >> 4) & 1][(x >> 1) & 7])
165
                        lb[x] = lut[lb[x]];
166
                }
167
                break;
168
        }
169
    }
170
}
171
 
172
/****
173
1.) NOTE: xpos can be negative, but the 'start' value that is added
174
    to xpos will ensure it is positive.
175
 
176
    For an EC sprite that is offscreen, 'start' will be larger
177
    than 'end' and the for-loop used for rendering will abort
178
    on the first pass.
179
***/
180
 
181
 
182
#define RENDER_TX_LINE \
183
        *lb++ = 0x10 | clut[ *bpex++ ]; \
184
        *lb++ = 0x10 | clut[ *bpex++ ]; \
185
        *lb++ = 0x10 | clut[ *bpex++ ]; \
186
        *lb++ = 0x10 | clut[ *bpex++ ]; \
187
        *lb++ = 0x10 | clut[ *bpex++ ]; \
188
        *lb++ = 0x10 | clut[ *bpex++ ];
189
 
190
#define RENDER_TX_BORDER \
191
        *lb++ = 0x10 | clut[0]; \
192
        *lb++ = 0x10 | clut[0]; \
193
        *lb++ = 0x10 | clut[0]; \
194
        *lb++ = 0x10 | clut[0]; \
195
        *lb++ = 0x10 | clut[0]; \
196
        *lb++ = 0x10 | clut[0]; \
197
        *lb++ = 0x10 | clut[0]; \
198
        *lb++ = 0x10 | clut[0]; \
199
        *lb++ = 0x10 | clut[0]; \
200
        *lb++ = 0x10 | clut[0]; \
201
        *lb++ = 0x10 | clut[0]; \
202
        *lb++ = 0x10 | clut[0]; \
203
        *lb++ = 0x10 | clut[0]; \
204
        *lb++ = 0x10 | clut[0]; \
205
        *lb++ = 0x10 | clut[0]; \
206
        *lb++ = 0x10 | clut[0];
207
 
208
#define RENDER_GR_LINE \
209
        *lb++ = 0x10 | clut[ *bpex++ ]; \
210
        *lb++ = 0x10 | clut[ *bpex++ ]; \
211
        *lb++ = 0x10 | clut[ *bpex++ ]; \
212
        *lb++ = 0x10 | clut[ *bpex++ ]; \
213
        *lb++ = 0x10 | clut[ *bpex++ ]; \
214
        *lb++ = 0x10 | clut[ *bpex++ ]; \
215
        *lb++ = 0x10 | clut[ *bpex++ ]; \
216
        *lb++ = 0x10 | clut[ *bpex++ ];
217
 
218
#define RENDER_MC_LINE \
219
        *lb++ = 0x10 | *mcex++; \
220
        *lb++ = 0x10 | *mcex++; \
221
        *lb++ = 0x10 | *mcex++; \
222
        *lb++ = 0x10 | *mcex++; \
223
        *lb++ = 0x10 | *mcex++; \
224
        *lb++ = 0x10 | *mcex++; \
225
        *lb++ = 0x10 | *mcex++; \
226
        *lb++ = 0x10 | *mcex++;
227
 
228
void make_tms_tables(void)
229
{
230
    int i, j, x;
231
    int bd, pg, ct;
232
    int sx, bx;
233
 
234
    for(sx = 0; sx < 16; sx++)
235
    {
236
        for(bx = 0; bx < 256; bx++)
237
        {
238
//          uint8 bd = (bx & 0x0F);
239
            uint8 bs = (bx & 0x40);
240
//          uint8 bt = (bd == 0) ? 1 : 0;
241
            uint8 sd = (sx & 0x0F);
242
//          uint8 st = (sd == 0) ? 1 : 0;
243
 
244
            // opaque sprite pixel, choose 2nd pal and set sprite marker
245
            if(sd && !bs)
246
            {
247
                tms_obj_lut[(sx<<8)|(bx)] = sd | 0x10 | 0x40;
248
            }
249
            else
250
            if(sd && bs)
251
            {
252
                // writing over a sprite
253
                tms_obj_lut[(sx<<8)|(bx)] = bx;
254
            }
255
            else
256
            {
257
                tms_obj_lut[(sx<<8)|(bx)] = bx;
258
            }
259
        }
260
    }
261
 
262
 
263
    /* Text lookup table */
264
    for(bd = 0; bd < 256; bd++)
265
    {
266
        uint8 bg = (bd >> 0) & 0x0F;
267
        uint8 fg = (bd >> 4) & 0x0F;
268
 
269
        /* If foreground is transparent, use background color */
270
        if(fg == 0) fg = bg;
271
 
272
        txt_lookup[bd][0] = bg;
273
        txt_lookup[bd][1] = fg;
274
    }
275
 
276
    /* Multicolor lookup table */
277
    for(bd = 0; bd < 16; bd++)
278
    {
279
        for(pg = 0; pg < 256; pg++)
280
        {
281
            int l = (pg >> 4) & 0x0F;
282
            int r = (pg >> 0) & 0x0F;
283
 
284
            /* If foreground is transparent, use background color */
285
            if(l == 0) l = bd;
286
            if(r == 0) r = bd;
287
 
288
            /* Unpack 2 nibbles across eight pixels */
289
            for(x = 0; x < 8; x++)
290
            {
291
                int c = (x & 4) ? r : l;
292
 
293
                mc_lookup[bd][pg][x] = c;
294
            }
295
        }
296
    }
297
 
298
    /* Make bitmap data expansion table */
299
    memset(bp_expand, 0, sizeof(bp_expand));
300
    for(i = 0; i < 256; i++)
301
    {
302
        for(j = 0; j < 8; j++)
303
        {
304
            int c = (i >> (j ^ 7)) & 1;
305
            bp_expand[i][j] = c;
306
        }
307
    }
308
 
309
    /* Graphics I/II lookup table */
310
    for(bd = 0; bd < 0x10; bd++)
311
    {
312
        for(ct = 0; ct < 0x100; ct++)
313
        {
314
            int backdrop = (bd & 0x0F);
315
            int background = (ct >> 0) & 0x0F;
316
            int foreground = (ct >> 4) & 0x0F;
317
 
318
            /* If foreground is transparent, use background color */
319
            if(background == 0) background = backdrop;
320
            if(foreground == 0) foreground = backdrop;
321
 
322
            tms_lookup[bd][ct][0] = background;
323
            tms_lookup[bd][ct][1] = foreground;
324
        }
325
    }
326
}
327
 
328
 
329
void render_bg_tms(int line)
330
{
331
    switch(vdp.mode & 7)
332
    {
333
        case 0: /* Graphics I */
334
            render_bg_m0(line);
335
            break;
336
 
337
        case 1: /* Text */
338
            render_bg_m1(line);
339
            break;
340
 
341
        case 2: /* Graphics II */
342
            render_bg_m2(line);
343
            break;
344
 
345
        case 3: /* Text (Extended PG) */
346
            render_bg_m1x(line);
347
            break;
348
 
349
        case 4: /* Multicolor */
350
            render_bg_m3(line);
351
            break;
352
 
353
        case 5: /* Invalid (1+3) */
354
            render_bg_inv(line);
355
            break;
356
 
357
        case 6: /* Multicolor (Extended PG) */
358
            render_bg_m3x(line);
359
            break;
360
 
361
        case 7: /* Invalid (1+2+3) */
362
            render_bg_inv(line);
363
            break;
364
    }
365
}
366
 
367
/* Graphics I */
368
void render_bg_m0(int line)
369
{
370
    int v_row  = (line & 7);
371
    int column;
372
    int name;
373
 
374
    uint8 *clut;
375
    uint8 *bpex;
376
    uint8 *lb = &linebuf[0];
377
    uint8 *pn = &vdp.vram[vdp.pn + ((line >> 3) << 5)];
378
    uint8 *ct = &vdp.vram[vdp.ct];
379
    uint8 *pg = &vdp.vram[vdp.pg | (v_row)];
380
 
381
    for(column = 0; column < 32; column++)
382
    {
383
        name = pn[column];
384
        clut = &tms_lookup[vdp.bd][ct[name >> 3]][0];
385
        bpex = &bp_expand[pg[name << 3]][0];
386
        RENDER_GR_LINE
387
    }
388
}
389
 
390
/* Text */
391
void render_bg_m1(int line)
392
{
393
    int v_row  = (line & 7);
394
    int column;
395
 
396
    uint8 *clut;
397
    uint8 *bpex;
398
    uint8 *lb = &linebuf[0];
399
//  uint8 *pn = &vdp.vram[vdp.pn + ((line >> 3) * 40)];
400
 
401
    uint8 *pn = &vdp.vram[vdp.pn + text_counter];
402
 
403
    uint8 *pg = &vdp.vram[vdp.pg | (v_row)];
404
    uint8 bk = vdp.reg[7];
405
 
406
    clut = &txt_lookup[bk][0];
407
 
408
    for(column = 0; column < 40; column++)
409
    {
410
        bpex = &bp_expand[pg[pn[column] << 3]][0];
411
        RENDER_TX_LINE
412
    }
413
 
414
    /* V3 */
415
    if((vdp.line & 7) == 7)
416
        text_counter += 40;
417
 
418
    RENDER_TX_BORDER
419
}
420
 
421
/* Text + extended PG */
422
void render_bg_m1x(int line)
423
{
424
    int v_row  = (line & 7);
425
    int column;
426
 
427
    uint8 *clut;
428
    uint8 *bpex;
429
    uint8 *lb = &linebuf[0];
430
    uint8 *pn = &vdp.vram[vdp.pn + ((line >> 3) * 40)];
431
    uint8 *pg = &vdp.vram[vdp.pg + (v_row) + ((line & 0xC0) << 5)];
432
    uint8 bk = vdp.reg[7];
433
 
434
    clut = &tms_lookup[0][bk][0];
435
 
436
    for(column = 0; column < 40; column++)
437
    {
438
        bpex = &bp_expand[pg[pn[column] << 3]][0];
439
        RENDER_TX_LINE
440
    }
441
    RENDER_TX_BORDER
442
}
443
 
444
/* Invalid (2+3/1+2+3) */
445
void render_bg_inv(int line)
446
{
447
    int column;
448
    uint8 *clut;
449
    uint8 *bpex;
450
    uint8 *lb = &linebuf[0];
451
    uint8 bk = vdp.reg[7];
452
 
453
    clut = &txt_lookup[bk][0];
454
 
455
    for(column = 0; column < 40; column++)
456
    {
457
        bpex = &bp_expand[0xF0][0];
458
        RENDER_TX_LINE
459
    }
460
}
461
 
462
/* Multicolor */
463
void render_bg_m3(int line)
464
{
465
    int column;
466
    uint8 *mcex;
467
    uint8 *lb = &linebuf[0];
468
 
469
    uint8 *pn = &vdp.vram[vdp.pn + ((line >> 3) << 5)];
470
    uint8 *pg = &vdp.vram[vdp.pg + ((line >> 2) & 7)];
471
 
472
    for(column = 0; column < 32; column++)
473
    {
474
        mcex = &mc_lookup[vdp.bd][pg[pn[column]<<3]][0];
475
        RENDER_MC_LINE
476
    }
477
}
478
 
479
/* Multicolor + extended PG */
480
void render_bg_m3x(int line)
481
{
482
    int column;
483
    uint8 *mcex;
484
    uint8 *lb = &linebuf[0];
485
    uint8 *pn = &vdp.vram[vdp.pn + ((line >> 3) << 5)];
486
    uint8 *pg = &vdp.vram[vdp.pg + ((line >> 2) & 7) + ((line & 0xC0) << 5)];
487
 
488
    for(column = 0; column < 32; column++)
489
    {
490
        mcex = &mc_lookup[vdp.bd][pg[pn[column]<<3]][0];
491
        RENDER_MC_LINE
492
    }
493
}
494
 
495
/* Graphics II */
496
void render_bg_m2(int line)
497
{
498
    int v_row  = (line & 7);
499
    int column;
500
    int name;
501
 
502
    uint8 *clut;
503
    uint8 *bpex;
504
    uint8 *lb = &linebuf[0];
505
    uint8 *pn = &vdp.vram[vdp.pn | ((line & 0xF8) << 2)];
506
    uint8 *ct = &vdp.vram[(vdp.ct & 0x2000) | (v_row) | ((line & 0xC0) << 5)];
507
    uint8 *pg = &vdp.vram[(vdp.pg & 0x2000) | (v_row) | ((line & 0xC0) << 5)];
508
 
509
    for(column = 0; column < 32; column++)
510
    {
511
        name = pn[column] << 3;
512
        clut = &tms_lookup[vdp.bd][ct[name]][0];
513
        bpex = &bp_expand[pg[name]][0];
514
        RENDER_GR_LINE
515
    }
516
}
517