/*
 * strmout_wrap_sim.c — host-runnable proof for DF-4031.
 *
 * Replicates r600_cs_check_reg() VGT_STRMOUT_BUFFER_SIZE_n handling
 * (sys/dev/drm/radeon/r600_cs.c:1090-1098) and the streamout check in
 * r600_cs_track_check() (r600_cs.c:717-736), plus the <<8 offset
 * truncation family (r600_cs.c:1084, 1281, 1295, 1308).
 */
#include <stdio.h>
#include <stdint.h>

int main(void)
{
	uint32_t raw = 0x40000000u;          /* VGT_STRMOUT_BUFFER_SIZE_0 value (DWs) */
	uint32_t bo_size = 4096;

	/* r600_cs.c:1096 — u32 multiply */
	uint32_t vgt_strmout_size = raw * 4; /* wraps to 0 */

	/* r600_cs.c:721-728 — the kernel-side bound check */
	uint64_t bo_offset = 0;              /* base raw = 0 -> <<8 = 0 */
	uint64_t offset = (uint64_t)bo_offset + (uint64_t)vgt_strmout_size;
	printf("VGT_STRMOUT_BUFFER_SIZE_0 = 0x%08x DWs\n", raw);
	printf("kernel track->vgt_strmout_size = raw*4 (u32) = 0x%08x\n",
	       vgt_strmout_size);
	printf("kernel check: offset (%llu) > bo_size (%u)? %s -> CS %s\n\n",
	       (unsigned long long)offset, bo_size,
	       offset > bo_size ? "YES" : "NO",
	       offset > bo_size ? "rejected" : "ACCEPTED");
	printf("GPU executes the register verbatim: streamout bound = raw*4 = "
	       "%llu bytes = 4 GiB of write space past the 4 KiB BO.\n\n",
	       (unsigned long long)raw * 4ull);

	/* <<8 truncation family: r600_cs.c:1084,1281,1295,1308 */
	uint32_t regval = 0x01000000u;       /* CB_COLOR0_BASE / DB_DEPTH_BASE raw */
	uint64_t kernel_offset = (uint64_t)(regval << 8);  /* u32 shift -> wraps */
	uint64_t gpu_offset = (uint64_t)regval << 8;       /* 40-bit, no wrap */
	printf("<<8 truncation: reg raw = 0x%08x\n", regval);
	printf("  kernel-tracked offset = (u32)(raw<<8) = 0x%010llx\n",
	       (unsigned long long)kernel_offset);
	printf("  GPU base offset       = (u64)raw<<8    = 0x%010llx\n",
	       (unsigned long long)gpu_offset);
	printf("  -> every CB/DB/htile/streamout BO-size check validates the\n"
	       "     WRONG offset; the GPU addresses %llu bytes away from where\n"
	       "     the kernel believes.\n",
	       (unsigned long long)(gpu_offset - kernel_offset));
	return 0;
}
