fwcutter/make: Avoid _DEFAULT_SOURCE warning
[b43-tools.git] / debug / libb43.py
1 """
2 #  b43 debugging library
3 #
4 #  Copyright (C) 2008-2010 Michael Buesch <m@bues.ch>
5 #
6 #  This program is free software: you can redistribute it and/or modify
7 #  it under the terms of the GNU General Public License version 3
8 #  as published by the Free Software Foundation.
9 #
10 #  This program is distributed in the hope that it will be useful,
11 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #  GNU General Public License for more details.
14 #
15 #  You should have received a copy of the GNU General Public License
16 #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 """
18
19 import sys
20 import os
21 import re
22 import hashlib
23 from tempfile import *
24
25
26 # SHM routing values
27 B43_SHM_UCODE           = 0
28 B43_SHM_SHARED          = 1
29 B43_SHM_REGS            = 2
30 B43_SHM_IHR             = 3
31 B43_SHM_RCMTA           = 4
32
33
34 class B43Exception(Exception):
35         pass
36
37
38 B43_MMIO_MACCTL         = 0x120
39 B43_MMIO_PSMDEBUG       = 0x154
40
41 B43_MACCTL_PSM_MACEN    = 0x00000001
42 B43_MACCTL_PSM_RUN      = 0x00000002
43 B43_MACCTL_PSM_JMP0     = 0x00000004
44 B43_MACCTL_PSM_DEBUG    = 0x00002000
45
46
47 class B43PsmDebug:
48         """Parse the contents of the PSM-debug register"""
49         def __init__(self, reg_content):
50                 self.raw = reg_content
51                 return
52
53         def getRaw(self):
54                 """Get the raw PSM-debug register value"""
55                 return self.raw
56
57         def getPc(self):
58                 """Get the microcode program counter"""
59                 return self.raw & 0xFFF
60
61
62 class B43:
63         """Hardware access layer. This accesses the hardware through the debugfs interface."""
64
65         def __init__(self, phy=None):
66                 debugfs_path = self.__debugfs_find()
67
68                 # Construct the debugfs b43 path to the device
69                 b43_path = debugfs_path + "/b43/"
70                 if phy:
71                         b43_path += phy
72                 else:
73                         # Get the PHY.
74                         try:
75                                 phys = os.listdir(b43_path)
76                         except OSError:
77                                 print "Could not find B43's debugfs directory: %s" % b43_path
78                                 raise B43Exception
79                         if not phys:
80                                 print "Could not find any b43 device"
81                                 raise B43Exception
82                         if len(phys) != 1:
83                                 print "Found multiple b43 devices."
84                                 print "You must call this tool with a phyX parameter to specify a device"
85                                 raise B43Exception
86                         phy = phys[0]
87                         b43_path += phy;
88
89                 # Open the debugfs files
90                 try:
91                         self.f_mmio16read = file(b43_path + "/mmio16read", "r+")
92                         self.f_mmio16write = file(b43_path + "/mmio16write", "w")
93                         self.f_mmio32read = file(b43_path + "/mmio32read", "r+")
94                         self.f_mmio32write = file(b43_path + "/mmio32write", "w")
95                         self.f_shm16read = file(b43_path + "/shm16read", "r+")
96                         self.f_shm16write = file(b43_path + "/shm16write", "w")
97                         self.f_shm32read = file(b43_path + "/shm32read", "r+")
98                         self.f_shm32write = file(b43_path + "/shm32write", "w")
99                 except IOError, e:
100                         print "Could not open debugfs file %s: %s" % (e.filename, e.strerror)
101                         raise B43Exception
102
103                 self.b43_path = b43_path
104                 return
105
106         # Get the debugfs mountpoint.
107         def __debugfs_find(self):
108                 mtab = file("/etc/mtab").read().splitlines()
109                 regexp = re.compile(r"^[\w\-_]+\s+([\w/\-_]+)\s+debugfs")
110                 path = None
111                 for line in mtab:
112                         m = regexp.match(line)
113                         if m:
114                                 path = m.group(1)
115                                 break
116                 if not path:
117                         print "Could not find debugfs in /etc/mtab"
118                         raise B43Exception
119                 return path
120
121         def read16(self, reg):
122                 """Do a 16bit MMIO read"""
123                 try:
124                         self.f_mmio16read.seek(0)
125                         self.f_mmio16read.write("0x%X" % reg)
126                         self.f_mmio16read.flush()
127                         self.f_mmio16read.seek(0)
128                         val = self.f_mmio16read.read()
129                 except IOError, e:
130                         print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
131                         raise B43Exception
132                 return int(val, 16)
133
134         def read32(self, reg):
135                 """Do a 32bit MMIO read"""
136                 try:
137                         self.f_mmio32read.seek(0)
138                         self.f_mmio32read.write("0x%X" % reg)
139                         self.f_mmio32read.flush()
140                         self.f_mmio32read.seek(0)
141                         val = self.f_mmio32read.read()
142                 except IOError, e:
143                         print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
144                         raise B43Exception
145                 return int(val, 16)
146
147         def maskSet16(self, reg, mask, set):
148                 """Do a 16bit MMIO mask-and-set operation"""
149                 try:
150                         mask &= 0xFFFF
151                         set &= 0xFFFF
152                         self.f_mmio16write.seek(0)
153                         self.f_mmio16write.write("0x%X 0x%X 0x%X" % (reg, mask, set))
154                         self.f_mmio16write.flush()
155                 except IOError, e:
156                         print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
157                         raise B43Exception
158                 return
159         
160         def write16(self, reg, value):
161                 """Do a 16bit MMIO write"""
162                 self.maskSet16(reg, 0, value)
163                 return
164
165         def maskSet32(self, reg, mask, set):
166                 """Do a 32bit MMIO mask-and-set operation"""
167                 try:
168                         mask &= 0xFFFFFFFF
169                         set &= 0xFFFFFFFF
170                         self.f_mmio32write.seek(0)
171                         self.f_mmio32write.write("0x%X 0x%X 0x%X" % (reg, mask, set))
172                         self.f_mmio32write.flush()
173                 except IOError, e:
174                         print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
175                         raise B43Exception
176                 return
177
178         def write32(self, reg, value):
179                 """Do a 32bit MMIO write"""
180                 self.maskSet32(reg, 0, value)
181                 return
182
183         def shmRead16(self, routing, offset):
184                 """Do a 16bit SHM read"""
185                 try:
186                         self.f_shm16read.seek(0)
187                         self.f_shm16read.write("0x%X 0x%X" % (routing, offset))
188                         self.f_shm16read.flush()
189                         self.f_shm16read.seek(0)
190                         val = self.f_shm16read.read()
191                 except IOError, e:
192                         print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
193                         raise B43Exception
194                 return int(val, 16)
195
196         def shmMaskSet16(self, routing, offset, mask, set):
197                 """Do a 16bit SHM mask-and-set operation"""
198                 try:
199                         mask &= 0xFFFF
200                         set &= 0xFFFF
201                         self.f_shm16write.seek(0)
202                         self.f_shm16write.write("0x%X 0x%X 0x%X 0x%X" % (routing, offset, mask, set))
203                         self.f_shm16write.flush()
204                 except IOError, e:
205                         print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
206                         raise B43Exception
207                 return
208
209         def shmWrite16(self, routing, offset, value):
210                 """Do a 16bit SHM write"""
211                 self.shmMaskSet16(routing, offset, 0, value)
212                 return
213
214         def shmRead32(self, routing, offset):
215                 """Do a 32bit SHM read"""
216                 try:
217                         self.f_shm32read.seek(0)
218                         self.f_shm32read.write("0x%X 0x%X" % (routing, offset))
219                         self.f_shm32read.flush()
220                         self.f_shm32read.seek(0)
221                         val = self.f_shm32read.read()
222                 except IOError, e:
223                         print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
224                         raise B43Exception
225                 return int(val, 16)
226
227         def shmMaskSet32(self, routing, offset, mask, set):
228                 """Do a 32bit SHM mask-and-set operation"""
229                 try:
230                         mask &= 0xFFFFFFFF
231                         set &= 0xFFFFFFFF
232                         self.f_shm32write.seek(0)
233                         self.f_shm32write.write("0x%X 0x%X 0x%X 0x%X" % (routing, offset, mask, set))
234                         self.f_shm32write.flush()
235                 except IOError, e:
236                         print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
237                         raise B43Exception
238                 return
239
240         def shmWrite32(self, routing, offset, value):
241                 """Do a 32bit SHM write"""
242                 self.shmMaskSet32(routing, offset, 0, value)
243                 return
244
245         def getGprs(self):
246                 """Returns an array of 64 ints. One for each General Purpose register."""
247                 ret = []
248                 for i in range(0, 64):
249                         val = self.shmRead16(B43_SHM_REGS, i)
250                         ret.append(val)
251                 return ret
252
253         def getLinkRegs(self):
254                 """Returns an array of 4 ints. One for each Link Register."""
255                 ret = []
256                 for i in range(0, 4):
257                         val = self.read16(0x4D0 + (i * 2))
258                         ret.append(val)
259                 return ret
260
261         def getOffsetRegs(self):
262                 """Returns an array of 7 ints. One for each Offset Register."""
263                 ret = []
264                 for i in range(0, 7):
265                         val = self.read16(0x4C0 + (i * 2))
266                         ret.append(val)
267                 return ret
268
269         def shmSharedRead(self):
270                 """Returns a string containing the SHM contents."""
271                 ret = ""
272                 for i in range(0, 4096, 4):
273                         val = self.shmRead32(B43_SHM_SHARED, i)
274                         ret += "%c%c%c%c" %     (val & 0xFF,
275                                                  (val >> 8) & 0xFF,
276                                                  (val >> 16) & 0xFF,
277                                                  (val >> 24) & 0xFF)
278                 return ret
279
280         def getPsmDebug(self):
281                 """Read the PSM-debug register and return an instance of B43PsmDebug."""
282                 val = self.read32(B43_MMIO_PSMDEBUG)
283                 return B43PsmDebug(val)
284
285         def getPsmConditions(self):
286                 """This returns the contents of the programmable-PSM-conditions register."""
287                 return self.read16(0x4D8)
288
289         def ucodeStop(self):
290                 """Unconditionally stop the microcode PSM. """
291                 self.maskSet32(B43_MMIO_MACCTL, ~B43_MACCTL_PSM_RUN, 0)
292                 return
293
294         def ucodeStart(self):
295                 """Unconditionally start the microcode PSM. This will restart the
296                 microcode on the current PC. It will not jump to 0. Warning: This will
297                 unconditionally restart the PSM and ignore any driver-state!"""
298                 self.maskSet32(B43_MMIO_MACCTL, ~0, B43_MACCTL_PSM_RUN)
299                 return
300
301 class Disassembler:
302         """Disassembler for b43 firmware."""
303         def __init__(self, binaryText, b43DasmOpts):
304                 input = NamedTemporaryFile()
305                 output = NamedTemporaryFile()
306
307                 input.write(binaryText)
308                 input.flush()
309                 #FIXME check b43-dasm errors
310                 os.system("b43-dasm %s %s %s" % (input.name, output.name, b43DasmOpts))
311
312                 self.asmText = output.read()
313
314         def getAsm(self):
315                 """Returns the assembly code."""
316                 return self.asmText
317
318 class Assembler:
319         """Assembler for b43 firmware."""
320         def __init__(self, assemblyText, b43AsmOpts):
321                 input = NamedTemporaryFile()
322                 output = NamedTemporaryFile()
323
324                 input.write(assemblyText)
325                 input.flush()
326                 #FIXME check b43-asm errors
327                 os.system("b43-asm %s %s %s" % (input.name, output.name, b43AsmOpts))
328
329                 self.binaryText = output.read()
330
331         def getBinary(self):
332                 """Returns the binary code."""
333                 return self.binaryText
334
335 class TextPatcher:
336         """A textfile patcher that does not include any target context.
337         This can be used to patch b43 firmware files."""
338
339         class TextLine:
340                 def __init__(self, index, line):
341                         self.index = index
342                         self.line = line
343                         self.deleted = False
344
345         def __init__(self, text, expected_md5sum):
346                 sum = hashlib.md5(text).hexdigest()
347                 if sum != expected_md5sum:
348                         print "Patcher: The text does not match the expected MD5 sum"
349                         print "Expected:   " + expected_md5sum
350                         print "Calculated: " + sum
351                         raise B43Exception
352                 text = text.splitlines()
353                 self.lines = []
354                 i = 0
355                 for line in text:
356                         self.lines.append(TextPatcher.TextLine(i, line))
357                         i += 1
358                 # Add an after-last dummy. Needed for the add-before logic
359                 lastDummy = TextPatcher.TextLine(i, "")
360                 lastDummy.deleted = True
361                 self.lines.append(lastDummy)
362
363         def getText(self):
364                 """This returns the current text."""
365                 textLines = []
366                 for l in self.lines:
367                         if not l.deleted:
368                                 textLines.append(l.line)
369                 return "\n".join(textLines)
370
371         def delLine(self, linenumber):
372                 """Delete a line of text. The linenumber corresponds to the
373                 original unmodified text."""
374                 for l in self.lines:
375                         if l.index == linenumber:
376                                 l.deleted = True
377                                 return
378                 print "Patcher deleteLine: Did not find the line!"
379                 raise B43Exception
380
381         def addText(self, beforeLineNumber, text):
382                 """Add a text before the specified linenumber. The linenumber
383                 corresponds to the original unmodified text."""
384                 text = text.splitlines()
385                 index = 0
386                 for l in self.lines:
387                         if l.index == beforeLineNumber:
388                                 break
389                         index += 1
390                 if index >= len(self.lines):
391                         print "Patcher addText: Did not find the line!"
392                         raise B43Exception
393                 for l in text:
394                         self.lines.insert(index, TextPatcher.TextLine(-1, l))
395                         index += 1
396
397 class B43SymbolicSpr:
398         """This class converts numeric SPR names into symbolic SPR names."""
399
400         def __init__(self, header_file):
401                 """The passed header_file parameter is a file path to the
402                 assembly file containing the symbolic SPR definitions."""
403                 try:
404                         defs = file(header_file).readlines()
405                 except IOError, e:
406                         print "B43SymbolicSpr: Could not read %s: %s" % (e.filename, e.strerror)
407                         B43Exception
408                 # Parse the definitions
409                 self.spr_names = { }
410                 r = re.compile(r"#define\s+(\w+)\s+(spr[a-fA-F0-9]+)")
411                 for line in defs:
412                         m = r.match(line)
413                         if not m:
414                                 continue # unknown line
415                         name = m.group(1)
416                         offset = m.group(2)
417                         self.spr_names[offset.lower()] = name
418
419         def get(self, spr):
420                 """Get the symbolic name for an SPR. The spr parameter
421                 must be a string like "sprXXX", where XXX is a hex number."""
422                 try:
423                         spr = self.spr_names[spr.lower()]
424                 except KeyError:
425                         pass # Symbol not found. Return numeric name.
426                 return spr
427
428         def getRaw(self, spr_hexnumber):
429                 """Get the symbolic name for an SPR. The spr_hexnumber
430                 parameter is the hexadecimal number for the SPR."""
431                 return self.get("spr%03X" % spr_hexnumber)
432
433 class B43SymbolicShm:
434         """This class converts numeric SHM offsets into symbolic SHM names."""
435
436         def __init__(self, header_file):
437                 """The passed header_file parameter is a file path to the
438                 assembly file containing the symbolic SHM definitions."""
439                 try:
440                         defs = file(header_file).readlines()
441                 except IOError, e:
442                         print "B43SymbolicShm: Could not read %s: %s" % (e.filename, e.strerror)
443                         raise B43Exception
444                 # Parse the definitions
445                 self.shm_names = { }
446                 in_abi_section = False
447                 r = re.compile(r"#define\s+(\w+)\s+SHM\((\w+)\).*")
448                 for line in defs:
449                         if line.startswith("/* BEGIN ABI"):
450                                 in_abi_section = True
451                         if line.startswith("/* END ABI"):
452                                 in_abi_section = False
453                         if not in_abi_section:
454                                 continue # Only parse ABI definitions
455                         m = r.match(line)
456                         if not m:
457                                 continue # unknown line
458                         name = m.group(1)
459                         offset = int(m.group(2), 16)
460                         offset /= 2
461                         self.shm_names[offset] = name
462
463         def get(self, shm_wordoffset):
464                 """Get the symbolic name for an SHM offset."""
465                 try:
466                         sym = self.shm_names[shm_wordoffset]
467                 except KeyError:
468                         # Symbol not found. Return numeric name.
469                         sym = "0x%03X" % shm_wordoffset
470                 return sym
471
472 class B43SymbolicCondition:
473         """This class converts numeric External Conditions into symbolic names."""
474
475         def __init__(self, header_file):
476                 """The passed header_file parameter is a file path to the
477                 assembly file containing the symbolic condition definitions."""
478                 try:
479                         defs = file(header_file).readlines()
480                 except IOError, e:
481                         print "B43SymbolicCondition: Could not read %s: %s" % (e.filename, e.strerror)
482                         raise B43Exception
483                 # Parse the definitions
484                 self.cond_names = { }
485                 r = re.compile(r"#define\s+(\w+)\s+EXTCOND\(\s*(\w+),\s*(\d+)\s*\).*")
486                 for line in defs:
487                         m = r.match(line)
488                         if not m:
489                                 continue # unknown line
490                         name = m.group(1)
491                         register = m.group(2)
492                         bit = int(m.group(3))
493                         if register == "CONDREG_RX":
494                                 register = 0
495                         elif register == "CONDREG_TX":
496                                 register = 2
497                         elif register == "CONDREG_PHY":
498                                 register = 3
499                         elif register == "CONDREG_4":
500                                 register = 4
501                         elif register == "CONDREG_PSM":
502                                 continue # No lookup table for this one
503                         elif register == "CONDREG_RCM":
504                                 register = 6
505                         elif register == "CONDREG_7":
506                                 register = 7
507                         else:
508                                 continue # unknown register
509                         cond_number = bit | (register << 4)
510                         self.cond_names[cond_number] = name
511
512         def get(self, cond_number):
513                 """Get the symbolic name for an External Condition."""
514                 register = (cond_number >> 4) & 0x7
515                 bit = cond_number & 0xF
516                 eoi = ((cond_number & 0x80) != 0)
517                 cond_number &= ~0x80
518                 if register == 5: # PSM register
519                         return "COND_PSM(%d)" % bit
520                 try:
521                         sym = self.cond_names[cond_number]
522                 except KeyError:
523                         # Symbol not found. Return numeric name.
524                         sym = "0x%02X" % cond_number
525                 if eoi:
526                         sym = "EOI(%s)" % sym
527                 return sym
528
529 class B43AsmLine:
530         def __init__(self, text):
531                 self.text = text
532
533         def getLine(self):
534                 return self.text
535
536         def __repr__(self):
537                 return self.getLine()
538
539         def isInstruction(self):
540                 return False
541
542 class B43AsmInstruction(B43AsmLine):
543         def __init__(self, opcode):
544                 self.setOpcode(opcode)
545                 self.clearOperands()
546
547         def getOpcode(self):
548                 return self.opcode
549
550         def setOpcode(self, opcode):
551                 self.opcode = opcode
552
553         def clearOperands(self):
554                 self.operands = []
555
556         def addOperand(self, operand):
557                 self.operands.append(operand)
558
559         def getOperands(self):
560                 return self.operands
561
562         def getLine(self):
563                 ret = "\t" + self.opcode
564                 if self.operands:
565                         ret += "\t"
566                 for op in self.operands:
567                         ret += op + ", "
568                 if self.operands:
569                         ret = ret[:-2]
570                 return ret
571
572         def isInstruction(self):
573                 return True
574
575 class B43AsmParser:
576         """A simple B43 assembly code parser."""
577
578         def __init__(self, asm_code):
579                 self.__parse_code(asm_code)
580
581         def __parse_code(self, asm_code):
582                 self.codelines = []
583                 label = re.compile(r"^\s*\w+:\s*$")
584                 insn_0 = re.compile(r"^\s*([@\.\w]+)\s*$")
585                 insn_2 = re.compile(r"^\s*([@\.\w]+)\s+([@\[\],\w]+),\s*([@\[\],\w]+)\s*$")
586                 insn_3 = re.compile(r"^\s*([@\.\w]+)\s+([@\[\],\w]+),\s*([@\[\],\w]+),\s*([@\[\],\w]+)\s*$")
587                 insn_5 = re.compile(r"^\s*([@\.\w]+)\s+([@\[\],\w]+),\s*([@\[\],\w]+),\s*([@\[\],\w]+),\s*([@\[\],\w]+),\s*([@\[\],\w]+)\s*$")
588                 for line in asm_code.splitlines():
589                         m = label.match(line)
590                         if m: # Label:
591                                 l = B43AsmLine(line)
592                                 self.codelines.append(l)
593                                 continue
594                         m = insn_0.match(line)
595                         if m: # No operands
596                                 insn = B43AsmInstruction(m.group(1))
597                                 self.codelines.append(insn)
598                                 continue
599                         m = insn_2.match(line)
600                         if m: # Two operands
601                                 insn = B43AsmInstruction(m.group(1))
602                                 insn.addOperand(m.group(2))
603                                 insn.addOperand(m.group(3))
604                                 self.codelines.append(insn)
605                                 continue
606                         m = insn_3.match(line)
607                         if m: # Three operands
608                                 insn = B43AsmInstruction(m.group(1))
609                                 insn.addOperand(m.group(2))
610                                 insn.addOperand(m.group(3))
611                                 insn.addOperand(m.group(4))
612                                 self.codelines.append(insn)
613                                 continue
614                         m = insn_5.match(line)
615                         if m: # Three operands
616                                 insn = B43AsmInstruction(m.group(1))
617                                 insn.addOperand(m.group(2))
618                                 insn.addOperand(m.group(3))
619                                 insn.addOperand(m.group(4))
620                                 insn.addOperand(m.group(5))
621                                 insn.addOperand(m.group(6))
622                                 self.codelines.append(insn)
623                                 continue
624                         # Unknown line
625                         l = B43AsmLine(line)
626                         self.codelines.append(l)
627
628 class B43Beautifier(B43AsmParser):
629         """A B43 assembly code beautifier."""
630
631         def __init__(self, asm_code, headers_dir):
632                 """asm_code is the assembly code. headers_dir is a full
633                 path to the directory containing the symbolic SPR,SHM,etc... definitions"""
634                 if headers_dir.endswith("/"):
635                         headers_dir = headers_dir[:-1]
636                 B43AsmParser.__init__(self, asm_code)
637                 self.symSpr = B43SymbolicSpr(headers_dir + "/spr.inc")
638                 self.symShm = B43SymbolicShm(headers_dir + "/shm.inc")
639                 self.symCond = B43SymbolicCondition(headers_dir + "/cond.inc")
640                 self.preamble = "#include \"%s/spr.inc\"\n" % headers_dir
641                 self.preamble += "#include \"%s/shm.inc\"\n" % headers_dir
642                 self.preamble += "#include \"%s/cond.inc\"\n" % headers_dir
643                 self.preamble += "\n"
644                 self.__process_code()
645
646         def __process_code(self):
647                 spr_re = re.compile(r"^spr\w\w\w$")
648                 shm_re = re.compile(r"^\[(0x\w+)\]$")
649                 code = self.codelines
650                 for line in code:
651                         if not line.isInstruction():
652                                 continue
653                         opcode = line.getOpcode()
654                         operands = line.getOperands()
655                         # Transform unconditional jump
656                         if opcode == "jext" and int(operands[0], 16) == 0x7F:
657                                 label = operands[1]
658                                 line.setOpcode("jmp")
659                                 line.clearOperands()
660                                 line.addOperand(label)
661                                 continue
662                         # Transform external conditions
663                         if opcode == "jext" or opcode == "jnext":
664                                 operands[0] = self.symCond.get(int(operands[0], 16))
665                                 continue
666                         # Transform orx 7,8,imm,imm,target to mov
667                         if opcode == "orx" and \
668                            int(operands[0], 16) == 7 and int(operands[1], 16) == 8 and\
669                            operands[2].startswith("0x") and operands[3].startswith("0x"):
670                                 value = int(operands[3], 16) & 0xFF
671                                 value |= (int(operands[2], 16) & 0xFF) << 8
672                                 target = operands[4]
673                                 line.setOpcode("mov")
674                                 line.clearOperands()
675                                 line.addOperand("0x%X" % value)
676                                 line.addOperand(target)
677                                 opcode = line.getOpcode()
678                                 operands = line.getOperands()
679                         for i in range(0, len(operands)):
680                                 o = operands[i]
681                                 # Transform SPR operands
682                                 m = spr_re.match(o)
683                                 if m:
684                                         operands[i] = self.symSpr.get(o)
685                                         continue
686                                 # Transform SHM operands
687                                 m = shm_re.match(o)
688                                 if m:
689                                         offset = int(m.group(1), 16)
690                                         operands[i] = "[" + self.symShm.get(offset) + "]"
691                                         continue
692
693         def getAsm(self):
694                 """Returns the beautified asm code."""
695                 ret = [ self.preamble ]
696                 for line in self.codelines:
697                         ret.append(str(line))
698                 return "\n".join(ret)