/* This is a bcm43xx microcode assembly example.
 *
 * Registers:
 *	GPRs:			r0 - r63	(General Purpose Register)
 *	Offset Registers:	off0 - off5
 *	SPRs:			spr000		(Special Purpose Register)
 *
 * SPRs map to the driver-side IHR registers.
 * An SPR offset is converted to an IHR offset by the following
 * calculation:  IHR = (SPR + 0x400) * 2
 *
 * To access memory, two methods can be used. Examples follow.
 * Direct linear:
 *	mov r0,[0xCA]
 * Indirect through Offset Register (pointer):
 *	mov r0,[0xCA,off0]
 */


/* The target architecture. Supported versions are 5 and 15 */
%arch	5

/* Program entry point */
%start	testlabel

#define	PSM_BRC		spr848

#define ECOND_MAC_ON	(0x20 | 4)

%assert ((((1))) == ((((2 - 1) & 0xFF))))
%assert ((1 == 2) || (1 == (0xFF & 1)))
%assert (1 != (~1))
%assert ((1 == (2 - 1)) && (2 == 2))

.text

	/* Inline assertion inside of a complex immediate.
	 * The %assert() expression will always return zero. */
	mov	(1 + (%assert(1 == ((1 + 2) - 2)))), r0

label:
	/* MUL instruction */
	mul	r0,r1,r2	/* mul, r2 := msb, spr6d := lsb */

	/* ADD instructions */
	add	r0,r1,r2	/* add */
	add.	r0,r1,r2	/* add, set carry */
	addc	r0,r1,r2	/* add with carry */
	addc.	r0,r1,r2	/* add with carry, set carry */

testlabel:
	/* SUB instructions */
	sub	r0,r1,r2	/* sub */
	sub.	r0,r1,r2	/* sub, set carry */
	subc	r0,r1,r2	/* sub with carry */
	subc.	r0,r1,r2	/* sub with carry, set carry */

	sra	r0,r1,r2	/* arithmetic rightshift */

	/* Logical instructions */
	or	r0,r1,r2	/* bitwise OR */
	and	r0,r1,r2	/* bitwise AND */
	xor	r0,r1,r2	/* bitwise XOR */
	sr	r0,r1,r2	/* rightshift */
	sl	r0,r1,r2	/* leftshift */

	srx	7,8,r0,r1,r2	/* eXtended right shift (two input regs) */

	rl	r0,r1,r2	/* rotate left */
	rr	r0,r1,r2	/* rotate right */
	nand	r0,r1,r2	/* clear bits (notmask + and) */

	orx	7,8,r0,r1,r2	/* eXtended OR */

	/* Copy instruction. This is a virtual instruction
	 * translated to more lowlevel stuff like OR. */
	mov	r0,r2		/* copy data */

	/* Jumps */
	jmp	label		/* unconditional jump */
	jand	r0,r1,label	/* jump if binary AND */
	jnand	r0,r1,label	/* jump if not binary AND */
	js	r0,r1,label	/* jump if all bits set */
	jns	r0,r1,label	/* jump if not all bits set */
	je	r0,r1,label	/* jump if equal */
	jne	r0,r1,label	/* jump if not equal */
	jls	r0,r1,label	/* jump if less (signed) */
	jges	r0,r1,label	/* jump if greater or equal (signed) */
	jgs	r0,r1,label	/* jump if greater (signed) */
	jles	r0,r1,label	/* jump if less or equal (signed) */
	jl	r0,r1,label	/* jump if less */
	jge	r0,r1,label	/* jump if greater or equal */
	jg	r0,r1,label	/* jump if greater */
	jle	r0,r1,label	/* jump if less or equal */
	jdn	r0,r1,label	/* jump if difference is negative */
	jdpz	r0,r1,label	/* jump if difference is non negative */
	jdp	r0,r1,label	/* jump if difference is positive */
	jdnz	r0,r1,label	/* jump if difference is non positive */

	jzx	7,8,r0,r1,label	/* Jump if zero after shift and mask */
	jnzx	7,8,r0,r1,label	/* Jump if nonzero after shift and mask */

	/* jump on external conditions */
	jext	ECOND_MAC_ON,label  /* jump if external condition is TRUE */
	jnext	ECOND_MAC_ON,label  /* jump if external condition is FALSE */

	/* Subroutines */
	call	lr0,label	/* store PC in lr0, call func at label */
	ret	lr0,lr1		/* store PC in lr0, return to lr1
				 * Both link registers can be the same
				 * and don't interfere. */

	/* TKIP sbox lookup */
	tkiph	r0,r2		/* Lookup high */
	tkiphs	r0,r2		/* Lookup high, byteswap */
	tkipl	r0,r2		/* Lookup low */
	tkipls	r0,r2		/* Lookup low, byteswap */

	nap			/* sleep until event */

	/* raw instruction */
	@160	r0,r1,r2	/* equivalent to  or r0,r1,r2 */
	@1C0	@C11, @C22, @BC3


	/* Support for directional jumps.
	 * Directional jumps can be used to conveniently jump inside of
	 * functions without using function specific label prefixes. Note
	 * that this does not establish a sub-namespace, though. "loop"
	 * and "out" are still in the global namespace and can't be used
	 * anymore for absolute jumps (Assembler will warn about duplication).
	 */
function_a:
	jl r0, r1, out+
 loop:
	nap
	jmp loop-
 out:
	mov r0, r0
	ret lr0, lr1

function_b:
	jl r0, r1, out+
 loop:
	nap
	jmp loop-
 out:
	mov r0, r0
	ret lr0, lr1


/* The assembler has support for fancy assemble-time
 * immediate constant expansion. This is called "complex immediates".
 * Complex immediates are _always_ clamped by parentheses. There is no
 * operator precedence. You must use parentheses to tell precedence.
 */
	mov	(2 + 3),r0
	mov	(6 - 2),r0
	mov	(2 * 3),r0
	mov	(10 / 5),r0
	mov	(1 | 2),r0
	mov	(3 & 2),r0
	mov	(3 ^ 2),r0
	mov	(~1),r0
	mov	(2 << 3),r0
	mov	(8 >> 2),r0
	mov	(1 << (0x3 + 2)),r0
	mov	(1 + (2 + (3 + 4))),r0
	mov	(4 >> (((((~5 | 0x21)))) | (~((10) & 2)))),r0


/* Some regression testing for the assembler follows */
	mov	2,off0			/* test memory stuff */
	xor	0x124,r1,[0x0,off0]	/* test memory stuff */
	xor	0x124,r0,[0x0]		/* test memory stuff */
	mov	-34,r0			/* negative dec numbers are supported */
	or	r0,r1,@BC2		/* We also support single raw operands */
	mov	0xEEEE,r0		/* MOV supports up to 16bit */
	jand	0x3800,r0,label		/* This is emulated by jnzx */
	jnand	0x3800,r0,label 	/* This is emulated by jzx */
	or	spr06c,0,spr06c		/* Can have one spr input and one spr output */
	or	[0],0,[0]		/* Can have one mem input and one mem output */
	mov	testlabel, r0		/* Can use label as immediate value */
	mov r0,r1;mov r2, r3		/* ; does split instructions */
	mov	[(1+1)],[(2+2),off0]	/* Can use complex immediates as memory offsets */
	orx	(0 + 1), (1 * 2), 0, 0, r0 /* Allow complex immediates as M or S */


/* The .initvals section generates an "Initial Values" file
 * with the name "foobar" in this example, which is uploaded
 * by the kernel driver on load. This is useful for writing ucode
 * specific values to the chip without bloating the small ucode
 * memory space with this initialization stuff.
 * Values are written in order they appear here.
 */
.initvals(foobar)
	mmio16	0x1234, 0xABC			/* Write 0x1234 to MMIO register 0xABC */
	mmio32	0x12345678, 0xABC		/* Write 0x12345678 to MMIO register 0xABC */
	phy	0x1234, 0xABC			/* Write 0x1234 to PHY register 0xABC */
	radio	0x1234, 0xABC			/* Write 0x1234 to RADIO register 0xABC */
	shm16	0x1234, 0x0001, 0x0002		/* Write 0x1234 to SHM routing 0x0001, register 0x0002 */
	shm32	0x12345678, 0x0001, 0x0002	/* Write 0x12345678 to SHM routing 0x0001, register 0x0002 */
	tram	0x12345678, 0x1234		/* Write 0x12345678 to Template Ram offset 0x1234 */


// vim: syntax=b43 ts=8
