Mercurial > lcfOS
annotate python/testasm.py @ 262:ed14e077124c
Added conditional branch instructions
author | Windel Bouwman |
---|---|
date | Fri, 09 Aug 2013 11:30:11 +0200 |
parents | 6ed3d3a82a63 |
children | 6f2423df0675 |
rev | line source |
---|---|
191 | 1 #!/usr/bin/python |
2 | |
199 | 3 import unittest, cProfile |
200 | 4 from ppci import CompilerError |
201 | 5 from asmnodes import AInstruction, ABinop, AUnop, ASymbol, ALabel, ANumber |
6 from asm import tokenize, Assembler | |
199 | 7 import msp430 |
218 | 8 import cortexm3 as arm |
236 | 9 import outstream |
10 from target import Label | |
191 | 11 |
198 | 12 class AssemblerLexingCase(unittest.TestCase): |
13 """ Tests the assemblers lexer """ | |
191 | 14 |
15 def testLex0(self): | |
16 """ Check if the lexer is OK """ | |
17 asmline, toks = 'mov rax, rbx ', ['ID', 'ID', ',', 'ID'] | |
198 | 18 self.assertSequenceEqual([tok.typ for tok in tokenize(asmline)], toks) |
191 | 19 |
20 def testLex1(self): | |
193 | 21 """ Test if lexer correctly maps some tokens """ |
191 | 22 asmline, toks = 'lab1: mov rax, rbx ', ['ID', ':', 'ID', 'ID', ',', 'ID'] |
198 | 23 self.assertSequenceEqual([tok.typ for tok in tokenize(asmline)], toks) |
191 | 24 |
193 | 25 def testLex1(self): |
26 """ Test if lexer correctly maps some tokens """ | |
27 asmline, toks = 'mov 3.13 0xC 13', ['ID', 'REAL', 'NUMBER', 'NUMBER'] | |
198 | 28 self.assertSequenceEqual([tok.typ for tok in tokenize(asmline)], toks) |
193 | 29 |
191 | 30 def testLex2(self): |
193 | 31 """ Test if lexer fails on a token that is invalid """ |
191 | 32 asmline = '0z4: mov rax, rbx $ ' |
200 | 33 with self.assertRaises(CompilerError): |
198 | 34 list(tokenize(asmline)) |
35 | |
36 class AssemblerParsingTestCase(unittest.TestCase): | |
37 """ | |
38 Tests the assembler parts | |
39 """ | |
199 | 40 def setUp(self): |
41 self.a = Assembler() | |
191 | 42 |
43 def testParse(self): | |
44 asmline = 'lab1: mov rax, rbx' | |
199 | 45 self.a.parse_line(asmline) |
191 | 46 |
236 | 47 def expectTree(self, asmline, stack): |
48 self.a.parse_line(asmline) | |
49 self.assertSequenceEqual(stack, self.a.stack) | |
50 | |
193 | 51 def testParse2(self): |
52 asmline = 'a: mov rax, [rbx + 2]' | |
195 | 53 output = [] |
54 output.append(ALabel('a')) | |
55 output.append(AInstruction('mov', [ASymbol('rax'), AUnop('[]', ASymbol('rbx') + ANumber(2))])) | |
236 | 56 self.expectTree(asmline, output) |
194 | 57 |
58 def testParse3(self): | |
59 # A label must be optional: | |
60 asmline = 'mov rax, 1' | |
199 | 61 output = [AInstruction('mov', [ASymbol('rax'), ANumber(1)])] |
236 | 62 self.expectTree(asmline, output) |
195 | 63 |
64 def testParse4(self): | |
65 # Test 3 operands: | |
66 asmline = 'add rax, [4*rbx + 22], rcx' | |
67 ops = [] | |
68 ops.append(ASymbol('rax')) | |
69 ops.append(AUnop('[]', ANumber(4) * ASymbol('rbx') + ANumber(22))) | |
70 ops.append(ASymbol('rcx')) | |
199 | 71 output = [AInstruction('add', ops)] |
236 | 72 self.expectTree(asmline, output) |
195 | 73 |
74 def testParse5(self): | |
75 # An instruction must be optional: | |
76 asmline = 'lab1:' | |
77 output = [] | |
78 output.append(ALabel('lab1')) | |
236 | 79 self.expectTree(asmline, output) |
196 | 80 |
81 def testParse6(self): | |
82 # A line can be empty | |
199 | 83 self.a.parse_line('') |
195 | 84 |
198 | 85 class AssemblerOtherTestCase(unittest.TestCase): |
200 | 86 def testWithoutTarget(self): |
87 a = Assembler() | |
88 with self.assertRaises(CompilerError): | |
89 a.assemble_line('') | |
201 | 90 |
200 | 91 @unittest.skip |
195 | 92 def testX86(self): |
198 | 93 testsrc = """ ; tst |
196 | 94 begin: |
198 | 95 mov rax, rbx ; 0x48, 0x89, 0xd8 |
96 xor rcx, rbx ; 0x48, 0x31, 0xd9 | |
97 inc rcx ; 0x48 0xff 0xc1 | |
196 | 98 """ |
198 | 99 a = Assembler() |
196 | 100 a.assemble(testsrc) |
101 # Compare with nasm output: | |
102 nasmbytes = [0x48, 0x89, 0xd8, 0x48, 0x31, 0xd9, 0x48, 0xff, 0xc1] | |
193 | 103 |
236 | 104 |
105 class OustreamTestCase(unittest.TestCase): | |
106 def test1(self): | |
107 o = outstream.BinOutputStream() | |
108 o.selectSection('.text') | |
109 o.emit(Label('a')) | |
110 self.assertSequenceEqual(bytes(), o.Data) | |
111 | |
112 | |
113 class AsmTestCaseBase(unittest.TestCase): | |
114 def feed(self, line): | |
115 self.a.assemble(line) | |
116 | |
117 def check(self, hexstr): | |
118 self.assertSequenceEqual(bytes.fromhex(hexstr), self.o.Data) | |
119 | |
120 | |
121 class AssemblerMSP430TestCase(AsmTestCaseBase): | |
199 | 122 def setUp(self): |
201 | 123 self.t = msp430.msp430target |
236 | 124 self.o = outstream.BinOutputStream() |
125 self.o.selectSection('.text') | |
126 self.a = Assembler(target=self.t, stream=self.o) | |
200 | 127 |
201 | 128 def testMapMovInstruction(self): |
200 | 129 i = AInstruction('mov', [ASymbol('r14'), ASymbol('r15')]) |
201 | 130 ri = self.t.mapInstruction(i) |
200 | 131 |
201 | 132 def testMapRetiInstruction(self): |
133 i = AInstruction('reti', []) | |
134 ri = self.t.mapInstruction(i) | |
135 | |
136 @unittest.skip | |
200 | 137 def testMapOperand(self): |
138 o = ASymbol('r14') | |
139 mo = self.t.mapOperand(o) | |
140 self.assertEqual(mo, msp430.r14) | |
141 | |
201 | 142 @unittest.skip |
200 | 143 def testMapOperandIndirection(self): |
144 o = AUnop('[]', ASymbol('r14')) | |
145 mo = self.t.mapOperand(o) | |
199 | 146 |
147 def testMov(self): | |
148 line1 = "mov r14, r15" | |
236 | 149 self.feed(line1) |
150 self.check('0F4E') | |
201 | 151 |
152 def testMov1337(self): | |
153 line1 = "mov 0x1337, r12" | |
236 | 154 self.feed(line1) |
155 self.check('3C403713') | |
199 | 156 |
157 def testAdd(self): | |
201 | 158 line1 = "add r15, r13" |
236 | 159 self.feed(line1) |
160 self.check('0D5F') | |
201 | 161 |
162 def testReti(self): | |
163 line1 = "reti" | |
236 | 164 self.feed(line1) |
165 self.check('0013') | |
201 | 166 |
167 def testMSPinstructionCount(self): | |
168 """ Check that there are 27 instructions """ | |
169 self.assertEqual(27, len(self.t.instructions)) | |
199 | 170 |
171 | |
236 | 172 class AssemblerARMTestCase(AsmTestCaseBase): |
202 | 173 def setUp(self): |
218 | 174 self.t = arm.armtarget |
236 | 175 self.o = outstream.BinOutputStream() |
176 self.o.selectSection('.text') | |
177 self.a = Assembler(target=self.t, stream=self.o) | |
232 | 178 |
202 | 179 def testMapOperand(self): |
180 pass | |
181 | |
182 def testMovImm8(self): | |
206 | 183 self.feed('mov r4, 100') |
184 self.check('6424') | |
202 | 185 |
186 def testYield(self): | |
206 | 187 self.feed('yield') |
188 self.check('10bf') | |
189 | |
190 def testPush(self): | |
191 self.feed('push {r2,r3,lr}') | |
192 self.check('0cb5') | |
193 | |
194 def testPop(self): | |
195 self.feed('pop {r4-r6, pc}') | |
196 self.check('70bd') | |
202 | 197 |
212 | 198 def testStr5(self): |
199 self.feed('str r4, [r1 + 0]') | |
200 self.check('0c60') | |
201 | |
202 def testLdr5(self): | |
203 self.feed('ldr r4, [r0 + 0]') | |
204 self.check('0468') | |
205 | |
219 | 206 def testLdrSpRel(self): |
207 self.feed('ldr r0, [sp + 4]') | |
208 self.check('0198') | |
209 | |
210 def testStrSpRel(self): | |
211 self.feed('str r0, [sp + 4]') | |
212 self.check('0190') | |
213 | |
234 | 214 def testLdrPcRel(self): |
237 | 215 self.feed('ldr r7, henkie') |
216 self.feed('ldr r6, henkie') | |
234 | 217 self.feed('ldr r1, henkie') |
236 | 218 self.feed('align 4') |
234 | 219 self.feed('dcd 1') |
220 self.feed('henkie: dcd 2') | |
237 | 221 self.check('024F024E 01490000 01000000 02000000') |
222 | |
223 def testBranch(self): | |
224 self.feed('start: b henkie') | |
225 self.feed('beq henkie') | |
226 self.feed('bne henkie') | |
227 self.feed('henkie: b start') | |
228 self.feed('eof: b eof') | |
229 self.check('01e000d0 ffd1fbe7 fee7') | |
230 | |
262 | 231 def testConditions(self): |
232 self.feed('blt x') | |
233 self.feed('bgt x') | |
234 self.feed('x:') | |
235 self.check('00dbffdc') | |
236 | |
237 | 237 def testBoff(self): |
238 self.feed('b henkie') | |
239 self.feed('b henkie') | |
240 self.feed('b henkie') | |
241 self.feed('b henkie') | |
242 self.feed('b henkie') | |
243 self.feed('b henkie') | |
244 self.feed('b henkie') | |
245 self.feed('henkie:') | |
246 self.feed('b henkie') | |
247 self.feed('b henkie') | |
248 self.feed('b henkie') | |
249 self.feed('b henkie') | |
250 self.check('05e004e0 03e002e0 01e000e0 ffe7fee7 fde7fce7 fbe7') | |
234 | 251 |
251
6ed3d3a82a63
Added another c3 example. First import attempt
Windel Bouwman
parents:
238
diff
changeset
|
252 def testBl(self): |
6ed3d3a82a63
Added another c3 example. First import attempt
Windel Bouwman
parents:
238
diff
changeset
|
253 self.feed('bl henkie') |
6ed3d3a82a63
Added another c3 example. First import attempt
Windel Bouwman
parents:
238
diff
changeset
|
254 self.feed('bl henkie') |
6ed3d3a82a63
Added another c3 example. First import attempt
Windel Bouwman
parents:
238
diff
changeset
|
255 self.feed('henkie:') |
6ed3d3a82a63
Added another c3 example. First import attempt
Windel Bouwman
parents:
238
diff
changeset
|
256 self.feed('bl henkie') |
6ed3d3a82a63
Added another c3 example. First import attempt
Windel Bouwman
parents:
238
diff
changeset
|
257 self.feed('bl henkie') |
6ed3d3a82a63
Added another c3 example. First import attempt
Windel Bouwman
parents:
238
diff
changeset
|
258 self.check('00f0 02f8 00f0 00f8 fff7 feff fff7 fcff') |
6ed3d3a82a63
Added another c3 example. First import attempt
Windel Bouwman
parents:
238
diff
changeset
|
259 |
218 | 260 def testCmpRegReg(self): |
261 self.feed('cmp r0, r1') | |
262 self.check('8842') | |
263 | |
232 | 264 def testLeftShit(self): |
265 self.feed('lsl r3, r5') | |
266 self.check('ab40') | |
267 | |
203 | 268 def testSequence1(self): |
206 | 269 self.feed('mov r5, 3') |
270 self.feed('add r4, r5, 0') | |
271 self.feed('loop: add r6, r4, 7') | |
272 self.feed('cmp r6, 5') | |
207 | 273 self.check('0325 2c1c e61d 052e') |
262 | 274 |
238 | 275 def testSequence2(self): |
276 self.feed('henkie:') | |
277 self.feed('push {r1,r4,r5}') | |
278 self.feed('add r5, r2, r4') | |
279 self.feed('cmp r4, r2') | |
280 self.feed('ldr r0, [sp + 4]') | |
281 self.feed('str r3, [sp + 16]') | |
282 self.feed('pop {r1, r4, r5}') | |
283 self.feed('lsl r3, r4') | |
284 self.feed('cmp r3, r5') | |
285 self.feed('beq henkie') | |
286 self.feed('bne henkie') | |
287 self.feed('b henkie') | |
288 self.check('32b41519 94420198 049332bc a340ab42 f6d0f5d1 f4e7') | |
202 | 289 |
191 | 290 if __name__ == '__main__': |
203 | 291 #cProfile.run('unittest.main()') |
191 | 292 unittest.main() |
293 |