add TMS9928a video chip to devices

This commit is contained in:
dinkc64 2014-08-17 20:04:19 +00:00
parent 65881cfdd9
commit 008ceba738
3 changed files with 731 additions and 1 deletions

View File

@ -76,7 +76,7 @@ depobj := $(drvobj) \
tiles_generic.o timer.o vector.o \
\
8255ppi.o 8257dma.o eeprom.o nmk004.o kaneko_tmap.o pandora.o seibusnd.o sknsspr.o slapstic.o t5182.o timekpr.o tms34061.o \
v3021.o vdc.o \
v3021.o vdc.o tms9928a.o \
\
ay8910.o burn_y8950.o burn_ym2151.o burn_ym2203.o burn_ym2413.o burn_ym2608.o burn_ym2610.o burn_ym2612.o \
burn_ym3526.o burn_ym3812.o burn_ymf278b.o c6280.o dac.o es5506.o es8712.o flt_rc.o fm.o fmopl.o ics2115.o iremga20.o \

View File

@ -0,0 +1,702 @@
#include "tiles_generic.h"
#include "tms9928a.h"
static int TMS9928A_palette[16] = {
0x000000, 0x000000, 0x21c842, 0x5edc78, 0x5455ed, 0x7d76fc, 0xd4524d, 0x42ebf5,
0xfc5554, 0xff7978, 0xd4c154, 0xe6ce80, 0x21b03b, 0xc95bba, 0xcccccc, 0xffffff
};
typedef struct {
unsigned char ReadAhead;
unsigned char Regs[8];
unsigned char StatusReg;
unsigned char FirstByte;
unsigned char latch;
unsigned char INT;
int Addr;
int colour;
int pattern;
int nametbl;
int spriteattribute;
int spritepattern;
int colourmask;
int patternmask;
unsigned char *vMem;
unsigned char *dBackMem;
unsigned short *tmpbmp;
int vramsize;
int model;
int max_x;
int min_x;
int max_y;
int min_y;
int LimitSprites;
int top_border;
int bottom_border;
void (*INTCallback)(int);
} TMS9928A;
static TMS9928A tms;
static unsigned int Palette[16]; // high color support
static void TMS89928aPaletteRecalc()
{
for (int i = 0; i < 16; i++) {
Palette[i] = BurnHighCol(TMS9928A_palette[i] >> 16, TMS9928A_palette[i] >> 8, TMS9928A_palette[i] >> 0 , 0);
}
}
static void change_register(int reg, unsigned char val)
{
static const unsigned char Mask[8] = { 0x03, 0xfb, 0x0f, 0xff, 0x07, 0x7f, 0x07, 0xff };
val &= Mask[reg];
tms.Regs[reg] = val;
switch (reg)
{
case 0:
{
if (val & 2) {
tms.colour = ((tms.Regs[3] & 0x80) * 64) & (tms.vramsize - 1);
tms.colourmask = (tms.Regs[3] & 0x7f) * 8 | 7;
tms.pattern = ((tms.Regs[4] & 4) * 2048) & (tms.vramsize - 1);
tms.patternmask = (tms.Regs[4] & 3) * 256 |
(tms.colourmask & 255);
} else {
tms.colour = (tms.Regs[3] * 64) & (tms.vramsize - 1);
tms.pattern = (tms.Regs[4] * 2048) & (tms.vramsize - 1);
}
}
break;
case 1:
{
int b = (val & 0x20) && (tms.StatusReg & 0x80);
if (b != tms.INT) {
tms.INT = b;
if (tms.INTCallback) tms.INTCallback (tms.INT);
}
}
break;
case 2:
tms.nametbl = (val * 1024) & (tms.vramsize - 1);
break;
case 3:
{
if (tms.Regs[0] & 2) {
tms.colour = ((val & 0x80) * 64) & (tms.vramsize - 1);
tms.colourmask = (val & 0x7f) * 8 | 7;
} else {
tms.colour = (val * 64) & (tms.vramsize - 1);
}
tms.patternmask = (tms.Regs[4] & 3) * 256 | (tms.colourmask & 255);
}
break;
case 4:
{
if (tms.Regs[0] & 2) {
tms.pattern = ((val & 4) * 2048) & (tms.vramsize - 1);
tms.patternmask = (val & 3) * 256 | 255;
} else {
tms.pattern = (val * 2048) & (tms.vramsize - 1);
}
}
break;
case 5:
tms.spriteattribute = (val * 128) & (tms.vramsize - 1);
break;
case 6:
tms.spritepattern = (val * 2048) & (tms.vramsize - 1);
break;
case 7:
/* The backdrop is updated at TMS9928A_refresh() */
break;
}
}
void TMS9928AReset()
{
for (int i = 0; i < 8; i++)
tms.Regs[i] = 0;
tms.StatusReg = 0;
tms.nametbl = tms.pattern = tms.colour = 0;
tms.spritepattern = tms.spriteattribute = 0;
tms.colourmask = tms.patternmask = 0;
tms.Addr = tms.ReadAhead = tms.INT = 0;
tms.FirstByte = 0;
tms.latch = 0;
}
void TMS9928AInit(int model, int vram, int borderx, int bordery, void (*INTCallback)(int))
{
GenericTilesInit();
tms.model = model;
tms.INTCallback = INTCallback;
tms.top_border = ((tms.model == TMS9929) || (tms.model == TMS9929A)) ? 51 : 27;
tms.bottom_border = ((tms.model == TMS9929) || (tms.model == TMS9929A)) ? 51 : 24;
#define MIN(x,y) ((x)<(y)?(x):(y))
tms.min_x = 15 - MIN(borderx, 15);
tms.max_x = 15 + 32*8 - 1 + MIN(borderx, 15);
tms.min_y = tms.top_border - MIN(bordery, tms.top_border);
tms.max_y = tms.top_border + 24*8 - 1 + MIN(bordery, tms.bottom_border);
#undef MIN
tms.vramsize = vram;
tms.vMem = (unsigned char*)malloc(tms.vramsize);
tms.dBackMem = (unsigned char*)malloc(256 * 192);
tms.tmpbmp = (unsigned short*)malloc(256 * 192 * sizeof(short));
TMS9928AReset ();
tms.LimitSprites = 1;
}
void TMS9928AExit()
{
TMS9928AReset();
GenericTilesExit();
free (tms.tmpbmp);
free (tms.vMem);
free (tms.dBackMem);
}
void TMS9928APostLoad()
{
for (int i = 0; i < 8; i++)
change_register(i, tms.Regs[i]);
if (tms.INTCallback) tms.INTCallback(tms.INT);
}
unsigned char TMS9928AReadVRAM()
{
int b = tms.ReadAhead;
tms.ReadAhead = tms.vMem[tms.Addr];
tms.Addr = (tms.Addr + 1) & (tms.vramsize - 1);
tms.latch = 0;
return b;
}
void TMS9928AWriteVRAM(int data)
{
tms.vMem[tms.Addr] = data;
tms.Addr = (tms.Addr + 1) & (tms.vramsize - 1);
tms.ReadAhead = data;
tms.latch = 0;
}
unsigned char TMS9928AReadRegs()
{
int b = tms.StatusReg;
tms.StatusReg = 0x1f;
if (tms.INT) {
tms.INT = 0;
if (tms.INTCallback) tms.INTCallback (tms.INT);
}
tms.latch = 0;
return b;
}
void TMS9928AWriteRegs(int data)
{
if (tms.latch) {
if (data & 0x80) {
change_register(data & 0x07, tms.FirstByte);
} else {
tms.Addr = ((unsigned short)data << 8 | tms.FirstByte) & (tms.vramsize - 1);
if (!(data & 0x40)) {
TMS9928AReadVRAM();
}
}
tms.latch = 0;
} else {
tms.FirstByte = data;
tms.latch = 1;
}
}
void TMS9928ASetSpriteslimit(int limit)
{
tms.LimitSprites = limit;
}
static void draw_mode0(unsigned short *bitmap)
{
unsigned char *patternptr;
for (int y = 0, name = 0; y < 24; y++)
{
for (int x = 0; x < 32; x++, name++)
{
int charcode = tms.vMem[tms.nametbl+name];
patternptr = tms.vMem + tms.pattern + charcode*8;
int color = tms.vMem[tms.colour+charcode/8];
int fg = color >> 4;
int bg = color & 0x0f;
for (int yy = 0; yy < 8; yy++)
{
int bits = *patternptr++;
for (int xx = 0; xx < 8; xx++, bits<<=1)
{
bitmap[(y * 8 + yy) * 256 + (x * 8 + xx)] = (bits & 0x80) ? fg : bg;
}
}
}
}
}
static void draw_mode1(unsigned short *bitmap)
{
int pattern,x,y,yy,xx,name,charcode;
UINT8 fg,bg,*patternptr;
fg = tms.Regs[7] / 16;
bg = tms.Regs[7] & 15;
for (y = 0; y < 191; y++) {
for (x = 0; x < 7; x++) {
bitmap[y * 256 + x + 248] = bitmap[y * 256 + x] = bg;
}
}
name = 0;
for (y=0;y<24;y++) {
for (x=0;x<40;x++) {
charcode = tms.vMem[tms.nametbl+name];
name++;
patternptr = tms.vMem + tms.pattern + (charcode*8);
for (yy=0;yy<8;yy++) {
pattern = *patternptr++;
for (xx=0;xx<6;xx++) {
bitmap[(y * 8 + yy) * 256 + (8 + x*6+xx)] = (pattern & 0x80) ? fg : bg;
pattern *= 2;
}
}
}
}
}
static void draw_mode12(unsigned short *bitmap)
{
int pattern,x,y,yy,xx,name,charcode;
UINT8 fg,bg,*patternptr;
fg = tms.Regs[7] / 16;
bg = tms.Regs[7] & 15;
for (y = 0; y < 191; y++) {
for (x = 0; x < 7; x++) {
bitmap[y * 256 + x + 248] = bitmap[y * 256 + x] = bg;
}
}
name = 0;
for (y=0;y<24;y++) {
for (x=0;x<40;x++) {
charcode = (tms.vMem[tms.nametbl+name]+(y/8)*256)&tms.patternmask;
name++;
patternptr = tms.vMem + tms.pattern + (charcode*8);
for (yy=0;yy<8;yy++) {
pattern = *patternptr++;
for (xx=0;xx<6;xx++) {
bitmap[(y * 8 + yy) * 256 + (8 + x*6+xx)] = (pattern & 0x80) ? fg : bg;
pattern *= 2;
}
}
}
}
}
static void draw_mode2(unsigned short *bitmap)
{
int colour,name,x,y,yy,pattern,xx,charcode;
UINT8 fg,bg;
UINT8 *colourptr,*patternptr;
name = 0;
for (y=0;y<24;y++) {
for (x=0;x<32;x++) {
charcode = tms.vMem[tms.nametbl+name]+(y/8)*256;
name++;
colour = (charcode&tms.colourmask);
pattern = (charcode&tms.patternmask);
patternptr = tms.vMem+tms.pattern+colour*8;
colourptr = tms.vMem+tms.colour+pattern*8;
for (yy=0;yy<8;yy++) {
pattern = *patternptr++;
colour = *colourptr++;
fg = colour / 16;
bg = colour & 15;
for (xx=0;xx<8;xx++) {
bitmap[(y * 8 + yy) * 256 + (x*8+xx)] = (pattern & 0x80) ? fg : bg;
pattern *= 2;
}
}
}
}
}
static void draw_mode3(unsigned short *bitmap)
{
int x,y,yy,yyy,name,charcode;
UINT8 fg,bg,*patternptr;
name = 0;
for (y=0;y<24;y++) {
for (x=0;x<32;x++) {
charcode = tms.vMem[tms.nametbl+name];
name++;
patternptr = tms.vMem+tms.pattern+charcode*8+(y&3)*2;
for (yy=0;yy<2;yy++) {
fg = (*patternptr / 16);
bg = ((*patternptr++) & 15);
for (yyy=0;yyy<4;yyy++) {
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+0)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+1)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+2)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+3)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+4)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+5)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+6)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+7)] = fg;
}
}
}
}
}
static void draw_mode23(unsigned short *bitmap)
{
int x,y,yy,yyy,name,charcode;
UINT8 fg,bg,*patternptr;
name = 0;
for (y=0;y<24;y++) {
for (x=0;x<32;x++) {
charcode = tms.vMem[tms.nametbl+name];
name++;
patternptr = tms.vMem + tms.pattern +
((charcode+(y&3)*2+(y/8)*256)&tms.patternmask)*8;
for (yy=0;yy<2;yy++) {
fg = (*patternptr / 16);
bg = ((*patternptr++) & 15);
for (yyy=0;yyy<4;yyy++) {
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+0)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+1)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+2)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+3)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+4)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+5)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+6)] = fg;
bitmap[(y*8+yy*4+yyy) * 256 + (x*8+7)] = fg;
}
}
}
}
}
static void draw_modebogus(unsigned short *bitmap)
{
UINT8 fg,bg;
int x,y,n,xx;
fg = tms.Regs[7] / 16;
bg = tms.Regs[7] & 15;
for (y=0;y<192;y++) {
xx=0;
n=8; while (n--) bitmap[y * 256 + (xx++)] = bg;
for (x=0;x<40;x++) {
n=4; while (n--) bitmap[y * 256 + (xx++)] = fg;
n=2; while (n--) bitmap[y * 256 + (xx++)] = bg;
}
n=8; while (n--) bitmap[y * 256 + (xx++)] = bg;
}
}
static void (*const ModeHandlers[])(unsigned short *bitmap) = {
draw_mode0, draw_mode1, draw_mode2, draw_mode12,
draw_mode3, draw_modebogus, draw_mode23,
draw_modebogus
};
static void draw_sprites()
{
UINT8 *attributeptr,*patternptr,c;
int p,x,y,size,i,j,large,yy,xx,limit[192],
illegalsprite,illegalspriteline;
UINT16 line,line2;
attributeptr = tms.vMem + tms.spriteattribute;
size = (tms.Regs[1] & 2) ? 16 : 8;
large = (int)(tms.Regs[1] & 1);
for (x=0;x<192;x++) limit[x] = 4;
tms.StatusReg = 0x80;
illegalspriteline = 255;
illegalsprite = 0;
memset (tms.dBackMem, 0, 256 * 192);
for (p=0;p<32;p++) {
y = *attributeptr++;
if (y == 208) break;
if (y > 208) {
y=-(~y&255);
} else {
y++;
}
x = *attributeptr++;
patternptr = tms.vMem + tms.spritepattern +
((size == 16) ? *attributeptr & 0xfc : *attributeptr) * 8;
attributeptr++;
c = (*attributeptr & 0x0f);
if (*attributeptr & 0x80) x -= 32;
attributeptr++;
if (!large) {
/* draw sprite (not enlarged) */
for (yy=y;yy<(y+size);yy++) {
if ( (yy < 0) || (yy > 191) ) continue;
if (limit[yy] == 0) {
/* illegal sprite line */
if (yy < illegalspriteline) {
illegalspriteline = yy;
illegalsprite = p;
} else if (illegalspriteline == yy) {
if (illegalsprite > p) {
illegalsprite = p;
}
}
if (tms.LimitSprites) continue;
} else limit[yy]--;
line = 256*patternptr[yy-y] + patternptr[yy-y+16];
for (xx=x;xx<(x+size);xx++) {
if (line & 0x8000) {
if ((xx >= 0) && (xx < 256)) {
if (tms.dBackMem[yy*256+xx]) {
tms.StatusReg |= 0x20;
} else {
tms.dBackMem[yy*256+xx] = 0x01;
}
if (c && ! (tms.dBackMem[yy*256+xx] & 0x02))
{
tms.dBackMem[yy*256+xx] |= 0x02;
pTransDraw[(tms.top_border+yy) * nScreenWidth + (15 + xx)] = c;
}
}
}
line *= 2;
}
}
} else {
/* draw enlarged sprite */
for (i=0;i<size;i++) {
yy=y+i*2;
line2 = 256*patternptr[i] + patternptr[i+16];
for (j=0;j<2;j++) {
if ( (yy >= 0) && (yy <= 191) ) {
if (limit[yy] == 0) {
/* illegal sprite line */
if (yy < illegalspriteline) {
illegalspriteline = yy;
illegalsprite = p;
} else if (illegalspriteline == yy) {
if (illegalsprite > p) {
illegalsprite = p;
}
}
if (tms.LimitSprites) continue;
} else limit[yy]--;
line = line2;
for (xx=x;xx<(x+size*2);xx+=2) {
if (line & 0x8000) {
if ((xx >=0) && (xx < 256)) {
if (tms.dBackMem[yy*256+xx]) {
tms.StatusReg |= 0x20;
} else {
tms.dBackMem[yy*256+xx] = 0x01;
}
if (c && ! (tms.dBackMem[yy*256+xx] & 0x02))
{
tms.dBackMem[yy*256+xx] |= 0x02;
pTransDraw[(tms.top_border+yy) * nScreenWidth + (15 + xx)] = c;
}
}
if (((xx+1) >=0) && ((xx+1) < 256)) {
if (tms.dBackMem[yy*256+xx+1]) {
tms.StatusReg |= 0x20;
} else {
tms.dBackMem[yy*256+xx+1] = 0x01;
}
if (c && ! (tms.dBackMem[yy*256+xx+1] & 0x02))
{
tms.dBackMem[yy*256+xx+1] |= 0x02;
pTransDraw[(tms.top_border+yy) * nScreenWidth + (15 + xx + 1)] = c;
}
}
}
line *= 2;
}
}
yy++;
}
}
}
}
if (illegalspriteline == 255) {
tms.StatusReg |= (p > 31) ? 31 : p;
} else {
tms.StatusReg |= 0x40 + illegalsprite;
}
}
int TMS9928ADraw()
{
int BackColour = tms.Regs[7] & 15;
if (!BackColour) BackColour=1;
TMS89928aPaletteRecalc();
Palette[0] = Palette[BackColour];
if (!(tms.Regs[1] & 0x40))
{
for (int i = 0; i < nScreenWidth * nScreenHeight; i++) {
pTransDraw[i] = BackColour;
}
}
else
{
int mode = ((((tms.model == TMS99x8A) || (tms.model == TMS9929A)) ? (tms.Regs[0] & 2) : 0) | ((tms.Regs[1] & 0x10)>>4) | ((tms.Regs[1] & 8)>>1));
(*ModeHandlers[mode])(tms.tmpbmp);
{
for (int y = 0; y < 192; y++)
{
for (int x = 0; x < 256; x++)
{
pTransDraw[(y + tms.top_border) * nScreenWidth + x + 15] = tms.tmpbmp[y * 256 + x];
}
}
}
{
for (int y = 0; y < tms.top_border; y++) { // top
for (int x = 0; x < 15 + 256 + 15; x++) {
pTransDraw[y * nScreenWidth + x] = BackColour;
}
}
for (int y = tms.top_border+192; y < tms.top_border+192+tms.bottom_border; y++) { // bottom
for (int x = 0; x < 15 + 256 + 15; x++) {
pTransDraw[y * nScreenWidth + x] = BackColour;
}
}
for (int y = tms.top_border; y < tms.top_border+192; y++) { // left
for (int x = 0; x < 15; x++) {
pTransDraw[y * nScreenWidth + x] = BackColour;
}
}
for (int y = tms.top_border; y < tms.top_border+192; y++) { // right
for (int x = 15+256; x < 15 + 256 + 15; x++) {
pTransDraw[y * nScreenWidth + x] = BackColour;
}
}
}
if ((tms.Regs[1] & 0x50) == 0x40)
draw_sprites();
}
BurnTransferCopy(Palette);
return 0;
}
int TMS9928AInterrupt()
{
int b = (tms.Regs[1] & 0x20) != 0;
tms.StatusReg |= 0x80;
if (b != tms.INT) {
tms.INT = b;
if (tms.INTCallback) tms.INTCallback (tms.INT);
}
return b;
}
int TMS9928AScan(int nAction, int *pnMin)
{
struct BurnArea ba;
if (pnMin) {
*pnMin = 0x029708;
}
if (nAction & ACB_VOLATILE) {
// memset(&ba, 0, sizeof(ba));
ba.Data = tms.vMem;
ba.nLen = tms.vramsize;
ba.szName = "video ram";
BurnAcb(&ba);
ba.Data = tms.Regs;
ba.nLen = 8;
ba.szName = "tms registers";
BurnAcb(&ba);
SCAN_VAR(tms.ReadAhead);
SCAN_VAR(tms.StatusReg);
SCAN_VAR(tms.FirstByte);
SCAN_VAR(tms.latch);
SCAN_VAR(tms.INT);
SCAN_VAR(tms.Addr);
SCAN_VAR(tms.colour);
SCAN_VAR(tms.pattern);
SCAN_VAR(tms.nametbl);
SCAN_VAR(tms.spriteattribute);
SCAN_VAR(tms.spritepattern);
SCAN_VAR(tms.colourmask);
SCAN_VAR(tms.patternmask);
}
return 0;
}

View File

@ -0,0 +1,28 @@
#define TMS9928A_PALETTE_SIZE 16
typedef enum
{
TMS_INVALID_MODEL,
TMS99x8,
TMS9929,
TMS99x8A,
TMS9929A
} tms9928a_model;
int TMS9928AInterrupt();
void TMS9928AInit(int model, int vram, int borderx, int bordery, void (*INTCallback)(int));
void TMS9928AReset();
void TMS9928AExit();
int TMS9928ADraw();
void TMS9928ASetSpriteslimit(int limit);
void TMS9928AWriteRegs(int data);
unsigned char TMS9928AReadRegs();
void TMS9928AWriteVRAM(int data);
unsigned char TMS9928AReadVRAM();
int TMS9928AScan(int nAction, int *pnMin);