Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
Macros | Functions | Variables
load-timings.c File Reference
#include "common/hardware/counters.h"
#include "common/syscalls/syscalls.h"
#include "installstdio.h"
#include "exotic/cester.h"
Include dependency graph for load-timings.c:

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 BIU_CONFIG_ADDR   0xfffe0130u
 
#define BIU_EXPECTED   0x0001e988u
 
#define N_READS   256
 
#define N_LOADS   32
 
#define REP4(x)   x x x x
 
#define REP16(x)   REP4(x) REP4(x) REP4(x) REP4(x)
 
#define REP32(x)   REP16(x) REP16(x)
 
#define REP64(x)   REP16(x) REP16(x) REP16(x) REP16(x)
 
#define REP128(x)   REP64(x) REP64(x)
 
#define REP256(x)   REP64(x) REP64(x) REP64(x) REP64(x)
 
#define ADDR_SCRATCH   0x1f800000u /* scratchpad SRAM (fast on-chip, no bus) */
 
#define ADDR_ISTAT   0xbf801070u /* on-die MMIO: interrupt controller I_STAT */
 
#define ADDR_DMA   0xbf8010a0u /* on-die MMIO: DMA channel 2 MADR */
 
#define ADDR_RAM_C   0x80100000u /* main RAM, cached mirror (KSEG0) */
 
#define ADDR_RAM_U   0xa0100000u /* main RAM, uncached mirror (KSEG1) */
 
#define ADDR_BIOS   0xbfc00000u /* BIOS ROM (KSEG1) */
 
#define ADDR_JOYSTAT   0xbf801044u /* on-die MMIO: controller port JOY_STAT */
 
#define ADDR_GPUSTAT   0xbf801814u /* GPU status - the GPU is a separate chip */
 
#define ADDR_MDECST   0xbf801824u /* MDEC status */
 
#define ADDR_CDROM   0xbf801800u /* CD-ROM controller index/status (8-bit bus) */
 
#define ADDR_SPU   0xbf801d80u /* SPU main volume left (16-bit bus) */
 
#define MAKE_SPACED(name, seq)
 
#define MAKE_GAP(name, op)
 
#define MAKE_RAW(name, seq)
 
#define SW16
 
#define MAKE_PRIME(name, primers, tail)
 
#define DEV2_DELAY   (*(volatile uint32_t *)0xbf801010)
 
#define DEV4_DELAY   (*(volatile uint32_t *)0xbf801014)
 
#define COM_DELAY   (*(volatile uint32_t *)0xbf801020)
 
#define CDROM_DELAY   (*(volatile uint32_t *)0xbf801018)
 
#define DELAY_REGS   ((volatile uint32_t *)0xbf801010)
 
#define PIN_COM_DELAY   0x00031125u
 
#define PIN_CDROM_DELAY   0x00020843u
 
#define ADDR_SPU_ADSR   0xbf801c08u /* voice 0 ADSR: unkeyed, harmless to write */
 
#define N_BUS   64
 
#define MAKE_BUS(name, insn)
 
#define RUN8(lo, hi, expr)
 
#define PRIME0   ""
 
#define PRIME1   PRIME0 "sw $0, 0(%0)\n"
 
#define PRIME2   PRIME1 "sw $0, 4(%0)\n"
 
#define PRIME3   PRIME2 "sw $0, 8(%0)\n"
 
#define PRIME4   PRIME3 "sw $0, 12(%0)\n"
 
#define PRIME5   PRIME4 "sw $0, 16(%0)\n"
 
#define PRIME6   PRIME5 "sw $0, 20(%0)\n"
 
#define SWEEP_PAD   ".rept 8\nnop\n.endr\n"
 
#define SHADOW_REPS   16
 
#define INTLCK_REPS   8
 
#define INTLCK_LEN   48
 
#define SWEEP_STR_(x)   #x
 
#define SWEEP_STR(x)   SWEEP_STR_(x)
 
#define MAKE_SHADOW(name, op, s)
 
#define MAKE_INTLCK(name, op, use, k)
 
#define SHADOW_POINTS(X)
 
#define INTLCK_POINTS(X)
 
#define SWEEP_LIST(n)   n,
 
#define SHADOW_COUNT   (sizeof(s_shadowPoints) / sizeof(s_shadowPoints[0]))
 
#define INTLCK_COUNT   (sizeof(s_intlckPoints) / sizeof(s_intlckPoints[0]))
 
#define SHADOW_CHECK   8
 
#define SHADOW_FNS(s)
 
#define INTLCK_FNS(k)
 
#define SHADOW_RUN_W(s)   { BENCH(x, shadow_w_##s, M); BENCH(y, shadow_n_##s, M); a[i] = x; b[i] = y; i++; }
 
#define SHADOW_RUN_B(s)   { BENCH(x, shadow_b_##s, M); BENCH(y, shadow_n_##s, M); a[i] = x; b[i] = y; i++; }
 
#define INTLCK_RUN_W(k)   { BENCH(x, intlck_w_##k, M); a[i] = x; b[i] = base; i++; }
 
#define INTLCK_RUN_B(k)   { BENCH(x, intlck_b_##k, M); a[i] = x; b[i] = base; i++; }
 
#define BENCH(ret, fn, p)
 
#define SWEEP_TARGETS   (sizeof(s_sweepTargets) / sizeof(s_sweepTargets[0]))
 

Functions

 CESTER_BODY (static int s_interruptsWereEnabled;static uint32_t s_entryDelay[5];static void pinDelayRegs(void) { COM_DELAY=PIN_COM_DELAY;CDROM_DELAY=PIN_CDROM_DELAY;} static __attribute__((always_inline)) uint32_t timed_read(volatile void *p) { register uint32_t sink;uint16_t before, after;before=COUNTERS[2].value;__asm__ volatile(REP256("lw %0, 0(%1)\n") :"=&r"(sink) :"r"(p) :"memory");after=COUNTERS[2].value;(void) sink;return(uint16_t)(after - before);} static __attribute__((always_inline)) uint32_t timed_nop(volatile void *p) { register uint32_t sink;uint16_t before, after;before=COUNTERS[2].value;__asm__ volatile(REP256("nop\n") :"=&r"(sink) :"r"(p) :"memory");after=COUNTERS[2].value;(void) sink;return(uint16_t)(after - before);} static __attribute__((always_inline)) uint32_t timed_pair(volatile void *a, volatile void *b) { register uint32_t sink;uint16_t before, after;before=COUNTERS[2].value;__asm__ volatile(REP128("lw %0, 0(%1)\nlw %0, 0(%2)\n") :"=&r"(sink) :"r"(a), "r"(b) :"memory");after=COUNTERS[2].value;(void) sink;return(uint16_t)(after - before);} static __attribute__((always_inline)) uint32_t timed_write(volatile void *p) { uint16_t before, after;register volatile char *q=(volatile char *) p;before=COUNTERS[2].value;__asm__ volatile(REP256("sw $0, 0(%0)\naddiu %0, %0, 4\n") :"+r"(q) ::"memory");after=COUNTERS[2].value;return(uint16_t)(after - before);} static __attribute__((always_inline)) uint32_t timed_walk(volatile void *p) { uint16_t before, after;register volatile char *q=(volatile char *) p;before=COUNTERS[2].value;__asm__ volatile(REP256("nop\naddiu %0, %0, 4\n") :"+r"(q) ::"memory");after=COUNTERS[2].value;return(uint16_t)(after - before);} static __attribute__((always_inline)) uint32_t timed_burst(volatile void *p) { uint16_t before, after;before=COUNTERS[2].value;__asm__ volatile(REP16(SW16) ::"r"(p) :"memory");after=COUNTERS[2].value;return(uint16_t)(after - before);} typedef uint32_t(*PrimeFn)(volatile void *, volatile void *);static void primeRow(int n, PrimeFn sync, PrimeFn base, volatile void *c, volatile void *u) { uint32_t bs=0xffffu, bb=0xffffu;for(int i=0;i< 8;i++) { uint32_t x=sync(c, u);uint32_t y=base(c, u);if(x< bs) bs=x;if(y< bb) bb=y;} ramsyscall_printf(" PRIME n=%d sync=%u base=%u delta=%d\n", n, bs, bb,(int) bs -(int) bb);} MAKE_RAW(raw_same, "sw $0, 0(%1)\nlw %0, 0(%1)\nnop\naddiu %0, %0, 1\n") MAKE_RAW(raw_other, "sw $0, 0(%1)\nlw %0, 0(%2)\nnop\naddiu %0, %0, 1\n") typedef struct { const char *name;uint32_t clr, set, flip;int nib;uint32_t val;} BusArm;static const BusArm s_busArms[]={ {"base", 0, 0, 0, -1, 0}, {"b8^", 0, 0, 0x100, -1, 0}, {"b9^", 0, 0, 0x200, -1, 0}, {"b10^", 0, 0, 0x400, -1, 0}, {"b11^", 0, 0, 0x800, -1, 0}, {"b8-11", 0, 0xf00, 0, -1, 0}, {"rd0", 0xf0, 0, 0, -1, 0}, {"rd15", 0, 0xf0, 0, -1, 0}, {"wr0", 0xf, 0, 0, -1, 0}, {"wr15", 0, 0xf, 0, -1, 0}, {"com0=0", 0, 0x100, 0, 0, 0}, {"com0=5", 0, 0x100, 0, 0, 5}, {"com0=15", 0, 0x100, 0, 0, 15}, {"com1=0", 0, 0x200, 0, 1, 0}, {"com1=5", 0, 0x200, 0, 1, 5}, {"com1=15", 0, 0x200, 0, 1, 15}, {"com2=0", 0, 0x400, 0, 2, 0}, {"com2=5", 0, 0x400, 0, 2, 5}, {"com2=15", 0, 0x400, 0, 2, 15}, {"com3=0", 0, 0x800, 0, 3, 0}, {"com3=5", 0, 0x800, 0, 3, 5}, {"com3=15", 0, 0x800, 0, 3, 15}, {"base", 0, 0, 0, -1, 0}, };typedef struct { uint32_t cd, com;uint32_t cdrom, spu;} CdArm;static const CdArm s_cdArms[]={ {0x00020843u, 0x00031125u, 646, 1349}, {0x00020843u, 0x0000132cu, 646, 1790}, {0x00020943u, 0x00031125u, 709, 1349}, {0x00020943u, 0x0000132cu, 1150, 1790}, };#define BENCH(ret, fn, p) static void report(const char *name, uint32_t raw, uint32_t base) { uint32_t abs_cc=(raw *100u+N_READS/2)/N_READS;uint32_t marg_cc=((raw - base) *100u+N_READS/2)/N_READS;ramsyscall_printf(" %s raw256=%u abs=%u.%02u marginal=%u.%02u cyc/read\n", name, raw, abs_cc/100u, abs_cc % 100u, marg_cc/100u, marg_cc % 100u);} static const uint8_t s_shadowPoints[]={ SHADOW_POINTS(SWEEP_LIST) };static const uint8_t s_intlckPoints[]={ INTLCK_POINTS(SWEEP_LIST) };static void sweepPrint(const char *sweep, const char *op, const char *target, const uint8_t *points, unsigned count, const uint32_t *a, const uint32_t *b, unsigned reps) { ramsyscall_printf(" %s %s %s ticks:", sweep, op, target);for(unsigned i=0;i< count;i++) ramsyscall_printf(" %u=%u", points[i], a[i]);ramsyscall_printf("\n %s %s %s base :", sweep, op, target);for(unsigned i=0;i< count;i++) ramsyscall_printf(" %u=%u", points[i], b[i]);ramsyscall_printf("\n %s %s %s cyc :", sweep, op, target);for(unsigned i=0;i< count;i++) { int d=(int) a[i] -(int) b[i];unsigned m=(unsigned)(d< 0 ? -d :d);unsigned cc=(m *100u+reps/2u)/reps;ramsyscall_printf(" %u=%s%u.%02u", points[i], d< 0 ? "-" :"", cc/100u, cc % 100u);} ramsyscall_printf("\n");} static __attribute__((noinline)) uint32_t shadowSweepW(const char *target, volatile void *M, uint32_t *a, uint32_t *b) { unsigned i=0;sweepPrint("SHADOW", "lw ", target, s_shadowPoints, SHADOW_COUNT, a, b, SHADOW_REPS);return a[SHADOW_CHECK] - b[SHADOW_CHECK];} static __attribute__((noinline)) uint32_t shadowSweepB(const char *target, volatile void *M, uint32_t *a, uint32_t *b) { unsigned i=0;sweepPrint("SHADOW", "lbu", target, s_shadowPoints, SHADOW_COUNT, a, b, SHADOW_REPS);return a[SHADOW_CHECK] - b[SHADOW_CHECK];} static __attribute__((noinline)) void intlckSweepW(const char *target, volatile void *M, uint32_t *a, uint32_t *b) { unsigned i=0;BENCH(base, intlck_w_base, M);sweepPrint("INTLCK", "lw ", target, s_intlckPoints, INTLCK_COUNT, a, b, INTLCK_REPS);} static __attribute__((noinline)) void intlckSweepB(const char *target, volatile void *M, uint32_t *a, uint32_t *b) { unsigned i=0;BENCH(base, intlck_b_base, M);sweepPrint("INTLCK", "lbu", target, s_intlckPoints, INTLCK_COUNT, a, b, INTLCK_REPS);} static const uint16_t s_shNop[]={35, 51, 67, 83, 99, 115, 131, 147, 163, 179, 195, 211, 227, 259, 291, 355, 419, 547, 675, 803};static const uint16_t s_shMmio[]={97, 113, 129, 130, 131, 147, 163, 179, 195, 211, 227, 243, 259, 291, 323, 387, 451, 579, 707, 835};static const uint16_t s_shRam[]={127, 143, 159, 160, 161, 162, 163, 179, 195, 211, 227, 243, 259, 291, 323, 387, 451, 579, 707, 835};static const uint16_t s_shRomW[]={445, 460, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 477, 481, 579, 707, 835};static const uint16_t s_shRomB[]={157, 173, 189, 190, 191, 192, 193, 194, 195, 211, 227, 243, 259, 291, 323, 387, 451, 579, 707, 835};static const uint16_t s_shCdrom[]={173, 188, 204, 205, 206, 207, 208, 209, 210, 211, 227, 243, 259, 291, 323, 387, 451, 579, 707, 835};static const uint16_t s_shSpu[]={348, 348, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 364, 366, 368, 387, 451, 579, 707, 835};static const uint16_t s_ilMmio[]={443, 443, 443, 435, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427};static const uint16_t s_ilScratch[]={411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411};static const uint16_t s_ilRam[]={459, 459, 459, 451, 443, 435, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427};static const uint16_t s_ilRomW[]={619, 619, 619, 611, 603, 595, 587, 579, 571, 563, 555, 547, 531, 515, 483, 451, 427, 427, 427};static const uint16_t s_ilRomB[]={475, 475, 475, 467, 459, 451, 443, 435, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427};static const uint16_t s_ilCdrom[]={483, 483, 483, 475, 467, 459, 451, 443, 435, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427};static const uint16_t s_ilSpu[]={563, 563, 563, 555, 547, 539, 531, 523, 515, 507, 499, 491, 475, 459, 427, 427, 427, 427, 427};typedef struct { const char *name;uint32_t addr;int byte;const uint16_t *shadow, *intlck;uint32_t intlckBase;} SweepTarget;static const SweepTarget s_sweepTargets[]={ {"I_STAT ", ADDR_ISTAT, 0, s_shMmio, s_ilMmio, 427}, {"JOY_STAT ", ADDR_JOYSTAT, 0, s_shMmio, s_ilMmio, 427}, {"GPUSTAT ", ADDR_GPUSTAT, 0, s_shMmio, s_ilMmio, 427}, {"MDEC stat ", ADDR_MDECST, 0, s_shMmio, s_ilMmio, 427}, {"scratchpad", ADDR_SCRATCH, 0, s_shNop, s_ilScratch, 411}, {"RAM cached", ADDR_RAM_C, 0, s_shRam, s_ilRam, 427}, {"RAM uncach", ADDR_RAM_U, 0, s_shRam, s_ilRam, 427}, {"BIOS ROM ", ADDR_BIOS, 0, s_shRomW, s_ilRomW, 427}, {"I_STAT ", ADDR_ISTAT, 1, s_shMmio, s_ilMmio, 427}, {"RAM uncach", ADDR_RAM_U, 1, s_shRam, s_ilRam, 427}, {"BIOS ROM ", ADDR_BIOS, 1, s_shRomB, s_ilRomB, 427}, {"CD-ROM ", ADDR_CDROM, 1, s_shCdrom, s_ilCdrom, 427}, {"SPU ", ADDR_SPU, 1, s_shSpu, s_ilSpu, 427}, };#define SWEEP_TARGETS static unsigned sweepMismatches(const char *sweep, const char *what, const SweepTarget *t, const uint8_t *points, unsigned count, const uint32_t *got, const uint16_t *row, uint32_t flat) { unsigned bad=0;for(unsigned i=0;i< count;i++) { uint32_t want=row ? row[i] :flat;if(got[i]==want) continue;ramsyscall_printf(" MISMATCH %s %s %s %s %u: got %u, expected %u\n", sweep, t->byte ? "lbu" :"lw ", t->name, what, points[i], got[i], want);bad++;} return bad;}) CESTER_BEFORE_ALL(load_tests
 
 for (int i=0;i< 5;i++) s_entryDelay[i]
 
 pinDelayRegs ()
 
 CESTER_AFTER_ALL (load_tests, for(int i=0;i< 5;i++) DELAY_REGS[i]=s_entryDelay[i];if(s_interruptsWereEnabled) leaveCriticalSection();) CESTER_BEFORE_EACH(load_tests
 
 CESTER_AFTER_EACH (CESTER_TEST(load_tests, testname, testindex)
 
 cester_assert_true (d0<=(uint32_t) N_READS/8u)
 
 CESTER_MAYBE_TEST (loadCostByGap, load_tests, volatile void *A=(volatile void *) ADDR_RAM_U;ramsyscall_printf("=== load cost by inter-access gap (32 reps, one uncached RAM address) ===\n");ramsyscall_printf(" Format: GAP d=<delay loop count> load=<ticks> nop=<ticks> delta=<ticks per 32 loads>\n");for(uint32_t d=1;d<=48;d++) { uint32_t bl=0xffffu, bn=0xffffu;for(int i=0;i< 8;i++) { uint32_t x=gap_load(A, d);uint32_t y=gap_nop(A, d);if(x< bl) bl=x;if(y< bn) bn=y;} ramsyscall_printf(" GAP d=%u load=%u nop=%u delta=%u\n", d, bl, bn, bl > bn ? bl - bn :0u);}) CESTER_MAYBE_TEST(storeCostByMirror
 
 BENCH (base, timed_walk,(volatile void *) ADDR_RAM_C)
 
 BENCH (w_c, timed_write,(volatile void *) ADDR_RAM_C)
 
 BENCH (w_u, timed_write,(volatile void *) ADDR_RAM_U)
 
 BENCH (nb, timed_nop,(volatile void *) ADDR_ISTAT)
 
 BENCH (b_c, timed_burst,(volatile void *) ADDR_RAM_C)
 
 BENCH (b_u, timed_burst,(volatile void *) ADDR_RAM_U)
 
 ramsyscall_printf ("=== store cost by mirror (N=%d sequential words) ===\n", N_READS)
 
 report ("store KSEG0:", w_c, base)
 
 report ("store KSEG1:", w_u, base)
 
 ramsyscall_printf (" --- saturating burst, 1 instr/store, nop baseline raw256=%u ---\n", nb)
 
 report ("burst KSEG0:", b_c, nb)
 
 report ("burst KSEG1:", b_u, nb)
 
 CESTER_MAYBE_TEST (kseg1StoreSync, load_tests, volatile void *C=(volatile void *) ADDR_RAM_C;volatile void *U=(volatile void *) ADDR_RAM_U;ramsyscall_printf("=== KSEG1 store sync vs primed queue depth (16 reps) ===\n");ramsyscall_printf(" Format: PRIME n=<KSEG0 stores ahead> sync=<ticks> base=<ticks> delta=<ticks per 16>\n");primeRow(0, prime0, pbase0, C, U);primeRow(1, prime1, pbase1, C, U);primeRow(2, prime2, pbase2, C, U);primeRow(3, prime3, pbase3, C, U);primeRow(4, prime4, pbase4, C, U);primeRow(5, prime5, pbase5, C, U);primeRow(6, prime6, pbase6, C, U);) CESTER_MAYBE_TEST(readAfterWrite
 
 CESTER_MAYBE_TEST (onDieUniformity, CESTER_MAYBE_TEST(load_tests, BENCH(istat, timed_read,(volatile void *) ADDR_ISTAT);BENCH(dma, timed_read,(volatile void *) ADDR_DMA);BENCH(rcnt0, timed_read,(volatile void *)&COUNTERS[0].value);BENCH(rcnt2, timed_read,(volatile void *)&COUNTERS[2].value);ramsyscall_printf("=== on-die uniformity ===\n");ramsyscall_printf(" I_STAT=%u DMA=%u RCNT0=%u RCNT2=%u\n", istat, dma, rcnt0, rcnt2);cester_assert_uint_eq(istat, dma);cester_assert_uint_eq(istat, rcnt0);cester_assert_uint_eq(istat, rcnt2);)
 
 cester_assert_uint_eq ((uint32_t) SHADOW_REPS *2u, check)
 
 CESTER_MAYBE_TEST (loadInterlockedByTarget, load_tests, ramsyscall_printf("=== load-interlocked sweep by target (%d loads, result read k instructions later) ===\n", INTLCK_REPS);ramsyscall_printf(" Format: <k>=<value>. ticks = result read, base = result not read, cyc = (ticks - base) / %d\n", INTLCK_REPS);uint32_t a[INTLCK_COUNT], b[INTLCK_COUNT];for(unsigned t=0;t< SWEEP_TARGETS;t++) { const SweepTarget *st=&s_sweepTargets[t];volatile void *M=(volatile void *) st->addr;if(st->byte) intlckSweepB(st->name, M, a, b);else intlckSweepW(st->name, M, a, b);unsigned bad=sweepMismatches("INTLCK", "k", st, s_intlckPoints, INTLCK_COUNT, a, st->intlck, 0);unsigned badBase=sweepMismatches("INTLCK", "base k", st, s_intlckPoints, INTLCK_COUNT, b, 0, st->intlckBase);cester_assert_uint_eq(0, bad);cester_assert_uint_eq(0, badBase);}) CESTER_TEST(busRegistersAtEntry
 
 for (uint32_t a=0xbf801000u;a<=0xbf801020u;a+=4u)
 
 cester_assert_uint_eq (PIN_COM_DELAY, COM_DELAY)
 
 cester_assert_uint_eq (PIN_CDROM_DELAY, CDROM_DELAY)
 
 CESTER_MAYBE_TEST (busDelaySweep, load_tests, volatile void *rom=(volatile void *) ADDR_BIOS;volatile void *spu=(volatile void *) ADDR_SPU_ADSR;uint32_t dev2=DEV2_DELAY, dev4=DEV4_DELAY, com=COM_DELAY;uint32_t nlo, nhi;RUN8(nlo, nhi, bus_nop(rom));ramsyscall_printf("=== bus delay sweep (N=%d, entry dev2=%08x dev4=%08x com=%08x) ===\n", N_BUS, dev2, dev4, com);ramsyscall_printf(" Format: BUSn <arm> dev=<reg> com=<reg> <access>=<min>/<max> ...\n");ramsyscall_printf(" BUSNOP nop=%u/%u\n", nlo, nhi);int subjects=0;uint32_t first2=0, last2=0, first4=0, last4=0;uint32_t nocom2[3]={0, 0, 0}, nocom4=0;int n=(int)(sizeof(s_busArms)/sizeof(s_busArms[0]));for(int d=0;d< 2;d++) { volatile uint32_t *reg=d==0 ? &DEV2_DELAY :&DEV4_DELAY;uint32_t v0= *reg;for(int k=0;k< n;k++) { const BusArm *arm=&s_busArms[k];uint32_t cfg=((v0 &~arm->clr)|arm->set) ^ arm->flip;uint32_t c=com;if(arm->nib >=0) c=(com &~(0xfu<<(4 *arm->nib)))|(arm->val<<(4 *arm->nib));uint32_t alo, ahi, blo, bhi, clo, chi, dlo=0, dhi=0;COM_DELAY=c; *reg=cfg;if(d==0) { RUN8(alo, ahi, bus_lw(rom));RUN8(blo, bhi, bus_lh(rom));RUN8(clo, chi, bus_lb(rom));} else { RUN8(alo, ahi, bus_sh(spu));RUN8(blo, bhi, bus_sw(spu));RUN8(clo, chi, bus_lhs(spu));RUN8(dlo, dhi, bus_lws(spu));} *reg=v0;COM_DELAY=com;if(d==0) { ramsyscall_printf(" BUS2 %-8s dev=%08x com=%08x lw=%u/%u lh=%u/%u lb=%u/%u\n", arm->name, cfg, c, alo, ahi, blo, bhi, clo, chi);if(k==0) first2=alo;if(k==3) { nocom2[0]=alo;nocom2[1]=blo;nocom2[2]=clo;} last2=alo;} else { ramsyscall_printf(" BUS4 %-8s dev=%08x com=%08x sh=%u/%u sw=%u/%u lh=%u/%u lw=%u/%u\n", arm->name, cfg, c, alo, ahi, blo, bhi, clo, chi, dlo, dhi);if(k==0) first4=blo;if(k==1) nocom4=dlo;last4=blo;} subjects++;} } uint32_t cd=CDROM_DELAY;int ncd=(int)(sizeof(s_cdArms)/sizeof(s_cdArms[0]));uint32_t cdlo[sizeof(s_cdArms)/sizeof(s_cdArms[0])], splo[sizeof(s_cdArms)/sizeof(s_cdArms[0])];for(int k=0;k< ncd;k++) { const CdArm *arm=&s_cdArms[k];uint32_t clo, chi, slo, shi;COM_DELAY=arm->com;CDROM_DELAY=arm->cd;RUN8(clo, chi, bus_lbu((volatile void *) ADDR_CDROM));RUN8(slo, shi, bus_lbu((volatile void *) ADDR_SPU));CDROM_DELAY=cd;COM_DELAY=com;ramsyscall_printf(" BUS5 cd=%08x com=%08x lbu-cdrom=%u/%u lbu-spu=%u/%u\n", arm->cd, arm->com, clo, chi, slo, shi);cdlo[k]=clo;splo[k]=slo;subjects++;} ramsyscall_printf(" BUS subjects=%d\n", subjects);cester_assert_int_eq(2 *n+ncd, subjects);cester_assert_uint_eq(dev2, DEV2_DELAY);cester_assert_uint_eq(dev4, DEV4_DELAY);cester_assert_uint_eq(com, COM_DELAY);cester_assert_uint_eq(cd, CDROM_DELAY);cester_assert_uint_eq(first2, last2);uint32_t d4=first4 > last4 ? first4 - last4 :last4 - first4;cester_assert_true(d4<=(uint32_t) N_BUS/8u);if(dev2==0x0013243fu) { cester_assert_uint_eq(1542, nocom2[0]);cester_assert_uint_eq(902, nocom2[1]);cester_assert_uint_eq(582, nocom2[2]);} if(dev4==0x200931e1u) cester_assert_uint_eq(2310, nocom4);for(int k=0;k< ncd;k++) { cester_assert_uint_eq(s_cdArms[k].cdrom, cdlo[k]);cester_assert_uint_eq(s_cdArms[k].spu, splo[k]);}) CESTER_OPTIONS(CESTER_VERBOSE()
 

Variables

 s_interruptsWereEnabled = enterCriticalSection()
 
COUNTERS[2] mode = 0
 
 testname
 
 testindex
 
uint32_t d0 = stride0 > ref ? stride0 - ref : ref - stride0
 
 load_tests
 
volatile void * c0 = (volatile void *)ADDR_RAM_C
 
volatile void * c1 = (volatile void *)(ADDR_RAM_C + 4096u)
 
volatile void * u0 = (volatile void *)ADDR_RAM_U
 
volatile void * u1 = (volatile void *)(ADDR_RAM_U + 4096u)
 
uint32_t sc = 0xffffu
 
uint32_t oc = 0xffffu
 
uint32_t su = 0xffffu
 
uint32_t ou = 0xffffu
 
uint32_t nl = 0xffffu
 

Macro Definition Documentation

◆ ADDR_BIOS

#define ADDR_BIOS   0xbfc00000u /* BIOS ROM (KSEG1) */

◆ ADDR_CDROM

#define ADDR_CDROM   0xbf801800u /* CD-ROM controller index/status (8-bit bus) */

◆ ADDR_DMA

#define ADDR_DMA   0xbf8010a0u /* on-die MMIO: DMA channel 2 MADR */

◆ ADDR_GPUSTAT

#define ADDR_GPUSTAT   0xbf801814u /* GPU status - the GPU is a separate chip */

◆ ADDR_ISTAT

#define ADDR_ISTAT   0xbf801070u /* on-die MMIO: interrupt controller I_STAT */

◆ ADDR_JOYSTAT

#define ADDR_JOYSTAT   0xbf801044u /* on-die MMIO: controller port JOY_STAT */

◆ ADDR_MDECST

#define ADDR_MDECST   0xbf801824u /* MDEC status */

◆ ADDR_RAM_C

#define ADDR_RAM_C   0x80100000u /* main RAM, cached mirror (KSEG0) */

◆ ADDR_RAM_U

#define ADDR_RAM_U   0xa0100000u /* main RAM, uncached mirror (KSEG1) */

◆ ADDR_SCRATCH

#define ADDR_SCRATCH   0x1f800000u /* scratchpad SRAM (fast on-chip, no bus) */

◆ ADDR_SPU

#define ADDR_SPU   0xbf801d80u /* SPU main volume left (16-bit bus) */

◆ ADDR_SPU_ADSR

#define ADDR_SPU_ADSR   0xbf801c08u /* voice 0 ADSR: unkeyed, harmless to write */

◆ BENCH

#define BENCH (   ret,
  fn,
  p 
)
Value:
uint32_t ret; do { \
uint32_t best = 0xffffu; \
for (int i = 0; i < 8; i++) { \
uint32_t skew = i * 19u; \
__asm__ volatile(".set push\n.set noreorder\n1: bnez %0, 1b\naddiu %0, %0, -1\n.set pop\n" \
: "+r"(skew)); \
uint32_t d = fn(p); \
if (d < best) best = d; \
} \
ret = best; \
} while (0);
int i
Definition gte-regio.c:299
__asm__(" .section .text.monitorSlotEntry, \"ax\", @progbits\n" " .align 2\n" " .global monitorSlotEntry\n" " .type monitorSlotEntry, @function\n" " .set push\n" " .set noreorder\n" " .set noat\n" "monitorSlotEntry:\n" " mfc0 $v0, $13\n" " nop\n" " andi $v0, $v0, 0x7c\n" " beqz $v0, 1f\n" " srl $v0, $v0, 2\n" " li $v1, " MON_STR(MON_SLOT_EXCMASK) "\n" " srlv $v1, $v1, $v0\n" " andi $v1, $v1, 1\n" " bnez $v1, 2f\n" " nop\n" " jr $ra\n" " nop\n" "1:\n" MON_SLOT_RX_TEST " jr $ra\n" " nop\n" "2:\n" " sw $a0, 0x10($k0)\n" " sw $a1, 0x14($k0)\n" " sw $a2, 0x18($k0)\n" " sw $a3, 0x1c($k0)\n" " mfc0 $a0, $12\n" " nop\n" " sw $a0, 0x8c($k0)\n" " mfc0 $a1, $13\n" " nop\n" " sw $a1, 0x90($k0)\n" " sw $k1, 0x6c($k0)\n" " sw $s0, 0x40($k0)\n" " sw $s1, 0x44($k0)\n" " sw $s2, 0x48($k0)\n" " sw $s3, 0x4c($k0)\n" " sw $s4, 0x50($k0)\n" " sw $s5, 0x54($k0)\n" " sw $s6, 0x58($k0)\n" " sw $s7, 0x5c($k0)\n" " sw $t0, 0x20($k0)\n" " sw $t1, 0x24($k0)\n" " sw $t2, 0x28($k0)\n" " sw $t3, 0x2c($k0)\n" " sw $t4, 0x30($k0)\n" " sw $t5, 0x34($k0)\n" " sw $t6, 0x38($k0)\n" " sw $t7, 0x3c($k0)\n" " sw $t8, 0x60($k0)\n" " sw $t9, 0x64($k0)\n" " sw $gp, 0x70($k0)\n" " sw $sp, 0x74($k0)\n" " sw $fp, 0x78($k0)\n" " mfhi $a0\n" " nop\n" " sw $a0, 0x84($k0)\n" " mflo $a0\n" " nop\n" " sw $a0, 0x88($k0)\n" " move $s0, $ra\n" " la $sp, monitorSlotStack + " MON_STR(MONITOR_SLOT_STACK_WORDS) " * 4 - 16\n" " jal monitorSlotDispatch\n" " nop\n" " lw $k0, 0x108($zero)\n" " move $ra, $s0\n" " lw $k0, 0($k0)\n" " nop\n" " addiu $k0, $k0, 8\n" " lw $a0, 0x84($k0)\n" " lw $a1, 0x88($k0)\n" " mthi $a0\n" " mtlo $a1\n" " lw $a0, 0x10($k0)\n" " lw $a1, 0x14($k0)\n" " lw $a2, 0x18($k0)\n" " lw $a3, 0x1c($k0)\n" " lw $t0, 0x20($k0)\n" " lw $t1, 0x24($k0)\n" " lw $t2, 0x28($k0)\n" " lw $t3, 0x2c($k0)\n" " lw $t4, 0x30($k0)\n" " lw $t5, 0x34($k0)\n" " lw $t6, 0x38($k0)\n" " lw $t7, 0x3c($k0)\n" " lw $t8, 0x60($k0)\n" " lw $t9, 0x64($k0)\n" " lw $s0, 0x40($k0)\n" " lw $sp, 0x74($k0)\n" " jr $ra\n" " nop\n" " .set pop\n" " .size monitorSlotEntry, . - monitorSlotEntry\n" " .previous\n")
static int ret
Definition syscalls.h:125

◆ BIU_CONFIG_ADDR

#define BIU_CONFIG_ADDR   0xfffe0130u

◆ BIU_EXPECTED

#define BIU_EXPECTED   0x0001e988u

◆ CDROM_DELAY

#define CDROM_DELAY   (*(volatile uint32_t *)0xbf801018)

◆ CESTER_MAYBE_TEST

#define CESTER_MAYBE_TEST   CESTER_TEST

◆ CESTER_NO_SIGNAL

#define CESTER_NO_SIGNAL

◆ CESTER_NO_TIME

#define CESTER_NO_TIME

◆ COM_DELAY

#define COM_DELAY   (*(volatile uint32_t *)0xbf801020)

◆ DELAY_REGS

#define DELAY_REGS   ((volatile uint32_t *)0xbf801010)

◆ DEV2_DELAY

#define DEV2_DELAY   (*(volatile uint32_t *)0xbf801010)

◆ DEV4_DELAY

#define DEV4_DELAY   (*(volatile uint32_t *)0xbf801014)

◆ EXIT_FAILURE

#define EXIT_FAILURE   1

◆ EXIT_SUCCESS

#define EXIT_SUCCESS   0

◆ INTLCK_COUNT

#define INTLCK_COUNT   (sizeof(s_intlckPoints) / sizeof(s_intlckPoints[0]))

◆ INTLCK_FNS

#define INTLCK_FNS (   k)
Value:
MAKE_INTLCK(intlck_w_##k, "lw %0, 0(%1)", "addiu %0, %0, 1", k) \
MAKE_INTLCK(intlck_b_##k, "lbu %0, 0(%1)", "addiu %0, %0, 1", k)
#define MAKE_INTLCK(name, op, use, k)
Definition load-timings.c:298

◆ INTLCK_LEN

#define INTLCK_LEN   48

◆ INTLCK_POINTS

#define INTLCK_POINTS (   X)
Value:
X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) \
X(14) X(16) X(20) X(24) X(32) X(40) X(48)

◆ INTLCK_REPS

#define INTLCK_REPS   8

◆ INTLCK_RUN_B

#define INTLCK_RUN_B (   k)    { BENCH(x, intlck_b_##k, M); a[i] = x; b[i] = base; i++; }

◆ INTLCK_RUN_W

#define INTLCK_RUN_W (   k)    { BENCH(x, intlck_w_##k, M); a[i] = x; b[i] = base; i++; }

◆ MAKE_BUS

#define MAKE_BUS (   name,
  insn 
)
Value:
static __attribute__((always_inline)) uint32_t name(volatile void *p) { \
register uint32_t sink = 0; \
uint16_t before, after; \
before = COUNTERS[2].value; \
__asm__ volatile(REP64(insn "\n") : "+r"(sink) : "r"(p) : "memory"); \
after = COUNTERS[2].value; \
(void)sink; \
return (uint16_t)(after - before); \
}
__attribute__((weak))
Definition clz.c:56
#define COUNTERS
Definition counters.h:40
#define REP64(x)
Definition load-timings.c:115
uint32_t before
Definition readnosetloc.c:138
uint32_t after
Definition readnosetloc.c:139

◆ MAKE_GAP

#define MAKE_GAP (   name,
  op 
)
Value:
static __attribute__((always_inline)) uint32_t name(volatile void *p, uint32_t d) { \
register uint32_t sink; \
uint16_t before, after; \
before = COUNTERS[2].value; \
__asm__ volatile(REP32(op "\n" \
"nop\n" \
"addiu %0, %0, 1\n" \
"move $t9, %2\n" \
"1: addiu $t9, $t9, -1\n" \
"bgtz $t9, 1b\n" \
"nop\n") \
: "=&r"(sink) : "r"(p), "r"(d) : "$t9", "memory"); \
after = COUNTERS[2].value; \
(void)sink; \
return (uint16_t)(after - before); \
}
#define REP32(x)
Definition load-timings.c:114

◆ MAKE_INTLCK

#define MAKE_INTLCK (   name,
  op,
  use,
  k 
)
Value:
static __attribute__((always_inline)) uint32_t name(volatile void *p) { \
register uint32_t sink; \
uint16_t before, after; \
before = COUNTERS[2].value; \
__asm__ volatile(".set push\n.set noreorder\n" SWEEP_PAD \
".rept " SWEEP_STR(INTLCK_REPS) "\n" op "\n" \
".rept " #k " - 1\nnop\n.endr\n" \
use "\n" \
".rept " SWEEP_STR(INTLCK_LEN) " - " #k "\nnop\n.endr\n" \
".endr\n" SWEEP_PAD ".set pop\n" \
: "=&r"(sink) : "r"(p) : "memory"); \
after = COUNTERS[2].value; \
(void)sink; \
return (uint16_t)(after - before); \
}
#define INTLCK_REPS
Definition load-timings.c:271
#define INTLCK_LEN
Definition load-timings.c:272
#define SWEEP_STR(x)
Definition load-timings.c:274
#define SWEEP_PAD
Definition load-timings.c:269

◆ MAKE_PRIME

#define MAKE_PRIME (   name,
  primers,
  tail 
)
Value:
static __attribute__((always_inline)) uint32_t name(volatile void *c, volatile void *u) { \
uint16_t before, after; \
before = COUNTERS[2].value; \
__asm__ volatile(REP16(primers tail) : : "r"(c), "r"(u) : "memory"); \
after = COUNTERS[2].value; \
return (uint16_t)(after - before); \
}
#define REP16(x)
Definition load-timings.c:113
static int c
Definition syscalls.h:172

◆ MAKE_RAW

#define MAKE_RAW (   name,
  seq 
)
Value:
static __attribute__((always_inline)) uint32_t name(volatile void *p, volatile void *q) { \
register uint32_t sink; \
uint16_t before, after; \
before = COUNTERS[2].value; \
__asm__ volatile(REP32(seq) : "=&r"(sink) : "r"(p), "r"(q) : "memory"); \
after = COUNTERS[2].value; \
(void)sink; \
return (uint16_t)(after - before); \
}

◆ MAKE_SHADOW

#define MAKE_SHADOW (   name,
  op,
  s 
)
Value:
static __attribute__((always_inline)) uint32_t name(volatile void *p) { \
register uint32_t sink; \
uint16_t before, after; \
before = COUNTERS[2].value; \
__asm__ volatile(".set push\n.set noreorder\n" SWEEP_PAD \
".rept " SWEEP_STR(SHADOW_REPS) "\n" op "\n" \
".rept " #s "\nnop\n.endr\n.endr\n" \
SWEEP_PAD ".set pop\n" \
: "=&r"(sink) : "r"(p) : "memory"); \
after = COUNTERS[2].value; \
(void)sink; \
return (uint16_t)(after - before); \
}
#define SHADOW_REPS
Definition load-timings.c:270
char * s
Definition string.c:48

◆ MAKE_SPACED

#define MAKE_SPACED (   name,
  seq 
)
Value:
static __attribute__((always_inline)) uint32_t name(volatile void *p) { \
register uint32_t sink; \
uint16_t before, after; \
before = COUNTERS[2].value; \
__asm__ volatile(REP32(seq) : "=&r"(sink) : "r"(p) : "memory"); \
after = COUNTERS[2].value; \
(void)sink; \
return (uint16_t)(after - before); \
}

◆ N_BUS

#define N_BUS   64

◆ N_LOADS

#define N_LOADS   32

◆ N_READS

#define N_READS   256

◆ PCSX_TESTS

#define PCSX_TESTS   0

◆ PIN_CDROM_DELAY

#define PIN_CDROM_DELAY   0x00020843u

◆ PIN_COM_DELAY

#define PIN_COM_DELAY   0x00031125u

◆ PRIME0

#define PRIME0   ""

◆ PRIME1

#define PRIME1   PRIME0 "sw $0, 0(%0)\n"

◆ PRIME2

#define PRIME2   PRIME1 "sw $0, 4(%0)\n"

◆ PRIME3

#define PRIME3   PRIME2 "sw $0, 8(%0)\n"

◆ PRIME4

#define PRIME4   PRIME3 "sw $0, 12(%0)\n"

◆ PRIME5

#define PRIME5   PRIME4 "sw $0, 16(%0)\n"

◆ PRIME6

#define PRIME6   PRIME5 "sw $0, 20(%0)\n"

◆ REP128

#define REP128 (   x)    REP64(x) REP64(x)

◆ REP16

#define REP16 (   x)    REP4(x) REP4(x) REP4(x) REP4(x)

◆ REP256

#define REP256 (   x)    REP64(x) REP64(x) REP64(x) REP64(x)

◆ REP32

#define REP32 (   x)    REP16(x) REP16(x)

◆ REP4

#define REP4 (   x)    x x x x

◆ REP64

#define REP64 (   x)    REP16(x) REP16(x) REP16(x) REP16(x)

◆ RUN8

#define RUN8 (   lo,
  hi,
  expr 
)
Value:
do { \
lo = 0xffffu; hi = 0u; \
for (int i_ = 0; i_ < 8; i_++) { \
uint32_t d_ = (expr); \
if (d_ < lo) lo = d_; \
if (d_ > hi) hi = d_; \
} \
} while (0)
int32_t hi
Definition cpu.c:154
int32_t lo
Definition cpu.c:154

◆ SHADOW_CHECK

#define SHADOW_CHECK   8

◆ SHADOW_COUNT

#define SHADOW_COUNT   (sizeof(s_shadowPoints) / sizeof(s_shadowPoints[0]))

◆ SHADOW_FNS

#define SHADOW_FNS (   s)
Value:
MAKE_SHADOW(shadow_w_##s, "lw %0, 0(%1)", s) \
MAKE_SHADOW(shadow_b_##s, "lbu %0, 0(%1)", s) \
MAKE_SHADOW(shadow_n_##s, "nop", s)
#define MAKE_SHADOW(name, op, s)
Definition load-timings.c:278

◆ SHADOW_POINTS

#define SHADOW_POINTS (   X)
Value:
X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) \
X(14) X(16) X(20) X(24) X(32) X(40) X(48)

◆ SHADOW_REPS

#define SHADOW_REPS   16

◆ SHADOW_RUN_B

#define SHADOW_RUN_B (   s)    { BENCH(x, shadow_b_##s, M); BENCH(y, shadow_n_##s, M); a[i] = x; b[i] = y; i++; }

◆ SHADOW_RUN_W

#define SHADOW_RUN_W (   s)    { BENCH(x, shadow_w_##s, M); BENCH(y, shadow_n_##s, M); a[i] = x; b[i] = y; i++; }

◆ SW16

#define SW16
Value:
"sw $0, 0(%0)\n" "sw $0, 4(%0)\n" "sw $0, 8(%0)\n" "sw $0, 12(%0)\n" \
"sw $0, 16(%0)\n" "sw $0, 20(%0)\n" "sw $0, 24(%0)\n" "sw $0, 28(%0)\n" \
"sw $0, 32(%0)\n" "sw $0, 36(%0)\n" "sw $0, 40(%0)\n" "sw $0, 44(%0)\n" \
"sw $0, 48(%0)\n" "sw $0, 52(%0)\n" "sw $0, 56(%0)\n" "sw $0, 60(%0)\n"

◆ SWEEP_LIST

#define SWEEP_LIST (   n)    n,

◆ SWEEP_PAD

#define SWEEP_PAD   ".rept 8\nnop\n.endr\n"

◆ SWEEP_STR

#define SWEEP_STR (   x)    SWEEP_STR_(x)

◆ SWEEP_STR_

#define SWEEP_STR_ (   x)    #x

◆ SWEEP_TARGETS

#define SWEEP_TARGETS   (sizeof(s_sweepTargets) / sizeof(s_sweepTargets[0]))

Function Documentation

◆ BENCH() [1/6]

BENCH ( b_c  ,
timed_burst  ,
(volatile void *)  ADDR_RAM_C 
)

◆ BENCH() [2/6]

BENCH ( b_u  ,
timed_burst  ,
(volatile void *)  ADDR_RAM_U 
)

◆ BENCH() [3/6]

BENCH ( base  ,
timed_walk  ,
(volatile void *)  ADDR_RAM_C 
)

◆ BENCH() [4/6]

BENCH ( nb  ,
timed_nop  ,
(volatile void *)  ADDR_ISTAT 
)

◆ BENCH() [5/6]

BENCH ( w_c  ,
timed_write  ,
(volatile void *)  ADDR_RAM_C 
)

◆ BENCH() [6/6]

BENCH ( w_u  ,
timed_write  ,
(volatile void *)  ADDR_RAM_U 
)

◆ CESTER_AFTER_ALL()

CESTER_AFTER_ALL ( load_tests  ,
for(int i=0;i< 5;i++)  DELAY_REGS[i] = s_entryDelay[i]; if (s_interruptsWereEnabled) leaveCriticalSection(); 
)

◆ CESTER_AFTER_EACH()

CESTER_AFTER_EACH ( CESTER_TEST(  load_tests,
testname  ,
testindex   
)

◆ cester_assert_true()

cester_assert_true ( d0<=(uint32_t) N_READS/  8u)

◆ cester_assert_uint_eq() [1/3]

cester_assert_uint_eq ( (uint32_t) SHADOW_REPS *  2u,
check   
)

◆ cester_assert_uint_eq() [2/3]

cester_assert_uint_eq ( PIN_CDROM_DELAY  ,
CDROM_DELAY   
)

◆ cester_assert_uint_eq() [3/3]

cester_assert_uint_eq ( PIN_COM_DELAY  ,
COM_DELAY   
)

◆ CESTER_BODY()

CESTER_BODY ( static int s_interruptsWereEnabled;static uint32_t s_entryDelay;static void pinDelayRegs(void) { COM_DELAY=PIN_COM_DELAY;CDROM_DELAY=PIN_CDROM_DELAY;} static __attribute__((always_inline)) uint32_t timed_read(volatile void *p) { register uint32_t sink;uint16_t before, after;before=COUNTERS[2].value;__asm__ volatile(REP256("lw %0, 0(%1)\n") :"=&r"(sink) :"r"(p) :"memory");after=COUNTERS[2].value;(void) sink;return(uint16_t)(after - before);} static __attribute__((always_inline)) uint32_t timed_nop(volatile void *p) { register uint32_t sink;uint16_t before, after;before=COUNTERS[2].value;__asm__ volatile(REP256("nop\n") :"=&r"(sink) :"r"(p) :"memory");after=COUNTERS[2].value;(void) sink;return(uint16_t)(after - before);} static __attribute__((always_inline)) uint32_t timed_pair(volatile void *a, volatile void *b) { register uint32_t sink;uint16_t before, after;before=COUNTERS[2].value;__asm__ volatile(REP128("lw %0, 0(%1)\nlw %0, 0(%2)\n") :"=&r"(sink) :"r"(a), "r"(b) :"memory");after=COUNTERS[2].value;(void) sink;return(uint16_t)(after - before);} static __attribute__((always_inline)) uint32_t timed_write(volatile void *p) { uint16_t before, after;register volatile char *q=(volatile char *) p;before=COUNTERS[2].value;__asm__ volatile(REP256("sw $0, 0(%0)\naddiu %0, %0, 4\n") :"+r"(q) ::"memory");after=COUNTERS[2].value;return(uint16_t)(after - before);} static __attribute__((always_inline)) uint32_t timed_walk(volatile void *p) { uint16_t before, after;register volatile char *q=(volatile char *) p;before=COUNTERS[2].value;__asm__ volatile(REP256("nop\naddiu %0, %0, 4\n") :"+r"(q) ::"memory");after=COUNTERS[2].value;return(uint16_t)(after - before);} static __attribute__((always_inline)) uint32_t timed_burst(volatile void *p) { uint16_t before, after;before=COUNTERS[2].value;__asm__ volatile(REP16(SW16) ::"r"(p) :"memory");after=COUNTERS[2].value;return(uint16_t)(after - before);} typedef uint32_t(*)(volatile void *, volatile void *) PrimeFn;static void primeRow(int n, PrimeFn sync, PrimeFn base, volatile void *c, volatile void *u) { uint32_t bs=0xffffu, bb=0xffffu;for(int i=0;i< 8;i++) { uint32_t x=sync(c, u);uint32_t y=base(c, u);if(x< bs) bs=x;if(y< bb) bb=y;} ramsyscall_printf(" PRIME n=%d sync=%u base=%u delta=%d\n", n, bs, bb,(int) bs -(int) bb);} MAKE_RAW(raw_same, "sw $0, 0(%1)\nlw %0, 0(%1)\nnop\naddiu %0, %0, 1\n") MAKE_RAW(raw_other, "sw $0, 0(%1)\nlw %0, 0(%2)\nnop\naddiu %0, %0, 1\n") typedef struct { const char *name;uint32_t clr, set, flip;int nib;uint32_t val;} BusArm;static const BusArm  s_busArms[5][] = { {"base", 0, 0, 0, -1, 0}, {"b8^", 0, 0, 0x100, -1, 0}, {"b9^", 0, 0, 0x200, -1, 0}, {"b10^", 0, 0, 0x400, -1, 0}, {"b11^", 0, 0, 0x800, -1, 0}, {"b8-11", 0, 0xf00, 0, -1, 0}, {"rd0", 0xf0, 0, 0, -1, 0}, {"rd15", 0, 0xf0, 0, -1, 0}, {"wr0", 0xf, 0, 0, -1, 0}, {"wr15", 0, 0xf, 0, -1, 0}, {"com0=0", 0, 0x100, 0, 0, 0}, {"com0=5", 0, 0x100, 0, 0, 5}, {"com0=15", 0, 0x100, 0, 0, 15}, {"com1=0", 0, 0x200, 0, 1, 0}, {"com1=5", 0, 0x200, 0, 1, 5}, {"com1=15", 0, 0x200, 0, 1, 15}, {"com2=0", 0, 0x400, 0, 2, 0}, {"com2=5", 0, 0x400, 0, 2, 5}, {"com2=15", 0, 0x400, 0, 2, 15}, {"com3=0", 0, 0x800, 0, 3, 0}, {"com3=5", 0, 0x800, 0, 3, 5}, {"com3=15", 0, 0x800, 0, 3, 15}, {"base", 0, 0, 0, -1, 0}, };  typedef struct { uint32_t cd, com; uint32_t cdrom, spu; } CdArm; static const CdArm s_cdArms[] = { {0x00020843u, 0x00031125u, 646, 1349}, {0x00020843u, 0x0000132cu, 646, 1790}, {0x00020943u, 0x00031125u, 709, 1349}, {0x00020943u, 0x0000132cu, 1150, 1790}, };  #define BENCH(ret, fn, p)  static void report(const char *name, uint32_t raw, uint32_t base) { uint32_t abs_cc = (raw * 100u + N_READS / 2) / N_READS; uint32_t marg_cc = ((raw - base) * 100u + N_READS / 2) / N_READS; ramsyscall_printf("  %s raw256=%u  abs=%u.%02u  marginal=%u.%02u cyc/read\n", name, raw,                          abs_cc / 100u, abs_cc % 100u, marg_cc / 100u, marg_cc % 100u); }  static const uint8_t s_shadowPoints[] = { SHADOW_POINTS(SWEEP_LIST) }; static const uint8_t s_intlckPoints[] = { INTLCK_POINTS(SWEEP_LIST) };  static void sweepPrint(const char *sweep, const char *op, const char *target, const uint8_t *points,                           unsigned count, const uint32_t *a, const uint32_t *b, unsigned reps) { ramsyscall_printf("  %s %s %s ticks:", sweep, op, target); for (unsigned i = 0; i < count; i++) ramsyscall_printf(" %u=%u", points[i], a[i]); ramsyscall_printf("\n  %s %s %s base :", sweep, op, target); for (unsigned i = 0; i < count; i++) ramsyscall_printf(" %u=%u", points[i], b[i]); ramsyscall_printf("\n  %s %s %s cyc  :", sweep, op, target); for (unsigned i = 0; i < count; i++) { int d = (int)a[i] - (int)b[i]; unsigned m = (unsigned)(d < 0 ? -d : d); unsigned cc = (m * 100u + reps / 2u) / reps; ramsyscall_printf(" %u=%s%u.%02u", points[i], d < 0 ? "-" : "", cc / 100u, cc % 100u); } ramsyscall_printf("\n"); }  static __attribute__((noinline)) uint32_t shadowSweepW(const char *target, volatile void *M, uint32_t *a, uint32_t *b) { unsigned i = 0; sweepPrint("SHADOW", "lw ", target, s_shadowPoints, SHADOW_COUNT, a, b, SHADOW_REPS); return a[SHADOW_CHECK] - b[SHADOW_CHECK]; } static __attribute__((noinline)) uint32_t shadowSweepB(const char *target, volatile void *M, uint32_t *a, uint32_t *b) { unsigned i = 0; sweepPrint("SHADOW", "lbu", target, s_shadowPoints, SHADOW_COUNT, a, b, SHADOW_REPS); return a[SHADOW_CHECK] - b[SHADOW_CHECK]; } static __attribute__((noinline)) void intlckSweepW(const char *target, volatile void *M, uint32_t *a, uint32_t *b) { unsigned i = 0; BENCH(base, intlck_w_base, M); sweepPrint("INTLCK", "lw ", target, s_intlckPoints, INTLCK_COUNT, a, b, INTLCK_REPS); } static __attribute__((noinline)) void intlckSweepB(const char *target, volatile void *M, uint32_t *a, uint32_t *b) { unsigned i = 0; BENCH(base, intlck_b_base, M); sweepPrint("INTLCK", "lbu", target, s_intlckPoints, INTLCK_COUNT, a, b, INTLCK_REPS); }  static const uint16_t s_shNop[] = {35, 51, 67, 83, 99, 115, 131, 147, 163, 179, 195, 211, 227, 259, 291, 355, 419, 547, 675, 803}; static const uint16_t s_shMmio[] = {97, 113, 129, 130, 131, 147, 163, 179, 195, 211, 227, 243, 259, 291, 323, 387, 451, 579, 707, 835}; static const uint16_t s_shRam[] = {127, 143, 159, 160, 161, 162, 163, 179, 195, 211, 227, 243, 259, 291, 323, 387, 451, 579, 707, 835}; static const uint16_t s_shRomW[] = {445, 460, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, 477, 481, 579, 707, 835}; static const uint16_t s_shRomB[] = {157, 173, 189, 190, 191, 192, 193, 194, 195, 211, 227, 243, 259, 291, 323, 387, 451, 579, 707, 835}; static const uint16_t s_shCdrom[] = {173, 188, 204, 205, 206, 207, 208, 209, 210, 211, 227, 243, 259, 291, 323, 387, 451, 579, 707, 835}; static const uint16_t s_shSpu[] = {348, 348, 363, 363, 363, 363, 363, 363, 363, 363, 363, 363, 364, 366, 368, 387, 451, 579, 707, 835}; static const uint16_t s_ilMmio[] = {443, 443, 443, 435, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427}; static const uint16_t s_ilScratch[] = {411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411, 411}; static const uint16_t s_ilRam[] = {459, 459, 459, 451, 443, 435, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427}; static const uint16_t s_ilRomW[] = {619, 619, 619, 611, 603, 595, 587, 579, 571, 563, 555, 547, 531, 515, 483, 451, 427, 427, 427}; static const uint16_t s_ilRomB[] = {475, 475, 475, 467, 459, 451, 443, 435, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427}; static const uint16_t s_ilCdrom[] = {483, 483, 483, 475, 467, 459, 451, 443, 435, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427}; static const uint16_t s_ilSpu[] = {563, 563, 563, 555, 547, 539, 531, 523, 515, 507, 499, 491, 475, 459, 427, 427, 427, 427, 427};  typedef struct { const char *name; uint32_t addr; int byte; const uint16_t *shadow, *intlck; uint32_t intlckBase; } SweepTarget; static const SweepTarget s_sweepTargets[] = { {"I_STAT    ", ADDR_ISTAT, 0, s_shMmio, s_ilMmio, 427}, {"JOY_STAT  ", ADDR_JOYSTAT, 0, s_shMmio, s_ilMmio, 427}, {"GPUSTAT   ", ADDR_GPUSTAT, 0, s_shMmio, s_ilMmio, 427}, {"MDEC stat ", ADDR_MDECST, 0, s_shMmio, s_ilMmio, 427}, {"scratchpad", ADDR_SCRATCH, 0, s_shNop, s_ilScratch, 411}, {"RAM cached", ADDR_RAM_C, 0, s_shRam, s_ilRam, 427}, {"RAM uncach", ADDR_RAM_U, 0, s_shRam, s_ilRam, 427}, {"BIOS ROM  ", ADDR_BIOS, 0, s_shRomW, s_ilRomW, 427}, {"I_STAT    ", ADDR_ISTAT, 1, s_shMmio, s_ilMmio, 427}, {"RAM uncach", ADDR_RAM_U, 1, s_shRam, s_ilRam, 427}, {"BIOS ROM  ", ADDR_BIOS, 1, s_shRomB, s_ilRomB, 427}, {"CD-ROM    ", ADDR_CDROM, 1, s_shCdrom, s_ilCdrom, 427}, {"SPU       ", ADDR_SPU, 1, s_shSpu, s_ilSpu, 427}, }; #define SWEEP_TARGETS  static unsigned sweepMismatches(const char *sweep, const char *what, const SweepTarget *t,                                    const uint8_t *points, unsigned count, const uint32_t *got,                                    const uint16_t *row, uint32_t flat) { unsigned bad = 0; for (unsigned i = 0; i < count; i++) { uint32_t want = row ? row[i] : flat; if (got[i] == want) continue; ramsyscall_printf("  MISMATCH %s %s %s %s %u: got %u, expected %u\n", sweep, t->byte ? "lbu" : "lw ",                              t->name, what, points[i], got[i], want); bad++; } return bad; })

◆ CESTER_MAYBE_TEST() [1/5]

CESTER_MAYBE_TEST ( busDelaySweep  ,
load_tests  ,
volatile void *  rom = (volatile void *) ADDR_BIOS;volatile void *spu=(volatile void *) ADDR_SPU_ADSR;uint32_t dev2=DEV2_DELAY,
dev4  = DEV4_DELAY,
com  = COM_DELAY;uint32_t nlo,
nhi;RUN8(nlo, nhi, bus_nop(rom));ramsyscall_printf("=== bus delay sweep (N=%d, entry dev2=%08x dev4=%08x com=%08x) ===\n", N_BUS, dev2, dev4, com);ramsyscall_printf(" Format: BUSn <arm> dev=<reg> com=<reg> <access>=<min>/<max> ...\n");ramsyscall_printf(" BUSNOP nop=%u/%u\n", nlo, nhi);int  subjects = 0;uint32_t first2=0,
last2  = 0,
first4  = 0,
last4  = 0;uint32_t nocom2[3]={0, 0, 0} 
)

◆ CESTER_MAYBE_TEST() [2/5]

CESTER_MAYBE_TEST ( kseg1StoreSync  ,
load_tests  ,
volatile void *  C = (volatile void *)ADDR_RAM_C; volatile void *U = (volatile void *)ADDR_RAM_U; ramsyscall_printf("=== KSEG1 store sync vs primed queue depth (16 reps) ===\n"); ramsyscall_printf("  Format: PRIME n=<KSEG0 stores ahead> sync=<ticks> base=<ticks> delta=<ticks per 16>\n"); primeRow(0, prime0, pbase0, C, U); primeRow(1, prime1, pbase1, C, U); primeRow(2, prime2, pbase2, C, U); primeRow(3, prime3, pbase3, C, U); primeRow(4, prime4, pbase4, C, U); primeRow(5, prime5, pbase5, C, U); primeRow(6, prime6, pbase6, C, U); 
)

◆ CESTER_MAYBE_TEST() [3/5]

CESTER_MAYBE_TEST ( loadCostByGap  ,
load_tests  ,
volatile void *  A = (volatile void *)ADDR_RAM_U; ramsyscall_printf("=== load cost by inter-access gap (32 reps, one uncached RAM address) ===\n"); ramsyscall_printf("  Format: GAP d=<delay loop count> load=<ticks> nop=<ticks> delta=<ticks per 32 loads>\n"); for (uint32_t d = 1; d <= 48; d++) { uint32_t bl = 0xffffu, bn = 0xffffu; for (int i = 0; i < 8; i++) { uint32_t x = gap_load(A, d); uint32_t y = gap_nop(A, d); if (x < bl) bl = x; if (y < bn) bn = y; } ramsyscall_printf("  GAP d=%u load=%u nop=%u delta=%u\n", d, bl, bn,                          bl > bn ? bl - bn : 0u); } 
)

◆ CESTER_MAYBE_TEST() [4/5]

CESTER_MAYBE_TEST ( loadInterlockedByTarget  ,
load_tests  ,
ramsyscall_printf("=== load-interlocked sweep by target (%d loads, result read k instructions later) ===\n", INTLCK_REPS);ramsyscall_printf(" Format: <k>=<value>. ticks = result read, base = result not read, cyc = (ticks - base) / %d\n", INTLCK_REPS);uint32_t  a[INTLCK_COUNT],
b;for(unsigned t=0;t< SWEEP_TARGETS;t++) { const SweepTarget *st=&s_sweepTargets[t];volatile void *M=(volatile void *) st->addr;if(st->byte) intlckSweepB(st->name, M, a, b);else intlckSweepW(st->name, M, a, b);unsigned bad=sweepMismatches("INTLCK", "k", st, s_intlckPoints, INTLCK_COUNT, a, st->intlck, 0);unsigned badBase=sweepMismatches("INTLCK", "base k", st, s_intlckPoints, INTLCK_COUNT, b, 0, st->intlckBase);cester_assert_uint_eq(0, bad);cester_assert_uint_eq(0, badBase);}  [INTLCK_COUNT] 
)

◆ CESTER_MAYBE_TEST() [5/5]

CESTER_MAYBE_TEST ( onDieUniformity  ,
CESTER_MAYBE_TEST(  load_tests,
BENCH(istat, timed_read,(volatile void *) ADDR_ISTAT);BENCH(dma, timed_read,(volatile void *) ADDR_DMA);BENCH(rcnt0, timed_read,(volatile void *)&COUNTERS[0].value);BENCH(rcnt2, timed_read,(volatile void *)&COUNTERS[2].value);ramsyscall_printf("=== on-die uniformity ===\n");ramsyscall_printf(" I_STAT=%u DMA=%u RCNT0=%u RCNT2=%u\n", istat, dma, rcnt0, rcnt2);cester_assert_uint_eq(istat, dma);cester_assert_uint_eq(istat, rcnt0);cester_assert_uint_eq(istat, rcnt2);   
)

◆ for() [1/2]

for ( )

◆ for() [2/2]

for ( uint32_t  a = 0xbf801000u; a <= 0xbf801020u; a += 4u)

◆ pinDelayRegs()

pinDelayRegs ( )

◆ ramsyscall_printf() [1/2]

ramsyscall_printf ( " --- saturating  burst,
1 instr/  store 
)

◆ ramsyscall_printf() [2/2]

ramsyscall_printf ( )

◆ report() [1/4]

report ( "burst KSEG0:"  ,
b_c  ,
nb   
)

◆ report() [2/4]

report ( "burst KSEG1:"  ,
b_u  ,
nb   
)

◆ report() [3/4]

report ( "store KSEG0:"  ,
w_c  ,
base   
)

◆ report() [4/4]

report ( "store KSEG1:"  ,
w_u  ,
base   
)

Variable Documentation

◆ c0

volatile void* c0 = (volatile void *)ADDR_RAM_C

◆ c1

volatile void* c1 = (volatile void *)(ADDR_RAM_C + 4096u)

◆ d0

uint32_t d0 = stride0 > ref ? stride0 - ref : ref - stride0

◆ load_tests

load_tests

◆ mode

COUNTERS [2] mode = 0

◆ nl

uint32_t nl = 0xffffu

◆ oc

uint32_t oc = 0xffffu

◆ ou

uint32_t ou = 0xffffu

◆ s_interruptsWereEnabled

s_interruptsWereEnabled = enterCriticalSection()

◆ sc

uint32_t sc = 0xffffu

◆ su

uint32_t su = 0xffffu

◆ testindex

testindex

◆ testname

testname

◆ u0

volatile void* u0 = (volatile void *)ADDR_RAM_U

◆ u1

volatile void* u1 = (volatile void *)(ADDR_RAM_U + 4096u)