PyHDI / Pyverilog

Python-based Hardware Design Processing Toolkit for Verilog HDL
Apache License 2.0
640 stars 180 forks source link

Parser Error for resettable D Flip-Flop #112

Open kwmartin opened 2 years ago

kwmartin commented 2 years ago

The D-Flip Flop below parses find using iverilog but gives a parse error at the ASSIGN token coming after a basic_statement: ERROR: Error : MODULE modulename paramlist portlist items ALWAYS senslist BEGIN IF LPAREN cond RPAREN BEGIN basic_statement . LexToken(ASSIGN,'assign',23,327) It seems to me that it should parse correctly as according to A.6.4 Statements, a conditional_statement is allowed wherever a blocking_assignment or a nonblocking_assignment is allowed? The verilog code for the D-Flip Flop is:

`define DLY_MLTPLY 1.0 // Change for different technologies
`timescale 1ps/10fs
module dg_dflp_r_3x1 (d,r,cp,cn,qop,qon,vdd,vss);
input d,r,cp,cn,vdd,vss;
output qop,qon;
reg qp,qn;
assign qop = qp;
assign qon = qn;
    initial
      begin
        qp = 0;
        qn = 1;
      end
    always @(r)
        begin
        if (r)
            begin
            #(20 * `DLY_MLTPLY);
            assign qp = 0;
            assign qn = 1;
            end
        else
            begin
            deassign qp;
            deassign qn;
            end
        end
    always @(negedge cp)
        begin
            qp <= #(75 * `DLY_MLTPLY) d; // non-blocking assignment occur simultaneously
            qn <= #(75 * `DLY_MLTPLY) ~d;
        end
endmodule
kwmartin commented 2 years ago

Making the following changes, allows the resettable D-FF to be parsed: 1) Remove the ';' from #(20 * `DLY_MLTPLY); This makes the delay part of the following assignment statement. This shouldn't be necessary; a simple delay statement should really be added to basic_statements: in parser.py 2) In lexer.py add DEASSIGN to the key words. 3) In parser.py add assignment and deassignment to basic_statements 4) In parser.py, I also added deassignment to standard_item:. I haven't tracked this down enough to know if this is correct 5) In parser.py, I added/changed the following rules (note: assignment: and assignment_delay: are unchanged but included for clarity

    def p_assignment(self, p):
        'assignment : ASSIGN lvalue EQUALS rvalue SEMICOLON'
        p[0] = Assign(p[2], p[4], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_assignment_delay(self, p):
        'assignment : ASSIGN delays lvalue EQUALS delays rvalue SEMICOLON'
        p[0] = Assign(p[3], p[6], p[2], p[5], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_assignment_delay2(self, p):
        'assignment : delays ASSIGN lvalue EQUALS rvalue SEMICOLON'
        p[0] = Assign(p[3], p[5], p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_deassignment(self, p):
        'deassignment : DEASSIGN lvalue SEMICOLON'
        p[0] = Deassign(p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_deassignment_delay(self, p):
        'deassignment : DEASSIGN delays lvalue SEMICOLON'
        p[0] = Deassign(p[3], p[2], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

    def p_deassignment_delay2(self, p):
        'deassignment : delays DEASSIGN lvalue SEMICOLON'
        p[0] = Deassign(p[3], p[1], lineno=p.lineno(1))
        p.set_lineno(0, p.lineno(1))

In ast.py, I added:

class Deassign(Node):
    attr_names = ()

    def __init__(self, left, ldelay=None, lineno=0):
        self.lineno = lineno
        self.left = left
        self.ldelay = ldelay

    def children(self):
        nodelist = []
        if self.left:
            nodelist.append(self.left)
        if self.ldelay:
            nodelist.append(self.ldelay)
        return tuple(nodelist)

This now allows my flip-flops in my stardard library to parse. I'm pretty sure, there are better ways of doing this; my approach is just quick and dirty to allow me to go forward. Since my changes will be over-written at the next update, it doesn't make sense right now to try and make them 'clean'. Still, if you use assign statements to implement asynchronous sets and resets, these changes should suffice.