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