#include "gpulocal.h"

int px,py,x_start,y_start,x_end,y_end;
UINT16 *pvram;
UINT8 inTrans, toUpdate;

static void dma_chain(UINT32 addr)
{
    do {
        addr &= 0x1FFFFF;
        {
            UINT32 *ptr = (UINT32*)&ram[addr];
            UINT32 data = SWAP32(*ptr++);
            int size = data>>24;
#ifdef MSB_FIRST
            UINT32 buf[256];
            int i;
            for (i=0; i<size; i++) {
              buf[i] = SWAP32(*ptr++);
            }
            ptr = buf;
#endif
            while (size) {
                int primsize;
                primsize = do_prim(ptr);
                ptr  += primsize;
                size -= primsize;
            }
            addr = data&0xffffff;
        }
        if (addr==0) { /*stop=1;*/ break; }
    } while(addr != 0xffffff);
}

static void dma_mem2vram(UINT32 *ptr,int size)
{
#ifdef MSB_FIRST
    UINT32 *buf;
    int i;

    buf = (UINT32 *)malloc(size*4);
    for (i=0; i<size; i++) {
      buf[i] = SWAP32(*ptr++);
    }
    ptr = buf;
#endif
    while(size) {
        if (inTrans) {
            while (size--) {
                UINT32 data = *ptr++;
                if (px<1024 && py<512)
                    pvram[px] = data;
                if (++px>=x_end) {
                    px = x_start;
                    pvram += 1024;
                    if (++py>=y_end) {
                        inTrans = 0;
                        break;
                    }
                }
                if (px<1024 && py<512)
                    pvram[px] = data>>16;
                if (++px>=x_end) {
                    px = x_start;
                    pvram += 1024;
                    if (++py>=y_end) {
                        inTrans = 0;
                        break;
                    }
                }
            }
            if (inTrans==0) {
                vramchange(x_start,y_start,x_end,y_end);
            }
        } else {
            int primsize;
            primsize = do_prim(ptr);
            ptr  += primsize;
            size -= primsize;
        }
    }
}

static void dma_vram2mem(UINT16 *ptr,int size)
{
     size*=2;
     do {
                if (px<1024 && py<512)
                    *ptr++ = pvram[px];
          if (++px>=x_end) {
               px = x_start;
               pvram += 1024;
               if (++py>=y_end) {
                    inTrans = 0;
                    break;
               }
          }
     } while (--size);
}

void GPU_DmaExec(UINT32 adr,UINT32 bcr,UINT32 chcr)
{
    UINT32 size = (bcr>>16)*(bcr&0xffff);

    switch(chcr){
    case 0x01000200:
        dma_vram2mem((void*)&ram[adr&0x1fffff],size);
        break;
    case 0x01000201:
        dma_mem2vram((void*)&ram[adr&0x1fffff],size);
        break;
    case 0x01000401:
        dma_chain(adr&0x1fffff);
        break;
    case 0x00000200:
    case 0x00000201:
    case 0x00000401: // disable dma
        break;
    default: printf("gpudma unknown %08x\n",(int)chcr);
    }
}