From 008ceba73897b072e7b292ef2300db9b8ec0e5b6 Mon Sep 17 00:00:00 2001 From: dinkc64 <12570148+dinkc64@users.noreply.github.com> Date: Sun, 17 Aug 2014 20:04:19 +0000 Subject: [PATCH] add TMS9928a video chip to devices --- makefile.burn_rules | 2 +- src/burn/devices/tms9928a.cpp | 702 ++++++++++++++++++++++++++++++++++ src/burn/devices/tms9928a.h | 28 ++ 3 files changed, 731 insertions(+), 1 deletion(-) create mode 100644 src/burn/devices/tms9928a.cpp create mode 100644 src/burn/devices/tms9928a.h diff --git a/makefile.burn_rules b/makefile.burn_rules index 8c4d9067d..001830e02 100644 --- a/makefile.burn_rules +++ b/makefile.burn_rules @@ -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 \ diff --git a/src/burn/devices/tms9928a.cpp b/src/burn/devices/tms9928a.cpp new file mode 100644 index 000000000..344599de7 --- /dev/null +++ b/src/burn/devices/tms9928a.cpp @@ -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= 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; +} diff --git a/src/burn/devices/tms9928a.h b/src/burn/devices/tms9928a.h new file mode 100644 index 000000000..870c1f1c7 --- /dev/null +++ b/src/burn/devices/tms9928a.h @@ -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);