add ports declarations
[sv2nmigen.git] / parse_sv.py
index e039650ea3749ce04f2b4981251b4c19f8617604..67ef513dd3abcc0ca034473761d8225e746d9156 100644 (file)
@@ -35,24 +35,24 @@ precedence = [\
               'K_MOD_EQ', 'K_AND_EQ', 'K_OR_EQ'),
     ('right', 'K_XOR_EQ', 'K_LS_EQ', 'K_RS_EQ', 'K_RSS_EQ'),
     ('right', '?', ':', 'K_inside'),
-    ('left', 'K_LOR'), 
-    ('left', 'K_LAND'), 
-    ('left', '|'), 
-    ('left', '^', 'K_NXOR', 'K_NOR'), 
-    ('left', '&', 'K_NAND'), 
-    ('left', 'K_EQ', 'K_NE', 'K_CEQ', 'K_CNE', 'K_WEQ', 'K_WNE'), 
-    ('left', 'K_GE', 'K_LE', '<', '>'), 
-    ('left', 'K_LS', 'K_RS', 'K_RSS'), 
-    ('left', '+', '-'), 
-    ('left', '*', '/', '%'), 
-    ('left', 'K_POW'), 
-    ('left', 'UNARY_PREC'), 
-    ('nonassoc', 'less_than_K_else'), 
-    ('nonassoc', 'K_else'), 
-    ('nonassoc', '('), 
-    ('nonassoc', 'K_exclude'), 
-    ('nonassoc', 'no_timeunits_declaration'), 
-    ('nonassoc', 'one_timeunits_declaration'), 
+    ('left', 'K_LOR'),
+    ('left', 'K_LAND'),
+    ('left', '|'),
+    ('left', '^', 'K_NXOR', 'K_NOR'),
+    ('left', '&', 'K_NAND'),
+    ('left', 'K_EQ', 'K_NE', 'K_CEQ', 'K_CNE', 'K_WEQ', 'K_WNE'),
+    ('left', 'K_GE', 'K_LE', '<', '>'),
+    ('left', 'K_LS', 'K_RS', 'K_RSS'),
+    ('left', '+', '-'),
+    ('left', '*', '/', '%'),
+    ('left', 'K_POW'),
+    ('left', 'UNARY_PREC'),
+    ('nonassoc', 'less_than_K_else'),
+    ('nonassoc', 'K_else'),
+    ('nonassoc', '('),
+    ('nonassoc', 'K_exclude'),
+    ('nonassoc', 'no_timeunits_declaration'),
+    ('nonassoc', 'one_timeunits_declaration'),
     ('nonassoc', 'K_timeunit', 'K_timeprecision')
     ]
 
@@ -60,6 +60,18 @@ precedence = [\
 IVL_VT_NO_TYPE = 'VT_NO_TYPE'
 IVL_VT_BOOL = 'VT_BOOL'
 IVL_VT_LOGIC = 'VT_LOGIC'
+"""
+      IVL_VT_VOID    = 0,  /* Not used */
+      IVL_VT_NO_TYPE = 1,  /* Place holder for missing/unknown type. */
+      IVL_VT_REAL    = 2,
+      IVL_VT_BOOL    = 3,
+      IVL_VT_LOGIC   = 4,
+      IVL_VT_STRING  = 5,
+      IVL_VT_DARRAY  = 6,  /* Array (esp. dynamic array) */
+      IVL_VT_CLASS   = 7,  /* SystemVerilog class instances */
+      IVL_VT_QUEUE   = 8,  /* SystemVerilog queue instances */
+      IVL_VT_VECTOR = IVL_VT_LOGIC /* For compatibility */
+"""
 
 NN_NONE = 'NONE'
 NN_IMPLICIT = 'IMPLICIT'
@@ -85,6 +97,32 @@ NP_POUTPUT = 'POUTPUT'
 NP_PINOUT = 'PINOUT'
 NP_PREF = 'PREF'
 
+def indent(s, i=4):
+    st = ''
+    for x in s:
+        st += str(x)
+    res = []
+    for p in st.split('\n'):
+        res.append(' ' * i + p)
+    return '\n'.join(res)
+
+
+class DataType:
+    def __init__(self, typ, signed):
+        self.typ = typ
+        self.signed = signed
+
+def port_decl(comment, dt, name):
+    if dt.dims is None:
+        width = '' # width: 1
+    else:
+        width = dt.dims
+        # XXX TODO, better checking, should be using data structure... *sigh*
+        width = width[1:-1] # strip brackets
+        width = width.split(':')
+        assert width[0] == '0'
+        width = width[1]
+    return 'self.%s = Signal(%s) # %s' % (name, width, comment)
 
 # -------------- RULES ----------------
 ()
@@ -519,6 +557,15 @@ def p_data_declaration_1(p):
 def p_data_type_1(p):
     '''data_type : integer_vector_type unsigned_signed_opt dimensions_opt '''
     print('data_type_1', list(p))
+    use_vtype = p[1]
+    reg_flag = False
+    if (use_vtype == IVL_VT_NO_TYPE):
+        use_vtype = IVL_VT_LOGIC
+        reg_flag = True
+    dt = DataType(use_vtype, signed=p[2])
+    dt.dims = p[3]
+    dt.reg_flag = reg_flag
+    p[0] = dt
     # { ivl_variable_type_t use_vtype = $1;
     #  bool reg_flag = false;
     #  if (use_vtype == IVL_VT_NO_TYPE) {
@@ -534,6 +581,7 @@ def p_data_type_1(p):
 def p_data_type_2(p):
     '''data_type : non_integer_type '''
     print('data_type_2', list(p))
+    p[0] = p[1]
     # { real_type_t*tmp = new real_type_t($1);
     #  FILE_NAME(tmp, @1);
     #  $$ = tmp;
@@ -542,6 +590,7 @@ def p_data_type_2(p):
 def p_data_type_3(p):
     '''data_type : struct_data_type '''
     print('data_type_3', list(p))
+    p[0] = p[1]
     # { if (!$1->packed_flag) {
     #        yyerror(@1, "sorry: Unpacked structs not supported.");
     #  }
@@ -987,13 +1036,13 @@ def p_loop_statement_2(p):
     print('loop_statement_2', list(p))
     # { pform_name_t tmp_hident;
     #  tmp_hident.push_back(name_component_t(lex_strings.make($4)));
-    # 
+    #
     #  PEIdent*tmp_ident = pform_new_ident(tmp_hident);
     #  FILE_NAME(tmp_ident, @4);
-    # 
+    #
     #  PForStatement*tmp_for = new PForStatement(tmp_ident, $6, $8, $10, $13);
     #  FILE_NAME(tmp_for, @1);
-    # 
+    #
     #  pform_pop_scope();
     #  vector<Statement*>tmp_for_list (1);
     #  tmp_for_list[0] = tmp_for;
@@ -1040,7 +1089,7 @@ def p_loop_statement_7(p):
     '''loop_statement : K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' _embed1_loop_statement statement_or_null '''
     print('loop_statement_7', list(p))
     # { PForeach*tmp_for = pform_make_foreach(@1, $3, $5, $9);
-    # 
+    #
     #  pform_pop_scope();
     #  vector<Statement*>tmp_for_list(1);
     #  tmp_for_list[0] = tmp_for;
@@ -1101,7 +1150,7 @@ def p__embed0_loop_statement(p):
     #  PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ);
     #  FILE_NAME(tmp, @1);
     #  current_block_stack.push(tmp);
-    # 
+    #
     #  list<decl_assignment_t*>assign_list;
     #  decl_assignment_t*tmp_assign = new decl_assignment_t;
     #  tmp_assign->name = lex_strings.make($4);
@@ -1115,11 +1164,11 @@ def p__embed1_loop_statement(p):
     #  char for_block_name[64];
     #  snprintf(for_block_name, sizeof for_block_name, "$ivl_foreach%u", foreach_counter);
     #  foreach_counter += 1;
-    # 
+    #
     #  PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ);
     #  FILE_NAME(tmp, @1);
     #  current_block_stack.push(tmp);
-    # 
+    #
     #  pform_make_foreach_declarations(@1, $5);
     #       }
 ()
@@ -1981,7 +2030,7 @@ def p_tf_port_item_1(p):
     #               use_port_type = port_declaration_context.port_type;
     #  perm_string name = lex_strings.make($3);
     #  list<perm_string>* ilist = list_from_identifier($3);
-    # 
+    #
     #  if (use_port_type == NetNet::PIMPLICIT) {
     #        yyerror(@1, "error: missing task/function port direction.");
     #        use_port_type = NetNet::PINPUT; // for error recovery
@@ -1996,7 +2045,7 @@ def p_tf_port_item_1(p):
     #        tmp = pform_make_task_ports(@3, use_port_type,
     #                                    port_declaration_context.data_type,
     #                                    ilist);
-    # 
+    #
     #  } else {
     #          // Otherwise, the decorations for this identifier
     #          // indicate the type. Save the type for any right
@@ -2012,7 +2061,7 @@ def p_tf_port_item_1(p):
     #  if ($4 != 0) {
     #        pform_set_reg_idx(name, $4);
     #  }
-    # 
+    #
     #  $$ = tmp;
     #  if ($5) {
     #        assert(tmp->size()==1);
@@ -2147,6 +2196,16 @@ def p_variable_dimension_1(p):
     #  tmp->push_back(index);
     #  $$ = tmp;
     #       }
+    # XXX TODO: subscriptlist
+    start = str(p[4])
+    end = str(p[2])
+    if end.endswith("-1"):
+        end = end[:-2]
+    elif end.isdigit():
+        end = str(int(end)+1)
+    else:
+        end = "1+%s" % end
+    p[0] = '[%s:%s]' % (start, end) # python slice is LO:HI+1
 ()
 def p_variable_dimension_2(p):
     '''variable_dimension : '[' expression ']' '''
@@ -2379,7 +2438,7 @@ def p_type_declaration_2(p):
     # { perm_string name = lex_strings.make($3.text);
     #  if (pform_test_type_identifier_local(name)) {
     #        yyerror(@3, "error: Typedef identifier \"%s\" is already a type name.", $3.text);
-    # 
+    #
     #  } else {
     #        pform_set_typedef(name, $2, NULL);
     #  }
@@ -2898,7 +2957,7 @@ def p_delay_value_simple_4(p):
     '''delay_value_simple : TIME_LITERAL '''
     print('delay_value_simple_4', list(p))
     # { int unit;
-    # 
+    #
     #            based_size = 0;
     #            $$         = 0;
     #            if ($1 == 0 || !get_time_unit($1, unit))
@@ -2907,7 +2966,7 @@ def p_delay_value_simple_4(p):
     #                  double p = pow(10.0,
     #                                 (double)(unit - pform_get_timeunit()));
     #                  double time = atof($1) * p;
-    # 
+    #
     #                  verireal *v = new verireal(time);
     #                  $$ = new PEFNumber(v);
     #                  FILE_NAME($$, @1);
@@ -3450,6 +3509,7 @@ def p_expression_25(p):
     #  FILE_NAME(tmp, @2);
     #  $$ = tmp;
     #       }
+    p[0] = Node(syms.atom, [p[1], Leaf(token.MINUS, '-'), p[4]])
 ()
 def p_expression_26(p):
     '''expression : expression '&' attribute_list_opt expression '''
@@ -3755,7 +3815,7 @@ def p_expr_primary_4(p):
     '''expr_primary : TIME_LITERAL '''
     print('expr_primary_4', list(p))
     # { int unit;
-    # 
+    #
     #           based_size = 0;
     #           $$         = 0;
     #           if ($1 == 0 || !get_time_unit($1, unit))
@@ -3763,7 +3823,7 @@ def p_expr_primary_4(p):
     #           else {
     #               double p = pow(10.0, (double)(unit - pform_get_timeunit()));
     #               double time = atof($1) * p;
-    # 
+    #
     #               verireal *v = new verireal(time);
     #               $$ = new PEFNumber(v);
     #               FILE_NAME($$, @1);
@@ -4642,6 +4702,7 @@ def p_list_of_ports_2(p):
 def p_list_of_port_declarations_1(p):
     '''list_of_port_declarations : port_declaration '''
     print('list_of_port_declarations_1', list(p))
+    p[0] = [p[1]]
     # { vector<Module::port_t*>*tmp
     #                    = new vector<Module::port_t*>(1);
     #            (*tmp)[0] = $1;
@@ -4651,6 +4712,10 @@ def p_list_of_port_declarations_1(p):
 def p_list_of_port_declarations_2(p):
     '''list_of_port_declarations : list_of_port_declarations ',' port_declaration '''
     print('list_of_port_declarations_2', list(p))
+    p[1].append(Leaf(token.NEWLINE, '\n')) # should be a comma
+    # XXX p[3].prefix=' ' # add a space after the NL, must go in parameter
+    p[1].append(p[3])
+    p[0] = p[1]
     # { vector<Module::port_t*>*tmp = $1;
     #            tmp->push_back($3);
     #            $$ = tmp;
@@ -4665,7 +4730,7 @@ def p_list_of_port_declarations_3(p):
     #                                               @3.first_line);
     #            vector<Module::port_t*>*tmp = $1;
     #            tmp->push_back(ptmp);
-    # 
+    #
     #              /* Get the port declaration details, the port type
     #                 and what not, from context data stored by the
     #                 last port_declaration rule. */
@@ -4696,6 +4761,9 @@ def p_list_of_port_declarations_5(p):
 def p_port_declaration_1(p):
     '''port_declaration : attribute_list_opt K_input net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt '''
     print('port_declaration_1', list(p))
+    # XXX TODO: python AST
+    comment, dt, name = p[2], p[4], p[5]
+    p[0] = port_decl(comment, dt, name)
     # { Module::port_t*ptmp;
     #  perm_string name = lex_strings.make($5);
     #  data_type_t*use_type = $4;
@@ -4766,6 +4834,9 @@ def p_port_declaration_4(p):
 def p_port_declaration_5(p):
     '''port_declaration : attribute_list_opt K_output net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt '''
     print('port_declaration_5', list(p))
+    # XXX TODO: python AST
+    comment, dt, name = p[2], p[4], p[5]
+    p[0] = port_decl(comment, dt, name)
     # { Module::port_t*ptmp;
     #  perm_string name = lex_strings.make($5);
     #  data_type_t*use_dtype = $4;
@@ -4779,7 +4850,7 @@ def p_port_declaration_5(p):
     #                    use_type = NetNet::IMPLICIT;
     #              else
     #                    use_type = NetNet::IMPLICIT_REG;
-    # 
+    #
     #                // The SystemVerilog types that can show up as
     #                // output ports are implicitly (on the inside)
     #                // variables because "reg" is not valid syntax
@@ -4841,9 +4912,9 @@ def p_port_declaration_7(p):
     #  port_declaration_context.port_type = NetNet::PINOUT;
     #  port_declaration_context.port_net_type = use_type;
     #  port_declaration_context.data_type = $4;
-    # 
+    #
     #  pform_make_var_init(@5, name, $7);
-    # 
+    #
     #  delete[]$5;
     #  $$ = ptmp;
     #       }
@@ -4856,7 +4927,7 @@ def p_net_type_opt_1(p):
 def p_net_type_opt_2(p):
     '''net_type_opt :  '''
     print('net_type_opt_2', list(p))
-    # { $$ = NetNet::IMPLICIT; }
+    p[0] = NN_IMPLICIT
 ()
 def p_unsigned_signed_opt_1(p):
     '''unsigned_signed_opt : K_signed '''
@@ -4991,13 +5062,16 @@ def p_module_1(p):
     else:
         stmts = Node(syms.small_stmt, [pass_stmt, Leaf(token.NEWLINE, '\n')])
         stmts = Node(syms.stmt, [stmts])
+
+    # XXX TODO ports as py nodes
+    ports = p[8]
+    stmts.children.append(Leaf(token.STRING, '\n' + indent(ports, 8)))
     suite = Node(syms.suite, [Leaf(token.NEWLINE, '\n'),
                               Leaf(token.INDENT, '    '),
                               stmts,
                               Leaf(token.DEDENT, '')
                              ])
-    clsdecl = Node(syms.classdef, clsname + [suite],
-                   prefix='', fixers_applied=[])
+    clsdecl = Node(syms.classdef, clsname + [suite])
     clsdecl = Node(syms.compound_stmt, [clsdecl])
     print ("clsdecl", repr(clsdecl))
     print ("clsstr:")
@@ -5187,7 +5261,8 @@ def p_module_parameter_port_list_3(p):
     '''module_parameter_port_list : module_parameter_port_list ',' K_parameter param_type parameter_assign '''
     print('module_parameter_port_list_3', list(p))
     p[1].append(Leaf(token.COMMA, ','))
-    p[5].prefix=' ' # add a space after the comma, must go in the parameter
+    p[1].append(Leaf(token.NEWLINE, '\n'))
+    p[5].prefix='                 ' # add space after newline
     p[1].append(p[5])
     p[0] = p[1]
 ()
@@ -5334,7 +5409,7 @@ def p_module_item_13(p):
     #              use_type = NetNet::REG;
     #        else
     #              use_type = NetNet::IMPLICIT_REG;
-    # 
+    #
     #          // The SystemVerilog types that can show up as
     #          // output ports are implicitly (on the inside)
     #          // variables because "reg" is not valid syntax
@@ -6142,7 +6217,7 @@ def p_parameter_value_opt_3(p):
     # { assert($2);
     #            PENumber*tmp = new PENumber($2);
     #            FILE_NAME(tmp, @1);
-    # 
+    #
     #            struct parmvalue_t*lst = new struct parmvalue_t;
     #            lst->by_order = new list<PExpr*>;
     #            lst->by_order->push_back(tmp);
@@ -6157,7 +6232,7 @@ def p_parameter_value_opt_4(p):
     # { assert($2);
     #            PEFNumber*tmp = new PEFNumber($2);
     #            FILE_NAME(tmp, @1);
-    # 
+    #
     #            struct parmvalue_t*lst = new struct parmvalue_t;
     #            lst->by_order = new list<PExpr*>;
     #            lst->by_order->push_back(tmp);
@@ -6343,20 +6418,20 @@ def p_port_reference_2(p):
     #    itmp.sel = index_component_t::SEL_PART;
     #    itmp.msb = $3;
     #    itmp.lsb = $5;
-    # 
+    #
     #    name_component_t ntmp (lex_strings.make($1));
     #    ntmp.index.push_back(itmp);
-    # 
+    #
     #    pform_name_t pname;
     #    pname.push_back(ntmp);
-    # 
+    #
     #    PEIdent*wtmp = new PEIdent(pname);
     #    FILE_NAME(wtmp, @1);
-    # 
+    #
     #    Module::port_t*ptmp = new Module::port_t;
     #    ptmp->name = perm_string();
     #    ptmp->expr.push_back(wtmp);
-    # 
+    #
     #    delete[]$1;
     #    $$ = ptmp;
     #  }
@@ -6368,16 +6443,16 @@ def p_port_reference_3(p):
     #    itmp.sel = index_component_t::SEL_BIT;
     #    itmp.msb = $3;
     #    itmp.lsb = 0;
-    # 
+    #
     #    name_component_t ntmp (lex_strings.make($1));
     #    ntmp.index.push_back(itmp);
-    # 
+    #
     #    pform_name_t pname;
     #    pname.push_back(ntmp);
-    # 
+    #
     #    PEIdent*tmp = new PEIdent(pname);
     #    FILE_NAME(tmp, @1);
-    # 
+    #
     #    Module::port_t*ptmp = new Module::port_t;
     #    ptmp->name = perm_string();
     #    ptmp->expr.push_back(tmp);