1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
/* 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
|