Skip to content
Snippets Groups Projects
Commit 95026195 authored by Stefan Tauner's avatar Stefan Tauner Committed by Wilson Snyder
Browse files

Support Verilog::SigParser pin select parsing, msg1626.

parent 16fd0e63
No related branches found
No related tags found
No related merge requests found
......@@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
* Verilog::Language 3.427 devel
** Support Verilog::SigParser pin select parsing, msg1626. [by Stefan Tauner]
* Verilog::Language 3.426 2017-06-06
......
......@@ -88,6 +88,7 @@ t/34_parser.out
t/34_parser.t
t/35_sigparser.out
t/35_sigparser.t
t/35_sigparser_ps.out
t/36_sigmany.t
t/40_netlist.t
t/41_example.t
......
......@@ -58,6 +58,7 @@ sub new {
use_vars => 1,
use_unreadback => 1, # Backward compatibility
use_protected => 1, # Backward compatibility
use_pinselects => 0, # Backward compatibility
use_std => undef, # Undef = silent
#use_cb_{callback-name} => 0/1
#
......@@ -72,6 +73,7 @@ sub new {
$self->{_sigparser},
$self->{use_unreadback},
$self->{use_protected},
$self->{use_pinselects}, # Undocumented as for use in SigParser only
);
$self->{use_cb_contassign} = $self->{use_vars} if !exists $self->{use_cb_contassign};
......
......@@ -44,6 +44,12 @@ extern "C" {
# undef open /* Perl 64 bit on solaris has a nasty hack that redefines open */
#endif
// This is a global constant pointer initialized to its own address to
// produce a unique address to distinguish hashes (pointers to
// struct VParseHashElem) from the strings (character pointers) used by
// callbackgen in its variadic parameters for VParserXs::call().
static void *hasharray_param = &hasharray_param;
class VFileLineParseXs;
#//**********************************************************************
......@@ -86,6 +92,7 @@ public:
bool m_useCb_package:1;
bool m_useCb_parampin:1;
bool m_useCb_pin:1;
bool m_useCb_pinselects:1;
bool m_useCb_port:1;
bool m_useCb_preproc:1;
bool m_useCb_program:1;
......@@ -101,8 +108,8 @@ public:
void cbFileline(VFileLine* filelinep) { m_cbFilelinep = filelinep; }
VParserXs(VFileLine* filelinep, av* symsp,
bool sigparser, bool useUnreadback, bool useProtected)
: VParse(filelinep, symsp, sigparser, useUnreadback, useProtected)
bool sigparser, bool useUnreadback, bool useProtected, bool usePinselects)
: VParse(filelinep, symsp, sigparser, useUnreadback, useProtected, usePinselects)
, m_cbFilelinep(filelinep)
{ set_cb_use(); }
virtual ~VParserXs();
......@@ -138,6 +145,7 @@ public:
m_useCb_package = true;
m_useCb_parampin = true;
m_useCb_pin = true;
m_useCb_pinselects = true;
m_useCb_port = true;
m_useCb_preproc = true;
m_useCb_program = true;
......@@ -184,6 +192,7 @@ public:
virtual void packageCb(VFileLine* fl, const string& kwd, const string& name);
virtual void parampinCb(VFileLine* fl, const string& name, const string& conn, int index);
virtual void pinCb(VFileLine* fl, const string& name, const string& conn, int index);
virtual void pinselectsCb(VFileLine* fl, const string& name, unsigned int arraycnt2, unsigned int elemcnt2, const VParseHashElem* conns2, int index);
virtual void portCb(VFileLine* fl, const string& name, const string& objof, const string& direction, const string& data_type
, const string& array, int index);
virtual void programCb(VFileLine* fl, const string& kwd, const string& name);
......@@ -262,14 +271,44 @@ void VParserXs::call (
XPUSHs(sv_2mortal(selfsv));
while (params--) {
char* text = va_arg(ap, char *);
char* textp = va_arg(ap, char *);
if (textp == hasharray_param) {
// First hasharray param defines number of array elements
unsigned int arrcnt = va_arg(ap, unsigned int);
AV* av = newAV();
av_extend(av, arrcnt);
// Second hasharray param defines how many keys are within one hash
unsigned int elemcnt = va_arg(ap, unsigned int);
// Followed by the hash array pointer...
VParseHashElem (*arrp)[elemcnt] = va_arg(ap, VParseHashElem (*)[elemcnt]);
for (unsigned int i = 0; i < arrcnt; i++) {
HV* hv = newHV();
const VParseHashElem* elemp = arrp[i];
for (unsigned int j = 0; j < elemcnt; j++) {
if (!elemp[j].keyp)
continue;
SV* sv;
if (text) {
sv = sv_2mortal(newSVpv (text, 0));
switch (elemp[j].val_type) {
case VParseHashElem::ELEM_INT:
sv = newSViv(elemp[j].val_int);
break;
case VParseHashElem::ELEM_STR:
default:
sv = newSVpv(elemp[j].val_str.c_str(), 0);
break;
}
hv_store(hv, elemp[j].keyp, strlen(elemp[j].keyp), sv, 0);
}
av_store(av, i, newRV_noinc((SV*)hv));
elemp++;
}
XPUSHs(newRV_noinc(sv_2mortal((SV*)av)));
} else if (textp) { // Non hasharray_param, so is text
XPUSHs(sv_2mortal(newSVpv (textp, 0)));
} else {
sv = &PL_sv_undef;
XPUSHs(&PL_sv_undef);
}
XPUSHs(sv); /* token */
}
PUTBACK; /* make local stack pointer global */
......@@ -305,14 +344,14 @@ MODULE = Verilog::Parser PACKAGE = Verilog::Parser
#// self->_new (class, sigparser)
static VParserXs *
VParserXs::_new (SV* SELF, AV* symsp, bool sigparser, bool useUnreadback, bool useProtected)
VParserXs::_new (SV* SELF, AV* symsp, bool sigparser, bool useUnreadback, bool useProtected, bool usePinselects)
PROTOTYPE: $$$$
CODE:
{
if (CLASS) {} /* Prevent unused warning */
if (!SvROK(SELF)) { warn("${Package}::$func_name() -- SELF is not a hash reference"); }
VFileLineParseXs* filelinep = new VFileLineParseXs(NULL/*ok,for initial*/);
VParserXs* parserp = new VParserXs(filelinep, symsp, sigparser, useUnreadback, useProtected);
VParserXs* parserp = new VParserXs(filelinep, symsp, sigparser, useUnreadback, useProtected, usePinselects);
filelinep->setParser(parserp);
parserp->m_self = SvRV(SELF);
RETVAL = parserp;
......
......@@ -40,6 +40,7 @@ our @_Callback_Names = qw(
package
parampin
pin
pinselects
port
program
task
......@@ -55,6 +56,7 @@ sub new {
my $self = $class->SUPER::new(_sigparser => 1,
use_unreadback => 0,
use_protected => 0,
use_pinselects => 0,
@_);
bless $self, $class;
$self->debug($Debug) if $Debug;
......@@ -208,6 +210,13 @@ sub pin {
my $number = shift;
}
sub pinselects {
my $self = shift;
my $name = shift;
my $conns = shift;
my $number = shift;
}
sub package {
my $self = shift;
my $kwd = shift;
......@@ -424,13 +433,22 @@ instantiation is for an UDP versus a module.
=item $self->pin ( $name, $connection, $index )
This method is called when a pin on a instant is defined. If a pin name
This method is called when a pin on an instant is defined and "use_pinselects"
is not set (the default, see pinselects() below. If a pin name
was not provided and the connection is by position, name will be '' or
undef.
If you do not need the pin nor var nor port callbacks, consider the
"$self->new (... use_vars=>0 ...)" option to accelerate parsing.
=item $self->pinselects ( $name, $connections, $index )
If "$self->new (... use_pinselects=>1 ...)" is used this function is called
instead of "$self->pin (...)". The difference is that the second parameter
("$connections") is a Perl hash that contains all connected nets in the
case of concatenations including the MSB and LSB bounds used at these
locations.
=item $self->port ( $name, $objof, $direction, $data_type, $array, $pinnum )
This method is called when a module port is defined. It may be called
......
......@@ -39,13 +39,14 @@ VParseGrammar* VParseGrammar::s_grammarp = NULL;
//*************************************************************************
VParse::VParse(VFileLine* filelinep, av* symsp,
bool sigParser, bool useUnreadbackFlag, bool useProtected)
bool sigParser, bool useUnreadbackFlag, bool useProtected, bool usePinselects)
: m_syms(filelinep, symsp)
{
m_inFilelinep = filelinep;
m_sigParser = sigParser;
m_useUnreadback = useUnreadbackFlag;
m_useProtected = useProtected;
m_usePinselects = usePinselects;
m_debug = 0;
m_lexp = new VParseLex(this);
m_grammarp = new VParseGrammar(this);
......
......@@ -38,6 +38,15 @@ struct VParseBisonYYSType;
struct av;
struct VParseHashElem {
const char* keyp;
enum {ELEM_STR, ELEM_INT} val_type;
string val_str; // When val_type==ELEM_STR
int val_int; // When val_type==ELEM_INT
VParseHashElem() { keyp = NULL; }
~VParseHashElem() {}
};
//**********************************************************************
// VParse
......@@ -57,6 +66,7 @@ private:
bool m_useUnreadback;///< Need m_unreadback tracking
bool m_useProtected; ///< Need `protected tracking
bool m_usePinselects;///< Need bit-select parsing
string m_unreadback; ///< Otherwise unprocessed whitespace before current token
deque<string> m_buffers; ///< Buffer of characters to process
......@@ -113,7 +123,7 @@ private:
public:
// CONSTRUCTORS
VParse(VFileLine* filelinep, av* symsp,
bool sigParser, bool useUnreadbackFlag, bool useProtected);
bool sigParser, bool useUnreadbackFlag, bool useProtected, bool usePinselects);
virtual ~VParse();
// ACCESSORS
......@@ -127,6 +137,7 @@ public:
void callbackMasterEna(bool flag) { m_callbackMasterEna=flag; }
bool callbackMasterEna() const { return m_callbackMasterEna; }
bool useProtected() const { return m_useProtected; }
bool usePinSelects() const { return m_usePinselects; }
VFileLine* inFilelinep() const; ///< File/Line number for last callback
void inFileline(const string& filename, int lineno) { m_inFilelinep = m_inFilelinep->create(filename, lineno); }
......@@ -184,6 +195,7 @@ public:
virtual void packageCb(VFileLine* fl, const string& kwd, const string& name) = 0;
virtual void parampinCb(VFileLine* fl, const string& name, const string& conn, int index) = 0;
virtual void pinCb(VFileLine* fl, const string& name, const string& conn, int index) = 0;
virtual void pinselectsCb(VFileLine* fl, const string& name, unsigned int arraycnt2, unsigned int elemcnt2, const VParseHashElem* conns2, int index) = 0;
virtual void portCb(VFileLine* fl, const string& name, const string& objof, const string& direction, const string& data_type
, const string& array, int index) = 0;
virtual void programCb(VFileLine* fl, const string& kwd, const string& name) = 0;
......
......@@ -30,6 +30,10 @@
#include <map>
#include <deque>
#include <cassert>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <climits>
#include "VParse.h"
#include "VParseGrammar.h"
......@@ -61,7 +65,10 @@
#define PINNUMINC() { GRAMMARP->pinNumInc(); }
#define INSTPREP(cellmod,cellparam) { GRAMMARP->pinNum(1); GRAMMARP->m_cellMod=(cellmod); GRAMMARP->m_cellParam=(cellparam); }
#define INSTPREP(cellmod,cellparam,withinInst) { GRAMMARP->pinNum(1); GRAMMARP->m_cellMod=(cellmod); GRAMMARP->m_cellParam=(cellparam); GRAMMARP->m_withinInst = 1; }
#define INSTDONE() { GRAMMARP->m_withinInst = 0; }
enum net_idx {NI_NETNAME = 0, NI_MSB, NI_LSB};
static void VARDONE(VFileLine* fl, const string& name, const string& array, const string& value) {
if (GRAMMARP->m_varIO!="" && GRAMMARP->m_varDecl=="") GRAMMARP->m_varDecl="port";
......@@ -85,22 +92,200 @@ static void VARDONETYPEDEF(VFileLine* fl, const string& name, const string& type
PARSEP->syms().replaceInsert(VAstType::TYPE,name);
}
static void parse_net_constants(VFileLine* fl, VParseHashElem nets[][3]) {
VParseHashElem (*net)[3] = &nets[0];
VParseHashElem* nhp = net[0];
std::deque<VParseNet>::iterator it = GRAMMARP->m_portStack.begin();
while (it != GRAMMARP->m_portStack.end()) {
// Default net name is simply the complete token
const char* netnamep = it->m_name.c_str();
size_t delim = it->m_name.find_first_of("'");
if (it->m_name[0] != '\\' && it->m_msb.empty() && it->m_name[delim] == '\'') {
// Handle sized integer constants (e.g., 7'b0) specifically
if (delim != 0) {
// Handle the first part that indicates the width for sized constants (guaranteed to be a decimal)
char* endp;
errno = 0;
long l = strtol(netnamep, &endp, 10);
if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX || l <= 0) {
fl->error((string)"Unexpected length in size of integer constant: \""+netnamep+"\".");
return;
}
// Skip whitespace
while (endp < netnamep + delim && isspace(*endp)) {
endp++;
}
if (endp != netnamep + delim) {
fl->error((string)"Could not convert size of integer constant: \""+netnamep+"\".");
return;
}
int count = l;
// Skip characters up to the delimiter ' to determine new netnamep
netnamep += delim;
// Test for legal base specifiers:
// d, D, h, H, o, O , b, or B for the decimal, hexadecimal, octal, and binary bases, respectively
char base = netnamep[1];
// 's' indicates a signed constant, is followed by the actual base; currently ignored
if (base == 's' || base == 'S') {
base = netnamep[2];
}
if (strchr("dDhHoObB", base) == NULL) {
fl->error((string)"Base specifier \""+base+"\" is not valid in integer constant \""+it->m_name.c_str()+"\".");
return;
}
// These assignments could be prettified with C++11
nhp[NI_MSB].keyp = "msb";
nhp[NI_MSB].val_type = VParseHashElem::ELEM_INT;
nhp[NI_MSB].val_int = count - 1;
nhp[NI_LSB].keyp = "lsb";
nhp[NI_LSB].val_type = VParseHashElem::ELEM_INT;
nhp[NI_LSB].val_int = 0;
} else {
// fl->error increases the error count which would create regressions for no good reasons.
// There is no ->warn or similar though but we could print, e.g., to stderr in these cases
//fl->error((string)"Unsized integer constant are not fully supported in nets (\""+netnamep+"\").");
//fprintf(stderr, "Unsized integer constant are not fully supported in nets (\"%s\").", netnamep);
}
} else {
// Ordinary net names might have a range attached or not.
// If it does then parse its bounds into proper integers.
const char *msbstr = it->m_msb.c_str();
if (msbstr[0] != '\0') {
{ // Parse NI_MSB
char* endp;
errno = 0;
long l = strtol(msbstr, &endp, 10);
// Test for range within int, and proper parsing
if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX || l < 0 || (endp != NULL && l == 0 && errno == ERANGE)) {
fl->error((string)"Unexpected length in msb specification of \""+netnamep+"\" (endp="+endp+", errno="+strerror(errno)+").");
return;
}
nhp[NI_MSB].keyp = "msb";
nhp[NI_MSB].val_type = VParseHashElem::ELEM_INT;
nhp[NI_MSB].val_int = (int)l;
}
{ // Parse NI_LSB
char* endp;
errno = 0;
long l = strtol(it->m_lsb.c_str(), &endp, 10);
if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX || l < 0 || (endp != NULL && l == 0 && errno == ERANGE)) {
fl->error((string)"Unexpected length in lsb specification of \""+netnamep+"\".");
return;
}
nhp[NI_LSB].keyp = "lsb";
nhp[NI_LSB].val_type = VParseHashElem::ELEM_INT;
nhp[NI_LSB].val_int = (int)l;
}
} else {
nhp[NI_MSB].keyp = NULL;
nhp[NI_LSB].keyp = NULL;
}
}
nhp[NI_NETNAME].keyp = "netname";
nhp[NI_NETNAME].val_type = VParseHashElem::ELEM_STR;
nhp[NI_NETNAME].val_str = netnamep;
*it++;
nhp += 3; // We operate on three elements in each iteration
}
}
static void PINDONE(VFileLine* fl, const string& name, const string& expr) {
if (GRAMMARP->m_cellParam) {
// Stack them until we create the instance itself
GRAMMARP->m_pinStack.push_back(VParseGPin(fl, name, expr, GRAMMARP->pinNum()));
} else {
PARSEP->pinCb(fl, name, expr, GRAMMARP->pinNum());
if (PARSEP->usePinSelects()) {
if (GRAMMARP->m_portStack.empty()) {
string netname;
if (GRAMMARP->m_portNextNetName.empty()) {
netname = expr;
} else {
netname = GRAMMARP->m_portNextNetName;
GRAMMARP->m_portNextNetName.clear();
}
size_t elem_cnt = GRAMMARP->m_portNextNetMsb.empty() ? 1 : 3;
VParseHashElem nets[elem_cnt];
// These assignments could be prettified with C++11
nets[NI_NETNAME].keyp = "netname";
nets[NI_NETNAME].val_type = VParseHashElem::ELEM_STR;
nets[NI_NETNAME].val_str = netname;
if (elem_cnt > 1) {
nets[NI_MSB].keyp = "msb";
nets[NI_MSB].val_type = VParseHashElem::ELEM_STR;
nets[NI_MSB].val_str = GRAMMARP->m_portNextNetMsb;
nets[NI_LSB].keyp = "lsb";
nets[NI_LSB].val_type = VParseHashElem::ELEM_STR;
nets[NI_LSB].val_str = GRAMMARP->m_portNextNetLsb;
}
PARSEP->pinselectsCb(fl, name, 1, elem_cnt, &nets[0], GRAMMARP->pinNum());
if (elem_cnt > 1) {
GRAMMARP->m_portNextNetMsb.clear();
GRAMMARP->m_portNextNetLsb.clear();
}
} else {
// Connection with multiple pins was parsed completely.
// There might be one net left in the pipe...
if (GRAMMARP->m_portNextNetValid) {
GRAMMARP->m_portStack.push_front(VParseNet(GRAMMARP->m_portNextNetName, GRAMMARP->m_portNextNetMsb, GRAMMARP->m_portNextNetLsb));
}
unsigned int arraycnt = GRAMMARP->m_portStack.size();
VParseHashElem nets[arraycnt][3];
parse_net_constants(fl, nets);
PARSEP->pinselectsCb(fl, name, arraycnt, 3, &nets[0][0], GRAMMARP->pinNum());
}
GRAMMARP->m_portNextNetValid = false;
GRAMMARP->m_portStack.clear();
}
}
}
static void PINPARAMS() {
// Throw out all the pins we found before we could do instanceCb
// Throw out all the "pins" we found before we could do instanceCb
while (!GRAMMARP->m_pinStack.empty()) {
VParseGPin& pinr = GRAMMARP->m_pinStack.front();
PARSEP->parampinCb(pinr.m_fl, pinr.m_name, pinr.m_conn, pinr.m_number);
GRAMMARP->m_pinStack.pop_front();
}
GRAMMARP->m_withinPin = true;
}
static void PORTNET(VFileLine* fl, const string& name) {
if (!GRAMMARP->m_withinInst) {
return;
}
GRAMMARP->m_portNextNetValid = true;
GRAMMARP->m_portNextNetName = name;
GRAMMARP->m_portNextNetMsb.clear();
GRAMMARP->m_portNextNetLsb.clear();
}
static void PORTRANGE(const string& msb, const string& lsb) {
if (!GRAMMARP->m_withinInst) {
return;
}
GRAMMARP->m_portNextNetMsb = msb;
GRAMMARP->m_portNextNetLsb = lsb;
}
static void PIN_CONCAT_APPEND(const string& expr) {
if (!GRAMMARP->m_withinPin) {
return;
}
// Only while not within a valid net term the expression is part of a replication constant.
if (!GRAMMARP->m_portNextNetValid) {
GRAMMARP->m_portStack.push_front(VParseNet(expr));
} else {
GRAMMARP->m_portStack.push_front(VParseNet(GRAMMARP->m_portNextNetName, GRAMMARP->m_portNextNetMsb, GRAMMARP->m_portNextNetLsb));
}
GRAMMARP->m_portNextNetValid = false;
}
/* Yacc */
......@@ -1973,10 +2158,11 @@ defparam_assignment: // ==IEEE: defparam_assignment
// checker_id name (pins) ; // checker_instantiation
etcInst: // IEEE: module_instantiation + gate_instantiation + udp_instantiation
instName {INSTPREP($1,1);} strengthSpecE parameter_value_assignmentE {INSTPREP($1,0);} instnameList ';'
{ }
instName { INSTPREP($1,1,0); } strengthSpecE parameter_value_assignmentE { INSTPREP($1,0,1); } instnameList ';'
{ INSTDONE(); }
// // IEEE: interface_identifier' .' modport_identifier list_of_interface_identifiers
| instName {INSTPREP($1,1);} '.' id {INSTPREP($1,0);} mpInstnameList ';' { }
| instName { INSTPREP($1,1,0); } '.' id {INSTPREP($1,0,0);} mpInstnameList ';'
{ INSTDONE(); }
;
instName<str>:
......@@ -1999,7 +2185,7 @@ mpInstnameParen: // Similar to instnameParen, but for modport instantiations wh
mpInstname: // Similar to instname, but for modport instantiations which have no parenthesis
// // id is-a: interface_port_identifier (interface.modport)
id instRangeE { PARSEP->instantCb($<fl>1, GRAMMARP->m_cellMod, $1, $2); PINPARAMS(); }
id instRangeE { PARSEP->instantCb($<fl>1, GRAMMARP->m_cellMod, $1, $2); }
;
instnameList:
......@@ -2027,11 +2213,11 @@ instRangeE<str>:
;
cellpinList:
{ VARRESET_LIST(""); } cellpinItList { VARRESET_NONLIST(""); }
{ VARRESET_LIST(""); } cellpinItList { VARRESET_NONLIST(""); GRAMMARP->m_withinPin = false; }
;
cellpinItList: // IEEE: list_of_port_connections + list_of_parameter_assignmente
cellpinItemE { }
{ GRAMMARP->m_portNextNetName.clear(); } cellpinItemE { }
| cellpinItList ',' cellpinItemE { }
;
......@@ -3123,7 +3309,7 @@ exprScope<str>: // scope and variable for use to inside an expression
| idArrayed { $<fl>$=$<fl>1; $$ = $1; }
| package_scopeIdFollows idArrayed { $<fl>$=$<fl>1; $$ = $1+$2; }
| class_scopeIdFollows idArrayed { $<fl>$=$<fl>1; $$ = $<str>1+$2; }
| ~l~expr '.' idArrayed { $<fl>$=$<fl>1; $$ = $1+"."+$3; }
| ~l~expr '.' idArrayed { $<fl>$=$<fl>1; $$ = $1+"."+$3; PORTNET($<fl>1, $$); }
// // expr below must be a "yTHIS"
| ~l~expr '.' ySUPER { $<fl>$=$<fl>1; $$ = $1+"."+$3; }
// // Part of implicit_class_handle
......@@ -3171,8 +3357,8 @@ exprOrDataTypeOrMinTypMax<str>: // exprOrDataType or mintypmax_expression
cateList<str>:
// // Not just 'expr' to prevent conflict via stream_concOrExprOrType
stream_expression { $<fl>$=$<fl>1; $$ = $1; }
| cateList ',' stream_expression { $<fl>$=$<fl>1; $$ = $1+","+$3; }
stream_expression { $<fl>$=$<fl>1; $$ = $1; PIN_CONCAT_APPEND($1); }
| cateList ',' stream_expression { $<fl>$=$<fl>1; $$ = $1+","+$3; PIN_CONCAT_APPEND($3); }
;
exprOrDataTypeList<str>:
......@@ -3291,15 +3477,15 @@ stream_expression<str>: // ==IEEE: stream_expression
// + n_input_gatetype + n_output_gatetype + pass_en_switchtype
// + pass_switchtype
gateKwd<str>:
ygenGATE { $<fl>$=$<fl>1; INSTPREP($1,0); }
| yAND { $<fl>$=$<fl>1; INSTPREP($1,0); }
| yBUF { $<fl>$=$<fl>1; INSTPREP($1,0); }
| yNAND { $<fl>$=$<fl>1; INSTPREP($1,0); }
| yNOR { $<fl>$=$<fl>1; INSTPREP($1,0); }
| yNOT { $<fl>$=$<fl>1; INSTPREP($1,0); }
| yOR { $<fl>$=$<fl>1; INSTPREP($1,0); }
| yXNOR { $<fl>$=$<fl>1; INSTPREP($1,0); }
| yXOR { $<fl>$=$<fl>1; INSTPREP($1,0); }
ygenGATE { $<fl>$=$<fl>1; INSTPREP($1,0,0); }
| yAND { $<fl>$=$<fl>1; INSTPREP($1,0,0); }
| yBUF { $<fl>$=$<fl>1; INSTPREP($1,0,0); }
| yNAND { $<fl>$=$<fl>1; INSTPREP($1,0,0); }
| yNOR { $<fl>$=$<fl>1; INSTPREP($1,0,0); }
| yNOT { $<fl>$=$<fl>1; INSTPREP($1,0,0); }
| yOR { $<fl>$=$<fl>1; INSTPREP($1,0,0); }
| yXNOR { $<fl>$=$<fl>1; INSTPREP($1,0,0); }
| yXOR { $<fl>$=$<fl>1; INSTPREP($1,0,0); }
;
// This list is also hardcoded in VParseLex.l
......@@ -3477,10 +3663,10 @@ idDottedForeachMore<str>:
// id below includes:
// enum_identifier
idArrayed<str>: // IEEE: id + select
id { $<fl>$=$<fl>1; $$ = $1; }
id { $<fl>$=$<fl>1; $$ = $1; PORTNET($<fl>1, $1);}
// // IEEE: part_select_range/constant_part_select_range
| idArrayed '[' expr ']' { $<fl>$=$<fl>1; $$ = $1+"["+$3+"]"; }
| idArrayed '[' constExpr ':' constExpr ']' { $<fl>$=$<fl>1; $$ = $1+"["+$3+":"+$5+"]"; }
| idArrayed '[' expr ']' { $<fl>$=$<fl>1; $$ = $1+"["+$3+"]"; PORTRANGE($3, $3);}
| idArrayed '[' constExpr ':' constExpr ']' { $<fl>$=$<fl>1; $$ = $1+"["+$3+":"+$5+"]"; PORTRANGE($3, $5);}
// // IEEE: indexed_range/constant_indexed_range
| idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $<fl>$=$<fl>1; $$ = $1+"["+$3+"+:"+$5+"]"; }
| idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $<fl>$=$<fl>1; $$ = $1+"["+$3+"-:"+$5+"]"; }
......
......@@ -33,7 +33,7 @@ using namespace std;
#include "VAst.h"
//============================================================================
// Container of things to put out later
// Containers of things to put out later
struct VParseGPin {
VFileLine* m_fl;
......@@ -44,6 +44,16 @@ struct VParseGPin {
: m_fl(fl), m_name(name), m_conn(conn), m_number(number) {}
};
struct VParseNet {
string m_name;
string m_msb;
string m_lsb;
VParseNet(const string& net, const string& msb, const string& lsb)
: m_name(net), m_msb(msb), m_lsb(lsb) {}
VParseNet(const string& net)
: m_name(net), m_msb(""), m_lsb("") {}
};
//============================================================================
// We can't use bison's %union as the string type doesn't fit in a union.
// It's fine to use a struct though!
......@@ -73,8 +83,16 @@ public: // Only for VParseBison
string m_cellMod;
bool m_cellParam;
bool m_portNextNetValid;
string m_portNextNetName;
string m_portNextNetMsb;
string m_portNextNetLsb;
bool m_withinPin;
bool m_withinInst;
deque<VParseGPin> m_pinStack;
deque<VParseNet> m_portStack;
public: // But for internal use only
static VParseGrammar* staticGrammarp() { return s_grammarp; }
......@@ -91,6 +109,9 @@ public:
s_grammarp = this;
m_pinNum = 0;
m_cellParam = false;
m_portNextNetValid = false;
m_withinInst = false;
m_withinPin = false;
}
~VParseGrammar() {
s_grammarp = NULL;
......
......@@ -52,6 +52,7 @@ my %Cbs =
package => {which=>'SigParser', args => [kwd=>'string', name=>'string']},
parampin => {which=>'SigParser', args => [name=>'string', conn=>'string', index=>'int']},
pin => {which=>'SigParser', args => [name=>'string', conn=>'string', index=>'int']},
pinselects => {which=>'SigParser', args => [name=>'string', conns=>'hash', index=>'int']},
port => {which=>'SigParser', args => [name=>'string', objof=>'string', direction=>'string',
data_type=>'string', array=>'string', index=>'int']},
program => {which=>'SigParser', args => [kwd=>'string', name=>'string'],},
......@@ -196,6 +197,8 @@ sub _arglist {
$args .= ", const string\& $arg";
} elsif ($type eq 'bool' || $type eq 'int') {
$args .= ", $type $arg";
} elsif ($type eq 'hash') {
$args .= ", unsigned int arraycnt${n}, unsigned int elemcnt${n}, const VParseHashElem* $arg${n}";
} elsif ($type eq 'undef') {
$args .= ", bool";
} else {
......@@ -228,6 +231,8 @@ sub _xs {
} elsif ($type eq 'int') {
push @out, " static string hold${n}; static char num".$n."[30]; sprintf(num${n},\"%d\",$arg); hold${n}=num${n};\n";
$callargs .= ", hold${n}.c_str()";
} elsif ($type eq 'hash') {
$callargs .= ", hasharray_param, arraycnt${n}, elemcnt${n}, ${arg}${n}";
} elsif ($type eq 'undef') {
$callargs .= ", NULL";
} else {
......
......@@ -9,7 +9,7 @@ use strict;
use Test::More;
use Data::Dumper; $Data::Dumper::Indent = 1;
BEGIN { plan tests => 4 }
BEGIN { plan tests => 6 }
BEGIN { require "./t/test_utils.pl"; }
our %_TestCoverage;
......@@ -34,6 +34,17 @@ BEGIN {
}
}
sub _serialize {
my $in = shift;
if (ref($in)) {
my $dd = Data::Dumper->new([$in], [qw(in)]);
$dd->Reset->Indent(0)->Terse(1)->Sortkeys(1);
return $dd->Dump;
} else {
return $in;
}
}
sub _common {
my $self = shift;
my $what = shift;
......@@ -42,7 +53,13 @@ sub _common {
$_TestCoverage{$what}++;
my $args="";
foreach (@args) { $args .= defined $_ ? " '$_'" : " undef"; }
foreach (@args) {
if (defined $_) {
$args .= " \'"._serialize($_)."\'";
} else {
$args .= " undef";
}
}
$self->{dump_fh}->printf("%s:%03d: %s %s\n",
$self->filename, $self->lineno,
uc $what,
......@@ -63,24 +80,18 @@ use Verilog::SigParser;
use Verilog::Preproc;
ok(1, "use");
# Use our class and dump to a file
my $dump_fh = new IO::File("test_dir/35.dmp","w")
or die "%Error: $! test_dir/35.dmp,";
read_test("/dev/null", $dump_fh); # Empty files should be ok
read_test("verilog/v_hier_subprim.v", $dump_fh);
read_test("verilog/v_hier_sub.v", $dump_fh);
read_test("verilog/parser_bugs.v", $dump_fh);
read_test("verilog/pinorder.v", $dump_fh);
read_test("verilog/parser_sv.v", $dump_fh);
read_test("verilog/parser_sv09.v", $dump_fh);
read_test("verilog/parser_vectors.v", $dump_fh);
read_tests("test_dir/35.dmp",
[]);
ok(1, "read");
$dump_fh->close();
# Did we read the right stuff?
ok(files_identical("test_dir/35.dmp", "t/35_sigparser.out"), "diff");
read_tests("test_dir/35_ps.dmp",
[use_pinselects => 1]);
ok(1, "read-pinselects");
# Did we read the right stuff?
ok(files_identical("test_dir/35_ps.dmp", "t/35_sigparser_ps.out"), "diff");
# Did we cover everything?
my $err;
foreach my $cb (sort keys %_TestCallbacks) {
......@@ -91,16 +102,37 @@ foreach my $cb (sort keys %_TestCallbacks) {
}
ok (!$err, "coverage");
######################################################################
# Use our class and dump to a file
sub read_tests {
my $dump_filename = shift;
my $option_ref = shift;
my $dump_fh = new IO::File($dump_filename,"w")
or die "%Error: $! $dump_filename,";
read_test($dump_fh, $option_ref, "/dev/null"); # Empty files should be ok
read_test($dump_fh, $option_ref, "verilog/v_hier_subprim.v");
read_test($dump_fh, $option_ref, "verilog/v_hier_sub.v");
read_test($dump_fh, $option_ref, "verilog/parser_bugs.v");
read_test($dump_fh, $option_ref, "verilog/pinorder.v");
read_test($dump_fh, $option_ref, "verilog/parser_sv.v");
read_test($dump_fh, $option_ref, "verilog/parser_sv09.v");
read_test($dump_fh, $option_ref, "verilog/parser_vectors.v");
$dump_fh->close();
}
sub read_test {
my $filename = shift;
my $dump_fh = shift;
my $option_ref = shift;
my $filename = shift;
my $pp = Verilog::Preproc->new(keep_comments=>1,);
my $parser = new MyParser (dump_fh => $dump_fh,
metacomment=>{synopsys=>1},);
metacomment=>{synopsys=>1},
@$option_ref);
if ($ENV{VERILOG_TEST_DEBUG}) { # For example, VERILOG_TEST_DEBUG=9
$parser->debug($ENV{VERILOG_TEST_DEBUG});
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment