Gabe Black has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/56343 )

Change subject: arch-x86: Add an include statement for the ucode assembler.
......................................................................

arch-x86: Add an include statement for the ucode assembler.

The includes can be relative to the file using it, or by absolute path.
The first include needs to be absolute because the microcode assembler
is still initiated using a string instead of a file.

Change-Id: Id9e44a441005ae75cc36b994422e7dae2d20bbfe
---
M src/arch/ucasmlib/assembler.py
1 file changed, 84 insertions(+), 20 deletions(-)



diff --git a/src/arch/ucasmlib/assembler.py b/src/arch/ucasmlib/assembler.py
index e9a5e1b..e2010df 100644
--- a/src/arch/ucasmlib/assembler.py
+++ b/src/arch/ucasmlib/assembler.py
@@ -30,6 +30,8 @@
 from ply import lex
 from ply import yacc

+import os.path
+
 class Macro:
     def __init__(self, name, params, body):
         self.name = name
@@ -53,7 +55,7 @@
     #
     ######################################################################

-    reserved = ('DEF', 'UNDEF', 'MACRO', 'MACROOP', 'ROM')
+    reserved = ('DEF', 'UNDEF', 'MACRO', 'MACROOP', 'ROM', 'INCLUDE')

     tokens = reserved + (
             # identifier
@@ -63,9 +65,11 @@
             # the params of a macro
             'PARAMS',

+            'STRING',
+
             'LPAREN', 'RPAREN',
             'LBRACE', 'RBRACE',
-            'SEMI'
+            'SEMI', 'NEWLINE',
             )

# New lines are ignored at the top level, but they end statements in the
@@ -73,6 +77,7 @@
     states = (
         ('asm', 'exclusive'),
         ('header', 'exclusive'),
+        ('include', 'exclusive'),
         ('macroheader', 'exclusive'),
         ('macroparams', 'exclusive'),
         ('macro', 'exclusive'),
@@ -85,7 +90,7 @@

     def t_macroheader_ID(self, t):
         r'[A-Za-z_]\w*'
-        t.lexer.pop_state()
+        self.lexer.pop_state()
         return t

     # Macro params are everything up to the next unescaped {.
@@ -102,33 +107,34 @@
     # Braces enter and exit blocks.
     def t_header_macroparams_LBRACE(self, t):
         r'\{'
-        t.lexer.pop_state()
+        self.lexer.pop_state()
         return t

     def t_undef_ID(self, t):
         r'[A-Za-z_]\w*'
         t.type = self.reserved_map.get(t.value, 'ID')
-        t.lexer.pop_state()
+        self.lexer.pop_state()
         return t

     def t_ANY_ID(self, t):
         r'[A-Za-z_]\w*'
         t.type = self.reserved_map.get(t.value, 'ID')
-        if t.type == 'UNDEF':
-            t.lexer.push_state('undef')
+        if t.type == 'INCLUDE':
+            self.lexer.push_state('include')
+        elif t.type == 'UNDEF':
+            self.lexer.push_state('undef')
         elif t.type == 'MACRO':
-            t.lexer.push_state('asm')
-            t.lexer.push_state('macroparams')
-            t.lexer.push_state('macroheader')
+            self.lexer.push_state('asm')
+            self.lexer.push_state('macroparams')
+            self.lexer.push_state('macroheader')
         elif t.type == 'MACROOP':
-            t.lexer.push_state('asm')
-            t.lexer.push_state('header')
+            self.lexer.push_state('asm')
+            self.lexer.push_state('header')
         elif t.type == 'ROM':
-            t.lexer.push_state('asm')
-            t.lexer.push_state('header')
+            self.lexer.push_state('asm')
+            self.lexer.push_state('header')
         return t

-
     #
# Blocks have lines in them which are terminated with unescaped newlines,
     # and end when a line starts with a }.
@@ -178,20 +184,47 @@

     @lex.TOKEN(body_re)
     def t_asm_BODY(self, t):
-        t.lexer.lineno += t.value.count('\n')
+        self.lexer.lineno += t.value.count('\n')
         t.value = (t.lineno, t.value)
         return t


     def t_asm_RBRACE(self, t):
         r'\}'
+        self.lexer.pop_state()
+        return t
+
+    def t_include_STRING(self, t):
+        r'"([^"\\]|(\\.))*"'
+        self.lexer.lineno += t.value.count('\n')
+        path = t.value.strip()[1:-1]
+        t.value = path
         t.lexer.pop_state()
+
+        curpath = self.lexers[-1][0]
+ rel = os.path.realpath(os.path.abspath(os.path.join(curpath, path)))
+        raw = os.path.realpath(os.path.abspath(path))
+        matches = list([p for p in (rel, raw) if os.path.exists(p)])
+        if not matches:
+            raise ValueError(f'Include "{path}" not found')
+        path = matches[0]
+        with open(path) as new_file:
+            new_lexer = self.lexer.clone()
+            new_lexer.lineno = 1
+            self.lexers.append((os.path.dirname(path), new_lexer))
+            new_lexer.input(new_file.read())
         return t

# Unless handled specially above, track newlines only for line counting.
     def t_ANY_NEWLINE(self, t):
         r'\n+'
-        t.lexer.lineno += t.value.count('\n')
+        self.lexer.lineno += t.value.count('\n')
+
+    def t_eof(self, t):
+        while t and t.type == 'eof' and len(self.lexers) > 1:
+            self.lexers.pop()
+            t = self.token()
+        return t if t and t.type != 'eof' else None

     # Basic regular expressions to pick out simple tokens
     t_ANY_LPAREN = r'\('
@@ -222,11 +255,16 @@

     # Objects can be of various types.
     def p_object(self, t):
-        '''object : macro_def
+        '''object : include
+                  | macro_def
                   | macro_undef
                   | rom_block
                   | macroop_def'''

+    # Includes have already been handled by the lexer.
+    def p_include(self, t):
+        'include : INCLUDE STRING'
+
     # An optional body for a block.
     def p_opt_body_0(self, t):
         'opt_body : BODY'
@@ -303,8 +341,21 @@
         else:
             t[0] = []

+    @property
+    def lexer(self):
+        return self.lexers[-1][1]
+
+    def token(self):
+        return self.lexer.token()
+
+    def input(self, *args, **kwargs):
+        return self.lexer.input(*args, **kwargs)
+
def __init__(self, macro_type, microops, rom=None, rom_macroop_type=None):
-        self.lexer = lex.lex(object=self)
+ # Set lexers to something so when lex.lex() scans for doc strings the
+        # "lexer" property can return something.
+        self.lexers = [('dummy', None)]
+        self.lexers = [('<string>', lex.lex(object=self))]
         self.parser = yacc.yacc(module=self)
         self.macro_type = macro_type
         self.macros = {}
@@ -315,5 +366,5 @@
         self.symbols = {}

     def assemble(self, asm):
-        self.parser.parse(asm, lexer=self.lexer)
+        self.parser.parse(asm, lexer=self)
         return self.macroops

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/56343
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: Id9e44a441005ae75cc36b994422e7dae2d20bbfe
Gerrit-Change-Number: 56343
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <gabe.bl...@gmail.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to