SPS2 - Direct PS2 Access Environment - Forums


Summary |  Forums |  Bugs |  News |  Source |  Files | 

Discussion Forums: Developers

Admin

Message: 44888
BY: panajev
DATE: 2004-Jul-27 06:44
SUBJECT: DMA crashes sps2, but not Linux

Hi, this is a followup on our frriend Ourumov's code as we are working on a project together.

I am trying to change the way he approaches DMA chains creation: I am trying to use NEXT tags then transfer 255 QWs of data and set the ADDR register to the next page and repeat the game... until I get to the last bunch of QWs which I transfer with an END tag.

Building the VIF packet ( with GIFTag, UNPACK and MSCALL ) I try to make sure that each packet is at best 255 QWs in size... actually I save 1 QW before the beginning of every packet to fit the DMA tag in the 4 KB limit.

So the packet I build in the packet building fucntion is actually 256 QWs or it should be.

Then in the FireToVif_1 function ( which prepares the DMA chain ) I try to access each page and store in the first QW the DMA tag ( the next 255 QWs should be the VIF packet ).

Here is the code for the two fucntions:

void object3d::build_packet_1(void *& pMem,int iSPS2Device,int iAllocPages) {



printf("%d\n",num_faces);
uint64 * pdwMem = (uint64 *)pMem;
sps2GIFPackedRegister_t * pRegister;
sps2GIFTag_t * pGIFTag;

int triangles_send=0;
int triangles_now=0;
int data_send=0;
int i=0;
int VU1_new_packet=1;


while(triangles_send<num_faces)
{

triangles_now=get_triangles(triangles_send);

/*if(VU1_mem_overflow_1(data_send))
{
//MAX_DATA_1 is 254 QW's. VIF UNPACK AND MSCALL take the rest of the space.
//WRITE MSCALL
//We write a MSCALL tag since we have surpassed 11KB of size
//Considering VU1 RAM is 16KB I decide to stop here
//writing mscall
pdwMem = (uint64 *)pRegister;
*pdwMem++ = (MSCALL(0) << 32) | FLUSH;
*pdwMem++ = (NOP << 32) | NOP;
//printf("Writing MSCALL\n");
//We need to add a new GIFTAG
//Hence we start again from 0
data_send=0;
VU1_new_packet=1;
}*/


if(VU1_new_packet)
{
//WRITE NEW TAG
pdwMem++;
pdwMem++; //leave some space for the NEXT DMA tag.
*pdwMem++ = (NOP << 32) | NOP;
//*pdwMem++ = (UNPACK(V4_32, triangles_now*9+1, data_send) << 32) | FLUSH;
*pdwMem++ = (UNPACK(V4_32, 252, data_send) << 32) | FLUSH;
//printf("%d %d\n",triangles_now*6+tag,data_send);
// UNPACK(V4_32, 7, 0) says to send each quad word
// of data to VU mem as it is (an array of 4 * 32 bit elements)
// 6 is the number of quadwords to send, 0 is how far into VU mem
// we want to put the data.
// Create a textured sprite
pGIFTag = (sps2GIFTag_t *)pdwMem;
pGIFTag->i128 = 0;
pGIFTag->s.NLOOP = 0; // Three vertexs
pGIFTag->s.PRE = 1; // Transfer PRIM to the GS
pGIFTag->s.EOP = 1; // This is the last giftag in the packet
//pGIFTag->s.PRIM = 11;//
pGIFTag->s.PRIM = GS_PRIM(PRIM_TRI,
PRIM_IIP_GOURAUD,
PRIM_TME_ON,
PRIM_FGE_OFF,
PRIM_ABE_ON,
PRIM_AA1_OFF,
PRIM_FST_UV,
PRIM_CTXT_CONTEXT1,
PRIM_FIX_NOFIXDDA);
pGIFTag->s.FLG = GIF_FLG_PACKED;//
pGIFTag->s.NREG = 0; //

SPS2_SET_GIF_REG(*pGIFTag, pGIFTag->s.NREG++, GIF_REG_RGBAQ); // Add another register. It will by an XYZ2 register
SPS2_SET_GIF_REG(*pGIFTag, pGIFTag->s.NREG++, GIF_REG_XYZ2);
SPS2_SET_GIF_REG(*pGIFTag, pGIFTag->s.NREG++, GIF_REG_UV);
// Set the register pointer to the memory just after the GIFTag
// pGIFTag + 1 will move the address of the pointer
// ahead by the sizeof(sps2GIFTag_t) which is 1 quadword (128 bits)
pRegister = (sps2GIFPackedRegister_t *)(pGIFTag + 1);
//printf("%d %d\n",triangles_now*6+tag,data_send);
data_send=1;
VU1_new_packet=0;
}

else
{
//WRITE UNPACK

pdwMem = (uint64 *)pRegister;
*pdwMem++ = (NOP << 32) | NOP;
*pdwMem++ = (UNPACK(V4_32, triangles_now*9, data_send) << 32 )| FLUSH;
pRegister = (sps2GIFPackedRegister_t *)pdwMem;
//printf("%d\n",((data_send*128)/8)/1024);
//printf("%d %d\n",triangles_now*6+tag,data_send);

}

if ( triangles_now >= 28 ) {
for(i=triangles_send;i<(triangles_send+28);i++)
{
pGIFTag->s.NLOOP++;

pRegister->i128=0; // Blank out this value
pRegister->RGBAQ.s.A=0x80;
pRegister->RGBAQ.s.R=0x80;
pRegister->RGBAQ.s.G=0x80;
pRegister->RGBAQ.s.B=0x80;
pRegister++;
pRegister->i128=0; // Blank out this value
pRegister->XYZ2.s.X=ConvertToScr((vertexs+faces[i*3+0])->x);
pRegister->XYZ2.s.Y=ConvertToScrY((vertexs+faces[i*3+0])->y);
pRegister->XYZ2.s.Z=ConvertToScr(500+(vertexs+faces[i*3+0])->z);
pRegister++;
pRegister->i128=0;
pRegister->UV.s.U=0<<4;
pRegister->UV.s.V=0<<4;
pRegister++;

pGIFTag->s.NLOOP++;
pRegister->i128=0; // Blank out this value
pRegister->RGBAQ.s.A=0x80; // Alpha = 127
pRegister->RGBAQ.s.R=0x80;
pRegister->RGBAQ.s.G=0x80;
pRegister->RGBAQ.s.B=0x80;
pRegister++;
pRegister->i128=0; // Blank out this value
pRegister->XYZ2.s.X=ConvertToScr((vertexs+faces[i*3+1])->x);
pRegister->XYZ2.s.Y=ConvertToScrY((vertexs+faces[i*3+1])->y);
pRegister->XYZ2.s.Z=ConvertToScr(500+(vertexs+faces[i*3+1])->z);
pRegister++;
pRegister->i128=0;
pRegister->UV.s.U=256<<4;
pRegister->UV.s.V=0<<4;
pRegister++;

pGIFTag->s.NLOOP++;
pRegister->i128=0; // Blank out this value
pRegister->RGBAQ.s.A=0x80; // Alpha = 127
pRegister->RGBAQ.s.R=0x80;
pRegister->RGBAQ.s.G=0x80;
pRegister->RGBAQ.s.B=0x80;
pRegister++;
pRegister->i128=0; // Blank out this value
pRegister->XYZ2.s.X=ConvertToScr((vertexs+faces[i*3+2])->x);
pRegister->XYZ2.s.Y=ConvertToScrY((vertexs+faces[i*3+2])->y);
pRegister->XYZ2.s.Z=ConvertToScr(500+(vertexs+faces[i*3+2])->z);
pRegister++;
pRegister->i128=0;
pRegister->UV.s.U=256<<4;
pRegister->UV.s.V=256<<4;
pRegister++;


}

// printf("%d\n",i);

triangles_send+=28;
data_send+=252;

pdwMem = (uint64 *)pRegister;
*pdwMem++ = (MSCALL(0) << 32) | FLUSH;
*pdwMem++ = (NOP << 32) | NOP;

VU1_new_packet=1;

}

else {

for(i=triangles_send;i<triangles_send+triangles_now;i++)
{
pGIFTag->s.NLOOP++;

pRegister->i128=0; // Blank out this value
pRegister->RGBAQ.s.A=0x80; // Alpha = 127
pRegister->RGBAQ.s.R=0x80;
pRegister->RGBAQ.s.G=0x80;
pRegister->RGBAQ.s.B=0x80;
pRegister++;
pRegister->i128=0; // Blank out this value
pRegister->XYZ2.s.X=ConvertToScr((vertexs+faces[i*3+0])->x);
pRegister->XYZ2.s.Y=ConvertToScrY((vertexs+faces[i*3+0])->y);
pRegister->XYZ2.s.Z=ConvertToScr(500+(vertexs+faces[i*3+0])->z);
pRegister++;
pRegister->i128=0;
pRegister->UV.s.U=0<<4;
pRegister->UV.s.V=0<<4;
pRegister++;

pGIFTag->s.NLOOP++;
pRegister->i128=0; // Blank out this value
pRegister->RGBAQ.s.A=0x80; // Alpha = 127
pRegister->RGBAQ.s.R=0x80;
pRegister->RGBAQ.s.G=0x80;
pRegister->RGBAQ.s.B=0x80;
pRegister++;
pRegister->i128=0; // Blank out this value
pRegister->XYZ2.s.X=ConvertToScr((vertexs+faces[i*3+1])->x);
pRegister->XYZ2.s.Y=ConvertToScrY((vertexs+faces[i*3+1])->y);
pRegister->XYZ2.s.Z=ConvertToScr(500+(vertexs+faces[i*3+1])->z);
pRegister++;
pRegister->i128=0;
pRegister->UV.s.U=256<<4;
pRegister->UV.s.V=0<<4;
pRegister++;

pGIFTag->s.NLOOP++;
pRegister->i128=0; // Blank out this value
pRegister->RGBAQ.s.A=0x80; // Alpha = 127
pRegister->RGBAQ.s.R=0x80;
pRegister->RGBAQ.s.G=0x80;
pRegister->RGBAQ.s.B=0x80;
pRegister++;
pRegister->i128=0; // Blank out this value
pRegister->XYZ2.s.X=ConvertToScr((vertexs+faces[i*3+2])->x);
pRegister->XYZ2.s.Y=ConvertToScrY((vertexs+faces[i*3+2])->y);
pRegister->XYZ2.s.Z=ConvertToScr(500+(vertexs+faces[i*3+2])->z);
pRegister++;
pRegister->i128=0;
pRegister->UV.s.U=256<<4;
pRegister->UV.s.V=256<<4;
pRegister++;

}

int local_QWs = triangles_now*9;

triangles_send+=triangles_now;
data_send+=triangles_now*9;
pdwMem = (uint64 *)pRegister;

if ( local_QWs < 252 ) {

local_QWs = 252 - local_QWs; //QWs still to fill to make a full packet
//252 WS + 1 QW (DMA tag) + 1 QW(VIF UNPACK)
//+ 1 QW (GIF Tag) + 1 QW (MSCALL) = 256

for (int n = 1; n < local_QWs; n++) {

*pdwMem++ = (NOP << 32) | NOP;
*pdwMem++ = (NOP << 32) | NOP; // TWO lines of NOPs = 1 QW

}

}

*pdwMem++ = (MSCALL(0) << 32) | FLUSH;
*pdwMem++ = (NOP << 32) | NOP;

VU1_new_packet=1;

}

}


// int NLOOP=pGIFTag->s.NLOOP;
// printf("%d\n",NLOOP*2 + 1);
// exit(0);
// Now for some more VIF codes
// First the FLUSH VIF code makes sure that the VU1 has finished what
// it was doing and that path1 and path2 are idle.
// Next MSCALL(0) starts the microprogram at address 0 in
// VU1 micro memory
pdwMem = (uint64 *)pRegister;
*pdwMem++ = (MSCALL(0) << 32) | FLUSH;
*pdwMem++ = (NOP << 32) | NOP;
pMem=(char*)pRegister;
// Important: Make sure all the data is written to the physical memory;
sps2FlushCache(iSPS2Device);
// Work out how much we just wrote
// int iWC = (int)pdwMem - (int)pMem;

//Set the memory pointer we used to the next free location
pMem = (char *)pdwMem;
// printf("start2: 0x%x\n", (unsigned int) pMem);
//return the number of bytes written to memory
// return iWC;

}


void object3d::FirePacketToVIF_1(void * const pStart, void * const pEnd, void * const pDMA,int iSPS2Device){


//pDMA and pStart are the same value look at main.cpp


Dn_CHCR_t chcr; // channel control register
Dn_TADR_t tadr; // Tag address register

// Use a NEXT tag to point the DMAC to the data
sps2DMATag_t DMANext;
uint64 * pDMATag = (uint64 *)(pDMA);
// printf("start1: 0x%x\n", (unsigned int) pDMATag);
//calculate how many bytes in the packet
int iWC = (int)pEnd - (int)pStart;

//printf("Packet Size = %d\n", iWC);

// return if no data
if(iWC == 0) return;

// Assert that we haven't written more data than 256k
// assert(iWC < (1024*256));

// Check if the packet extends over a 4k Page


int aux=0;
int i = 0;
assert((((uint32) pDMA)&0xf) == 0); // must be 16 byte aligned
aux = (((uint32) pDMA)&0xfff)>>4; //We are working with 4KB pages, so we get the last 12 significative bits (2^12=4096)
//printf("AUX:%d\n",aux); //Each DMATAG is 16B=128 bits=1 QUAD
//We just find out how many QUADS ahead are we

if(iWC > PAGE4K)
{
// Configure the NEXT Tags to send 4k of data
//DMARef.i64 = 0;
//DMARef.s.QWC = PAGE4K >> 4; // Transfer 4K
//DMARef.s.ID = DMA_ID_SOURCE_REF;



// Now set up all the 4k pages

do
{

//DMARef.i64 = 0; //zero the tag
//DMARef.s.QWC = 255;
//DMARef.s.ID = DMA_ID_SOURCE_NEXT; //this is a next tag
//ADDR points to the location of the next tag
//which is a qword ahead, just over the 4k boundary
//DMARef.s.ADDR = GetPhysicalAddress((void *)(((int)pDMATag) + 0x10));

DMANext.i64 = 0; //zero the tag
DMANext.s.QWC = 255;

iWC -= PAGE4K;

DMANext.s.ID = DMA_ID_SOURCE_NEXT;
//i++;

pDMATag = ((uint64 *)pStart + (i*PAGE4K));
*pDMATag = DMANext.i64;

i++;

DMANext.s.ADDR = GetPhysicalAddress((void *)(((char *)pStart) + (i*PAGE4K)));



}while(iWC > PAGE4K);

// If there is remaining data, send it with an END tag
if(iWC > 0)
{
sps2DMATag_t DMAEnd;

DMAEnd.i64 = 0;
DMAEnd.s.QWC = iWC >> 4;;
DMAEnd.s.ID = DMA_ID_SOURCE_END;

// Add the DMA tag to the chain

*pDMATag = DMANext.i64;



}

}
// The Packet is less than 4k - send it with one END tag
else
{

sps2DMATag_t DMAEnd;

DMAEnd.i64 = 0;


// Add the DMA tag to the chain
//*pDMATag = DMAEnd.i64;

DMAEnd.s.QWC = iWC >> 4;

DMAEnd.s.ID = DMA_ID_SOURCE_END;


*pDMATag = DMAEnd.i64;
//pDMATag = (pStart + (i*PAGE4K));


}

// Now that we have uploaded the data, the DMA chain needs to be ended.


// Importand - Try to remember this!!!!!!!!!!!!!!!!!!!!
//FlushCache();
// printf("start2: 0x%x\n", (unsigned int) pDMATag);
sps2FlushCache(iSPS2Device);

// Set the address of the first tag (right at the start of the chain)
tadr.i32 = 0;
tadr.s.SPR = 0;
tadr.s.ADDR = GetPhysicalAddress(pDMA);
*EE_D1_TADR = tadr.i32;

// Don't transfer any data from MADR
*EE_D1_QWC = 0;

// Set the channel control register
chcr.i32 = 0;
chcr.s.MOD = CHCR_MOD_CHAIN;
chcr.s.STR = 1;
chcr.s.DIR = 1; // We are going FROM main memory
chcr.s.TTE = 0; // Don't transfer the tag

// Fire off the packet!
*EE_D1_CHCR = chcr.i32;

// Wait for it to complete
//WaitForDMA(1);

sps2WaitForDMA(1, iSPS2Device);

return;

}





And this is part of main.cpp ( the main () function ):

int main()
{



// Open sps2-library and setup PS2Linux stuff
iSPS2Device = sps2Init();

if (iSPS2Device<0) {
printf("Can't open SPS2 device. Is the module loaded?\n");
exit(-1);
}
//table_sin();
//table_cos();
uint32 uAllocDmaMegs = 4;
sps2Memory_t * pDescCached = sps2Allocate(uAllocDmaMegs*1024*1024, SPS2_MAP_BLOCK_4K | SPS2_MAP_CACHED, iSPS2Device);

int iAllocPages=(uAllocDmaMegs*1024*1024)/4096;
printf("iAllocPages=%d\n",iAllocPages);
sps2Memory_t * pDescUncached = sps2Remap(pDescCached, SPS2_MAP_UNCACHED, iSPS2Device);
DistribGlobPtrs(pDescCached, pDescUncached);

// void * pAllDmaMem = pDescCached->pvStart;

char * m_pCached = (char*)pDescCached->pvStart;

int iVPU0; iVPU0=open("/dev/ps2vpu0", O_RDWR);
int iVPU1; iVPU1=open("/dev/ps2vpu1", O_RDWR);

for(int sig=0; sig<128; sig++) // catch as many signals as possible
signal(sig, sig_handle);



// Setup Screen
cScreen=new CScreen;
atexit(delete_screen);
cScreen->ScreenSetup();

// Setup a Camera
float fScrWdth = cScreen->GetWidth();
float fScrHgt = cScreen->GetHeight();
float fDepthZ = cScreen->GetDepth();
CCamera cCam;
cCam.SetBitmapSize(fScrWdth, -fScrHgt, fDepthZ);
cCam.SetViewPortOffset(2048, 2048, fDepthZ);
cCam.SetClipPlanes(-10, -10000);
cCam.SetEyePos(Vec3(0,0,1));
float fFov = 0.524f; // total view of 60 degrees
float fMinU = -tanf(fFov);
float fMinV = (fMinU*3)/4;
cCam.SetBoundVRC(fMinU, fMinV, -fMinU, -fMinV);
cCam.SetPosViewPlane(Vec3(0,0,600));
cCam.SetRotViewPlane(Vec3(0,0,1), Vec3(0,1,0));
float angle=0.0f;
// Flush Cache
sps2FlushCache(iSPS2Device);




uint32 iCodeLengthInDWORDs = (((uint32)&VU_vu1code_end - (uint32)&VU_vu1code_start) + 7) >> 3;

memcpy(VU1_MICRO_MEM, &VU_vu1code_start, iCodeLengthInDWORDs * 8);


void * pMemEnd = (void *)(&m_pCached[0]);
void * m_Prim1Base = (void *)(&m_pCached[0]);
void * m_Prim1DmaBase = (void *)(&m_pCached[(iAllocPages - 64 + 0) * 4096]);
m_Prim1DmaBase = (void *)(&m_pCached[(iAllocPages - 64 + 0) * 4096]);
void * m_Tex1Base = (void *)(&m_pCached[(iAllocPages - 64 * 3) * 4096]);
void * m_Tex1DmaBase = (void *)(&m_pCached[(iAllocPages - 32 - 1) * 4096]);

CTexture Tex1CTexture(m_Tex1Base, m_Tex1DmaBase, pDescCached,iSPS2Device);
printf("0\n");
Tex1CTexture.LoadBitmap("metalsheet03.bmp", true, false);
printf("1\n");
sps2FlushCache(iSPS2Device);
object3d tie("./avioj.ASE",pDescCached);
//tie.build_packet_1(pMemEnd,iSPS2Device,iAllocPages);
tie.build_packet(pMemEnd,iSPS2Device,iAllocPages);
Tex1CTexture.InitDmaChain();
printf("2\n");
Tex1CTexture.Upload();

while(loop_again)
{



//tie.FirePacketToVIF_1(m_Prim1Base,pMemEnd,m_Prim1Base,iSPS2Device);
tie.FirePacketToVIF(m_Prim1Base,pMemEnd,m_Prim1DmaBase,iSPS2Device);
//tie.FirePacketToGS(m_Prim1Base,pMemEnd,m_Prim1DmaBase,iSPS2Device);
//tie.render(pAllDmaMem,iSPS2Device);

cScreen->Swap();
angle=(angle+0.1f);

}

return 0;
}


 

Thread View

Thread Author Date
DMA crashes sps2, but not Linuxpanajev2004-Jul-27 06:44
      RE: DMA crashes sps2, but not Linuxpanajev2004-Jul-27 07:59
            RE: DMA crashes sps2, but not Linuxsauce2004-Jul-27 10:26

 

Post a followup to this message

You could post if you were [logged in]