|
Nugget
Bare-metal libraries and examples for the original PlayStation
|
#include <stdint.h>#include "common/hardware/hwregs.h"#include "common/syscalls/syscalls.h"#include "prim.h"#include "prims.h"#include "exotic/cester.h"
Macros | |
| #define | PCSX_TESTS 0 |
| #define | CESTER_MAYBE_TEST CESTER_TEST |
| #define | CESTER_NO_SIGNAL |
| #define | CESTER_NO_TIME |
| #define | EXIT_SUCCESS 0 |
| #define | EXIT_FAILURE 1 |
| #define | R32(a) (*(volatile uint32_t *)(a)) |
| #define | D2_MADR R32(0xbf8010a0) |
| #define | D2_BCR R32(0xbf8010a4) |
| #define | D2_CHCR R32(0xbf8010a8) |
| #define | D_DPCR R32(0xbf8010f0) |
| #define | D_DICR R32(0xbf8010f4) |
| #define | T2_VALUE R32(0xbf801120) |
| #define | T2_MODE R32(0xbf801124) |
| #define | GPU_READ R32(0xbf801810) |
| #define | REPS 5 |
| #define | LIST_COPIES 16 |
| #define | LIST_MAX_SIZE 64 |
| #define | CMD_MAX 64 |
| #define | BIG_WORDS (240 * 240 / 2) |
| #define | SENTINEL_FILL 0x080808u |
| #define | SENTINEL_PIXEL 0x0421u |
| #define | UPLOAD_Y 256 |
| #define | COPY_DST_X 256 |
| #define | COPY_DST_Y 256 |
| #define | GP0_FIFO_WORDS 16 |
| #define | N_POLY_SIZES (sizeof(s_polySizes) / sizeof(s_polySizes[0])) |
| #define | N_RECT_SIZES (sizeof(s_rectSizes) / sizeof(s_rectSizes[0])) |
| #define | N_LINE_LENS (sizeof(s_lineLens) / sizeof(s_lineLens[0])) |
| #define | N_XFER (sizeof(s_xferShapes) / sizeof(s_xferShapes[0])) |
Functions | |
| CESTER_BODY (#define R32(a) #define D2_MADR #define D2_BCR #define D2_CHCR #define D_DPCR #define D_DICR #define T2_VALUE #define T2_MODE #define GPU_READ #define REPS #define LIST_COPIES #define LIST_MAX_SIZE #define CMD_MAX #define BIG_WORDS #define SENTINEL_FILL #define SENTINEL_PIXEL #define UPLOAD_Y #define COPY_DST_X #define COPY_DST_Y static uint32_t s_cmd[CMD_MAX];static const uint32_t s_zero[CMD_MAX];static uint32_t s_list[LIST_COPIES *(CMD_MAX+1)];static uint32_t s_big[BIG_WORDS];static int s_interruptsWereEnabled;static uint32_t s_acc, s_prev;static unsigned s_classes, s_badDraw, s_badGrow, s_badZero;static unsigned s_lineClasses, s_lineBadDraw, s_lineBadGrow, s_lineUnbuilt;static uint32_t s_idx7, s_idx7Primed;static inline void tick(void) { uint32_t t=T2_VALUE &0xffff;s_acc+=(t - s_prev) &0xffff;s_prev=t;} static inline void startClock(void) { s_prev=T2_VALUE &0xffff;s_acc=0;} static inline int gpuIdle(void) { return(GPU_STATUS &0x14000000)==0x14000000;} static void waitIdle(void) { while(!gpuIdle()) { } } static inline void waitIdleTimed(void) { while(!gpuIdle()) tick();tick();} #define GP0_FIFO_WORDS static uint32_t timeWordsLong(const uint32_t *w, unsigned n) { waitIdle();startClock();for(unsigned i=0;i< n;i++) { if(i >=GP0_FIFO_WORDS) { while(!(GPU_STATUS &0x02000000)) tick();} GPU_DATA=w[i];if((i &15)==15) tick();} waitIdleTimed();return s_acc;} static uint32_t timeWords(const uint32_t *w, unsigned n, int pace) { if(n > GP0_FIFO_WORDS &&w !=s_zero) return timeWordsLong(w, n);waitIdle();startClock();for(unsigned i=0;i< n;i++) { if(pace &&(i &7)==0) { while(!(GPU_STATUS &0x02000000)) tick();} GPU_DATA=w[i];if((i &15)==15) tick();} waitIdleTimed();return s_acc;} static uint32_t timeList(const uint32_t *w, unsigned n) { for(unsigned k=0;k< LIST_COPIES;k++) { uint32_t *node=&s_list[k *(n+1)];uint32_t next=k+1< LIST_COPIES ?((uint32_t)&s_list[(k+1) *(n+1)] &0xffffff) :0xffffff;node[0]=(n<< 24)|next;for(unsigned i=0;i< n;i++) node[i+1]=w[i];} waitIdle();GPU_STATUS=0x04000002;startClock();D2_MADR=(uint32_t)&s_list[0] &0xffffff;D2_BCR=0;D2_CHCR=0x01000401;while(D2_CHCR &0x01000000) tick();GPU_STATUS=0x04000001;waitIdleTimed();return s_acc;} static void sort5(uint32_t *v) { for(int i=1;i< REPS;i++) { uint32_t x=v[i];int j=i - 1;while(j >=0 &&v[j] > x) { v[j+1]=v[j];j--;} v[j+1]=x;} } struct Sample { uint32_t min, med, max, base;};static struct Sample measure(const uint32_t *w, unsigned n, int pace) { uint32_t t[REPS], b[REPS];for(int r=0;r< REPS;r++) { t[r]=timeWords(w, n, pace);b[r]=timeWords(s_zero, n, pace);} sort5(t);sort5(b);struct Sample s={t[0], t[REPS/2], t[REPS - 1], b[REPS/2]};return s;} static uint32_t measureCold(const uint32_t *w, unsigned n) { uint32_t t[REPS];for(int r=0;r< REPS;r++) { waitIdle();GPU_DATA=0x01000000;waitIdle();t[r]=timeWords(w, n, 0);} sort5(t);return t[REPS/2];} static uint32_t measureList(const uint32_t *w, unsigned n) { uint32_t t[REPS];for(int r=0;r< REPS;r++) t[r]=timeList(w, n);sort5(t);return t[REPS/2]/LIST_COPIES;} static uint32_t net(const struct Sample *s) { return s->med > s->base ? s->med - s->base :0;} static void gp0Fill(unsigned x, unsigned y, unsigned w, unsigned h, uint32_t color) { waitIdle();GPU_DATA=0x02000000|color;GPU_DATA=(y<< 16)|x;GPU_DATA=(h<< 16)|w;waitIdle();} static unsigned s_readTimeouts;static uint32_t readWord(unsigned x, unsigned y) { waitIdle();GPU_DATA=0xc0000000;GPU_DATA=(y<< 16)|x;GPU_DATA=(1<< 16)|2;unsigned polls=0;while(!(GPU_STATUS &0x08000000) &&polls< 400000) polls++;if(polls==400000) { s_readTimeouts++;GPU_STATUS=0x01000000;return 0xffffffff;} uint32_t v=GPU_READ;waitIdle();return v;} static uint16_t readPixel(unsigned x, unsigned y) { return readWord(x, y) &0xffff;} static void uploadRect(unsigned x, unsigned y, unsigned w, unsigned h, uint16_t(*gen)(unsigned, unsigned)) { waitIdle();GPU_DATA=0xa0000000;GPU_DATA=(y<< 16)|x;GPU_DATA=(h<< 16)|w;unsigned i=0;for(unsigned yy=0;yy< h;yy++) { for(unsigned xx=0;xx< w;xx+=2, i++) { if((i &7)==0) { while(!(GPU_STATUS &0x02000000)) { } } GPU_DATA=(uint32_t) gen(xx, yy)|((uint32_t) gen(xx+1, yy)<< 16);} } waitIdle();} static uint16_t genTexel15(unsigned x, unsigned y) { uint16_t v=(uint16_t)((x *0x0843u+y *0x1085u+0x0421u) &0x7fff);if(!v) v=1;return v|0x8000;} static uint16_t genIndex(unsigned x, unsigned y) { return(uint16_t)(x *0x3197u+y *0x5ac3u);} static uint16_t genClut(unsigned x, unsigned y) {(void) y;uint16_t v=(uint16_t)((x *0x0c63u+0x0842u) &0x7fff);if(!v) v=1;return v|0x8000;} static void setupGpu(void) { GPU_STATUS=0x00000000;GPU_STATUS=0x06000000|0x260|(0xc60<< 12);GPU_STATUS=0x07000000|0x010|(0x100<< 10);GPU_STATUS=0x05000000;GPU_STATUS=0x08000001;GPU_DATA=0xe1000400;GPU_DATA=0xe2000000;GPU_DATA=0xe3000000;GPU_DATA=0xe4000000|1023|(511<< 10);GPU_DATA=0xe5000000;GPU_DATA=0xe6000000;GPU_STATUS=0x03000000;GPU_STATUS=0x04000001;waitIdle();uploadRect(TP4_X, 0, 64, 256, genIndex);uploadRect(TP8_X, 0, 128, 256, genIndex);uploadRect(TP15_X, 0, 256, 256, genTexel15);uploadRect(512, CLUT4_Y, 16, 1, genClut);uploadRect(512, CLUT8_Y, 256, 1, genClut);} static void setE1(unsigned tex, unsigned semi, unsigned dither) { uint32_t v=(abr(semi)<< 5)|(1u<< 10)|(dither<< 9);if(tex) v|=tpageX(tex)|(tdepth(tex)<< 7);waitIdle();GPU_DATA=0xe1000000|v;waitIdle();} static void classDone(char kind, unsigned tag, int drawn, int grow, int isLine) { ramsyscall_printf("K %c %x drawn=%d grow=%d\n", kind, tag, drawn, grow);if(isLine) { s_lineClasses++;if(!drawn) s_lineBadDraw++;if(!grow) s_lineBadGrow++;} else { s_classes++;if(!drawn) s_badDraw++;if(!grow) s_badGrow++;} } static const unsigned s_polySizes[]={1, 2, 4, 8, 16, 32, 64, 96, 128, 160, 192, 240};#define N_POLY_SIZES static int polyDrawn(unsigned quad, unsigned g, unsigned tex, unsigned semi) { gp0Fill(0, 0, 256, 256, SENTINEL_FILL);unsigned n=buildPoly(s_cmd, quad, g, tex, semi, 0, 240, 240);timeWords(s_cmd, n, 0);waitIdle();return readPixel(60, 60) !=SENTINEL_PIXEL;} static void polyPoint(char arm, unsigned quad, unsigned g, unsigned tex, unsigned semi, unsigned d, unsigned x0, unsigned w, unsigned h, struct Sample *out) { unsigned n=buildPoly(s_cmd, quad, g, tex, semi, x0, w, h);struct Sample s=measure(s_cmd, n, 0);uint32_t list=(w<=LIST_MAX_SIZE &&h<=LIST_MAX_SIZE &&arm=='M') ? measureList(s_cmd, n) :0;uint32_t cold=(tex &&arm=='M') ? measureCold(s_cmd, n) :0;ramsyscall_printf("P %c %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", arm, quad, g, tex, semi, d, x0, w, h, s.min, s.med, s.max, s.base, list, cold);if(out) *out=s;} static void polyClass(char arm, unsigned quad, unsigned g, unsigned tex, unsigned semi, unsigned d) { setE1(tex, semi, d);struct Sample first={0}, last={0};for(unsigned i=0;i< N_POLY_SIZES;i++) { unsigned L=s_polySizes[i];struct Sample s;polyPoint(arm, quad, g, tex, semi, d, 0, L, L, &s);if(i==0) first=s;last=s;} int drawn=polyDrawn(quad, g, tex, semi);unsigned tag=(quad<< 16)|(g<< 12)|(tex<< 4)|(semi<< 1)|d;classDone(arm, tag, drawn, net(&last) > net(&first)+1000, 0);} static void polyShapes(unsigned quad, unsigned g, unsigned tex, unsigned semi, unsigned d) { setE1(tex, semi, d);for(unsigned i=0;i< N_POLY_SIZES;i++) { unsigned L=s_polySizes[i];polyPoint('W', quad, g, tex, semi, d, 0, L, 8, 0);polyPoint('H', quad, g, tex, semi, d, 0, 8, L, 0);} for(unsigned x0=0;x0< 16;x0++) polyPoint('X', quad, g, tex, semi, d, x0, 64, 64, 0);} static const unsigned s_rectSizes[]={1, 2, 4, 8, 16, 32, 64, 128, 240};#define N_RECT_SIZES static void rectPoint(char arm, unsigned size, unsigned tex, unsigned semi, unsigned raw, unsigned w, unsigned h, struct Sample *out) { unsigned n=buildRect(s_cmd, size, tex, semi, raw, w, h);struct Sample s=measure(s_cmd, n, 0);uint32_t cold=(tex &&arm=='M') ? measureCold(s_cmd, n) :0;ramsyscall_printf("R %c %d %d %d %d %d %d %d %d %d %d %d\n", arm, size, tex, semi, raw, w, h, s.min, s.med, s.max, s.base, cold);if(out) *out=s;} static void rectClass(char arm, unsigned tex, unsigned semi, unsigned raw) { setE1(tex, semi, 0);struct Sample first={0}, last={0};for(unsigned i=0;i< N_RECT_SIZES;i++) { unsigned L=s_rectSizes[i];struct Sample s;rectPoint(arm, 0, tex, semi, raw, L, L, &s);if(i==0) first=s;last=s;} rectPoint(arm, 1, tex, semi, raw, 1, 1, 0);rectPoint(arm, 8, tex, semi, raw, 8, 8, 0);rectPoint(arm, 16, tex, semi, raw, 16, 16, 0);gp0Fill(0, 0, 256, 256, SENTINEL_FILL);unsigned n=buildRect(s_cmd, 0, tex, semi, raw, 240, 240);timeWords(s_cmd, n, 0);int drawn=readPixel(60, 60) !=SENTINEL_PIXEL;unsigned tag=0x100000|(tex<< 4)|(semi<< 1)|raw;classDone(arm, tag, drawn, net(&last) > net(&first)+1000, 0);} static const unsigned s_lineLens[]={1, 2, 4, 8, 16, 32, 64, 128, 255};#define N_LINE_LENS static const unsigned s_lineSegs[]={2, 4, 8, 16};static void lineClass(unsigned kind, unsigned semi, unsigned d) { unsigned k=kind|(semi ? LINE_SEMI :0);if(!buildLineCommand(s_cmd, k, 1,(kind &LINE_POLY) ? 2 :1)) { s_lineUnbuilt++;ramsyscall_printf("L kind %d unbuilt\n", k);return;} setE1(0, semi, d);struct Sample first={0}, last={0};unsigned segs=(kind &LINE_POLY) ? 2 :1;for(unsigned i=0;i< N_LINE_LENS;i++) { unsigned n=buildLineCommand(s_cmd, k, s_lineLens[i], segs);struct Sample s=measure(s_cmd, n, 0);ramsyscall_printf("L M %d %d %d %d %d %d %d %d %d\n", k, d, semi, segs, s_lineLens[i], s.min, s.med, s.max, s.base);if(i==0) first=s;last=s;} if(kind &LINE_POLY) { for(unsigned i=0;i< sizeof(s_lineSegs)/sizeof(s_lineSegs[0]);i++) { unsigned n=buildLineCommand(s_cmd, k, 64, s_lineSegs[i]);struct Sample s=measure(s_cmd, n, 0);ramsyscall_printf("L S %d %d %d %d %d %d %d %d %d\n", k, d, semi, s_lineSegs[i], 64, s.min, s.med, s.max, s.base);} } gp0Fill(0, 0, 256, 256, SENTINEL_FILL);unsigned n=buildLineCommand(s_cmd, k, 255, segs);timeWords(s_cmd, n, 0);int drawn=readPixel(0, 0) !=SENTINEL_PIXEL;classDone('L', 0x200000|(k<< 4)|(semi<< 1)|d, drawn, net(&last) > net(&first)+64, 1);} static const unsigned s_fillSizes[]={16, 32, 48, 64, 128, 256};static void fillClass(void) { struct Sample first={0}, last={0};for(unsigned i=0;i< sizeof(s_fillSizes)/sizeof(s_fillSizes[0]);i++) { unsigned L=s_fillSizes[i];s_cmd[0]=0x02000000|0x50a020;s_cmd[1]=0;s_cmd[2]=(L<< 16)|L;struct Sample s=measure(s_cmd, 3, 0);ramsyscall_printf("F %d %d %d %d %d %d\n", L, L, s.min, s.med, s.max, s.base);if(i==0) first=s;last=s;} gp0Fill(0, 0, 256, 256, SENTINEL_FILL);waitIdle();for(unsigned k=0;k< 3;k++) GPU_DATA=s_cmd[k];waitIdle();unsigned L=s_fillSizes[sizeof(s_fillSizes)/sizeof(s_fillSizes[0]) - 1];classDone('F', 0x300000, readPixel(0, 0)==0x2a84 &&readPixel(L - 1, L - 1)==0x2a84, net(&last) > net(&first)+1000, 0);} static void copyClass(void) { struct Sample first={0}, last={0};gp0Fill(0, 0, 256, 256, 0x00f8f8);for(unsigned i=0;i< N_RECT_SIZES;i++) { unsigned L=s_rectSizes[i];s_cmd[0]=0x80000000;s_cmd[1]=0;s_cmd[2]=vtx(COPY_DST_X, COPY_DST_Y);s_cmd[3]=(L<< 16)|L;struct Sample s=measure(s_cmd, 4, 0);ramsyscall_printf("C %d %d %d %d %d %d\n", L, L, s.min, s.med, s.max, s.base);if(i==0) first=s;last=s;} gp0Fill(COPY_DST_X, COPY_DST_Y, 256, 240, SENTINEL_FILL);s_cmd[3]=(240<< 16)|240;timeWords(s_cmd, 4, 0);classDone('C', 0x400000, readPixel(COPY_DST_X+60, COPY_DST_Y+60)==0x03ff, net(&last) > net(&first)+1000, 0);} struct Shape { uint16_t w, h;};static const struct Shape s_xferShapes[]={{8, 8}, {16, 16}, {32, 32}, {64, 64}, {128, 128}, {240, 240}, {320, 16}, {16, 240}};#define N_XFER static unsigned s_dmaTimeouts;static uint32_t timeUpload(unsigned w, unsigned h, unsigned dma) { unsigned words=w *h/2;waitIdle();startClock();GPU_DATA=0xa0000000;GPU_DATA=vtx(0, UPLOAD_Y);GPU_DATA=(h<< 16)|w;if(dma) { GPU_STATUS=0x04000002;D2_MADR=(uint32_t) s_big &0xffffff;D2_BCR=dma|((words/dma)<< 16);D2_CHCR=0x01000201;unsigned polls=0;while(D2_CHCR &0x01000000) { tick();if(++polls > 4000000) { D2_CHCR=0x00000201;s_dmaTimeouts++;GPU_STATUS=0x01000000;break;} } GPU_STATUS=0x04000001;} else { for(unsigned i=0;i< words;i++) { if((i &7)==0) { while(!(GPU_STATUS &0x02000000)) tick();} GPU_DATA=s_big[i];if((i &15)==15) tick();} } waitIdleTimed();return s_acc;} static uint32_t timeDownload(unsigned w, unsigned h, int dma) { unsigned words=w *h/2;waitIdle();startClock();GPU_DATA=0xc0000000;GPU_DATA=0;GPU_DATA=(h<< 16)|w;while(!(GPU_STATUS &0x08000000)) tick();if(dma) { GPU_STATUS=0x04000003;D2_MADR=(uint32_t) s_big &0xffffff;D2_BCR=16|((words/16)<< 16);D2_CHCR=0x01000200;while(D2_CHCR &0x01000000) tick();GPU_STATUS=0x04000001;} else { for(unsigned i=0;i< words;i++) { while(!(GPU_STATUS &0x08000000)) tick();s_big[i]=GPU_READ;if((i &15)==15) tick();} } waitIdleTimed();return s_acc;} static void xferClass(char kind, int dma) { struct Sample first={0}, last={0};for(unsigned i=0;i< N_XFER;i++) { unsigned w=s_xferShapes[i].w, h=s_xferShapes[i].h;uint32_t t[REPS], b[REPS];for(int r=0;r< REPS;r++) { if(kind=='U') { for(unsigned j=0;j< w *h/2;j++) s_big[j]=0x7c1f03e0u ^(j *0x00210021u);t[r]=timeUpload(w, h, dma ? 16 :0);} else { t[r]=timeDownload(w, h, dma);} b[r]=timeWords(s_zero, 3, 0);} sort5(t);sort5(b);struct Sample s={t[0], t[REPS/2], t[REPS - 1], b[REPS/2]};ramsyscall_printf("%c %d %d %d %d %d %d %d\n", kind, dma, w, h, s.min, s.med, s.max, s.base);if(i==0) first=s;if(w==240) last=s;} int ok;if(kind=='U') { ok=readPixel(0, UPLOAD_Y)==(s_big[0] &0xffff);} else { gp0Fill(0, 0, 16, 16, 0x00f8f8);s_big[0]=0;timeDownload(16, 16, dma);ok=(s_big[0] &0xffff)==0x03ff;} classDone(kind, 0x500000|dma, ok, net(&last) > net(&first)+1000, 0);} static unsigned s_blockFails;static void uploadBlockSizes(void) { unsigned timeoutsBefore=s_dmaTimeouts;static const uint8_t sizes[]={1, 2, 4, 8, 16};static const struct Shape shapes[]={{16, 16}, {64, 64}, {240, 240}, {320, 16}};for(unsigned b=0;b< sizeof(sizes);b++) { for(unsigned i=0;i< sizeof(shapes)/sizeof(shapes[0]);i++) { unsigned w=shapes[i].w, h=shapes[i].h, words=w *h/2;uint32_t t[REPS];for(int r=0;r< REPS;r++) { for(unsigned j=0;j< words;j++) s_big[j]=0x7c1f03e0u ^((j+r) *0x00210021u);t[r]=timeUpload(w, h, sizes[b]);} int ok=readPixel(0, UPLOAD_Y)==(s_big[0] &0xffff) &&readPixel(w - 1, UPLOAD_Y+h - 1)==(s_big[words - 1] > > 16);if(!ok) s_blockFails++;sort5(t);ramsyscall_printf("B %d %d %d %d %d %d %d\n", sizes[b], w, h, t[0], t[REPS/2], t[REPS - 1], ok);} } if(s_dmaTimeouts !=timeoutsBefore) s_blockFails++;ramsyscall_printf("B timeouts=%d\n", s_dmaTimeouts);} static void windowArm(void) { waitIdle();GPU_DATA=0xe2000000|0x1e|(0x1e<< 5);for(unsigned quad=0;quad< 2;quad++) for(unsigned g=0;g< 2;g++) for(unsigned ti=1;ti< 4;ti++) for(unsigned semi=0;semi< 5;semi+=4) polyClass('T', quad, g, ti==1 ? 4 :ti==2 ? 8 :15, semi, 0);for(unsigned ti=1;ti< 4;ti++) rectClass('T', ti==1 ? 4 :ti==2 ? 8 :15, 0, 1);waitIdle();GPU_DATA=0xe2000000;} static void zeroPoint(unsigned how, unsigned quad, unsigned g, unsigned tex, unsigned semi, unsigned L) { unsigned n;if(quad==2) { n=buildRect(s_cmd, 0, tex, semi, 0, how==3 ? 0 :L, how==4 ? 0 :L);} else { n=buildPoly(s_cmd, quad, g, tex, semi, 0, how==1 ? 0 :L, how==0 ? L :0);} struct Sample s=measure(s_cmd, n, 0);ramsyscall_printf("Z %d %d %d %d %d %d %d %d %d %d\n", how, quad, g, tex, semi, L, s.min, s.med, s.max, s.base);} static void zeroArm(void) { static const unsigned sizes[]={1, 64, 240};for(unsigned quad=0;quad< 3;quad++) for(unsigned g=0;g<(quad==2 ? 1u :2u);g++) for(unsigned ti=0;ti< 4;ti++) for(unsigned semi=0;semi< 2;semi++) { unsigned tex=ti==0 ? 0 :ti==1 ? 4 :ti==2 ? 8 :15;setE1(tex, semi, 0);waitIdle();GPU_DATA=0xe3000000|1000|(500<< 10);GPU_DATA=0xe4000000|1010|(510<< 10);for(unsigned i=0;i< 3;i++) zeroPoint(0, quad, g, tex, semi, sizes[i]);waitIdle();GPU_DATA=0xe3000000;GPU_DATA=0xe4000000|1023|(511<< 10);if(quad==2) { for(unsigned i=0;i< 3;i++) zeroPoint(3, quad, g, tex, semi, sizes[i]);for(unsigned i=0;i< 3;i++) zeroPoint(4, quad, g, tex, semi, sizes[i]);} else { zeroPoint(1, quad, g, tex, semi, 1);for(unsigned i=0;i< 3;i++) zeroPoint(2, quad, g, tex, semi, sizes[i]);} } setE1(0, 0, 0);gp0Fill(0, 0, 256, 256, SENTINEL_FILL);unsigned n=buildPoly(s_cmd, 1, 0, 0, 0, 0, 240, 0);timeWords(s_cmd, n, 0);uint16_t quadRow=readPixel(60, 0);gp0Fill(0, 0, 256, 256, SENTINEL_FILL);n=buildPoly(s_cmd, 0, 0, 0, 0, 0, 0, 0);timeWords(s_cmd, n, 0);uint16_t triPoint=readPixel(0, 0);gp0Fill(0, 0, 256, 256, SENTINEL_FILL);n=buildRect(s_cmd, 0, 0, 0, 0, 0, 240);timeWords(s_cmd, n, 0);uint16_t rectW0=readPixel(0, 60);gp0Fill(0, 0, 256, 256, SENTINEL_FILL);n=buildRect(s_cmd, 0, 0, 0, 0, 240, 0);timeWords(s_cmd, n, 0);uint16_t rectH0=readPixel(60, 0);waitIdle();GPU_DATA=0xe3000000|1000|(500<< 10);GPU_DATA=0xe4000000|1010|(510<< 10);gp0Fill(0, 0, 256, 256, SENTINEL_FILL);n=buildPoly(s_cmd, 1, 0, 0, 0, 0, 240, 240);timeWords(s_cmd, n, 0);n=buildRect(s_cmd, 0, 0, 0, 0, 240, 240);timeWords(s_cmd, n, 0);waitIdle();GPU_DATA=0xe3000000;GPU_DATA=0xe4000000|1023|(511<< 10);uint16_t clipped=readPixel(60, 60);if(quadRow !=SENTINEL_PIXEL||triPoint !=SENTINEL_PIXEL||rectW0 !=SENTINEL_PIXEL||rectH0 !=SENTINEL_PIXEL||clipped !=SENTINEL_PIXEL) s_badZero++;ramsyscall_printf("Z control quadrow=%04x tripoint=%04x rectw0=%04x recth0=%04x clipped=%04x\n", quadRow, triPoint, rectW0, rectH0, clipped);} static void probeRevision(void) { gp0Fill(0, 0, 16, 16, 0x00f8f8);s_idx7Primed=readWord(0, 0);GPU_STATUS=0x10000007;for(volatile int i=0;i< 64;i++) { } s_idx7=GPU_READ;ramsyscall_printf("REV idx7=%08x primed=%08x\n", s_idx7, s_idx7Primed);} static void runAll(void) { D_DPCR|=0x00000800;D_DICR=0;T2_MODE=0;setupGpu();probeRevision();ramsyscall_printf("# P arm quad gouraud tex semi dither x w h min med max base list cold\n");for(unsigned quad=0;quad< 2;quad++) for(unsigned g=0;g< 2;g++) for(unsigned ti=0;ti< 4;ti++) for(unsigned semi=0;semi< 5;semi++) for(unsigned d=0;d< 2;d++) polyClass('M', quad, g, ti==0 ? 0 :ti==1 ? 4 :ti==2 ? 8 :15, semi, d);polyShapes(1, 0, 0, 0, 0);polyShapes(1, 1, 15, 1, 1);polyShapes(1, 0, 4, 0, 0);polyShapes(1, 0, 8, 0, 0);windowArm();zeroArm();ramsyscall_printf("# R arm size tex semi raw w h min med max base cold\n");for(unsigned ti=0;ti< 4;ti++) { unsigned tex=ti==0 ? 0 :ti==1 ? 4 :ti==2 ? 8 :15;for(unsigned semi=0;semi< 5;semi++) for(unsigned raw=0;raw<(tex ? 2u :1u);raw++) rectClass('M', tex, semi, raw);} ramsyscall_printf("# L arm kind dither semi segs len min med max base\n");for(unsigned kind=0;kind< 4;kind++) for(unsigned semi=0;semi< 5;semi++) for(unsigned o=0;o< 4;o++) for(unsigned d=0;d< 2;d++) lineClass(kind|((o &1) ? LINE_SLANTED :0)|((o &2) ? LINE_VERTICAL :0), semi, d);fillClass();copyClass();xferClass('U', 0);xferClass('U', 1);xferClass('D', 0);xferClass('D', 1);uploadBlockSizes();GPU_STATUS=0x03000001;polyClass('D', 1, 0, 0, 0, 0);polyClass('D', 1, 1, 15, 1, 1);polyClass('D', 1, 0, 4, 0, 0);rectClass('D', 0, 0, 0);rectClass('D', 15, 0, 1);GPU_STATUS=0x03000000;ramsyscall_printf("SUMMARY classes=%d baddraw=%d badgrow=%d lines=%d linebaddraw=%d linebadgrow=%d lineunbuilt=%d readtimeouts=%d\n", s_classes, s_badDraw, s_badGrow, s_lineClasses, s_lineBadDraw, s_lineBadGrow, s_lineUnbuilt, s_readTimeouts);} static int lineWordsAtLen(unsigned kind, unsigned segs, unsigned len) { uint32_t out[LINE_MAX_WORDS+4];for(unsigned i=0;i< LINE_MAX_WORDS+4;i++) out[i]=0xdeadbeef;unsigned n=buildLineCommand(out, kind, len, segs);unsigned g=kind &LINE_GOURAUD, poly=kind &LINE_POLY;unsigned verts=poly ? segs+1 :2;unsigned want=1+verts+(g ? verts - 1 :0)+(poly ? 1 :0);if(n !=want) return 0;unsigned op=0x40|(g ? 0x10 :0)|(poly ? 0x08 :0)|((kind &LINE_SEMI) ? 0x02 :0);if((out[0] > > 24) !=op) return 0;if((out[0] &0xffffff)==0) return 0;unsigned major=len, minor=(kind &LINE_SLANTED) ? len/2 :0;unsigned ex=(kind &LINE_VERTICAL) ? minor :major, ey=(kind &LINE_VERTICAL) ? major :minor;for(unsigned v=0;v< verts;v++) { unsigned at=1+v *(g ? 2 :1);uint32_t vtx=(v &1) ?((ey<< 16)|ex) :0;if(out[at] !=vtx) return 0;if(g &&v > 0 &&(out[at - 1] &0xffffff)==0) return 0;} if(poly &&(out[n - 1] &0xf000f000) !=0x50005000) return 0;if(out[n] !=0xdeadbeef) return 0;return 1;} static int lineWordsOk(unsigned kind, unsigned segs) { return lineWordsAtLen(kind, segs, 32) &&lineWordsAtLen(kind, segs, 1) &&lineWordsAtLen(kind, segs, 255);}) CESTER_BEFORE_ALL(gputiming | |
| runAll () | |
| CESTER_AFTER_ALL (CESTER_MAYBE_TEST(gputiming, D2_CHCR=0x00000401;GPU_STATUS=0x00000000;if(s_interruptsWereEnabled) leaveCriticalSection();) | |
Variables | |
| s_interruptsWereEnabled = enterCriticalSection() | |
| IMASK = 0 | |
| #define BIG_WORDS (240 * 240 / 2) |
| #define CESTER_MAYBE_TEST CESTER_TEST |
| #define CESTER_NO_SIGNAL |
| #define CESTER_NO_TIME |
| #define CMD_MAX 64 |
| #define COPY_DST_X 256 |
| #define COPY_DST_Y 256 |
| #define D2_BCR R32(0xbf8010a4) |
| #define D2_CHCR R32(0xbf8010a8) |
| #define D2_MADR R32(0xbf8010a0) |
| #define D_DICR R32(0xbf8010f4) |
| #define D_DPCR R32(0xbf8010f0) |
| #define EXIT_FAILURE 1 |
| #define EXIT_SUCCESS 0 |
| #define GP0_FIFO_WORDS 16 |
| #define GPU_READ R32(0xbf801810) |
| #define LIST_COPIES 16 |
| #define LIST_MAX_SIZE 64 |
| #define N_LINE_LENS (sizeof(s_lineLens) / sizeof(s_lineLens[0])) |
| #define N_POLY_SIZES (sizeof(s_polySizes) / sizeof(s_polySizes[0])) |
| #define N_RECT_SIZES (sizeof(s_rectSizes) / sizeof(s_rectSizes[0])) |
| #define N_XFER (sizeof(s_xferShapes) / sizeof(s_xferShapes[0])) |
| #define PCSX_TESTS 0 |
| #define R32 | ( | a | ) | (*(volatile uint32_t *)(a)) |
| #define REPS 5 |
| #define SENTINEL_FILL 0x080808u |
| #define SENTINEL_PIXEL 0x0421u |
| #define T2_MODE R32(0xbf801124) |
| #define T2_VALUE R32(0xbf801120) |
| #define UPLOAD_Y 256 |
| CESTER_AFTER_ALL | ( | CESTER_MAYBE_TEST( | gputiming, |
| D2_CHCR | = 0x00000401; GPU_STATUS = 0x00000000; if (s_interruptsWereEnabled) leaveCriticalSection(); |
||
| ) |
| CESTER_BODY | ( | #define R32(a) #define D2_MADR #define D2_BCR #define D2_CHCR #define D_DPCR #define D_DICR #define T2_VALUE #define T2_MODE #define GPU_READ #define REPS #define LIST_COPIES #define LIST_MAX_SIZE #define CMD_MAX #define BIG_WORDS #define SENTINEL_FILL #define SENTINEL_PIXEL #define UPLOAD_Y #define COPY_DST_X #define COPY_DST_Y static uint32_t s_cmd;static const uint32_t s_zero;static uint32_t s_list;static uint32_t s_big;static int s_interruptsWereEnabled;static uint32_t | s_acc[CMD_MAX][CMD_MAX][LIST_COPIES *(CMD_MAX+1)][BIG_WORDS], |
| s_prev;static unsigned | s_classes, | ||
| s_badDraw | , | ||
| s_badGrow | , | ||
| s_badZero;static unsigned | s_lineClasses, | ||
| s_lineBadDraw | , | ||
| s_lineBadGrow | , | ||
| s_lineUnbuilt;static uint32_t | s_idx7, | ||
| s_idx7Primed;static inline void tick(void) { uint32_t t=T2_VALUE &0xffff;s_acc+=(t - s_prev) &0xffff;s_prev=t;} static inline void startClock(void) { s_prev=T2_VALUE &0xffff;s_acc=0;} static inline int gpuIdle(void) { return(GPU_STATUS &0x14000000)==0x14000000;} static void waitIdle(void) { while(!gpuIdle()) { } } static inline void waitIdleTimed(void) { while(!gpuIdle()) tick();tick();} #define GP0_FIFO_WORDS static uint32_t timeWordsLong(const uint32_t *w, unsigned n) { waitIdle();startClock();for(unsigned i=0;i< n;i++) { if(i >=GP0_FIFO_WORDS) { while(!(GPU_STATUS &0x02000000)) tick();} GPU_DATA=w[i];if((i &15)==15) tick();} waitIdleTimed();return s_acc;} static uint32_t timeWords(const uint32_t *w, unsigned n, int pace) { if(n > GP0_FIFO_WORDS &&w !=s_zero) return timeWordsLong(w, n);waitIdle();startClock();for(unsigned i=0;i< n;i++) { if(pace &&(i &7)==0) { while(!(GPU_STATUS &0x02000000)) tick();} GPU_DATA=w[i];if((i &15)==15) tick();} waitIdleTimed();return s_acc;} static uint32_t timeList(const uint32_t *w, unsigned n) { for(unsigned k=0;k< LIST_COPIES;k++) { uint32_t *node=&s_list[k *(n+1)];uint32_t next=k+1< LIST_COPIES ?((uint32_t)&s_list[(k+1) *(n+1)] &0xffffff) :0xffffff;node[0]=(n<< 24)|next;for(unsigned i=0;i< n;i++) node[i+1]=w[i];} waitIdle();GPU_STATUS=0x04000002;startClock();D2_MADR=(uint32_t)&s_list[0] &0xffffff;D2_BCR=0;D2_CHCR=0x01000401;while(D2_CHCR &0x01000000) tick();GPU_STATUS=0x04000001;waitIdleTimed();return s_acc;} static void sort5(uint32_t *v) { for(int i=1;i< REPS;i++) { uint32_t x=v[i];int j=i - 1;while(j >=0 &&v[j] > x) { v[j+1]=v[j];j--;} v[j+1]=x;} } struct Sample { uint32_t min, med, max, base;};static struct Sample measure(const uint32_t *w, unsigned n, int pace) { uint32_t t[REPS], b[REPS];for(int r=0;r< REPS;r++) { t[r]=timeWords(w, n, pace);b[r]=timeWords(s_zero, n, pace);} sort5(t);sort5(b);struct Sample s={t[0], t[REPS/2], t[REPS - 1], b[REPS/2]};return s;} static uint32_t measureCold(const uint32_t *w, unsigned n) { uint32_t t[REPS];for(int r=0;r< REPS;r++) { waitIdle();GPU_DATA=0x01000000;waitIdle();t[r]=timeWords(w, n, 0);} sort5(t);return t[REPS/2];} static uint32_t measureList(const uint32_t *w, unsigned n) { uint32_t t[REPS];for(int r=0;r< REPS;r++) t[r]=timeList(w, n);sort5(t);return t[REPS/2]/LIST_COPIES;} static uint32_t net(const struct Sample *s) { return s->med > s->base ? s->med - s->base :0;} static void gp0Fill(unsigned x, unsigned y, unsigned w, unsigned h, uint32_t color) { waitIdle();GPU_DATA=0x02000000|color;GPU_DATA=(y<< 16)|x;GPU_DATA=(h<< 16)|w;waitIdle();} static unsigned s_readTimeouts;static uint32_t readWord(unsigned x, unsigned y) { waitIdle();GPU_DATA=0xc0000000;GPU_DATA=(y<< 16)|x;GPU_DATA=(1<< 16)|2;unsigned polls=0;while(!(GPU_STATUS &0x08000000) &&polls< 400000) polls++;if(polls==400000) { s_readTimeouts++;GPU_STATUS=0x01000000;return 0xffffffff;} uint32_t v=GPU_READ;waitIdle();return v;} static uint16_t readPixel(unsigned x, unsigned y) { return readWord(x, y) &0xffff;} static void uploadRect(unsigned x, unsigned y, unsigned w, unsigned h, uint16_t(*gen)(unsigned, unsigned)) { waitIdle();GPU_DATA=0xa0000000;GPU_DATA=(y<< 16)|x;GPU_DATA=(h<< 16)|w;unsigned i=0;for(unsigned yy=0;yy< h;yy++) { for(unsigned xx=0;xx< w;xx+=2, i++) { if((i &7)==0) { while(!(GPU_STATUS &0x02000000)) { } } GPU_DATA=(uint32_t) gen(xx, yy)|((uint32_t) gen(xx+1, yy)<< 16);} } waitIdle();} static uint16_t genTexel15(unsigned x, unsigned y) { uint16_t v=(uint16_t)((x *0x0843u+y *0x1085u+0x0421u) &0x7fff);if(!v) v=1;return v|0x8000;} static uint16_t genIndex(unsigned x, unsigned y) { return(uint16_t)(x *0x3197u+y *0x5ac3u);} static uint16_t genClut(unsigned x, unsigned y) {(void) y;uint16_t v=(uint16_t)((x *0x0c63u+0x0842u) &0x7fff);if(!v) v=1;return v|0x8000;} static void setupGpu(void) { GPU_STATUS=0x00000000;GPU_STATUS=0x06000000|0x260|(0xc60<< 12);GPU_STATUS=0x07000000|0x010|(0x100<< 10);GPU_STATUS=0x05000000;GPU_STATUS=0x08000001;GPU_DATA=0xe1000400;GPU_DATA=0xe2000000;GPU_DATA=0xe3000000;GPU_DATA=0xe4000000|1023|(511<< 10);GPU_DATA=0xe5000000;GPU_DATA=0xe6000000;GPU_STATUS=0x03000000;GPU_STATUS=0x04000001;waitIdle();uploadRect(TP4_X, 0, 64, 256, genIndex);uploadRect(TP8_X, 0, 128, 256, genIndex);uploadRect(TP15_X, 0, 256, 256, genTexel15);uploadRect(512, CLUT4_Y, 16, 1, genClut);uploadRect(512, CLUT8_Y, 256, 1, genClut);} static void setE1(unsigned tex, unsigned semi, unsigned dither) { uint32_t v=(abr(semi)<< 5)|(1u<< 10)|(dither<< 9);if(tex) v|=tpageX(tex)|(tdepth(tex)<< 7);waitIdle();GPU_DATA=0xe1000000|v;waitIdle();} static void classDone(char kind, unsigned tag, int drawn, int grow, int isLine) { ramsyscall_printf("K %c %x drawn=%d grow=%d\n", kind, tag, drawn, grow);if(isLine) { s_lineClasses++;if(!drawn) s_lineBadDraw++;if(!grow) s_lineBadGrow++;} else { s_classes++;if(!drawn) s_badDraw++;if(!grow) s_badGrow++;} } static const unsigned | s_polySizes[] = {1, 2, 4, 8, 16, 32, 64, 96, 128, 160, 192, 240}; #define N_POLY_SIZES static int polyDrawn(unsigned quad, unsigned g, unsigned tex, unsigned semi) { gp0Fill(0, 0, 256, 256, SENTINEL_FILL); unsigned n = buildPoly(s_cmd, quad, g, tex, semi, 0, 240, 240); timeWords(s_cmd, n, 0); waitIdle(); return readPixel(60, 60) != SENTINEL_PIXEL; } static void polyPoint(char arm, unsigned quad, unsigned g, unsigned tex, unsigned semi, unsigned d, unsigned x0, unsigned w, unsigned h, struct Sample *out) { unsigned n = buildPoly(s_cmd, quad, g, tex, semi, x0, w, h); struct Sample s = measure(s_cmd, n, 0); uint32_t list = (w <= LIST_MAX_SIZE && h <= LIST_MAX_SIZE && arm == 'M') ? measureList(s_cmd, n) : 0; uint32_t cold = (tex && arm == 'M') ? measureCold(s_cmd, n) : 0; ramsyscall_printf("P %c %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", arm, quad, g, tex, semi, d, x0, w, h, s.min, s.med, s.max, s.base, list, cold); if (out) *out = s; } static void polyClass(char arm, unsigned quad, unsigned g, unsigned tex, unsigned semi, unsigned d) { setE1(tex, semi, d); struct Sample first = {0}, last = {0}; for (unsigned i = 0; i < N_POLY_SIZES; i++) { unsigned L = s_polySizes[i]; struct Sample s; polyPoint(arm, quad, g, tex, semi, d, 0, L, L, &s); if (i == 0) first = s; last = s; } int drawn = polyDrawn(quad, g, tex, semi); unsigned tag = (quad << 16) | (g << 12) | (tex << 4) | (semi << 1) | d; classDone(arm, tag, drawn, net(&last) > net(&first) + 1000, 0); } static void polyShapes(unsigned quad, unsigned g, unsigned tex, unsigned semi, unsigned d) { setE1(tex, semi, d); for (unsigned i = 0; i < N_POLY_SIZES; i++) { unsigned L = s_polySizes[i]; polyPoint('W', quad, g, tex, semi, d, 0, L, 8, 0); polyPoint('H', quad, g, tex, semi, d, 0, 8, L, 0); } for (unsigned x0 = 0; x0 < 16; x0++) polyPoint('X', quad, g, tex, semi, d, x0, 64, 64, 0); } static const unsigned s_rectSizes[] = {1, 2, 4, 8, 16, 32, 64, 128, 240}; #define N_RECT_SIZES static void rectPoint(char arm, unsigned size, unsigned tex, unsigned semi, unsigned raw, unsigned w, unsigned h, struct Sample *out) { unsigned n = buildRect(s_cmd, size, tex, semi, raw, w, h); struct Sample s = measure(s_cmd, n, 0); uint32_t cold = (tex && arm == 'M') ? measureCold(s_cmd, n) : 0; ramsyscall_printf("R %c %d %d %d %d %d %d %d %d %d %d %d\n", arm, size, tex, semi, raw, w, h, s.min, s.med, s.max, s.base, cold); if (out) *out = s; } static void rectClass(char arm, unsigned tex, unsigned semi, unsigned raw) { setE1(tex, semi, 0); struct Sample first = {0}, last = {0}; for (unsigned i = 0; i < N_RECT_SIZES; i++) { unsigned L = s_rectSizes[i]; struct Sample s; rectPoint(arm, 0, tex, semi, raw, L, L, &s); if (i == 0) first = s; last = s; } rectPoint(arm, 1, tex, semi, raw, 1, 1, 0); rectPoint(arm, 8, tex, semi, raw, 8, 8, 0); rectPoint(arm, 16, tex, semi, raw, 16, 16, 0); gp0Fill(0, 0, 256, 256, SENTINEL_FILL); unsigned n = buildRect(s_cmd, 0, tex, semi, raw, 240, 240); timeWords(s_cmd, n, 0); int drawn = readPixel(60, 60) != SENTINEL_PIXEL; unsigned tag = 0x100000 | (tex << 4) | (semi << 1) | raw; classDone(arm, tag, drawn, net(&last) > net(&first) + 1000, 0); } static const unsigned s_lineLens[] = {1, 2, 4, 8, 16, 32, 64, 128, 255}; #define N_LINE_LENS static const unsigned s_lineSegs[] = {2, 4, 8, 16}; static void lineClass(unsigned kind, unsigned semi, unsigned d) { unsigned k = kind | (semi ? LINE_SEMI : 0); if (!buildLineCommand(s_cmd, k, 1, (kind & LINE_POLY) ? 2 : 1)) { s_lineUnbuilt++; ramsyscall_printf("L kind %d unbuilt\n", k); return; } setE1(0, semi, d); struct Sample first = {0}, last = {0}; unsigned segs = (kind & LINE_POLY) ? 2 : 1; for (unsigned i = 0; i < N_LINE_LENS; i++) { unsigned n = buildLineCommand(s_cmd, k, s_lineLens[i], segs); struct Sample s = measure(s_cmd, n, 0); ramsyscall_printf("L M %d %d %d %d %d %d %d %d %d\n", k, d, semi, segs, s_lineLens[i], s.min, s.med, s.max, s.base); if (i == 0) first = s; last = s; } if (kind & LINE_POLY) { for (unsigned i = 0; i < sizeof(s_lineSegs) / sizeof(s_lineSegs[0]); i++) { unsigned n = buildLineCommand(s_cmd, k, 64, s_lineSegs[i]); struct Sample s = measure(s_cmd, n, 0); ramsyscall_printf("L S %d %d %d %d %d %d %d %d %d\n", k, d, semi, s_lineSegs[i], 64, s.min, s.med, s.max, s.base); } } gp0Fill(0, 0, 256, 256, SENTINEL_FILL); unsigned n = buildLineCommand(s_cmd, k, 255, segs); timeWords(s_cmd, n, 0); int drawn = readPixel(0, 0) != SENTINEL_PIXEL; classDone('L', 0x200000 | (k << 4) | (semi << 1) | d, drawn, net(&last) > net(&first) + 64, 1); } static const unsigned s_fillSizes[] = {16, 32, 48, 64, 128, 256}; static void fillClass(void) { struct Sample first = {0}, last = {0}; for (unsigned i = 0; i < sizeof(s_fillSizes) / sizeof(s_fillSizes[0]); i++) { unsigned L = s_fillSizes[i]; s_cmd[0] = 0x02000000 | 0x50a020; s_cmd[1] = 0; s_cmd[2] = (L << 16) | L; struct Sample s = measure(s_cmd, 3, 0); ramsyscall_printf("F %d %d %d %d %d %d\n", L, L, s.min, s.med, s.max, s.base); if (i == 0) first = s; last = s; } gp0Fill(0, 0, 256, 256, SENTINEL_FILL); waitIdle(); for (unsigned k = 0; k < 3; k++) GPU_DATA = s_cmd[k]; waitIdle(); unsigned L = s_fillSizes[sizeof(s_fillSizes) / sizeof(s_fillSizes[0]) - 1]; classDone('F', 0x300000, readPixel(0, 0) == 0x2a84 && readPixel(L - 1, L - 1) == 0x2a84, net(&last) > net(&first) + 1000, 0); } static void copyClass(void) { struct Sample first = {0}, last = {0}; gp0Fill(0, 0, 256, 256, 0x00f8f8); for (unsigned i = 0; i < N_RECT_SIZES; i++) { unsigned L = s_rectSizes[i]; s_cmd[0] = 0x80000000; s_cmd[1] = 0; s_cmd[2] = vtx(COPY_DST_X, COPY_DST_Y); s_cmd[3] = (L << 16) | L; struct Sample s = measure(s_cmd, 4, 0); ramsyscall_printf("C %d %d %d %d %d %d\n", L, L, s.min, s.med, s.max, s.base); if (i == 0) first = s; last = s; } gp0Fill(COPY_DST_X, COPY_DST_Y, 256, 240, SENTINEL_FILL); s_cmd[3] = (240 << 16) | 240; timeWords(s_cmd, 4, 0); classDone('C', 0x400000, readPixel(COPY_DST_X + 60, COPY_DST_Y + 60) == 0x03ff, net(&last) > net(&first) + 1000, 0); } struct Shape { uint16_t w, h; }; static const struct Shape s_xferShapes[] = {{8, 8}, {16, 16}, {32, 32}, {64, 64}, {128, 128}, {240, 240}, {320, 16}, {16, 240}}; #define N_XFER static unsigned s_dmaTimeouts; static uint32_t timeUpload(unsigned w, unsigned h, unsigned dma) { unsigned words = w * h / 2; waitIdle(); startClock(); GPU_DATA = 0xa0000000; GPU_DATA = vtx(0, UPLOAD_Y); GPU_DATA = (h << 16) | w; if (dma) { GPU_STATUS = 0x04000002; D2_MADR = (uint32_t)s_big & 0xffffff; D2_BCR = dma | ((words / dma) << 16); D2_CHCR = 0x01000201; unsigned polls = 0; while (D2_CHCR & 0x01000000) { tick(); if (++polls > 4000000) { D2_CHCR = 0x00000201; s_dmaTimeouts++; GPU_STATUS = 0x01000000; break; } } GPU_STATUS = 0x04000001; } else { for (unsigned i = 0; i < words; i++) { if ((i & 7) == 0) { while (!(GPU_STATUS & 0x02000000)) tick(); } GPU_DATA = s_big[i]; if ((i & 15) == 15) tick(); } } waitIdleTimed(); return s_acc; } static uint32_t timeDownload(unsigned w, unsigned h, int dma) { unsigned words = w * h / 2; waitIdle(); startClock(); GPU_DATA = 0xc0000000; GPU_DATA = 0; GPU_DATA = (h << 16) | w; while (!(GPU_STATUS & 0x08000000)) tick(); if (dma) { GPU_STATUS = 0x04000003; D2_MADR = (uint32_t)s_big & 0xffffff; D2_BCR = 16 | ((words / 16) << 16); D2_CHCR = 0x01000200; while (D2_CHCR & 0x01000000) tick(); GPU_STATUS = 0x04000001; } else { for (unsigned i = 0; i < words; i++) { while (!(GPU_STATUS & 0x08000000)) tick(); s_big[i] = GPU_READ; if ((i & 15) == 15) tick(); } } waitIdleTimed(); return s_acc; } static void xferClass(char kind, int dma) { struct Sample first = {0}, last = {0}; for (unsigned i = 0; i < N_XFER; i++) { unsigned w = s_xferShapes[i].w, h = s_xferShapes[i].h; uint32_t t[REPS], b[REPS]; for (int r = 0; r < REPS; r++) { if (kind == 'U') { for (unsigned j = 0; j < w * h / 2; j++) s_big[j] = 0x7c1f03e0u ^ (j * 0x00210021u); t[r] = timeUpload(w, h, dma ? 16 : 0); } else { t[r] = timeDownload(w, h, dma); } b[r] = timeWords(s_zero, 3, 0); } sort5(t); sort5(b); struct Sample s = {t[0], t[REPS / 2], t[REPS - 1], b[REPS / 2]}; ramsyscall_printf("%c %d %d %d %d %d %d %d\n", kind, dma, w, h, s.min, s.med, s.max, s.base); if (i == 0) first = s; if (w == 240) last = s; } int ok; if (kind == 'U') { ok = readPixel(0, UPLOAD_Y) == (s_big[0] & 0xffff); } else { gp0Fill(0, 0, 16, 16, 0x00f8f8); s_big[0] = 0; timeDownload(16, 16, dma); ok = (s_big[0] & 0xffff) == 0x03ff; } classDone(kind, 0x500000 | dma, ok, net(&last) > net(&first) + 1000, 0); } static unsigned s_blockFails; static void uploadBlockSizes(void) { unsigned timeoutsBefore = s_dmaTimeouts; static const uint8_t sizes[] = {1, 2, 4, 8, 16}; static const struct Shape shapes[] = {{16, 16}, {64, 64}, {240, 240}, {320, 16}}; for (unsigned b = 0; b < sizeof(sizes); b++) { for (unsigned i = 0; i < sizeof(shapes) / sizeof(shapes[0]); i++) { unsigned w = shapes[i].w, h = shapes[i].h, words = w * h / 2; uint32_t t[REPS]; for (int r = 0; r < REPS; r++) { for (unsigned j = 0; j < words; j++) s_big[j] = 0x7c1f03e0u ^ ((j + r) * 0x00210021u); t[r] = timeUpload(w, h, sizes[b]); } int ok = readPixel(0, UPLOAD_Y) == (s_big[0] & 0xffff) && readPixel(w - 1, UPLOAD_Y + h - 1) == (s_big[words - 1] >> 16); if (!ok) s_blockFails++; sort5(t); ramsyscall_printf("B %d %d %d %d %d %d %d\n", sizes[b], w, h, t[0], t[REPS / 2], t[REPS - 1], ok); } } if (s_dmaTimeouts != timeoutsBefore) s_blockFails++; ramsyscall_printf("B timeouts=%d\n", s_dmaTimeouts); } static void windowArm(void) { waitIdle(); GPU_DATA = 0xe2000000 | 0x1e | (0x1e << 5); for (unsigned quad = 0; quad < 2; quad++) for (unsigned g = 0; g < 2; g++) for (unsigned ti = 1; ti < 4; ti++) for (unsigned semi = 0; semi < 5; semi += 4) polyClass('T', quad, g, ti == 1 ? 4 : ti == 2 ? 8 : 15, semi, 0); for (unsigned ti = 1; ti < 4; ti++) rectClass('T', ti == 1 ? 4 : ti == 2 ? 8 : 15, 0, 1); waitIdle(); GPU_DATA = 0xe2000000; } static void zeroPoint(unsigned how, unsigned quad, unsigned g, unsigned tex, unsigned semi, unsigned L) { unsigned n; if (quad == 2) { n = buildRect(s_cmd, 0, tex, semi, 0, how == 3 ? 0 : L, how == 4 ? 0 : L); } else { n = buildPoly(s_cmd, quad, g, tex, semi, 0, how == 1 ? 0 : L, how == 0 ? L : 0); } struct Sample s = measure(s_cmd, n, 0); ramsyscall_printf("Z %d %d %d %d %d %d %d %d %d %d\n", how, quad, g, tex, semi, L, s.min, s.med, s.max, s.base); } static void zeroArm(void) { static const unsigned sizes[] = {1, 64, 240}; for (unsigned quad = 0; quad < 3; quad++) for (unsigned g = 0; g < (quad == 2 ? 1u : 2u); g++) for (unsigned ti = 0; ti < 4; ti++) for (unsigned semi = 0; semi < 2; semi++) { unsigned tex = ti == 0 ? 0 : ti == 1 ? 4 : ti == 2 ? 8 : 15; setE1(tex, semi, 0); waitIdle(); GPU_DATA = 0xe3000000 | 1000 | (500 << 10); GPU_DATA = 0xe4000000 | 1010 | (510 << 10); for (unsigned i = 0; i < 3; i++) zeroPoint(0, quad, g, tex, semi, sizes[i]); waitIdle(); GPU_DATA = 0xe3000000; GPU_DATA = 0xe4000000 | 1023 | (511 << 10); if (quad == 2) { for (unsigned i = 0; i < 3; i++) zeroPoint(3, quad, g, tex, semi, sizes[i]); for (unsigned i = 0; i < 3; i++) zeroPoint(4, quad, g, tex, semi, sizes[i]); } else { zeroPoint(1, quad, g, tex, semi, 1); for (unsigned i = 0; i < 3; i++) zeroPoint(2, quad, g, tex, semi, sizes[i]); } } setE1(0, 0, 0); gp0Fill(0, 0, 256, 256, SENTINEL_FILL); unsigned n = buildPoly(s_cmd, 1, 0, 0, 0, 0, 240, 0); timeWords(s_cmd, n, 0); uint16_t quadRow = readPixel(60, 0); gp0Fill(0, 0, 256, 256, SENTINEL_FILL); n = buildPoly(s_cmd, 0, 0, 0, 0, 0, 0, 0); timeWords(s_cmd, n, 0); uint16_t triPoint = readPixel(0, 0); gp0Fill(0, 0, 256, 256, SENTINEL_FILL); n = buildRect(s_cmd, 0, 0, 0, 0, 0, 240); timeWords(s_cmd, n, 0); uint16_t rectW0 = readPixel(0, 60); gp0Fill(0, 0, 256, 256, SENTINEL_FILL); n = buildRect(s_cmd, 0, 0, 0, 0, 240, 0); timeWords(s_cmd, n, 0); uint16_t rectH0 = readPixel(60, 0); waitIdle(); GPU_DATA = 0xe3000000 | 1000 | (500 << 10); GPU_DATA = 0xe4000000 | 1010 | (510 << 10); gp0Fill(0, 0, 256, 256, SENTINEL_FILL); n = buildPoly(s_cmd, 1, 0, 0, 0, 0, 240, 240); timeWords(s_cmd, n, 0); n = buildRect(s_cmd, 0, 0, 0, 0, 240, 240); timeWords(s_cmd, n, 0); waitIdle(); GPU_DATA = 0xe3000000; GPU_DATA = 0xe4000000 | 1023 | (511 << 10); uint16_t clipped = readPixel(60, 60); if (quadRow != SENTINEL_PIXEL || triPoint != SENTINEL_PIXEL || rectW0 != SENTINEL_PIXEL || rectH0 != SENTINEL_PIXEL || clipped != SENTINEL_PIXEL) s_badZero++; ramsyscall_printf("Z control quadrow=%04x tripoint=%04x rectw0=%04x recth0=%04x clipped=%04x\n", quadRow, triPoint, rectW0, rectH0, clipped); } static void probeRevision(void) { gp0Fill(0, 0, 16, 16, 0x00f8f8); s_idx7Primed = readWord(0, 0); GPU_STATUS = 0x10000007; for (volatile int i = 0; i < 64; i++) { } s_idx7 = GPU_READ; ramsyscall_printf("REV idx7=%08x primed=%08x\n", s_idx7, s_idx7Primed); } static void runAll(void) { D_DPCR |= 0x00000800; D_DICR = 0; T2_MODE = 0; setupGpu(); probeRevision(); ramsyscall_printf("# P arm quad gouraud tex semi dither x w h min med max base list cold\n"); for (unsigned quad = 0; quad < 2; quad++) for (unsigned g = 0; g < 2; g++) for (unsigned ti = 0; ti < 4; ti++) for (unsigned semi = 0; semi < 5; semi++) for (unsigned d = 0; d < 2; d++) polyClass('M', quad, g, ti == 0 ? 0 : ti == 1 ? 4 : ti == 2 ? 8 : 15, semi, d); polyShapes(1, 0, 0, 0, 0); polyShapes(1, 1, 15, 1, 1); polyShapes(1, 0, 4, 0, 0); polyShapes(1, 0, 8, 0, 0); windowArm(); zeroArm(); ramsyscall_printf("# R arm size tex semi raw w h min med max base cold\n"); for (unsigned ti = 0; ti < 4; ti++) { unsigned tex = ti == 0 ? 0 : ti == 1 ? 4 : ti == 2 ? 8 : 15; for (unsigned semi = 0; semi < 5; semi++) for (unsigned raw = 0; raw < (tex ? 2u : 1u); raw++) rectClass('M', tex, semi, raw); } ramsyscall_printf("# L arm kind dither semi segs len min med max base\n"); for (unsigned kind = 0; kind < 4; kind++) for (unsigned semi = 0; semi < 5; semi++) for (unsigned o = 0; o < 4; o++) for (unsigned d = 0; d < 2; d++) lineClass(kind | ((o & 1) ? LINE_SLANTED : 0) | ((o & 2) ? LINE_VERTICAL : 0), semi, d); fillClass(); copyClass(); xferClass('U', 0); xferClass('U', 1); xferClass('D', 0); xferClass('D', 1); uploadBlockSizes(); GPU_STATUS = 0x03000001; polyClass('D', 1, 0, 0, 0, 0); polyClass('D', 1, 1, 15, 1, 1); polyClass('D', 1, 0, 4, 0, 0); rectClass('D', 0, 0, 0); rectClass('D', 15, 0, 1); GPU_STATUS = 0x03000000; ramsyscall_printf( "SUMMARY classes=%d baddraw=%d badgrow=%d lines=%d linebaddraw=%d linebadgrow=%d lineunbuilt=%d readtimeouts=%d\n", s_classes, s_badDraw, s_badGrow, s_lineClasses, s_lineBadDraw, s_lineBadGrow, s_lineUnbuilt, s_readTimeouts); } static int lineWordsAtLen(unsigned kind, unsigned segs, unsigned len) { uint32_t out[LINE_MAX_WORDS + 4]; for (unsigned i = 0; i < LINE_MAX_WORDS + 4; i++) out[i] = 0xdeadbeef; unsigned n = buildLineCommand(out, kind, len, segs); unsigned g = kind & LINE_GOURAUD, poly = kind & LINE_POLY; unsigned verts = poly ? segs + 1 : 2; unsigned want = 1 + verts + (g ? verts - 1 : 0) + (poly ? 1 : 0); if (n != want) return 0; unsigned op = 0x40 | (g ? 0x10 : 0) | (poly ? 0x08 : 0) | ((kind & LINE_SEMI) ? 0x02 : 0); if ((out[0] >> 24) != op) return 0; if ((out[0] & 0xffffff) == 0) return 0; unsigned major = len, minor = (kind & LINE_SLANTED) ? len / 2 : 0; unsigned ex = (kind & LINE_VERTICAL) ? minor : major, ey = (kind & LINE_VERTICAL) ? major : minor; for (unsigned v = 0; v < verts; v++) { unsigned at = 1 + v * (g ? 2 : 1); uint32_t vtx = (v & 1) ? ((ey << 16) | ex) : 0; if (out[at] != vtx) return 0; if (g && v > 0 && (out[at - 1] & 0xffffff) == 0) return 0; } if (poly && (out[n - 1] & 0xf000f000) != 0x50005000) return 0; if (out[n] != 0xdeadbeef) return 0; return 1; } static int lineWordsOk(unsigned kind, unsigned segs) { return lineWordsAtLen(kind, segs, 32) && lineWordsAtLen(kind, segs, 1) && lineWordsAtLen(kind, segs, 255); } |
||
| ) |
| runAll | ( | ) |
| IMASK = 0 |
| s_interruptsWereEnabled = enterCriticalSection() |