/*
 * Probe timing-dependent bugs in Maverick FPU
 * as used in Cirrus Logic EP93xx chips.
 *
 * cc -mcpu=ep9312 -mfpu=maverick and -mfloat-abi=softfp if using EABI.
 *
 * Martin Guy <martinwguy@yahoo.it> 5 Oct 2007 - 1 Apr 2008
 */
#include <stdlib.h>
#include <stdio.h>

unsigned long i32;

main()
{
	i32 = 21; erratum2_condexec();
	printf("Erratum 2 with condexec: %s\n", i32==42 ? "ok" : "buggy");

	i32 = 21; erratum2_branch();
	printf("Erratum 2 with branch: %s\n", i32==42 ? "ok" : "buggy");

	exit(0);
}

erratum2_condexec()
{
	/* FP instruction with same target not executed due to false condition:
	 * following instruction with register as source gets old value unless
	 * three extra nops are inserted between the first and last insns
	 * There are only two here - the bug still occurs.
	 */
	asm("ldr	r3, =i32");		/* r3 = &i32 */
	asm("cmp	r3, r3");		/* set eq condition */
	asm("cfldr32	mvfx0, [r3]");		/* c0 = i32 */

	asm("cfadd32	MVFX0,mvfx0,mvfx0");	/* double it */
	asm("nop");
	asm("cfadd32ne	MVFX0,mvfx0,mvfx0");	/* not exec with same target */
	asm("nop");
	asm("cfstr32	MVFX0, [r3]");		/* stores value in i32 */
}

erratum2_branch()
{
	/* FP instruction with same target not executed due to branch taken:
	 * the following instruction with that as source register gets old value
	 * unless
	 * - one nop after branch instruction, or
	 * - one nop after foo:
	 * The errata say that it should also fail if it is in the second slot
	 * after the branch, but that appears not to be true on E2 silicon.
	 */
	asm("  ldr	r3, =i32");		/* r3 = &i32 */
	asm("  cfldr32	mvfx0, [r3]");		/* mvd0 = i32 */

	asm("  cfadd32	MVFX0,mvfx0,mvfx0");	/* double it */
	asm("  b		foo");
	asm("  cfadd32	MVFX0,mvfx0,mvfx0");	/* FP insn with same target */

	asm("foo:");
	asm("  cfstr32	MVFX0, [r3]");		/* stores value in i32 */
}
