/* V2MemTest - A CLI Tool to test & fix Voodoo² TMU System * Copyright (C) 2026 ChaCha * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include <3dfx.h> #include #include "FaultSources.h" #include "Utils.h" #include "Draw.h" #include "Test_Data_Huge.h" #define _DEF_NB_PIXEL_ROW 256 #define _DEF_NB_PIXEL_COL 256 //#define _PROFILING static unsigned long long RenderTest( sst1DeviceInfoStruct* devInfo, FxU32* sst, SstRegs *sstregs, const char ucNumTMU, const FxU32 mem) { unsigned long NbErr = 0; #ifdef _PROFILING clock_t begin = clock(); #endif ISET(sstregs->texBaseAddr, (mem>>3)); /* set to mem addr */ static unsigned short ar_u16Pixels[_DEF_NB_PIXEL_ROW][_DEF_NB_PIXEL_COL]; static unsigned long ar_u16PixelsRaw[_DEF_NB_PIXEL_ROW][_DEF_NB_PIXEL_COL/2]; static unsigned short ar_u16PixelsReRead[_DEF_NB_PIXEL_ROW][_DEF_NB_PIXEL_COL]; for(unsigned short iter_row = 0; iter_row < _DEF_NB_PIXEL_ROW; iter_row++) { for(unsigned short iter_col = 0; iter_col < _DEF_NB_PIXEL_COL; iter_col+=2) { const unsigned long NewData = get_notnull_random_balanced_mByte(); ar_u16PixelsRaw[iter_row][iter_col/2] = NewData; ar_u16Pixels[iter_row][iter_col] = NewData >>16; ar_u16Pixels[iter_row][iter_col+1] = NewData & 0xFFFF; } } #ifdef _PROFILING clock_t after_create = clock(); #endif volatile FxU32 *texRowAddr = (ucNumTMU<<(21-2)) + (((FxU32)0/*LOD0*/)<<(17-2)) + (FxU32 *)SST_TEX_ADDRESS(sst); for(unsigned short iter_row = 0; iter_row < _DEF_NB_PIXEL_ROW; iter_row++) { for(unsigned short iter_col = 0; iter_col < _DEF_NB_PIXEL_COL/2; iter_col++) { //printf("writing %d\n",ar_u16PixelsRaw[iter_row][iter_col]); ISET(texRowAddr[iter_col], ar_u16PixelsRaw[iter_row][iter_col]); } texRowAddr += (1<<(9-2)); //jump to next line } #ifdef _PROFILING clock_t after_write = clock(); #define NB_CHECK_LOOP 3 clock_t before_draw[NB_CHECK_LOOP]; clock_t after_draw[NB_CHECK_LOOP]; clock_t after_read[NB_CHECK_LOOP]; clock_t after_check[NB_CHECK_LOOP]; #endif for(unsigned int i = 0; i> 16; ar_u16PixelsReRead[iter_row][iter_col+1] = *rptr & 0xFFFF; rptr+=1; } rptr+=info.strideInBytes>>2; } grLfbUnlock(GR_LFB_READ_ONLY,GR_BUFFER_FRONTBUFFER); } else { printf("NOT LFB access.\n"); } */ volatile FxU32* pLFB = sst + (SST_LFB_ADDR>>2); for(unsigned short iter_row = 0; iter_row < _DEF_NB_PIXEL_ROW; iter_row++) { //printf("reading row %d\n",iter_row); for(unsigned short iter_col = 0; iter_col < _DEF_NB_PIXEL_COL; iter_col+=2) { const FxU32 u32Data = *pLFB++; ar_u16PixelsReRead[iter_row][iter_col] = u32Data >> 16; ar_u16PixelsReRead[iter_row][iter_col+1] = u32Data & 0xFFFF; //printf("read: %d\n",u32Data); } pLFB += ((2048)>>2) - ((_DEF_NB_PIXEL_COL*2) >>2) ; } #ifdef _PROFILING after_read[i] = clock(); #endif for(unsigned short iter_row = 0; iter_row < _DEF_NB_PIXEL_ROW; iter_row++) { //printf("checking row %d\n",iter_row); for(unsigned short iter_col = 0; iter_col < _DEF_NB_PIXEL_COL; iter_col+=2) { if(ar_u16PixelsReRead[iter_row][iter_col] != ar_u16Pixels[iter_row][iter_col]) {/* printf("Error pix1 on row %d, col %d: expected %04x, got %04x\n", iter_row, iter_col, ar_u16Pixels[iter_row][iter_col], ar_u16PixelsReRead[iter_row][iter_col]);*/ NbErr++; } if(ar_u16PixelsReRead[iter_row][iter_col+1] != ar_u16Pixels[iter_row][iter_col+1]) {/* printf("Error pix2 on row %d, col %d: expected %04x, got %04x\n", iter_row, iter_col, ar_u16Pixels[iter_row][iter_col+1], ar_u16PixelsReRead[iter_row][iter_col+1]);*/ NbErr++; } } } #ifdef _PROFILING after_check[i] = clock(); #endif } #ifdef _PROFILING clock_t end = clock(); printf("time to create: %f\n",(double)(after_create-begin)/CLOCKS_PER_SEC); printf("time to write: %f\n",(double)(after_write-after_create)/CLOCKS_PER_SEC); for(unsigned int i = 0; itmuInit0[(int)ucNumTMU] = SST_TREXINIT0_DEFAULT ; sst1InitIdle(sst); ISET(SST_TREX(sstregs,ucNumTMU)->trexInit0, devInfo->tmuInit0[(int)ucNumTMU]); sst1InitIdle(sst); // set downstream TMUs to passthrough for (int i=0; itextureMode, SST_TC_PASS | SST_TCA_PASS); for( int iMemBlock = 0; iMemBlock <= sizeof(ar_memBlocks)/sizeof(def_sMemBlock); iMemBlock++) { const def_sMemBlock* pMemBlk = &ar_memBlocks[iMemBlock]; if(RamSizeMB<4 && pMemBlk->ulAddStart >= 0x300000) continue; if(RamSizeMB<3 && pMemBlk->ulAddStart >= 0x200000) continue; if(RamSizeMB<2 && pMemBlk->ulAddStart >= 0x100000) continue; //printf("RamSizeMB= %d, ulAddStart=%08x\n", RamSizeMB,pMemBlk->ulAddStart); for( FxU32 addrTest = pMemBlk->ulAddStart ; addrTest < (pMemBlk->ulAddStart + pMemBlk->ulAddLength); addrTest += 65536) //256x256x2 (16bit pixels texture) { //printf("Testing memory block 0x%08x ...\n", addrTest); ullNbErrorAll += RenderTest( devInfo, sst, sstregs, ucNumTMU, addrTest); } } /* reset the Init0 register back to its previous value */ sst1InitIdle(sst); ISET(SST_TREX(sst,ucNumTMU)->trexInit0, devInfo->tmuInit0[(int)ucNumTMU]); sst1InitIdle(sst); return ullNbErrorAll; }