/* 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