If you are still using the old URL (datacrystal.romhacking.net), please update your bookmarks! The old URL may stop working at any time.
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; }