d9d9d1b21f5db13c3de87f0f06603c64e449eb2a
1 # Copyright (c) 2003-2005 The Regents of The University of Michigan
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 # Prepend the directory where the PLY lex & yacc modules are found
39 sys
.path
[0:0] = [os
.environ
['M5_PLY']]
44 ##########################################################################
46 # Base classes for use outside of the assembler
48 ##########################################################################
50 class Micro_Container(object):
51 def __init__(self
, name
):
55 self
.micro_classes
= {}
58 def add_microop(self
, microop
):
59 self
.microops
.append(microop
)
62 string
= "%s:\n" % self
.name
63 for microop
in self
.microops
:
64 string
+= " %s\n" % microop
67 class Combinational_Macroop(Micro_Container
):
70 class Rom_Macroop(object):
71 def __init__(self
, name
, target
):
75 class Rom(Micro_Container
):
76 def __init__(self
, name
):
77 super(Rom
, self
).__init
__(name
)
80 ##########################################################################
84 ##########################################################################
95 class Statement(object):
97 self
.is_microop
= False
98 self
.is_directive
= False
101 class Microop(Statement
):
103 super(Microop
, self
).__init
__()
106 self
.is_microop
= True
108 class Directive(Statement
):
110 super(Directive
, self
).__init
__()
112 self
.is_directive
= True
114 ##########################################################################
116 # Functions that handle common tasks
118 ##########################################################################
120 def print_error(message
):
122 print "*** %s" % message
125 def handle_statement(parser
, container
, statement
):
126 if statement
.is_microop
:
128 microop
= eval('parser.microops[statement.mnemonic](%s)' %
131 print_error("Error creating microop object.")
134 for label
in statement
.labels
:
135 container
.labels
[label
.name
] = microop
137 container
.externs
[label
.name
] = microop
138 container
.add_microop(microop
)
140 print_error("Error adding microop.")
142 elif statement
.is_directive
:
144 eval('container.directives[statement.name](%s)' % statement
.params
)
146 print_error("Error executing directive.")
147 print container
.directives
150 raise Exception, "Didn't recognize the type of statement", statement
152 ##########################################################################
154 # Lexer specification
156 ##########################################################################
158 # Error handler. Just call exit. Output formatted to work under
159 # Emacs compile-mode. Optional 'print_traceback' arg, if set to True,
160 # prints a Python stack backtrace too (can be handy when trying to
161 # debug the parser itself).
162 def error(lineno
, string
, print_traceback
= False):
163 # Print a Python stack backtrace if requested.
164 if (print_traceback
):
165 traceback
.print_exc()
167 line_str
= "%d:" % lineno
170 sys
.exit("%s %s" % (line_str
, string
))
172 reserved
= ('DEF', 'MACROOP', 'ROM', 'EXTERN')
174 tokens
= reserved
+ (
177 # arguments for microops and directives
182 'COLON', 'SEMI', 'DOT',
186 # New lines are ignored at the top level, but they end statements in the
189 ('asm', 'exclusive'),
190 ('params', 'exclusive'),
195 reserved_map
[r
.lower()] = r
197 def t_ANY_COMMENT(t
):
199 #print "t_ANY_COMMENT %s" % t.value
201 def t_ANY_MULTILINECOMMENT(t
):
202 r
'/\*([^/]|((?<!\*)/))*\*/'
203 #print "t_ANY_MULTILINECOMMENT %s" % t.value
205 def t_params_COLON(t
):
208 #print "t_params_COLON %s" % t.value
213 t
.type = reserved_map
.get(t
.value
, 'ID')
214 t
.lexer
.begin('params')
215 #print "t_asm_ID %s" % t.value
220 t
.type = reserved_map
.get(t
.value
, 'ID')
221 #print "t_ANY_ID %s" % t.value
224 def t_params_PARAMS(t
):
225 r
'([^\n;]|((?<=\\)[\n;]))+'
226 t
.lineno
+= t
.value
.count('\n')
228 #print "t_params_PARAMS %s" % t.value
231 def t_INITIAL_LBRACE(t
):
234 #print "t_INITIAL_LBRACE %s" % t.value
239 t
.lexer
.begin('INITIAL')
240 #print "t_asm_RBRACE %s" % t.value
243 def t_INITIAL_NEWLINE(t
):
245 t
.lineno
+= t
.value
.count('\n')
246 #print "t_INITIAL_NEWLINE %s" % t.value
248 def t_asm_NEWLINE(t
):
250 t
.lineno
+= t
.value
.count('\n')
251 #print "t_asm_NEWLINE %s" % t.value
254 def t_params_NEWLINE(t
):
256 t
.lineno
+= t
.value
.count('\n')
258 #print "t_params_NEWLINE %s" % t.value
261 def t_params_SEMI(t
):
264 #print "t_params_SEMI %s" % t.value
267 # Basic regular expressions to pick out simple tokens
273 t_ANY_ignore
= ' \t\x0c'
276 error(t
.lineno
, "illegal character '%s'" % t
.value
[0])
279 ##########################################################################
281 # Parser specification
283 ##########################################################################
285 # Start symbol for a file which may have more than one macroop or rom
288 'file : opt_rom_or_macros'
290 def p_opt_rom_or_macros_0(t
):
291 'opt_rom_or_macros : '
293 def p_opt_rom_or_macros_1(t
):
294 'opt_rom_or_macros : rom_or_macros'
296 def p_rom_or_macros_0(t
):
297 'rom_or_macros : rom_or_macro'
299 def p_rom_or_macros_1(t
):
300 'rom_or_macros : rom_or_macros rom_or_macro'
302 def p_rom_or_macro_0(t
):
303 '''rom_or_macro : rom_block'''
305 def p_rom_or_macro_1(t
):
306 '''rom_or_macro : macroop_def'''
308 # A block of statements
310 'block : LBRACE statements RBRACE'
312 block
.statements
= t
[2]
315 # Defines a section of microcode that should go in the current ROM
317 'rom_block : DEF ROM block SEMI'
319 print_error("Rom block found, but no Rom object specified.")
320 raise TypeError, "Rom block found, but no Rom object was specified."
321 for statement
in t
[3].statements
:
322 handle_statement(t
.parser
, t
.parser
.rom
, statement
)
325 # Defines a macroop that jumps to an external label in the ROM
326 def p_macroop_def_0(t
):
327 'macroop_def : DEF MACROOP ID LPAREN ID RPAREN SEMI'
328 if not t
.parser
.rom_macroop_type
:
329 print_error("ROM based macroop found, but no ROM macroop class was specified.")
330 raise TypeError, "ROM based macroop found, but no ROM macroop class was specified."
331 macroop
= t
.parser
.rom_macroop_type(t
[3], t
[5])
335 # Defines a macroop that is combinationally generated
336 def p_macroop_def_1(t
):
337 'macroop_def : DEF MACROOP ID block SEMI'
339 curop
= t
.parser
.macro_type(t
[3])
341 print_error("Error creating macroop object.")
343 for statement
in t
[4].statements
:
344 handle_statement(t
.parser
, curop
, statement
)
345 t
.parser
.macroops
[t
[3]] = curop
347 def p_statements_0(t
):
348 'statements : statement'
354 def p_statements_1(t
):
355 'statements : statements statement'
361 'statement : content_of_statement end_of_statement'
364 # A statement can be a microop or an assembler directive
365 def p_content_of_statement_0(t
):
366 '''content_of_statement : microop
370 def p_content_of_statement_1(t
):
371 'content_of_statement : '
374 # Statements are ended by newlines or a semi colon
375 def p_end_of_statement(t
):
376 '''end_of_statement : NEWLINE
381 'microop : labels ID'
383 microop
.labels
= t
[1]
384 microop
.mnemonic
= t
[2]
390 microop
.mnemonic
= t
[1]
394 'microop : labels ID PARAMS'
396 microop
.labels
= t
[1]
397 microop
.mnemonic
= t
[2]
398 microop
.params
= t
[3]
402 'microop : ID PARAMS'
404 microop
.mnemonic
= t
[1]
405 microop
.params
= t
[2]
413 'labels : labels label'
420 label
.is_extern
= False
425 'label : EXTERN ID COLON'
427 label
.is_extern
= True
431 def p_directive_0(t
):
433 directive
= Directive()
434 directive
.name
= t
[2]
437 def p_directive_1(t
):
438 'directive : DOT ID PARAMS'
439 directive
= Directive()
440 directive
.name
= t
[2]
441 directive
.params
= t
[3]
444 # Parse error handler. Note that the argument here is the offending
445 # *token*, not a grammar symbol (hence the need to use t.value)
448 error(t
.lineno
, "syntax error at '%s'" % t
.value
)
450 error(0, "unknown syntax error", True)
452 class MicroAssembler(object):
454 def __init__(self
, macro_type
, microops
,
455 rom
= None, rom_macroop_type
= None):
456 self
.lexer
= lex
.lex()
457 self
.parser
= yacc
.yacc()
458 self
.parser
.macro_type
= macro_type
459 self
.parser
.macroops
= {}
460 self
.parser
.microops
= microops
461 self
.parser
.rom
= rom
462 self
.parser
.rom_macroop_type
= rom_macroop_type
464 def assemble(self
, asm
):
465 self
.parser
.parse(asm
, lexer
=self
.lexer
)
466 # Begin debug printing
467 for macroop
in self
.parser
.macroops
.values():
469 print self
.parser
.rom
471 macroops
= self
.parser
.macroops
472 self
.parser
.macroops
= {}