// $Id: V9990CmdEngine.cc 5847 2006-11-04 20:50:36Z m9710797 $ #include "V9990CmdEngine.hh" #include "V9990.hh" #include "V9990VRAM.hh" #include "MSXMotherBoard.hh" #include "RenderSettings.hh" #include "BooleanSetting.hh" #include namespace openmsx { // Timing tables TODO const unsigned LMMV_TIMING[2] = { 24, 0 }; const unsigned LMMM_TIMING[2] = { 24, 0 }; const unsigned CMMM_TIMING[2] = { 24, 0 }; const unsigned BMXL_TIMING[2] = { 24, 0 }; const unsigned BMLX_TIMING[2] = { 24, 0 }; const unsigned BMLL_TIMING[2] = { 24, 0 }; const unsigned LINE_TIMING[2] = { 24, 0 }; const unsigned SRCH_TIMING[2] = { 24, 0 }; static byte bitLUT[8][16][2][2]; static byte logOpLUT[4][16][0x100][0x100]; // 4MB !! optimize if needed enum { LOG_NO_T, LOG_BPP2, LOG_BPP4, LOG_BPP8 }; enum CommandMode { CMD_P1, CMD_P2, CMD_BPP2, CMD_BPP4, CMD_BPP8, CMD_BPP16 }; static void initBitTab() { for (unsigned op = 0; op < 16; ++op) { unsigned tmp = op; for (unsigned src = 0; src < 2; ++src) { for (unsigned dst = 0; dst < 2; ++dst) { unsigned b = tmp & 1; for (unsigned bit = 0; bit < 8; ++bit) { bitLUT[bit][op][src][dst] = b << bit; } tmp >>= 1; } } } } static inline byte func01(unsigned op, unsigned src, unsigned dst) { if ((src & 0x03) == 0) return dst & 0x03; byte res = 0; res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0]; res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1]; return res; } static inline byte func23(unsigned op, unsigned src, unsigned dst) { if ((src & 0x0C) == 0) return dst & 0x0C; byte res = 0; res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2]; res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3]; return res; } static inline byte func45(unsigned op, unsigned src, unsigned dst) { if ((src & 0x30) == 0) return dst & 0x30; byte res = 0; res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4]; res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5]; return res; } static inline byte func67(unsigned op, unsigned src, unsigned dst) { if ((src & 0xC0) == 0) return dst & 0xC0; byte res = 0; res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6]; res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7]; return res; } static inline byte func03(unsigned op, unsigned src, unsigned dst) { if ((src & 0x0F) == 0) return dst & 0x0F; byte res = 0; res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0]; res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1]; res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2]; res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3]; return res; } static inline byte func47(unsigned op, unsigned src, unsigned dst) { if ((src & 0xF0) == 0) return dst & 0xF0; byte res = 0; res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4]; res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5]; res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6]; res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7]; return res; } static inline byte func07(unsigned op, unsigned src, unsigned dst) { // if (src == 0) return dst; // handled in fillTable8 byte res = 0; res |= bitLUT[0][op][(src & 0x01) >> 0][(dst & 0x01) >> 0]; res |= bitLUT[1][op][(src & 0x02) >> 1][(dst & 0x02) >> 1]; res |= bitLUT[2][op][(src & 0x04) >> 2][(dst & 0x04) >> 2]; res |= bitLUT[3][op][(src & 0x08) >> 3][(dst & 0x08) >> 3]; res |= bitLUT[4][op][(src & 0x10) >> 4][(dst & 0x10) >> 4]; res |= bitLUT[5][op][(src & 0x20) >> 5][(dst & 0x20) >> 5]; res |= bitLUT[6][op][(src & 0x40) >> 6][(dst & 0x40) >> 6]; res |= bitLUT[7][op][(src & 0x80) >> 7][(dst & 0x80) >> 7]; return res; } static void fillTableNoT(unsigned op, byte* table) { for (unsigned dst = 0; dst < 256; ++dst) { for (unsigned src = 0; src < 256; ++src) { table[dst * 256 + src] = func07(op, src, dst); } } } static void fillTable2(unsigned op, byte* table) { for (unsigned dst = 0; dst < 256; ++dst) { for (unsigned src = 0; src < 256; ++src) { byte res = 0; res |= func01(op, src, dst); res |= func23(op, src, dst); res |= func45(op, src, dst); res |= func67(op, src, dst); table[dst * 256 + src] = res; } } } static void fillTable4(unsigned op, byte* table) { for (unsigned dst = 0; dst < 256; ++dst) { for (unsigned src = 0; src < 256; ++src) { byte res = 0; res |= func03(op, src, dst); res |= func47(op, src, dst); table[dst * 256 + src] = res; } } } static void fillTable8(unsigned op, byte* table) { for (unsigned dst = 0; dst < 256; ++dst) { { // src == 0 table[dst * 256 + 0 ] = dst; } for (unsigned src = 1; src < 256; ++src) { // src != 0 table[dst * 256 + src] = func07(op, src, dst); } } } static void initTabs() { initBitTab(); for (int op = 0; op < 0x10; ++op) { fillTableNoT(op, &logOpLUT[LOG_NO_T][op][0][0]); fillTable2 (op, &logOpLUT[LOG_BPP2][op][0][0]); fillTable4 (op, &logOpLUT[LOG_BPP4][op][0][0]); fillTable8 (op, &logOpLUT[LOG_BPP8][op][0][0]); } } static const byte DIY = 0x08; static const byte DIX = 0x04; static const byte NEQ = 0x02; static const byte MAJ = 0x01; // P1 -------------------------------------------------------------- inline unsigned V9990CmdEngine::V9990P1::getPitch(unsigned width) { return width / 2; } inline unsigned V9990CmdEngine::V9990P1::addressOf( unsigned x, unsigned y, unsigned pitch) { //return V9990VRAM::transformP1(((x / 2) & (pitch - 1)) + y * pitch) & 0x7FFFF; // TODO figure out exactly how the coordinate system maps to vram in P1 unsigned addr = V9990VRAM::transformP1(((x / 2) & (pitch - 1)) + y * pitch); return (addr & 0x3FFFF) | ((x & 0x200) << 9); } inline byte V9990CmdEngine::V9990P1::point( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch) { return vram.readVRAMDirect(addressOf(x, y, pitch)); } inline byte V9990CmdEngine::V9990P1::shift( byte value, unsigned fromX, unsigned toX) { int shift = 4 * ((toX & 1) - (fromX & 1)); return (shift > 0) ? (value >> shift) : (value << -shift); } inline const byte* V9990CmdEngine::V9990P1::getLogOpLUT(byte op) { return &logOpLUT[(op & 0x10) ? LOG_BPP4 : LOG_NO_T][op & 0xF][0][0]; } inline byte V9990CmdEngine::V9990P1::logOp( const byte* lut, byte src, byte dst) { return lut[256 * dst + src]; } inline void V9990CmdEngine::V9990P1::pset( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, byte srcColor, word mask, const byte* lut, byte /*op*/) { unsigned addr = addressOf(x, y, pitch); byte dstColor = vram.readVRAMDirect(addr); byte newColor = logOp(lut, srcColor, dstColor); byte mask1 = (addr & 0x40000) ? (mask >> 8) : (mask & 0xFF); byte mask2 = mask1 & (0xF0 >> (4 * (x & 1))); byte result = (dstColor & ~mask2) | (newColor & mask2); vram.writeVRAMDirect(addr, result); } inline void V9990CmdEngine::V9990P1::psetColor( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, word color, word mask, const byte* lut, byte /*op*/) { unsigned addr = addressOf(x, y, pitch); byte srcColor = (addr & 0x40000) ? (color >> 8) : (color & 0xFF); byte dstColor = vram.readVRAMDirect(addr); byte newColor = logOp(lut, srcColor, dstColor); byte mask1 = (addr & 0x40000) ? (mask >> 8) : (mask & 0xFF); byte mask2 = mask1 & (0xF0 >> (4 * (x & 1))); byte result = (dstColor & ~mask2) | (newColor & mask2); vram.writeVRAMDirect(addr, result); } // P2 -------------------------------------------------------------- inline unsigned V9990CmdEngine::V9990P2::getPitch(unsigned width) { return width / 2; } inline unsigned V9990CmdEngine::V9990P2::addressOf( unsigned x, unsigned y, unsigned pitch) { // TODO check return V9990VRAM::transformP2(((x / 2) & (pitch - 1)) + y * pitch) & 0x7FFFF; } inline byte V9990CmdEngine::V9990P2::point( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch) { return vram.readVRAMDirect(addressOf(x, y, pitch)); } inline byte V9990CmdEngine::V9990P2::shift( byte value, unsigned fromX, unsigned toX) { int shift = 4 * ((toX & 1) - (fromX & 1)); return (shift > 0) ? (value >> shift) : (value << -shift); } inline const byte* V9990CmdEngine::V9990P2::getLogOpLUT(byte op) { return &logOpLUT[(op & 0x10) ? LOG_BPP4 : LOG_NO_T][op & 0xF][0][0]; } inline byte V9990CmdEngine::V9990P2::logOp( const byte* lut, byte src, byte dst) { return lut[256 * dst + src]; } inline void V9990CmdEngine::V9990P2::pset( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, byte srcColor, word mask, const byte* lut, byte /*op*/) { unsigned addr = addressOf(x, y, pitch); byte dstColor = vram.readVRAMDirect(addr); byte newColor = logOp(lut, srcColor, dstColor); byte mask1 = (addr & 0x40000) ? (mask >> 8) : (mask & 0xFF); byte mask2 = mask1 & (0xF0 >> (4 * (x & 1))); byte result = (dstColor & ~mask2) | (newColor & mask2); vram.writeVRAMDirect(addr, result); } inline void V9990CmdEngine::V9990P2::psetColor( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, word color, word mask, const byte* lut, byte /*op*/) { unsigned addr = addressOf(x, y, pitch); byte srcColor = (addr & 0x40000) ? (color >> 8) : (color & 0xFF); byte dstColor = vram.readVRAMDirect(addr); byte newColor = logOp(lut, srcColor, dstColor); byte mask1 = (addr & 0x40000) ? (mask >> 8) : (mask & 0xFF); byte mask2 = mask1 & (0xF0 >> (4 * (x & 1))); byte result = (dstColor & ~mask2) | (newColor & mask2); vram.writeVRAMDirect(addr, result); } // 2 bpp -------------------------------------------------------------- inline unsigned V9990CmdEngine::V9990Bpp2::getPitch(unsigned width) { return width / 4; } inline unsigned V9990CmdEngine::V9990Bpp2::addressOf( unsigned x, unsigned y, unsigned pitch) { return V9990VRAM::transformBx(((x / 4) & (pitch - 1)) + y * pitch) & 0x7FFFF; } inline byte V9990CmdEngine::V9990Bpp2::point( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch) { return vram.readVRAMDirect(addressOf(x, y, pitch)); } inline byte V9990CmdEngine::V9990Bpp2::shift( byte value, unsigned fromX, unsigned toX) { int shift = 2 * ((toX & 3) - (fromX & 3)); return (shift > 0) ? (value >> shift) : (value << -shift); } inline const byte* V9990CmdEngine::V9990Bpp2::getLogOpLUT(byte op) { return &logOpLUT[(op & 0x10) ? LOG_BPP2 : LOG_NO_T][op & 0xF][0][0]; } inline byte V9990CmdEngine::V9990Bpp2::logOp( const byte* lut, byte src, byte dst) { return lut[256 * dst + src]; } inline void V9990CmdEngine::V9990Bpp2::pset( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, byte srcColor, word mask, const byte* lut, byte /*op*/) { unsigned addr = addressOf(x, y, pitch); byte dstColor = vram.readVRAMDirect(addr); byte newColor = logOp(lut, srcColor, dstColor); byte mask1 = (addr & 0x40000) ? (mask >> 8) : (mask & 0xFF); byte mask2 = mask1 & (0xC0 >> (2 * (x & 3))); byte result = (dstColor & ~mask2) | (newColor & mask2); vram.writeVRAMDirect(addr, result); } inline void V9990CmdEngine::V9990Bpp2::psetColor( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, word color, word mask, const byte* lut, byte /*op*/) { unsigned addr = addressOf(x, y, pitch); byte srcColor = (addr & 0x40000) ? (color >> 8) : (color & 0xFF); byte dstColor = vram.readVRAMDirect(addr); byte newColor = logOp(lut, srcColor, dstColor); byte mask1 = (addr & 0x40000) ? (mask >> 8) : (mask & 0xFF); byte mask2 = mask1 & (0xC0 >> (2 * (x & 3))); byte result = (dstColor & ~mask2) | (newColor & mask2); vram.writeVRAMDirect(addr, result); } // 4 bpp -------------------------------------------------------------- inline unsigned V9990CmdEngine::V9990Bpp4::getPitch(unsigned width) { return width / 2; } inline unsigned V9990CmdEngine::V9990Bpp4::addressOf( unsigned x, unsigned y, unsigned pitch) { return V9990VRAM::transformBx(((x / 2) & (pitch - 1)) + y * pitch) & 0x7FFFF; } inline byte V9990CmdEngine::V9990Bpp4::point( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch) { return vram.readVRAMDirect(addressOf(x, y, pitch)); } inline byte V9990CmdEngine::V9990Bpp4::shift( byte value, unsigned fromX, unsigned toX) { int shift = 4 * ((toX & 1) - (fromX & 1)); return (shift > 0) ? (value >> shift) : (value << -shift); } inline const byte* V9990CmdEngine::V9990Bpp4::getLogOpLUT(byte op) { return &logOpLUT[(op & 0x10) ? LOG_BPP4 : LOG_NO_T][op & 0xF][0][0]; } inline byte V9990CmdEngine::V9990Bpp4::logOp( const byte* lut, byte src, byte dst) { return lut[256 * dst + src]; } inline void V9990CmdEngine::V9990Bpp4::pset( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, byte srcColor, word mask, const byte* lut, byte /*op*/) { unsigned addr = addressOf(x, y, pitch); byte dstColor = vram.readVRAMDirect(addr); byte newColor = logOp(lut, srcColor, dstColor); byte mask1 = (addr & 0x40000) ? (mask >> 8) : (mask & 0xFF); byte mask2 = mask1 & (0xF0 >> (4 * (x & 1))); byte result = (dstColor & ~mask2) | (newColor & mask2); vram.writeVRAMDirect(addr, result); } inline void V9990CmdEngine::V9990Bpp4::psetColor( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, word color, word mask, const byte* lut, byte /*op*/) { unsigned addr = addressOf(x, y, pitch); byte srcColor = (addr & 0x40000) ? (color >> 8) : (color & 0xFF); byte dstColor = vram.readVRAMDirect(addr); byte newColor = logOp(lut, srcColor, dstColor); byte mask1 = (addr & 0x40000) ? (mask >> 8) : (mask & 0xFF); byte mask2 = mask1 & (0xF0 >> (4 * (x & 1))); byte result = (dstColor & ~mask2) | (newColor & mask2); vram.writeVRAMDirect(addr, result); } // 8 bpp -------------------------------------------------------------- inline unsigned V9990CmdEngine::V9990Bpp8::getPitch(unsigned width) { return width; } inline unsigned V9990CmdEngine::V9990Bpp8::addressOf( unsigned x, unsigned y, unsigned pitch) { return V9990VRAM::transformBx((x & (pitch - 1)) + y * pitch) & 0x7FFFF; } inline byte V9990CmdEngine::V9990Bpp8::point( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch) { return vram.readVRAMDirect(addressOf(x, y, pitch)); } inline byte V9990CmdEngine::V9990Bpp8::shift( byte value, unsigned /*fromX*/, unsigned /*toX*/) { return value; } inline const byte* V9990CmdEngine::V9990Bpp8::getLogOpLUT(byte op) { return &logOpLUT[(op & 0x10) ? LOG_BPP8 : LOG_NO_T][op & 0xF][0][0]; } inline byte V9990CmdEngine::V9990Bpp8::logOp( const byte* lut, byte src, byte dst) { return lut[256 * dst + src]; } inline void V9990CmdEngine::V9990Bpp8::pset( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, byte srcColor, word mask, const byte* lut, byte /*op*/) { unsigned addr = addressOf(x, y, pitch); byte dstColor = vram.readVRAMDirect(addr); byte newColor = logOp(lut, srcColor, dstColor); byte mask1 = (addr & 0x40000) ? (mask >> 8) : (mask & 0xFF); byte result = (dstColor & ~mask1) | (newColor & mask1); vram.writeVRAMDirect(addr, result); } inline void V9990CmdEngine::V9990Bpp8::psetColor( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, word color, word mask, const byte* lut, byte /*op*/) { unsigned addr = addressOf(x, y, pitch); byte srcColor = (addr & 0x40000) ? (color >> 8) : (color & 0xFF); byte dstColor = vram.readVRAMDirect(addr); byte newColor = logOp(lut, srcColor, dstColor); byte mask1 = (addr & 0x40000) ? (mask >> 8) : (mask & 0xFF); byte result = (dstColor & ~mask1) | (newColor & mask1); vram.writeVRAMDirect(addr, result); } // 16 bpp ------------------------------------------------------------- inline unsigned V9990CmdEngine::V9990Bpp16::getPitch(unsigned width) { //return width * 2; return width; } inline unsigned V9990CmdEngine::V9990Bpp16::addressOf( unsigned x, unsigned y, unsigned pitch) { //return V9990VRAM::transformBx(((x * 2) & (pitch - 1)) + y * pitch) & 0x7FFFF; return ((x & (pitch - 1)) + y * pitch) & 0x3FFFF; } inline word V9990CmdEngine::V9990Bpp16::point( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch) { unsigned addr = addressOf(x, y, pitch); return vram.readVRAMDirect(addr + 0x00000) + vram.readVRAMDirect(addr + 0x40000) * 256; } inline word V9990CmdEngine::V9990Bpp16::shift( word value, unsigned /*fromX*/, unsigned /*toX*/) { return value; } inline const byte* V9990CmdEngine::V9990Bpp16::getLogOpLUT(byte op) { return &logOpLUT[LOG_NO_T][op & 0xF][0][0]; } inline word V9990CmdEngine::V9990Bpp16::logOp( const byte* lut, word src, word dst, bool transp) { if (transp && (src == 0)) return dst; return (lut[((dst & 0x00FF) << 8) + ((src & 0x00FF) >> 0)] << 0) + (lut[((dst & 0xFF00) << 0) + ((src & 0xFF00) >> 8)] << 8); } inline void V9990CmdEngine::V9990Bpp16::pset( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, word srcColor, word mask, const byte* lut, byte op) { unsigned addr = addressOf(x, y, pitch); word dstColor = vram.readVRAMDirect(addr + 0x00000) + vram.readVRAMDirect(addr + 0x40000) * 256; word newColor = logOp(lut, srcColor, dstColor, op & 0x10); word result = (dstColor & ~mask) | (newColor & mask); vram.writeVRAMDirect(addr + 0x00000, result & 0xFF); vram.writeVRAMDirect(addr + 0x40000, result >> 8); } inline void V9990CmdEngine::V9990Bpp16::psetColor( V9990VRAM& vram, unsigned x, unsigned y, unsigned pitch, word srcColor, word mask, const byte* lut, byte op) { unsigned addr = addressOf(x, y, pitch); word dstColor = vram.readVRAMDirect(addr + 0x00000) + vram.readVRAMDirect(addr + 0x40000) * 256; word newColor = logOp(lut, srcColor, dstColor, op & 0x10); word result = (dstColor & ~mask) | (newColor & mask); vram.writeVRAMDirect(addr + 0x00000, result & 0xFF); vram.writeVRAMDirect(addr + 0x40000, result >> 8); } // ==================================================================== /** Constructor */ V9990CmdEngine::V9990CmdEngine(V9990& vdp_, const EmuTime& time, RenderSettings& settings_) : vdp(vdp_), settings(settings_) { MSXMotherBoard::SharedStuff& info = vdp.getMotherBoard().getSharedStuff("v9990cmdtrace"); if (info.counter == 0) { assert(info.stuff == NULL); info.stuff = new BooleanSetting( vdp.getMotherBoard().getCommandController(), "v9990cmdtrace", "V9990 command tracing on/off", false); } ++info.counter; cmdTraceSetting = reinterpret_cast(info.stuff); initTabs(); CmdSTOP* stopCmd = new CmdSTOP(*this, vdp.getVRAM()); for (int mode = 0; mode < 6; ++mode) { commands[0][mode] = stopCmd; } createEngines (0x01); createEngines (0x02); createEngines (0x03); createEngines (0x04); createEngines (0x05); createEngines (0x06); createEngines (0x07); createEngines (0x08); createEngines (0x09); createEngines (0x0A); createEngines (0x0B); createEngines (0x0C); createEngines(0x0D); createEngines (0x0E); createEngines (0x0F); update(settings.getCmdTiming()); settings.getCmdTiming().attach(*this); reset(time); } template