If you are still using the old URL (datacrystal.romhacking.net), please update your bookmarks! The old URL may stop working soon.
The current URL is datacrystal.tcrf.net.
The current URL is datacrystal.tcrf.net.
Talk:Video (PC8801)
Jump to navigation
Jump to search
m88 Source
// --------------------------------------------------------------------------- // M88 - PC-88 Emulator. // Copyright (C) cisc 1998. // --------------------------------------------------------------------------- // ‰æ–ʧŒä‚ƃOƒ‰ƒtƒBƒbƒNƒX‚̃Gƒ~ƒ…ƒŒ[ƒVƒ‡ƒ“ // --------------------------------------------------------------------------- // ’ŽF // fullline = false Žž‚Ì”ñ•`‰æƒ‰ƒCƒ“‚ÌF‚ª palette 0 ˆË‘¶ // #include <stdio.h> #include <string.h> #include "Screen.h" // #include "Screen_i.h" static const bool fullline = true; #ifndef RELEASEBUILD // #define SCREEN_LOGGING #endif #ifdef SCREEN_LOGGING #define LOG0(a) if (fp) fprintf(fp, a) #define LOG1(a, b) if (fp) fprintf(fp, a, b) #define LOG2(a, b, c) if (fp) fprintf(fp, a, b, c) #define LOG3(a, b, c, d) if (fp) fprintf(fp, a, b, c, d) static FILE* fp; #else #define LOG0(a) #define LOG1(a, b) #define LOG2(a, b, c) #define LOG3(a, b, c, d) #endif // --------------------------------------------------------------------------- // \’z/Á–Å // --------------------------------------------------------------------------- Screen::Screen() { #ifdef SCREEN_LOGGING fp = fopen("screen.log", "w"); #endif CreateTable(); for (int i=0; i<8; i++) green[i] = red[i] = blue[i] = 0; line400 = false; port32 = 0; LOG0("Initial "); Reset(); } Screen::~Screen() { #ifdef SCREEN_LOGGING if (fp) fclose(fp); #endif } // --------------------------------------------------------------------------- // ‰Šú‰» // --------------------------------------------------------------------------- void Screen::Reset() { displaytext = true; // ƒeƒLƒXƒg‚ð•\Ž¦ selectedplane = 3; // RAM ‚ð‘I‘ð // nreads = nwrites = 0; SelectAccessFunc(); // ƒƒ‚ƒŠƒAƒNƒZƒXŠÖ”‚ðÝ’è LOG0("Reset!\n"); bgred = bggreen = bgblue = 0; } void Screen::Init() { displaygraphics = 7; InitPalette(); } // --------------------------------------------------------------------------- // ƒpƒŒƒbƒg‚ð‰Šú‰» // --------------------------------------------------------------------------- void Screen::InitPalette() { int i; if (color) { LOG2("mode: color %s\ttext %s\n", displaygraphics ? "enabled" : "disabled", displaytext ? "on" : "off"); int j = displaytext ? 0x40 : 0x80; for (i=0; i<j; i++) // ƒOƒ‰ƒtƒBƒbƒNƒX•” { SetPalette(i, red[i & displaygraphics], green[i & displaygraphics], blue[i & displaygraphics] ); // SetPalette(i, i & 2 ? 7 : 0, i & 4 ? 7 : 0, i & 1 ? 7 : 0); } if (!(port30 & 2)) { for (;i<0x80; i++) { #if 1 SetPalette(i, (i & 0x10) ? 7 : 0, (i & 0x20) ? 7 : 0, (i & 0x08) ? 7 : 0); #else // ƒeƒLƒXƒg”¼“§–¾ SetPalette(i, ((i & 0x10 ? 7 : 0) + red[i & displaygraphics]) / 2, ((i & 0x20 ? 7 : 0) + green[i & displaygraphics]) / 2, ((i & 0x08 ? 7 : 0) + blue[i & displaygraphics]) / 2 ); #endif } } else { for (;i<0x80; i++) SetPalette(i, 7, 7, 7); } } else { LOG3("mode: mono %s(%d)\ttext %s\n", displaygraphics ? "enabled" : "disabled", displayplane, displaytext ? "on" : "off"); if (!(port30 & 2)) { if (port32 & 0x20) { for (i=0; i<0x80; i++) { if (((i & 0x40) && displaytext) || (i & displayplane & displaygraphics)) SetPalette(i, red[(i>>3) & 7], green[(i>>3) & 7], blue[(i>>3) & 7]); else SetPalette(i, bgred, bggreen, bgblue); } } else { for (i=0; i<0x80; i++) { if (((i & 0x40) && displaytext) || (i & displayplane & displaygraphics)) SetPalette(i, i & 16 ? 7 : 0, i & 32 ? 7 : 0, i & 8 ? 7 : 0); else SetPalette(i, bgred, bggreen, bgblue); } } } else { for (i=0; i<0x80; i++) { if (((i & 0x40) && displaytext) || (i & displayplane & displaygraphics)) SetPalette(i, 7, 7, 7); else SetPalette(i, bgred, bggreen, bgblue); } } } } // --------------------------------------------------------------------------- // Out 52 // --------------------------------------------------------------------------- void Screen::Out52(uint data) { if (!(port32 & 0x20)) { bgblue = (data & 0x08) ? 7 : 0; bgred = (data & 0x10) ? 7 : 0; bggreen = (data & 0x20) ? 7 : 0; LOG1("bgpalette(d) = %3x\n", bggreen*256+bgred*16+bgblue); if (!color) reinitpalette = true; } } // --------------------------------------------------------------------------- // Out 53 // --------------------------------------------------------------------------- void Screen::Out53(uint data) { LOG1("port 53: %.2x\n", data); uint8 dpp = displayplane; bool dtp = displaytext; displayplane = ((~data >> 1) & 7); displaytext = !(data & 1); #ifndef RELEASEBUILD // displaytext = true; #endif if (dpp != displayplane || dtp != displaytext) reinitpalette = true; } // --------------------------------------------------------------------------- // Out 54 // --------------------------------------------------------------------------- void Screen::Out54(uint data) { if (port32 & 0x20) { if (data & 0x80) { // BG Color if (data & 0x40) bggreen = data & 7; else bgblue = data & 7, bgred = (data / 8) & 7; LOG1("bgpalette(a) = %3x\n", bggreen*256+bgred*16+bgblue); } else { if (data & 0x40) green[0] = data & 7; else blue[0] = data & 7, red[0] = (data/8) & 7; LOG1("palette(a) 0 = %3x\n", green[0]*256+red[0]*16+blue[0]); } } else { blue[0] = (data & 1) ? 7 : 0; red[0] = (data & 2) ? 7 : 0; green[0] = (data & 4) ? 7 : 0; LOG1("palette(d) 0 = %3x\n", green[0]*256+red[0]*16+blue[0]); } reinitpalette = true; } // --------------------------------------------------------------------------- // Out 55 - 5b // --------------------------------------------------------------------------- void Screen::Out55to5b(uint port, uint data) { LOG2("port %2x: %.2x\t\t", port, data); uint num = port - 0x54; if (port32 & 0x20) { if (data & 0x40) green[num] = data & 7; else blue[num] = data & 7, red[num] = (data/8) & 7; LOG2("palette(a) %d = %3x\n", num, green[num]*256+red[num]*16+blue[num]); } else { blue[num] = (data & 1) ? 7 : 0; red[num] = (data & 2) ? 7 : 0; green[num] = (data & 4) ? 7 : 0; LOG2("palette(d) %d = %3x\n", num, green[num]*256+red[num]*16+blue[num]); } reinitpalette = true; } // --------------------------------------------------------------------------- // Memory R/W ŠÖ”‚Ì‘I‘ð // --------------------------------------------------------------------------- void Screen::SelectAccessFunc() { static const Reader readfunc[4] = { &Screen::ReadPlane0, &Screen::ReadPlane1, &Screen::ReadPlane2, &Screen::Readdummy }; static const Writer writefunc[4] = { &Screen::WritePlane0, &Screen::WritePlane1, &Screen::WritePlane2, &Screen::Writedummy }; static const Writer aluwrite[4] = { &Screen::WriteALUSet, &Screen::WriteALURGB, &Screen::WriteALUB, &Screen::WriteALUR, }; // uint8 access; if (port32 & 0x40) { if (port35 & 0x80) { reader = &Screen::ReadALU; writer = aluwrite[ (port35 >> 4) & 3 ]; // access = 'A'; } else { reader = &Screen::Readdummy; writer = &Screen::Writedummy; // access = ' '; } } else { reader = readfunc[ selectedplane ]; writer = writefunc[ selectedplane ]; // access = selectedplane == 3 ? ' ' : selectedplane + '0'; } // LOG3("r:%8d w:%8d (%c) ", nreads, nwrites, access); // nreads = nwrites = 0; } // --------------------------------------------------------------------------- // •ÏXˆÊ’u‚Ì‹L˜^ // --------------------------------------------------------------------------- inline void Screen::SetDirtyFlag(uint addr) { dirtyline[addr >> 4] = true; } // --------------------------------------------------------------------------- // GVRAM planer access // --------------------------------------------------------------------------- uint8 Screen::ReadPlane0(uint addr) { return gvram[addr].byte[0]; } uint8 Screen::ReadPlane1(uint addr) { return gvram[addr].byte[1]; } uint8 Screen::ReadPlane2(uint addr) { return gvram[addr].byte[2]; } void Screen::WritePlane0(uint addr, uint data) { gvram[addr].byte[0] = data; SetDirtyFlag(addr); } void Screen::WritePlane1(uint addr, uint data) { gvram[addr].byte[1] = data; SetDirtyFlag(addr); } void Screen::WritePlane2(uint addr, uint data) { gvram[addr].byte[2] = data; SetDirtyFlag(addr); } // --------------------------------------------------------------------------- // GVRAM access via ALU // --------------------------------------------------------------------------- void Screen::WriteALUSet(uint addr, uint d) { quadbyte q; q.pack = ExpandTable[d & 0xff]; gvram[addr].pack = ((gvram[addr].pack & ~(q.pack & maskr.pack)) | (q.pack & masks.pack)) ^ (q.pack & maski.pack); SetDirtyFlag(addr); } void Screen::WriteALURGB(uint addr, uint d) { gvram[addr] = alureg; SetDirtyFlag(addr); } void Screen::WriteALUR(uint addr, uint d) { gvram[addr].byte[1] = alureg.byte[0]; SetDirtyFlag(addr); } void Screen::WriteALUB(uint addr, uint d) { gvram[addr].byte[0] = alureg.byte[1]; SetDirtyFlag(addr); } uint8 Screen::ReadALU(uint addr) { quadbyte q; alureg = gvram[addr]; q.pack = alureg.pack ^ aluread.pack; return ~(q.byte[0] | q.byte[1] | q.byte[2]); } // --------------------------------------------------------------------------- // Memory R/W dummy // --------------------------------------------------------------------------- void Screen::Writedummy(uint, uint) { } uint8 Screen::Readdummy(uint) { return 0xff; } // --------------------------------------------------------------------------- // Table ì¬ // --------------------------------------------------------------------------- packed Screen::ExpandTable[256] = { 1 }; packed Screen::ByteExpandTable[1 << sizeof(packed)]; void Screen::CreateTable() { if (ExpandTable[0]) { int i; for (i=0; i<0x100; i++) ExpandTable[i] = PACK(i); for (i=0; i<(1 << sizeof(packed)); i++) { packed p=0; for (int j=0; j<sizeof(packed); j++) { #ifdef ENDIAN_IS_BIG p = (p << 8) | (((1 << (sizeof(packed)-j)) & i) ? 7 : 0); #else p = (p << 8) | (((1 << j) & i) ? 7 : 0); #endif } ByteExpandTable[i] = p; } } } // --------------------------------------------------------------------------- // ‰æ–ÊXV // image “WŠJæ bitmap (8bps) // bpl bitmap ‚Ì• (640 ˆÈãA‘½•ª 4 bytes aligned ‚¶‚á‚È‚¢‚Æ‘Ê–Ú‚¾‚ÆŽv‚¤) // region update ‚µ‚½—̈æ‚ð—^‚¦‚邽‚ß‚Ì pointer (int 2 ŒÂ•ª) // [0] ŠJŽn (400 ˆÈã‚ÌꇂÍXV—̈æ‚È‚µ‚̈Ӗ¡) // [1] I—¹ (region[0] < region[1]) // void Screen::UpdateScreen(uint8* image, int bpl, int* region) { bool updateall = false; if (reinitpalette) { reinitpalette = false; updateall = true; InitPalette(); } if (shouldredraw) { shouldredraw = false; updateall = true; Redraw(image, bpl); } if (line400) UpdateScreen400(image, bpl, region); else UpdateScreen200(image, bpl, region); if (updateall) { region[0] = 0; region[1] = 399; } } // --------------------------------------------------------------------------- // ‰æ–ÊXV—pƒ}ƒNƒ // packed.‚Ì‘å‚«‚³‚Ɉˑ¶ // --------------------------------------------------------------------------- #define WRITE0(s, d) dest[d] = \ (dest[d] & ~PACK(GVRAM_BIT)) \ | (ByteExpandTable[src[s].byte[0] >> 4] & PACK(GVRAM0_SET)) \ | (ByteExpandTable[src[s].byte[1] >> 4] & PACK(GVRAM1_SET)) \ | (ByteExpandTable[src[s].byte[2] >> 4] & PACK(GVRAM2_SET)) #define WRITE1(s, d) dest[d] = \ (dest[d] & ~PACK(GVRAM_BIT)) \ | (ByteExpandTable[src[s].byte[0] & 15] & PACK(GVRAM0_SET)) \ | (ByteExpandTable[src[s].byte[1] & 15] & PACK(GVRAM1_SET)) \ | (ByteExpandTable[src[s].byte[2] & 15] & PACK(GVRAM2_SET)) #define WRITE0F(s, d) dest[d] = *((packed*)(((uint8*)(dest+d))+bpl)) = \ (dest[d] & ~PACK(GVRAM_BIT)) \ | (ByteExpandTable[src[s].byte[0] >> 4] & PACK(GVRAM0_SET)) \ | (ByteExpandTable[src[s].byte[1] >> 4] & PACK(GVRAM1_SET)) \ | (ByteExpandTable[src[s].byte[2] >> 4] & PACK(GVRAM2_SET)) #define WRITE1F(s, d) dest[d] = *((packed*)(((uint8*)(dest+d))+bpl)) = \ (dest[d] & ~PACK(GVRAM_BIT)) \ | (ByteExpandTable[src[s].byte[0] & 15] & PACK(GVRAM0_SET)) \ | (ByteExpandTable[src[s].byte[1] & 15] & PACK(GVRAM1_SET)) \ | (ByteExpandTable[src[s].byte[2] & 15] & PACK(GVRAM2_SET)) #define WRITE400(d, s, b) \ (d)[0] = ((d)[0] & 0xf8f8f8f8) | ByteExpandTable[(s)->byte[b] >> 4]; \ (d)[1] = ((d)[1] & 0xf8f8f8f8) | ByteExpandTable[(s)->byte[b] & 15]; // --------------------------------------------------------------------------- // ‰æ–ÊXV (200 line mode) // --------------------------------------------------------------------------- void Screen::UpdateScreen200(uint8* image, int bpl, int* region) { int y; for (y=0; y<1000; y+=sizeof(packed)) // ʼn‚ÉXV‚·‚郉ƒCƒ“‚ð’T‚· { if (*(packed*)(&dirtyline[y])) break; } if (y < 1000) { y /= 5; region[0] = y * 2; int lasty = -1; uint8* d = image + y * bpl * 2; volatile bool* dline = dirtyline + y * 5; if (!fullline) { quadbyte* src = gvram + y * 80; for (; y<200; y++, d += bpl*2) { packed* dest = (packed*) d; for (int x=0; x<5; x++, dline++, src += 16, dest += 32) { if (*dline) { *dline = 0; lasty = y; for (int j=0; j<16; j+=4) { WRITE0(j, j*2 ); WRITE1(j, j*2+1); WRITE0(j+1, j*2+2); WRITE1(j+1, j*2+3); WRITE0(j+2, j*2+4); WRITE1(j+2, j*2+5); WRITE0(j+3, j*2+6); WRITE1(j+3, j*2+7); } } } } } else // ‚±‚Ì’†Š‡ŒÊ“à‚̓}ƒNƒˆÈŠO“¯‚¶ { quadbyte* src = gvram + y * 80; for (; y<200; y++, d += bpl*2) { packed* dest = (packed*) d; for (int x=0; x<5; x++, dline++, src += 16, dest += 32) { if (*dline) { *dline = 0; lasty = y; for (int j=0; j<16; j+=4) { WRITE0F(j, j*2 ); WRITE1F(j, j*2+1); WRITE0F(j+1, j*2+2); WRITE1F(j+1, j*2+3); WRITE0F(j+2, j*2+4); WRITE1F(j+2, j*2+5); WRITE0F(j+3, j*2+6); WRITE1F(j+3, j*2+7); } } } } } region[1] = lasty * 2 + 1; } else { region[0] = 400; region[1] = -1; } } // --------------------------------------------------------------------------- // ‰æ–ÊXV (400 line mode) // --------------------------------------------------------------------------- void Screen::UpdateScreen400(uint8* image, int bpl, int* region) { int y; for (y=0; y<1000; y+=sizeof(packed)) // ʼn‚ÉXV‚·‚郉ƒCƒ“‚ð’T‚· { if (*(packed*)(&dirtyline[y])) break; } if (y < 1000) { y /= 5; region[0] = y; int lasty = -1000; volatile bool* dline = dirtyline + y * 5; uint8* d0 = image + y * bpl; uint8* d1 = d0 + 200 * bpl; quadbyte* src = gvram + y * 80; for (; y<200; y++, d0+=bpl, d1+=bpl) { packed* dest0 = (packed*) d0; packed* dest1 = (packed*) d1; for (int x=0; x<5; x++) { if (*dline) { *dline=0; lasty = y; for (int j=0; j<16; j++) { WRITE400(dest0+j*2, src+j, 0); WRITE400(dest1+j*2, src+j, 1); } } dline++; src += 16; dest0 += 32; dest1 += 32; } } region[1] = lasty + 200; } else { region[0] = 400; region[1] = -1; } } // --------------------------------------------------------------------------- // ‰æ–ÊÄ•`‰æ // --------------------------------------------------------------------------- void Screen::Redraw(uint8* image, int bpl) { int i; if (!(fullline || line400)) // ƒOƒ‰ƒtƒBƒbƒNƒX‚̃‰ƒCƒ“ŠÔ‚ðÁ‹Ž { uint8* dest = image + bpl; for (i=1; i<400; i+=2, dest+=bpl*2) { packed* d = (packed*) dest; for (int j=0; j<640/8/sizeof(packed); j++) { d[0] &= ~PACK(GVRAM_BIT); d[1] &= ~PACK(GVRAM_BIT); d[2] &= ~PACK(GVRAM_BIT); d[3] &= ~PACK(GVRAM_BIT); d[4] &= ~PACK(GVRAM_BIT); d[5] &= ~PACK(GVRAM_BIT); d[6] &= ~PACK(GVRAM_BIT); d[7] &= ~PACK(GVRAM_BIT); d += 8; } } } for (i=0; i<1024; i++) dirtyline[i] = true; }