|
Nugget
Bare-metal libraries and examples for the original PlayStation
|
#include "common/hardware/counters.h"#include "common/syscalls/syscalls.h"#include "installstdio.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 | 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 |
| #define ADDR_CDROM 0xbf801800u /* CD-ROM controller index/status (8-bit bus) */ |
| #define ADDR_DMA 0xbf8010a0u /* on-die MMIO: DMA channel 2 MADR */ |
| #define ADDR_GPUSTAT 0xbf801814u /* GPU status - the GPU is a separate chip */ |
| #define ADDR_ISTAT 0xbf801070u /* on-die MMIO: interrupt controller I_STAT */ |
| #define ADDR_JOYSTAT 0xbf801044u /* on-die MMIO: controller port JOY_STAT */ |
| #define ADDR_MDECST 0xbf801824u /* MDEC status */ |
| #define ADDR_RAM_C 0x80100000u /* main RAM, cached mirror (KSEG0) */ |
| #define ADDR_SCRATCH 0x1f800000u /* scratchpad SRAM (fast on-chip, no bus) */ |
| #define ADDR_SPU 0xbf801d80u /* SPU main volume left (16-bit bus) */ |
| #define ADDR_SPU_ADSR 0xbf801c08u /* voice 0 ADSR: unkeyed, harmless to write */ |
| #define BENCH | ( | ret, | |
| fn, | |||
| p | |||
| ) |
| #define BIU_CONFIG_ADDR 0xfffe0130u |
| #define BIU_EXPECTED 0x0001e988u |
| #define CDROM_DELAY (*(volatile uint32_t *)0xbf801018) |
| #define CESTER_MAYBE_TEST CESTER_TEST |
| #define CESTER_NO_SIGNAL |
| #define CESTER_NO_TIME |
| #define COM_DELAY (*(volatile uint32_t *)0xbf801020) |
| #define DELAY_REGS ((volatile uint32_t *)0xbf801010) |
| #define DEV2_DELAY (*(volatile uint32_t *)0xbf801010) |
| #define DEV4_DELAY (*(volatile uint32_t *)0xbf801014) |
| #define EXIT_FAILURE 1 |
| #define EXIT_SUCCESS 0 |
| #define INTLCK_COUNT (sizeof(s_intlckPoints) / sizeof(s_intlckPoints[0])) |
| #define INTLCK_FNS | ( | k | ) |
| #define INTLCK_LEN 48 |
| #define INTLCK_POINTS | ( | X | ) |
| #define INTLCK_REPS 8 |
| #define MAKE_BUS | ( | name, | |
| insn | |||
| ) |
| #define MAKE_GAP | ( | name, | |
| op | |||
| ) |
| #define MAKE_INTLCK | ( | name, | |
| op, | |||
| use, | |||
| k | |||
| ) |
| #define MAKE_PRIME | ( | name, | |
| primers, | |||
| tail | |||
| ) |
| #define MAKE_RAW | ( | name, | |
| seq | |||
| ) |
| #define MAKE_SHADOW | ( | name, | |
| op, | |||
| s | |||
| ) |
| #define MAKE_SPACED | ( | name, | |
| seq | |||
| ) |
| #define N_BUS 64 |
| #define N_LOADS 32 |
| #define N_READS 256 |
| #define PCSX_TESTS 0 |
| #define PIN_CDROM_DELAY 0x00020843u |
| #define PIN_COM_DELAY 0x00031125u |
| #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 REP4 | ( | x | ) | x x x x |
| #define SHADOW_CHECK 8 |
| #define SHADOW_COUNT (sizeof(s_shadowPoints) / sizeof(s_shadowPoints[0])) |
| #define SHADOW_FNS | ( | s | ) |
| #define SHADOW_POINTS | ( | X | ) |
| #define SHADOW_REPS 16 |
| #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 SHADOW_RUN_W | ( | s | ) | { BENCH(x, shadow_w_##s, M); BENCH(y, shadow_n_##s, M); a[i] = x; b[i] = y; i++; } |
| #define SW16 |
| #define SWEEP_LIST | ( | n | ) | n, |
| #define SWEEP_PAD ".rept 8\nnop\n.endr\n" |
| #define SWEEP_STR | ( | x | ) | SWEEP_STR_(x) |
| #define SWEEP_STR_ | ( | x | ) | #x |
| #define SWEEP_TARGETS (sizeof(s_sweepTargets) / sizeof(s_sweepTargets[0])) |
| BENCH | ( | b_c | , |
| timed_burst | , | ||
| (volatile void *) | ADDR_RAM_C | ||
| ) |
| BENCH | ( | b_u | , |
| timed_burst | , | ||
| (volatile void *) | ADDR_RAM_U | ||
| ) |
| BENCH | ( | base | , |
| timed_walk | , | ||
| (volatile void *) | ADDR_RAM_C | ||
| ) |
| BENCH | ( | nb | , |
| timed_nop | , | ||
| (volatile void *) | ADDR_ISTAT | ||
| ) |
| BENCH | ( | w_c | , |
| timed_write | , | ||
| (volatile void *) | ADDR_RAM_C | ||
| ) |
| BENCH | ( | w_u | , |
| timed_write | , | ||
| (volatile void *) | ADDR_RAM_U | ||
| ) |
| 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_TEST( | load_tests, |
| testname | , | ||
| testindex | |||
| ) |
| cester_assert_uint_eq | ( | (uint32_t) SHADOW_REPS * | 2u, |
| check | |||
| ) |
| cester_assert_uint_eq | ( | PIN_CDROM_DELAY | , |
| CDROM_DELAY | |||
| ) |
| cester_assert_uint_eq | ( | PIN_COM_DELAY | , |
| COM_DELAY | |||
| ) |
| 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 | ( | 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 | ( | 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 | ( | 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 | ( | 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 | ( | 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 | ( | ) |
| for | ( | uint32_t | a = 0xbf801000u; a <= 0xbf801020u; a += 4u | ) |
| pinDelayRegs | ( | ) |
| ramsyscall_printf | ( | " --- saturating | burst, |
| 1 instr/ | store | ||
| ) |
| ramsyscall_printf | ( | ) |
| report | ( | "burst KSEG0:" | , |
| b_c | , | ||
| nb | |||
| ) |
| report | ( | "burst KSEG1:" | , |
| b_u | , | ||
| nb | |||
| ) |
| report | ( | "store KSEG0:" | , |
| w_c | , | ||
| base | |||
| ) |
| report | ( | "store KSEG1:" | , |
| w_u | , | ||
| base | |||
| ) |
| volatile void* c0 = (volatile void *)ADDR_RAM_C |
| volatile void* c1 = (volatile void *)(ADDR_RAM_C + 4096u) |
| uint32_t d0 = stride0 > ref ? stride0 - ref : ref - stride0 |
| load_tests |
| COUNTERS [2] mode = 0 |
| uint32_t nl = 0xffffu |
| uint32_t oc = 0xffffu |
| uint32_t ou = 0xffffu |
| s_interruptsWereEnabled = enterCriticalSection() |
| uint32_t sc = 0xffffu |
| uint32_t su = 0xffffu |
| testindex |
| testname |
| volatile void* u0 = (volatile void *)ADDR_RAM_U |
| volatile void* u1 = (volatile void *)(ADDR_RAM_U + 4096u) |