30#define PROGRAM_AT 0x2000u
31#define RESULT_AT 0x2100u
36static void fail(
const char* what,
unsigned wanted,
unsigned got)
39 printf(
" FAIL %s: want %04x got %04x\n", what, wanted, got);
42static void regWrite(uint8_t reg, uint8_t value)
48static void unlock(
void)
62static void loadProgram(
void)
64 static const uint8_t program[] = {0x02, 0x00, 0xbe, 0xef, 0xc8, 0x00,
65 0x21, 0x00, 0x02, 0xc3, 0x03, 0x40};
67 for (
unsigned i = 0; i <
sizeof(program); ++i) tms9918->vram.bytes[PROGRAM_AT + i] = program[i];
69 tms9918->vram.bytes[RESULT_AT] = 0;
70 tms9918->vram.bytes[RESULT_AT + 1] = 0;
73static uint16_t result(
void)
75 return (uint16_t)((tms9918->vram.bytes[RESULT_AT] << 8) | tms9918->vram.bytes[RESULT_AT + 1]);
81 regWrite(0x36, (uint8_t)(PROGRAM_AT >> 8));
82 regWrite(0x37, (uint8_t)(PROGRAM_AT & 0xff));
94static void loadDmaProgram(
void)
96 static const uint8_t program[] = {0x02, 0x01, 0x80, 0x08, 0x02, 0x02,
97 0x01, 0x00, 0xc4, 0x42, 0x03, 0x40};
99 for (
unsigned i = 0; i <
sizeof(program); ++i) tms9918->vram.bytes[PROGRAM_AT + i] = program[i];
102#define NEW_WP 0x2800u
109static void loadWorkspaceProgram(
void)
111 static const uint8_t program[] = {0x02, 0xe0, 0x28, 0x00, 0x02, 0x00, 0xbe, 0xef, 0x03, 0x40};
113 for (
unsigned i = 0; i <
sizeof(program); ++i) tms9918->vram.bytes[PROGRAM_AT + i] = program[i];
115 tms9918->vram.bytes[NEW_WP] = 0;
116 tms9918->vram.bytes[NEW_WP + 1] = 0;
117 tms9918->vram.map.wrksp[0] = 0;
118 tms9918->vram.bytes[PICO9918_GPU_WORKSPACE] = 0;
125static void loadEchoProgram(
void)
127 static const uint8_t program[] = {0xc8, 0x00, 0x21, 0x00, 0x03, 0x40};
129 for (
unsigned i = 0; i <
sizeof(program); ++i) tms9918->vram.bytes[PROGRAM_AT + i] = program[i];
131 tms9918->vram.bytes[RESULT_AT] = 0;
132 tms9918->vram.bytes[RESULT_AT + 1] = 0;
133 tms9918->vram.bytes[PICO9918_GPU_WORKSPACE] = 0;
134 tms9918->vram.bytes[PICO9918_GPU_WORKSPACE + 1] = 0;
141static void loadStatusProgram(
void)
143 static const uint8_t program[] = {0x02, 0xc3, 0x03, 0x40};
145 for (
unsigned i = 0; i <
sizeof(program); ++i) tms9918->vram.bytes[PROGRAM_AT + i] = program[i];
148#define DMA_SRC 0x1000u
149#define DMA_DST 0x1800u
153static void dma(uint32_t src, uint32_t dst, uint8_t width, uint8_t height, uint8_t stride,
156 for (
unsigned i = 0; i < 0x400; ++i)
158 tms9918->vram.bytes[DMA_SRC + i] = (uint8_t)(0x40 + i);
159 tms9918->vram.bytes[DMA_DST + i] = 0;
162 tms9918->vram.bytes[0x8000] = (uint8_t)(src >> 8);
163 tms9918->vram.bytes[0x8001] = (uint8_t)src;
164 tms9918->vram.bytes[0x8002] = (uint8_t)(dst >> 8);
165 tms9918->vram.bytes[0x8003] = (uint8_t)dst;
166 tms9918->vram.bytes[0x8004] = width;
167 tms9918->vram.bytes[0x8005] = height;
168 tms9918->vram.bytes[0x8006] = stride;
169 tms9918->vram.bytes[0x8007] = params;
175static void expect(
const char* what, uint32_t at, uint8_t wanted)
177 if (tms9918->vram.bytes[at] != wanted) fail(what, wanted, tms9918->vram.bytes[at]);
180static uint16_t stepPc[8];
181static unsigned stepCalls;
182static uint16_t stepStopAt;
183static unsigned stepWrongArgs;
185static bool stepWatch(pico9918_t* vdp, uint16_t pc,
void* userdata)
187 if (vdp != tms9918 || userdata != &stepStopAt) ++stepWrongArgs;
188 if (stepCalls < 8) stepPc[stepCalls] = pc;
191 return pc != stepStopAt;
194#if PICO9918_BUILD_STEP_CALLBACK
195static uint16_t armedPc[8];
196static unsigned armedCalls;
197static uint16_t armedStopAt;
198static unsigned armedWrongArgs;
200static bool armedWatch(pico9918_t* vdp, uint16_t pc,
void* userdata)
202 if (vdp != tms9918 || userdata != &armedStopAt) ++armedWrongArgs;
203 if (armedCalls < 8) armedPc[armedCalls] = pc;
206 return pc != armedStopAt;
221 if (result() != 0) fail(
"no-rate-ran", 0, result());
232 tms9918->vram.bytes[0x4100] = 0x5a;
243 if (result() != MARKER) fail(
"host-driven", MARKER, result());
250 tms9918->vram.map.wrksp[0] = 0x12;
251 tms9918->vram.map.wrksp[1] = 0x34;
274 if (result() != MARKER) fail(
"armed-not-run", MARKER, result());
282 if (result() != 0) fail(
"r56-early-run", 0, result());
286 if (result() != MARKER) fail(
"r56-not-run", MARKER, result());
301 if (result() != 0) fail(
"locked-ran", 0, result());
311 if (result() != MARKER) fail(
"relocked", MARKER, result());
317 if (result() != 0) fail(
"cleared-rate-ran", 0, result());
322 for (
int stepped = 0; stepped < 2; ++stepped)
324 const char* leg = stepped ?
"wp-stepped" :
"wp-one-slice";
326 loadWorkspaceProgram();
340 expect(stepped ?
"wp-stepped-r0-hi" :
"wp-one-slice-r0-hi", NEW_WP, MARKER >> 8);
341 expect(stepped ?
"wp-stepped-r0-lo" :
"wp-one-slice-r0-lo", NEW_WP + 1, MARKER & 0xff);
342 expect(stepped ?
"wp-stepped-not-start" :
"wp-one-slice-not-start", PICO9918_GPU_WORKSPACE, 0);
345 fail(stepped ?
"wp-stepped-reg" :
"wp-one-slice-reg", MARKER,
357 loadWorkspaceProgram();
364 expect(
"set-reg-hi", NEW_WP + 6, 0x12);
365 expect(
"set-reg-lo", NEW_WP + 7, 0x34);
367 pico9918_debug_gpu_set_reg_value(
PICO9918_INST 0x13, 0x5678);
371 if (!pico9918_debug_gpu_set_wp(
PICO9918_INST PICO9918_GPU_WORKSPACE)) fail(
"set-wp-kept", 1, 0);
376 expect(
"set-reg-overflow-hi", PICO9918_GPU_WORKSPACE + 30, MARKER >> 8);
396 if (!pico9918_debug_gpu_set_wp(
PICO9918_INST NEW_WP)) fail(
"set-wp-armed", 1, 0);
402 if (result() != MARKER) fail(
"set-wp-ran", MARKER, result());
403 expect(
"set-wp-not-start", PICO9918_GPU_WORKSPACE, 0);
418 fail(
"step-cb-still-running", 0, 1);
419 if (stepWrongArgs) fail(
"step-cb-args", 0, stepWrongArgs);
420 if (stepCalls != 4) fail(
"step-cb-count", 4, stepCalls);
421 if (stepPc[0] != PROGRAM_AT) fail(
"step-cb-pc0", PROGRAM_AT, stepPc[0]);
422 if (stepPc[1] != PROGRAM_AT + 4) fail(
"step-cb-pc1", PROGRAM_AT + 4, stepPc[1]);
423 if (stepPc[2] != PROGRAM_AT + 8) fail(
"step-cb-pc2", PROGRAM_AT + 8, stepPc[2]);
424 if (stepPc[3] != PROGRAM_AT + 10) fail(
"step-cb-pc3", PROGRAM_AT + 10, stepPc[3]);
425 if (result() != MARKER) fail(
"step-cb-ran", MARKER, result());
430 stepStopAt = PROGRAM_AT + 4;
435 fail(
"step-cb-break-stopped", 1, 0);
436 if (stepCalls != 2) fail(
"step-cb-break-count", 2, stepCalls);
439 if (result() != 0) fail(
"step-cb-break-early", 0, result());
446 fail(
"step-cb-resume-running", 0, 1);
447 if (stepCalls != 3) fail(
"step-cb-resume-count", 3, stepCalls);
448 if (result() != MARKER) fail(
"step-cb-resume-ran", MARKER, result());
456 if (stepCalls) fail(
"step-cb-persisted", 0, stepCalls);
457 if (result() != MARKER) fail(
"step-cb-plain-ran", MARKER, result());
462 if (stepCalls) fail(
"step-cb-null-called", 0, stepCalls);
463 if (result() != MARKER) fail(
"step-cb-null-ran", MARKER, result());
465#if PICO9918_BUILD_STEP_CALLBACK
469 armedStopAt = 0xffff;
471 void* armedData = NULL;
472 pico9918_debug_set_step_callback(
PICO9918_INST armedWatch, &armedStopAt);
473 if (pico9918_debug_step_callback(
PICO9918_INST &armedData) != armedWatch)
474 fail(
"armed-cb-readback", 1, 0);
475 if (armedData != &armedStopAt) fail(
"armed-cb-readback-data", 1, 0);
480 if (armedWrongArgs) fail(
"armed-cb-args", 0, armedWrongArgs);
481 if (armedCalls != 4) fail(
"armed-cb-count", 4, armedCalls);
482 if (result() != MARKER) fail(
"armed-cb-ran", MARKER, result());
487 armedStopAt = PROGRAM_AT + 4;
491 if (armedCalls != 2) fail(
"armed-cb-break-count", 2, armedCalls);
494 if (result() != 0) fail(
"armed-cb-break-early", 0, result());
501 if (armedCalls != 1) fail(
"armed-cb-rebreak-count", 1, armedCalls);
502 if (armedPc[0] != PROGRAM_AT + 4) fail(
"armed-cb-rebreak-pc", PROGRAM_AT + 4, armedPc[0]);
503 if (result() != 0) fail(
"armed-cb-rebreak-early", 0, result());
507 armedStopAt = 0xffff;
509 if (armedCalls != 3) fail(
"armed-cb-rebreak-resume-count", 3, armedCalls);
510 if (result() != MARKER) fail(
"armed-cb-rebreak-resume-ran", MARKER, result());
515 armedStopAt = 0xffff;
519 if (armedCalls != 4) fail(
"armed-cb-clocked-count", 4, armedCalls);
520 if (result() != MARKER) fail(
"armed-cb-clocked-ran", MARKER, result());
525 if (pico9918_debug_step_callback(
PICO9918_INST NULL) != armedWatch) fail(
"armed-cb-reset", 1, 0);
535 fail(
"armed-cb-override-running", 0, 1);
536 if (stepCalls != 4) fail(
"armed-cb-override-count", 4, stepCalls);
537 if (armedCalls) fail(
"armed-cb-override-leaked", 0, armedCalls);
540 if (pico9918_debug_step_callback(
PICO9918_INST NULL)) fail(
"armed-cb-disarm", 0, 1);
546 if (armedCalls) fail(
"armed-cb-disarmed-called", 0, armedCalls);
547 if (result() != MARKER) fail(
"armed-cb-disarmed-ran", MARKER, result());
556 dma(DMA_SRC, DMA_DST, 4, 3, 4, 0x00);
557 expect(
"dma-run-first", DMA_DST, 0x40);
558 expect(
"dma-run-last", DMA_DST + 11, 0x4b);
559 expect(
"dma-run-past", DMA_DST + 12, 0x00);
561 dma(DMA_SRC, DMA_DST, 4, 3, 16, 0x00);
562 expect(
"dma-stride-row0", DMA_DST, 0x40);
563 expect(
"dma-stride-gap", DMA_DST + 4, 0x00);
564 expect(
"dma-stride-row1", DMA_DST + 16, 0x50);
565 expect(
"dma-stride-row2", DMA_DST + 32, 0x60);
568 dma(DMA_SRC, DMA_DST, 4, 3, 0, 0x00);
569 expect(
"dma-stride0-row0", DMA_DST, 0x40);
570 expect(
"dma-stride0-end", DMA_DST + 4, 0x00);
571 expect(
"dma-stride0-not256", DMA_DST + 256, 0x00);
575 dma(0x1100, 0x1900, 8, 2, 200, 0x00);
576 expect(
"dma-back-row0", 0x1900, 0x40);
577 expect(
"dma-back-row1", 0x18c8, 0x08);
578 expect(
"dma-back-not-forward", 0x19c8, 0x00);
581 dma(0x1100, 0x1900, 8, 2, 134, 0x00);
582 expect(
"dma-edge-fwd-row1", 0x1986, 0xc6);
583 expect(
"dma-edge-fwd-gap", 0x1985, 0x00);
585 dma(0x1100, 0x1900, 8, 2, 135, 0x00);
586 expect(
"dma-edge-back-row1", 0x1887, 0xc7);
587 expect(
"dma-edge-back-not-forward", 0x1987, 0x00);
590 dma(DMA_SRC, DMA_DST, 0, 1, 0, 0x00);
591 expect(
"dma-width256-first", DMA_DST, 0x40);
592 expect(
"dma-width256-last", DMA_DST + 255, 0x3f);
593 expect(
"dma-width256-past", DMA_DST + 256, 0x00);
596 dma(DMA_SRC, DMA_DST, 1, 0, 1, 0x00);
597 expect(
"dma-height256-first", DMA_DST, 0x40);
598 expect(
"dma-height256-last", DMA_DST + 255, 0x3f);
599 expect(
"dma-height256-past", DMA_DST + 256, 0x00);
602 dma(DMA_SRC, DMA_DST, 255, 1, 255, 0x00);
603 expect(
"dma-width255-first", DMA_DST, 0x40);
604 expect(
"dma-width255-last", DMA_DST + 254, 0x3e);
605 expect(
"dma-width255-past", DMA_DST + 255, 0x00);
607 dma(DMA_SRC, DMA_DST, 1, 255, 1, 0x00);
608 expect(
"dma-height255-first", DMA_DST, 0x40);
609 expect(
"dma-height255-last", DMA_DST + 254, 0x3e);
610 expect(
"dma-height255-past", DMA_DST + 255, 0x00);
613 dma(DMA_SRC, DMA_DST, 8, 2, 4, 0x00);
614 expect(
"dma-narrow-kept", DMA_DST + 3, 0x43);
615 expect(
"dma-narrow-rewritten", DMA_DST + 4, 0x44);
616 expect(
"dma-narrow-last", DMA_DST + 11, 0x4b);
617 expect(
"dma-narrow-past", DMA_DST + 12, 0x00);
620 dma(DMA_SRC, DMA_DST, 4, 3, 4, 0xfc);
621 expect(
"dma-params-spare-first", DMA_DST, 0x40);
622 expect(
"dma-params-spare-last", DMA_DST + 11, 0x4b);
623 expect(
"dma-params-spare-past", DMA_DST + 12, 0x00);
626 dma(0x1100, 0x1900, 4, 2, 4, 0x03);
627 expect(
"dma-fill-dec-first", 0x1900, 0x40);
628 expect(
"dma-fill-dec-row0", 0x18fd, 0x40);
629 expect(
"dma-fill-dec-row1", 0x18f9, 0x40);
630 expect(
"dma-fill-dec-past", 0x18f8, 0x00);
635 dma(DMA_SRC, DMA_SRC + 2, 8, 1, 8, 0x00);
636 expect(
"dma-overlap-0", DMA_SRC + 2, 0x40);
637 expect(
"dma-overlap-2", DMA_SRC + 4, 0x40);
638 expect(
"dma-overlap-7", DMA_SRC + 9, 0x41);
641 dma(DMA_SRC, 0xfffe, 4, 1, 4, 0x00);
642 expect(
"dma-dst-wrap-before", 0xffff, 0x41);
643 expect(
"dma-dst-wrap-after", 0x0000, 0x42);
644 expect(
"dma-dst-wrap-last", 0x0001, 0x43);
646 tms9918->vram.bytes[0xfffe] = 0x11;
647 tms9918->vram.bytes[0xffff] = 0x22;
648 tms9918->vram.bytes[0x0000] = 0x33;
649 tms9918->vram.bytes[0x0001] = 0x44;
650 dma(0xfffe, DMA_DST, 4, 1, 4, 0x00);
651 expect(
"dma-src-wrap-before", DMA_DST + 1, 0x22);
652 expect(
"dma-src-wrap-after", DMA_DST + 2, 0x33);
653 expect(
"dma-src-wrap-last", DMA_DST + 3, 0x44);
656 dma(DMA_SRC, DMA_DST, 4, 3, 16, 0x01);
657 expect(
"dma-fill-row0", DMA_DST + 3, 0x40);
658 expect(
"dma-fill-gap", DMA_DST + 4, 0x00);
659 expect(
"dma-fill-row2", DMA_DST + 32, 0x40);
662 dma(0x1100, 0x1900, 4, 2, 4, 0x02);
663 expect(
"dma-dec-row0-first", 0x1900, 0x40);
664 expect(
"dma-dec-row0-last", 0x18fd, 0x3d);
665 expect(
"dma-dec-row1-first", 0x18fc, 0x3c);
666 expect(
"dma-dec-row1-last", 0x18f9, 0x39);
667 expect(
"dma-dec-past", 0x1901, 0x00);
670 dma(0x1100, 0x1900, 4, 3, 0, 0x02);
671 expect(
"dma-dec-stride0-first", 0x1900, 0x40);
672 expect(
"dma-dec-stride0-last", 0x18fd, 0x3d);
673 expect(
"dma-dec-stride0-end", 0x18fc, 0x00);
674 expect(
"dma-dec-stride0-past", 0x1901, 0x00);
680 dma(0x1100, 0x1900, 8, 2, 200, 0x02);
681 expect(
"dma-dec-fwd-row0-first", 0x1900, 0x40);
682 expect(
"dma-dec-fwd-row0-last", 0x18f9, 0x39);
683 expect(
"dma-dec-fwd-row1-first", 0x1938, 0x78);
684 expect(
"dma-dec-fwd-row1-last", 0x1931, 0x71);
685 expect(
"dma-dec-fwd-gap", 0x1901, 0x00);
686 expect(
"dma-dec-fwd-not-back", 0x18c8, 0x00);
690 dma(0x1100, 0x1900, 8, 2, 135, 0x02);
691 expect(
"dma-dec-edge-back-row1", 0x1879, 0xb9);
692 expect(
"dma-dec-edge-back-not-forward", 0x1979, 0x00);
694 dma(0x1100, 0x1900, 8, 2, 136, 0x02);
695 expect(
"dma-dec-edge-fwd-row1", 0x1978, 0xb8);
696 expect(
"dma-dec-edge-fwd-not-back", 0x1878, 0x00);
698 printf(
"%s: library-paced GPU, %d failure(s)\n", failures ?
"FAIL" :
"PASS", failures);
699 return failures != 0;
uint16_t pico9918_gpu_status(pico9918_t *tms9918)
see the header.
uint16_t pico9918_gpu_pc(pico9918_t *tms9918)
see the header.
bool pico9918_debug_gpu_step_n(pico9918_t *tms9918, uint32_t instructions, pico9918_gpu_step_fn cb, void *userdata)
see pico9918_debug.h.
void pico9918_gpu_init(pico9918_t *tms9918)
Initialize the TMS9900 GPU.
uint32_t pico9918_gpu_mem_size(void)
see the header.
uint16_t pico9918_gpu_wp(pico9918_t *tms9918)
see the header.
uint8_t pico9918_gpu_mem_value(pico9918_t *tms9918, uint32_t addr)
see the header.
uint16_t pico9918_gpu_reg_value(pico9918_t *tms9918, uint8_t reg)
see the header.
bool pico9918_gpu_step_n(pico9918_t *tms9918, uint32_t instructions)
The same pass, capped at instructions, returning true while the program still has work left.
void pico9918_gpu_set_clock(pico9918_t *tms9918, uint32_t instructionsPerSecond)
Hand GPU execution to the library, at this many instructions a second.
pico9918-core - GPU Interface
#define PICO9918_GPU_ST_P
ST5, odd parity.
#define PICO9918_GPU_IPS_PRO
PICO9918 PRO, RP2350 at 352MHz.
#define PICO9918_GPU_ST_LGT
ST0, logical greater than.
#define PICO9918_GPU_ST_OV
ST4, overflow.
#define PICO9918_GPU_ST_EQ
ST2, equal.
#define PICO9918_GPU_ST_C
ST3, carry.
uint8_t pico9918_vram_value(pico9918_t *tms9918, uint16_t addr)
return a value from vram
void pico9918_reset(pico9918_t *tms9918)
reset the new TMS9918
#define PICO9918_INST_ONLY
pass the instance as the only argument
#define PICO9918_INST
pass the instance ahead of other arguments
pico9918-core - debugger access
pico9918-core - the private instance layout
PICO9918_INTERNAL void pico9918_write_reg_value_impl(pico9918_t *tms9918, uint8_t regSelect, uint8_t value)
set a register from the second byte of a host register write