Merge pull request #86 from orsonmmz/files
Basic support for std.textio/ieee.std_logic_textio
This commit is contained in:
commit
fbeac729af
|
|
@ -1072,6 +1072,7 @@ int main(int argc, char **argv)
|
||||||
how to handle them. */
|
how to handle them. */
|
||||||
fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep);
|
fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep);
|
||||||
fprintf(iconfig_file, "sys_func:%s%cvhdl_sys.sft\n", base, sep);
|
fprintf(iconfig_file, "sys_func:%s%cvhdl_sys.sft\n", base, sep);
|
||||||
|
fprintf(iconfig_file, "sys_func:%s%cvhdl_textio.sft\n", base, sep);
|
||||||
|
|
||||||
/* If verilog-2005/09/12 is enabled or icarus-misc or verilog-ams,
|
/* If verilog-2005/09/12 is enabled or icarus-misc or verilog-ams,
|
||||||
* then include the v2005_math library. */
|
* then include the v2005_math library. */
|
||||||
|
|
|
||||||
1
main.cc
1
main.cc
|
|
@ -832,6 +832,7 @@ int main(int argc, char*argv[])
|
||||||
// Start the module list with the base system module.
|
// Start the module list with the base system module.
|
||||||
add_vpi_module("system");
|
add_vpi_module("system");
|
||||||
add_vpi_module("vhdl_sys");
|
add_vpi_module("vhdl_sys");
|
||||||
|
add_vpi_module("vhdl_textio");
|
||||||
|
|
||||||
flags["-o"] = strdup("a.out");
|
flags["-o"] = strdup("a.out");
|
||||||
min_typ_max_flag = TYP;
|
min_typ_max_flag = TYP;
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,8 @@ rm -rf $RPM_BUILD_ROOT
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/v2009.vpi
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/v2009.vpi
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.sft
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.sft
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.vpi
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_sys.vpi
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_textio.sft
|
||||||
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vhdl_textio.vpi
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/vpi_debug.vpi
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/vpi_debug.vpi
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/cadpli.vpl
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/cadpli.vpl
|
||||||
%attr(-,root,root) %{_libdir}/libvpi%{suff}.a
|
%attr(-,root,root) %{_libdir}/libvpi%{suff}.a
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
# include "architec.h"
|
# include "architec.h"
|
||||||
# include "expression.h"
|
# include "expression.h"
|
||||||
# include "parse_types.h"
|
# include "parse_types.h"
|
||||||
|
# include "sequential.h"
|
||||||
// Need this for parse_errors?
|
// Need this for parse_errors?
|
||||||
# include "parse_api.h"
|
# include "parse_api.h"
|
||||||
# include <cassert>
|
# include <cassert>
|
||||||
|
|
@ -229,18 +230,33 @@ Expression*ComponentInstantiation::find_generic_map(perm_string by_name) const
|
||||||
return p->second;
|
return p->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StatementList::StatementList(std::list<SequentialStmt*>*statement_list)
|
||||||
|
{
|
||||||
|
if(statement_list)
|
||||||
|
statements_.splice(statements_.end(), *statement_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementList::~StatementList()
|
||||||
|
{
|
||||||
|
for(std::list<SequentialStmt*>::iterator it = statements_.begin();
|
||||||
|
it != statements_.end(); ++it) {
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ProcessStatement::ProcessStatement(perm_string iname,
|
ProcessStatement::ProcessStatement(perm_string iname,
|
||||||
std::list<Expression*>*sensitivity_list,
|
std::list<Expression*>*sensitivity_list,
|
||||||
std::list<SequentialStmt*>*statements_list)
|
std::list<SequentialStmt*>*statements_list)
|
||||||
: iname_(iname)
|
: StatementList(statements_list), iname_(iname)
|
||||||
{
|
{
|
||||||
if (sensitivity_list)
|
if (sensitivity_list)
|
||||||
sensitivity_list_.splice(sensitivity_list_.end(), *sensitivity_list);
|
sensitivity_list_.splice(sensitivity_list_.end(), *sensitivity_list);
|
||||||
if (statements_list)
|
|
||||||
statements_list_.splice(statements_list_.end(), *statements_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessStatement::~ProcessStatement()
|
ProcessStatement::~ProcessStatement()
|
||||||
{
|
{
|
||||||
|
for(std::list<Expression*>::iterator it = sensitivity_list_.begin();
|
||||||
|
it != sensitivity_list_.end(); ++it) {
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,44 @@ class ComponentInstantiation : public Architecture::Statement {
|
||||||
std::map<perm_string,Expression*> port_map_;
|
std::map<perm_string,Expression*> port_map_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProcessStatement : public Architecture::Statement {
|
class StatementList : public Architecture::Statement {
|
||||||
|
public:
|
||||||
|
StatementList(std::list<SequentialStmt*>*statement_list);
|
||||||
|
virtual ~StatementList();
|
||||||
|
|
||||||
|
virtual int elaborate(Entity*ent, Architecture*arc);
|
||||||
|
virtual int emit(ostream&out, Entity*entity, Architecture*arc);
|
||||||
|
virtual void dump(ostream&out, int indent =0) const;
|
||||||
|
|
||||||
|
std::list<SequentialStmt*>& stmt_list() { return statements_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<SequentialStmt*> statements_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// There is no direct VHDL countepart to SV 'initial' statement,
|
||||||
|
// but we can still use it during the translation process.
|
||||||
|
class InitialStatement : public StatementList {
|
||||||
|
public:
|
||||||
|
InitialStatement(std::list<SequentialStmt*>*statement_list)
|
||||||
|
: StatementList(statement_list) {}
|
||||||
|
|
||||||
|
int emit(ostream&out, Entity*entity, Architecture*arc);
|
||||||
|
void dump(ostream&out, int indent =0) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// There is no direct VHDL countepart to SV 'final' statement,
|
||||||
|
// but we can still use it during the translation process.
|
||||||
|
class FinalStatement : public StatementList {
|
||||||
|
public:
|
||||||
|
FinalStatement(std::list<SequentialStmt*>*statement_list)
|
||||||
|
: StatementList(statement_list) {}
|
||||||
|
|
||||||
|
int emit(ostream&out, Entity*entity, Architecture*arc);
|
||||||
|
void dump(ostream&out, int indent =0) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProcessStatement : public StatementList {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ProcessStatement(perm_string iname,
|
ProcessStatement(perm_string iname,
|
||||||
|
|
@ -223,20 +260,16 @@ class ProcessStatement : public Architecture::Statement {
|
||||||
std::list<SequentialStmt*>*statement_list);
|
std::list<SequentialStmt*>*statement_list);
|
||||||
~ProcessStatement();
|
~ProcessStatement();
|
||||||
|
|
||||||
virtual int elaborate(Entity*ent, Architecture*arc);
|
int elaborate(Entity*ent, Architecture*arc);
|
||||||
virtual int emit(ostream&out, Entity*entity, Architecture*arc);
|
int emit(ostream&out, Entity*entity, Architecture*arc);
|
||||||
virtual void dump(ostream&out, int indent =0) const;
|
void dump(ostream&out, int indent =0) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int rewrite_as_always_edge_(Entity*ent, Architecture*arc);
|
int rewrite_as_always_edge_(Entity*ent, Architecture*arc);
|
||||||
int extract_anyedge_(Entity*ent, Architecture*arc);
|
int extract_anyedge_(Entity*ent, Architecture*arc);
|
||||||
|
|
||||||
private:
|
|
||||||
perm_string iname_;
|
perm_string iname_;
|
||||||
|
|
||||||
std::list<Expression*> sensitivity_list_;
|
std::list<Expression*> sensitivity_list_;
|
||||||
std::list<SequentialStmt*> statements_list_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* IVL_architec_H */
|
#endif /* IVL_architec_H */
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,30 @@ void SignalAssignment::dump(ostream&out, int indent) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StatementList::dump(ostream&out, int indent) const
|
||||||
|
{
|
||||||
|
out << setw(indent+3) << "" << "sequence of statements:" << endl;
|
||||||
|
|
||||||
|
for (list<SequentialStmt*>::const_iterator cur = statements_.begin()
|
||||||
|
; cur != statements_.end() ; ++cur) {
|
||||||
|
(*cur)->dump(out, indent+4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitialStatement::dump(ostream&out, int indent) const
|
||||||
|
{
|
||||||
|
out << setw(indent) << "" << "InitialStatement file=" << get_fileline() << endl;
|
||||||
|
|
||||||
|
StatementList::dump(out, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FinalStatement::dump(ostream&out, int indent) const
|
||||||
|
{
|
||||||
|
out << setw(indent) << "" << "FinalStatment file=" << get_fileline() << endl;
|
||||||
|
|
||||||
|
StatementList::dump(out, indent);
|
||||||
|
}
|
||||||
|
|
||||||
void ProcessStatement::dump(ostream&out, int indent) const
|
void ProcessStatement::dump(ostream&out, int indent) const
|
||||||
{
|
{
|
||||||
out << setw(indent) << "" << "ProcessStatement name_=" << iname_
|
out << setw(indent) << "" << "ProcessStatement name_=" << iname_
|
||||||
|
|
@ -107,10 +131,5 @@ void ProcessStatement::dump(ostream&out, int indent) const
|
||||||
(*cur)->dump(out, indent+4);
|
(*cur)->dump(out, indent+4);
|
||||||
}
|
}
|
||||||
|
|
||||||
out << setw(indent+3) << "" << "sequence of statements:" << endl;
|
StatementList::dump(out, indent);
|
||||||
|
|
||||||
for (list<SequentialStmt*>::const_iterator cur = statements_list_.begin()
|
|
||||||
; cur != statements_list_.end() ; ++cur) {
|
|
||||||
(*cur)->dump(out, indent+4);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,14 @@ int Architecture::elaborate(Entity*entity)
|
||||||
cur->second->elaborate_init_expr(entity, this);
|
cur->second->elaborate_init_expr(entity, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create 'initial' and 'final' blocks for implicit
|
||||||
|
// initalization and clean-up actions
|
||||||
|
if(!initializers_.empty())
|
||||||
|
statements_.push_front(new InitialStatement(&initializers_));
|
||||||
|
|
||||||
|
if(!finalizers_.empty())
|
||||||
|
statements_.push_front(new FinalStatement(&finalizers_));
|
||||||
|
|
||||||
for (list<Architecture::Statement*>::iterator cur = statements_.begin()
|
for (list<Architecture::Statement*>::iterator cur = statements_.begin()
|
||||||
; cur != statements_.end() ; ++cur) {
|
; cur != statements_.end() ; ++cur) {
|
||||||
|
|
||||||
|
|
@ -179,11 +187,11 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// If there are multiple statements, I give up.
|
// If there are multiple statements, I give up.
|
||||||
if (statements_list_.size() != 1)
|
if (stmt_list().size() != 1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
Expression*se = sensitivity_list_.front();
|
Expression*se = sensitivity_list_.front();
|
||||||
SequentialStmt*stmt_raw = statements_list_.front();
|
SequentialStmt*stmt_raw = stmt_list().front();
|
||||||
|
|
||||||
// If the statement is not an if-statement, I give up.
|
// If the statement is not an if-statement, I give up.
|
||||||
IfSequential*stmt = dynamic_cast<IfSequential*> (stmt_raw);
|
IfSequential*stmt = dynamic_cast<IfSequential*> (stmt_raw);
|
||||||
|
|
@ -258,22 +266,33 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*)
|
||||||
// Replace the statement with the body of the always
|
// Replace the statement with the body of the always
|
||||||
// statement, which is the true clause of the top "if"
|
// statement, which is the true clause of the top "if"
|
||||||
// statement. There should be no "else" clause.
|
// statement. There should be no "else" clause.
|
||||||
assert(statements_list_.size() == 1);
|
assert(stmt_list().size() == 1);
|
||||||
statements_list_.pop_front();
|
stmt_list().pop_front();
|
||||||
|
|
||||||
stmt->extract_true(statements_list_);
|
stmt->extract_true(stmt_list());
|
||||||
|
|
||||||
delete stmt;
|
delete stmt;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int StatementList::elaborate(Entity*ent, Architecture*arc)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
for (std::list<SequentialStmt*>::iterator it = statements_.begin();
|
||||||
|
it != statements_.end(); ++it) {
|
||||||
|
errors += (*it)->elaborate(ent, arc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Change the "process (<expr>) <stmt>" into "always @(<expr>) ..."
|
* Change the "process (<expr>) <stmt>" into "always @(<expr>) ..."
|
||||||
*/
|
*/
|
||||||
int ProcessStatement::extract_anyedge_(Entity*, Architecture*)
|
int ProcessStatement::extract_anyedge_(Entity*, Architecture*)
|
||||||
{
|
{
|
||||||
|
|
||||||
vector<Expression*> se;
|
vector<Expression*> se;
|
||||||
while (! sensitivity_list_.empty()) {
|
while (! sensitivity_list_.empty()) {
|
||||||
se.push_back(sensitivity_list_.front());
|
se.push_back(sensitivity_list_.front());
|
||||||
|
|
@ -297,10 +316,7 @@ int ProcessStatement::elaborate(Entity*ent, Architecture*arc)
|
||||||
extract_anyedge_(ent, arc);
|
extract_anyedge_(ent, arc);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (list<SequentialStmt*>::iterator cur = statements_list_.begin()
|
StatementList::elaborate(ent, arc);
|
||||||
; cur != statements_list_.end() ; ++cur) {
|
|
||||||
errors += (*cur)->elaborate(ent, arc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,36 @@ int IfGenerate::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int StatementList::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
for (std::list<SequentialStmt*>::iterator it = statements_.begin();
|
||||||
|
it != statements_.end(); ++it) {
|
||||||
|
errors += (*it)->emit(out, ent, arc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
int InitialStatement::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
|
{
|
||||||
|
out << "initial begin" << endl;
|
||||||
|
int errors = StatementList::emit(out, ent, arc);
|
||||||
|
out << "end" << endl;
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FinalStatement::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
|
{
|
||||||
|
out << "final begin" << endl;
|
||||||
|
int errors = StatementList::emit(out, ent, arc);
|
||||||
|
out << "end" << endl;
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emit a process statement using "always" syntax.
|
* Emit a process statement using "always" syntax.
|
||||||
*
|
*
|
||||||
|
|
@ -256,14 +286,9 @@ int IfGenerate::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
*/
|
*/
|
||||||
int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc)
|
int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
|
||||||
|
|
||||||
out << "always begin" << endl;
|
out << "always begin" << endl;
|
||||||
|
|
||||||
for (list<SequentialStmt*>::iterator cur = statements_list_.begin()
|
int errors = StatementList::emit(out, ent, arc);
|
||||||
; cur != statements_list_.end() ; ++cur) {
|
|
||||||
errors += (*cur)->emit(out, ent, arc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! sensitivity_list_.empty()) {
|
if (! sensitivity_list_.empty()) {
|
||||||
out << "@(";
|
out << "@(";
|
||||||
|
|
|
||||||
|
|
@ -415,12 +415,8 @@ void ExpRelation::dump(ostream&out, int indent) const
|
||||||
|
|
||||||
void ExpString::dump(ostream&out, int indent) const
|
void ExpString::dump(ostream&out, int indent) const
|
||||||
{
|
{
|
||||||
out << setw(indent) << "" << "String \"";
|
out << setw(indent) << "" << "String \"" << value_;
|
||||||
for(vector<char>::const_iterator it = value_.begin();
|
out << "\"" << " at " << get_fileline() << endl;
|
||||||
it != value_.end(); ++it)
|
|
||||||
out << *it;
|
|
||||||
out << "\""
|
|
||||||
<< " at " << get_fileline() << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpUAbs::dump(ostream&out, int indent) const
|
void ExpUAbs::dump(ostream&out, int indent) const
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,10 @@ class InterfacePort : public LineInfo {
|
||||||
: mode(PORT_NONE), type(typ), expr(NULL)
|
: mode(PORT_NONE), type(typ), expr(NULL)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
InterfacePort(const VType*typ, port_mode_t mod)
|
||||||
|
: mode(mod), type(typ), expr(NULL)
|
||||||
|
{}
|
||||||
|
|
||||||
// Port direction from the source code.
|
// Port direction from the source code.
|
||||||
port_mode_t mode;
|
port_mode_t mode;
|
||||||
// Name of the port from the source code
|
// Name of the port from the source code
|
||||||
|
|
|
||||||
|
|
@ -632,10 +632,8 @@ ExpShift::ExpShift(ExpShift::shift_t op, Expression*op1, Expression*op2)
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpString::ExpString(const char* value)
|
ExpString::ExpString(const char* value)
|
||||||
: value_(strlen(value))
|
: value_(value)
|
||||||
{
|
{
|
||||||
for(size_t idx = 0; idx < value_.size(); idx += 1)
|
|
||||||
value_[idx] = value[idx];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpString::~ExpString()
|
ExpString::~ExpString()
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,7 @@ class ExpUnary : public Expression {
|
||||||
inline const Expression*peek_operand() const { return operand1_; }
|
inline const Expression*peek_operand() const { return operand1_; }
|
||||||
|
|
||||||
const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const;
|
const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const;
|
||||||
|
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
|
||||||
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||||
void visit(ExprVisitor& func);
|
void visit(ExprVisitor& func);
|
||||||
|
|
||||||
|
|
@ -304,7 +305,6 @@ class ExpAggregate : public Expression {
|
||||||
|
|
||||||
Expression*clone() const;
|
Expression*clone() const;
|
||||||
|
|
||||||
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
|
|
||||||
const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const;
|
const VType*fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*atype) const;
|
||||||
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||||
void write_to_stream(std::ostream&fd) const;
|
void write_to_stream(std::ostream&fd) const;
|
||||||
|
|
@ -730,7 +730,6 @@ class ExpNameALL : public ExpName {
|
||||||
ExpNameALL() : ExpName(perm_string()) { }
|
ExpNameALL() : ExpName(perm_string()) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int elaborate_lval(Entity*ent, ScopeBase*scope, bool);
|
|
||||||
const VType* probe_type(Entity*ent, ScopeBase*scope) const;
|
const VType* probe_type(Entity*ent, ScopeBase*scope) const;
|
||||||
void dump(ostream&out, int indent =0) const;
|
void dump(ostream&out, int indent =0) const;
|
||||||
};
|
};
|
||||||
|
|
@ -796,13 +795,17 @@ class ExpString : public Expression {
|
||||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
bool is_primary(void) const;
|
bool is_primary(void) const;
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
const std::vector<char>& get_value() const { return value_; }
|
const std::string& get_value() const { return value_; }
|
||||||
|
|
||||||
|
// Converts quotation marks (") to its escaped
|
||||||
|
// counterpart in SystemVerilog (\")
|
||||||
|
static std::string escape_quot(const std::string& str);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int emit_as_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*arr);
|
int emit_as_array_(ostream&out, Entity*ent, ScopeBase*scope, const VTypeArray*arr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<char> value_;
|
std::string value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExpUAbs : public ExpUnary {
|
class ExpUAbs : public ExpUnary {
|
||||||
|
|
@ -888,8 +891,8 @@ class ExpTime : public Expression {
|
||||||
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||||
void write_to_stream(std::ostream&) const;
|
void write_to_stream(std::ostream&) const;
|
||||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
bool evaluate(ScopeBase*scope, int64_t&val) const;
|
//bool evaluate(ScopeBase*scope, int64_t&val) const;
|
||||||
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
//bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -899,4 +902,8 @@ class ExpTime : public Expression {
|
||||||
timeunit_t unit_;
|
timeunit_t unit_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Elaborates an expression used as an argument in a procedure/function call.
|
||||||
|
int elaborate_argument(Expression*expr, const SubprogramHeader*subp,
|
||||||
|
int idx, Entity*ent, ScopeBase*scope);
|
||||||
|
|
||||||
#endif /* IVL_expression_H */
|
#endif /* IVL_expression_H */
|
||||||
|
|
|
||||||
|
|
@ -316,11 +316,6 @@ int ExpName::elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lva
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExpNameALL::elaborate_lval(Entity*ent, ScopeBase*scope, bool is_sequ)
|
|
||||||
{
|
|
||||||
return Expression::elaborate_lval(ent, scope, is_sequ);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Expression::elaborate_expr(Entity*, ScopeBase*, const VType*)
|
int Expression::elaborate_expr(Entity*, ScopeBase*, const VType*)
|
||||||
{
|
{
|
||||||
cerr << get_fileline() << ": internal error: I don't know how to elaborate expression type=" << typeid(*this).name() << endl;
|
cerr << get_fileline() << ": internal error: I don't know how to elaborate expression type=" << typeid(*this).name() << endl;
|
||||||
|
|
@ -376,6 +371,11 @@ const VType*ExpUnary::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*aty
|
||||||
return operand1_->fit_type(ent, scope, atype);
|
return operand1_->fit_type(ent, scope, atype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VType*ExpUnary::probe_type(Entity*ent, ScopeBase*scope) const
|
||||||
|
{
|
||||||
|
return operand1_->probe_type(ent, scope);
|
||||||
|
}
|
||||||
|
|
||||||
int ExpUnary::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
|
int ExpUnary::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
|
||||||
{
|
{
|
||||||
ivl_assert(*this, ltype != 0);
|
ivl_assert(*this, ltype != 0);
|
||||||
|
|
@ -383,11 +383,6 @@ int ExpUnary::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
|
||||||
return operand1_->elaborate_expr(ent, scope, ltype);
|
return operand1_->elaborate_expr(ent, scope, ltype);
|
||||||
}
|
}
|
||||||
|
|
||||||
const VType*ExpAggregate::probe_type(Entity*ent, ScopeBase*scope) const
|
|
||||||
{
|
|
||||||
return Expression::probe_type(ent, scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
const VType*ExpAggregate::fit_type(Entity*, ScopeBase*, const VTypeArray*host) const
|
const VType*ExpAggregate::fit_type(Entity*, ScopeBase*, const VTypeArray*host) const
|
||||||
{
|
{
|
||||||
ivl_assert(*this, elements_.size() == 1);
|
ivl_assert(*this, elements_.size() == 1);
|
||||||
|
|
@ -782,14 +777,8 @@ int ExpFunc::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
|
||||||
def_ = prog;
|
def_ = prog;
|
||||||
|
|
||||||
// Elaborate arguments
|
// Elaborate arguments
|
||||||
for (size_t idx = 0 ; idx < argv_.size() ; idx += 1) {
|
for (size_t idx = 0; idx < argv_.size(); ++idx) {
|
||||||
const VType*tmp = argv_[idx]->probe_type(ent, scope);
|
errors += elaborate_argument(argv_[idx], prog, idx, ent, scope);
|
||||||
const VType*param_type = prog ? prog->peek_param_type(idx) : NULL;
|
|
||||||
|
|
||||||
if(!tmp && param_type)
|
|
||||||
tmp = param_type;
|
|
||||||
|
|
||||||
errors += argv_[idx]->elaborate_expr(ent, scope, tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SystemVerilog functions work only with defined size data types, therefore
|
// SystemVerilog functions work only with defined size data types, therefore
|
||||||
|
|
@ -1058,3 +1047,28 @@ int ExpTime::elaborate_expr(Entity*, ScopeBase*, const VType*)
|
||||||
set_type(&primitive_INTEGER);
|
set_type(&primitive_INTEGER);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int elaborate_argument(Expression*expr, const SubprogramHeader*subp,
|
||||||
|
int idx, Entity*ent, ScopeBase*scope)
|
||||||
|
{
|
||||||
|
const VType*type = expr->probe_type(ent, scope);
|
||||||
|
|
||||||
|
if(subp) {
|
||||||
|
const InterfacePort*param = subp->peek_param(idx);
|
||||||
|
|
||||||
|
// Enable reg_flag for variables that might be modified in subprograms
|
||||||
|
if(param->mode == PORT_OUT || param->mode == PORT_INOUT) {
|
||||||
|
if(const ExpName*e = dynamic_cast<const ExpName*>(expr)) {
|
||||||
|
if(Signal*sig = scope->find_signal(e->peek_name()))
|
||||||
|
sig->count_ref_sequ();
|
||||||
|
else if(Variable*var = scope->find_variable(e->peek_name()))
|
||||||
|
var->count_ref_sequ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!type)
|
||||||
|
type = param->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr->elaborate_expr(ent, scope, type);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -375,6 +375,22 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
||||||
|
if(fun_ == REM) {
|
||||||
|
// Special case: division remainder, defined in the VHDL standard 1076-2008/9.2.7
|
||||||
|
// there is no direct counterpart, therefore output the formula to
|
||||||
|
// compute a remainder: A rem B = A - (A/B) * B;
|
||||||
|
out << "((";
|
||||||
|
errors += emit_operand1(out, ent, scope);
|
||||||
|
out << ")-((";
|
||||||
|
errors += emit_operand1(out, ent, scope);
|
||||||
|
out << ")/(";
|
||||||
|
errors += emit_operand2(out, ent, scope);
|
||||||
|
out << "))*(";
|
||||||
|
errors += emit_operand2(out, ent, scope);
|
||||||
|
out << "))";
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
errors += emit_operand1(out, ent, scope);
|
errors += emit_operand1(out, ent, scope);
|
||||||
|
|
||||||
switch (fun_) {
|
switch (fun_) {
|
||||||
|
|
@ -396,9 +412,8 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
case POW:
|
case POW:
|
||||||
out << " ** ";
|
out << " ** ";
|
||||||
break;
|
break;
|
||||||
case REM:
|
case REM: // should not happen as it is handled above, suppress warnings
|
||||||
out << " /* ?remainder? */ ";
|
ivl_assert(*this, 0);
|
||||||
break;
|
|
||||||
case xCONCAT:
|
case xCONCAT:
|
||||||
ivl_assert(*this, 0);
|
ivl_assert(*this, 0);
|
||||||
out << " /* ?concat? */ ";
|
out << " /* ?concat? */ ";
|
||||||
|
|
@ -901,11 +916,8 @@ int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope)
|
||||||
return emit_as_array_(out, ent, scope, arr);
|
return emit_as_array_(out, ent, scope, arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
out << "\"";
|
out << "\"" << escape_quot(value_) << "\"";
|
||||||
for(vector<char>::const_iterator it = value_.begin()
|
|
||||||
; it != value_.end(); ++it)
|
|
||||||
out << *it;
|
|
||||||
out << "\"";
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -919,7 +931,7 @@ int ExpString::emit_as_array_(ostream& out, Entity*, ScopeBase*, const VTypeArra
|
||||||
|
|
||||||
// Detect the special case that this is an array of
|
// Detect the special case that this is an array of
|
||||||
// CHARACTER. In this case, emit at a Verilog string.
|
// CHARACTER. In this case, emit at a Verilog string.
|
||||||
if (etype->type()==VTypePrimitive::CHARACTER) {
|
if (arr->element_type() == &primitive_CHARACTER) {
|
||||||
vector<char> tmp (value_.size() + 3);
|
vector<char> tmp (value_.size() + 3);
|
||||||
tmp[0] = '"';
|
tmp[0] = '"';
|
||||||
memcpy(&tmp[1], &value_[0], value_.size());
|
memcpy(&tmp[1], &value_[0], value_.size());
|
||||||
|
|
@ -944,6 +956,19 @@ int ExpString::emit_as_array_(ostream& out, Entity*, ScopeBase*, const VTypeArra
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ExpString::escape_quot(const std::string& str)
|
||||||
|
{
|
||||||
|
size_t idx = 0;
|
||||||
|
string result(str);
|
||||||
|
|
||||||
|
while((idx = result.find('"', idx)) != string::npos) {
|
||||||
|
result.replace(idx, 1, "\\\"");
|
||||||
|
idx += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
int ExpUAbs::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
# include "architec.h"
|
# include "architec.h"
|
||||||
# include <ivl_assert.h>
|
# include <ivl_assert.h>
|
||||||
# include <limits>
|
# include <limits>
|
||||||
|
# include <cmath>
|
||||||
|
|
||||||
bool Expression::evaluate(ScopeBase*, int64_t&) const
|
bool Expression::evaluate(ScopeBase*, int64_t&) const
|
||||||
{
|
{
|
||||||
|
|
@ -68,9 +69,13 @@ bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const
|
||||||
val = val1 % val2;
|
val = val1 % val2;
|
||||||
break;
|
break;
|
||||||
case REM:
|
case REM:
|
||||||
|
if (val2 == 0)
|
||||||
|
return false;
|
||||||
|
val = val1 - (val1 / val2) * val2;
|
||||||
return false;
|
return false;
|
||||||
case POW:
|
case POW:
|
||||||
return false;
|
val = (int64_t) pow(val1, val2);
|
||||||
|
break;
|
||||||
case xCONCAT: // not possible
|
case xCONCAT: // not possible
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -247,7 +252,7 @@ bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpTime::evaluate(ScopeBase*, int64_t&val) const
|
/*bool ExpTime::evaluate(ScopeBase*, int64_t&val) const
|
||||||
{
|
{
|
||||||
double v = to_fs();
|
double v = to_fs();
|
||||||
|
|
||||||
|
|
@ -263,5 +268,5 @@ bool ExpTime::evaluate(ScopeBase*, int64_t&val) const
|
||||||
|
|
||||||
bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const
|
bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const
|
||||||
{
|
{
|
||||||
return evaluate(NULL, NULL, val);
|
return evaluate(NULL, val);
|
||||||
}
|
}*/
|
||||||
|
|
|
||||||
|
|
@ -272,10 +272,15 @@ void ExpShift::write_to_stream(ostream&out) const
|
||||||
void ExpString::write_to_stream(ostream&fd) const
|
void ExpString::write_to_stream(ostream&fd) const
|
||||||
{
|
{
|
||||||
fd << "\"";
|
fd << "\"";
|
||||||
for(vector<char>::const_iterator it = value_.begin();
|
|
||||||
it != value_.end(); ++it) {
|
// Restore double quotation marks
|
||||||
fd << *it;
|
for(string::const_iterator it = value_.begin(); it != value_.end(); ++it) {
|
||||||
|
if(*it == '"')
|
||||||
|
fd << "\"\"";
|
||||||
|
else
|
||||||
|
fd << *it;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd << "\"";
|
fd << "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,7 @@ time {integer}{W}*([fFpPnNuUmM]?[sS])
|
||||||
return CHARACTER_LITERAL;
|
return CHARACTER_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
(\"([^\"]|(\"\"))*?\")|(\"[^\"]*\") {
|
(\"([^\"]|(\"\"))*?\") {
|
||||||
/* first pattern: string literals with doubled quotation mark */
|
|
||||||
/* second pattern: string literals without doubled quotation */
|
|
||||||
yylval.text = escape_quot_and_dup(yytext);
|
yylval.text = escape_quot_and_dup(yytext);
|
||||||
assert(yylval.text);
|
assert(yylval.text);
|
||||||
return STRING_LITERAL;
|
return STRING_LITERAL;
|
||||||
|
|
|
||||||
|
|
@ -361,13 +361,15 @@ static void import_ieee_use(ActiveScope*res, perm_string package, perm_string na
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void import_std_use(const YYLTYPE&loc, ActiveScope*/*res*/, perm_string package, perm_string name)
|
static void import_std_use(const YYLTYPE&loc, ActiveScope*res, perm_string package, perm_string name)
|
||||||
{
|
{
|
||||||
if (package == "standard") {
|
if (package == "standard") {
|
||||||
// do nothing
|
// do nothing
|
||||||
return;
|
return;
|
||||||
} else if (package == "textio") {
|
} else if (package == "textio") {
|
||||||
cerr << "warning: textio package not really supported" << endl;
|
res->use_name(perm_string::literal("text"), &primitive_INTEGER);
|
||||||
|
res->use_name(perm_string::literal("line"), &primitive_STRING);
|
||||||
|
res->use_name(type_FILE_OPEN_KIND.peek_name(), &type_FILE_OPEN_KIND);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
sorrymsg(loc, "package %s of library %s not yet supported", package.str(), name.str());
|
sorrymsg(loc, "package %s of library %s not yet supported", package.str(), name.str());
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,8 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
||||||
ReportStmt::severity_t severity;
|
ReportStmt::severity_t severity;
|
||||||
|
|
||||||
SubprogramHeader*subprogram;
|
SubprogramHeader*subprogram;
|
||||||
|
|
||||||
|
file_open_info_t*file_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The keywords are all tokens. */
|
/* The keywords are all tokens. */
|
||||||
|
|
@ -343,6 +345,8 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
||||||
%type <expr_list> process_sensitivity_list process_sensitivity_list_opt
|
%type <expr_list> process_sensitivity_list process_sensitivity_list_opt
|
||||||
%type <expr_list> selected_names use_clause
|
%type <expr_list> selected_names use_clause
|
||||||
|
|
||||||
|
%type <file_info> file_open_information file_open_information_opt
|
||||||
|
|
||||||
%type <named_expr> association_element
|
%type <named_expr> association_element
|
||||||
%type <named_expr_list> association_list port_map_aspect port_map_aspect_opt
|
%type <named_expr_list> association_list port_map_aspect port_map_aspect_opt
|
||||||
%type <named_expr_list> generic_map_aspect generic_map_aspect_opt
|
%type <named_expr_list> generic_map_aspect generic_map_aspect_opt
|
||||||
|
|
@ -1235,6 +1239,63 @@ factor
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
file_declaration
|
||||||
|
: K_file identifier_list ':' IDENTIFIER file_open_information_opt ';'
|
||||||
|
{
|
||||||
|
if (strcasecmp($4, "TEXT"))
|
||||||
|
sorrymsg(@1, "file declaration currently handles only TEXT type.\n");
|
||||||
|
|
||||||
|
for (std::list<perm_string>::iterator cur = $2->begin()
|
||||||
|
; cur != $2->end() ; ++cur) {
|
||||||
|
Variable*var = new Variable(*cur, &primitive_INTEGER);
|
||||||
|
FILE_NAME(var, @1);
|
||||||
|
active_scope->bind_name(*cur, var);
|
||||||
|
|
||||||
|
// there was a file name specified, so it needs an implicit call
|
||||||
|
// to open it at the beginning of simulation and close it at the end
|
||||||
|
if($5) {
|
||||||
|
std::list<Expression*> params;
|
||||||
|
|
||||||
|
// add file_open() call in 'initial' block
|
||||||
|
params.push_back(new ExpName(*cur));
|
||||||
|
params.push_back($5->filename());
|
||||||
|
params.push_back($5->kind());
|
||||||
|
ProcedureCall*fopen_call = new ProcedureCall(perm_string::literal("file_open"), ¶ms);
|
||||||
|
active_scope->add_initializer(fopen_call);
|
||||||
|
|
||||||
|
// add file_close() call in 'final' block
|
||||||
|
params.clear();
|
||||||
|
params.push_back(new ExpName(*cur));
|
||||||
|
ProcedureCall*fclose_call = new ProcedureCall(perm_string::literal("file_close"), ¶ms);
|
||||||
|
active_scope->add_finalizer(fclose_call);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete $2;
|
||||||
|
}
|
||||||
|
| K_file error ';'
|
||||||
|
{ errormsg(@2, "Syntax error in file declaration.\n");
|
||||||
|
yyerrok;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
file_open_information
|
||||||
|
: K_open IDENTIFIER K_is STRING_LITERAL
|
||||||
|
{
|
||||||
|
ExpName*mode = new ExpName(lex_strings.make($2));
|
||||||
|
delete[]$2;
|
||||||
|
$$ = new file_open_info_t(new ExpString($4), mode);
|
||||||
|
}
|
||||||
|
| K_is STRING_LITERAL
|
||||||
|
{
|
||||||
|
$$ = new file_open_info_t(new ExpString($2));
|
||||||
|
}
|
||||||
|
|
||||||
|
file_open_information_opt
|
||||||
|
: file_open_information { $$ = $1; }
|
||||||
|
| { $$ = 0; }
|
||||||
|
;
|
||||||
|
|
||||||
for_generate_statement
|
for_generate_statement
|
||||||
: IDENTIFIER ':' K_for IDENTIFIER K_in range
|
: IDENTIFIER ':' K_for IDENTIFIER K_in range
|
||||||
K_generate generate_statement_body
|
K_generate generate_statement_body
|
||||||
|
|
@ -1553,14 +1614,8 @@ loop_statement
|
||||||
if($1) delete[]$1;
|
if($1) delete[]$1;
|
||||||
if($8) delete[]$8;
|
if($8) delete[]$8;
|
||||||
|
|
||||||
ExpLogical* cond = dynamic_cast<ExpLogical*>($3);
|
WhileLoopStatement* tmp = new WhileLoopStatement(loop_name, $3, $5);
|
||||||
if(!cond) {
|
|
||||||
errormsg(@3, "Iteration condition is not a correct logical expression.\n");
|
|
||||||
}
|
|
||||||
WhileLoopStatement* tmp = new WhileLoopStatement(loop_name, cond, $5);
|
|
||||||
FILE_NAME(tmp, @1);
|
FILE_NAME(tmp, @1);
|
||||||
|
|
||||||
sorrymsg(@1, "Loop statements are not supported.\n");
|
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1873,10 +1928,10 @@ primary
|
||||||
else if(!strcasecmp($2, "fs"))
|
else if(!strcasecmp($2, "fs"))
|
||||||
unit = ExpTime::FS;
|
unit = ExpTime::FS;
|
||||||
else
|
else
|
||||||
errormsg(@2, "Invalid time unit (accepted are fs, ps, ns, us, ms, s).");
|
errormsg(@2, "Invalid time unit (accepted are fs, ps, ns, us, ms, s).\n");
|
||||||
|
|
||||||
if($1 < 0)
|
if($1 < 0)
|
||||||
errormsg(@1, "Time cannot be negative.");
|
errormsg(@1, "Time cannot be negative.\n");
|
||||||
|
|
||||||
ExpTime*tmp = new ExpTime($1, unit);
|
ExpTime*tmp = new ExpTime($1, unit);
|
||||||
FILE_NAME(tmp, @1);
|
FILE_NAME(tmp, @1);
|
||||||
|
|
@ -1961,6 +2016,7 @@ procedure_specification /* IEEE 1076-2008 P4.2.1 */
|
||||||
|
|
||||||
process_declarative_item
|
process_declarative_item
|
||||||
: variable_declaration
|
: variable_declaration
|
||||||
|
| file_declaration
|
||||||
;
|
;
|
||||||
|
|
||||||
process_declarative_part
|
process_declarative_part
|
||||||
|
|
@ -2506,6 +2562,7 @@ subprogram_declaration
|
||||||
|
|
||||||
subprogram_declarative_item /* IEEE 1079-2008 P4.3 */
|
subprogram_declarative_item /* IEEE 1079-2008 P4.3 */
|
||||||
: variable_declaration
|
: variable_declaration
|
||||||
|
| file_declaration
|
||||||
;
|
;
|
||||||
|
|
||||||
subprogram_declarative_item_list
|
subprogram_declarative_item_list
|
||||||
|
|
@ -2586,7 +2643,7 @@ suffix
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| K_all
|
| K_all
|
||||||
{ //do not have now better idea than using char constant
|
{ //do not have now better idea than using char constant
|
||||||
$$ = strcpy(new char[strlen("all"+1)], "all");
|
$$ = strdup("all");
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
|
||||||
const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
|
const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
|
||||||
ScopeBase*scope,
|
ScopeBase*scope,
|
||||||
Expression*range_left,
|
Expression*range_left,
|
||||||
bool /* downto*/ ,
|
bool downto,
|
||||||
Expression*range_right)
|
Expression*range_right)
|
||||||
{
|
{
|
||||||
const VType*base_type = parse_type_by_name(lex_strings.make(base_name));
|
const VType*base_type = parse_type_by_name(lex_strings.make(base_name));
|
||||||
|
|
@ -143,15 +143,13 @@ const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
|
||||||
assert(range_left && range_right);
|
assert(range_left && range_right);
|
||||||
|
|
||||||
int64_t left_val, right_val;
|
int64_t left_val, right_val;
|
||||||
bool rc = range_left->evaluate(scope, left_val);
|
VTypeRange*subtype;
|
||||||
if (rc == false)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
rc = range_right->evaluate(scope, right_val);
|
if(range_left->evaluate(scope, left_val) && range_right->evaluate(scope, right_val)) {
|
||||||
if (rc == false)
|
subtype = new VTypeRangeConst(base_type, left_val, right_val);
|
||||||
return 0;
|
} else {
|
||||||
|
subtype = new VTypeRangeExpr(base_type, range_left, range_right, downto);
|
||||||
|
}
|
||||||
|
|
||||||
VTypeRange*sub_type = new VTypeRange(base_type, left_val, right_val);
|
return subtype;
|
||||||
|
|
||||||
return sub_type;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,4 +102,23 @@ struct adding_term {
|
||||||
Expression*term;
|
Expression*term;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Stores information for file declarations containing a file name and open mode
|
||||||
|
// (VHDL-2008 6.4.2.5)
|
||||||
|
class file_open_info_t {
|
||||||
|
public:
|
||||||
|
file_open_info_t(ExpString*filename, ExpName*kind = NULL)
|
||||||
|
: kind_(kind), filename_(filename) {
|
||||||
|
// By default files are opened in read-only mode
|
||||||
|
if(!kind_) kind_ = new ExpName(perm_string::literal("read_mode"));
|
||||||
|
}
|
||||||
|
~file_open_info_t() { delete kind_; delete filename_; }
|
||||||
|
|
||||||
|
ExpName*kind() { return kind_; }
|
||||||
|
ExpString*filename() { return filename_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ExpName*kind_;
|
||||||
|
ExpString*filename_;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* IVL_parse_types_H */
|
#endif /* IVL_parse_types_H */
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,9 @@ ScopeBase::ScopeBase(const ActiveScope&ref)
|
||||||
|
|
||||||
use_enums_ = ref.use_enums_;
|
use_enums_ = ref.use_enums_;
|
||||||
|
|
||||||
|
initializers_ = ref.initializers_;
|
||||||
|
finalizers_ = ref.finalizers_;
|
||||||
|
|
||||||
// This constructor is invoked when the parser is finished with
|
// This constructor is invoked when the parser is finished with
|
||||||
// an active scope and is making the actual scope. At this point
|
// an active scope and is making the actual scope. At this point
|
||||||
// we know that "this" is the parent scope for the subprograms,
|
// we know that "this" is the parent scope for the subprograms,
|
||||||
|
|
@ -99,11 +102,10 @@ const VType*ScopeBase::find_type(perm_string by_name)
|
||||||
if (cur == cur_types_.end()) {
|
if (cur == cur_types_.end()) {
|
||||||
cur = use_types_.find(by_name);
|
cur = use_types_.find(by_name);
|
||||||
if (cur == use_types_.end())
|
if (cur == use_types_.end())
|
||||||
return 0;
|
return NULL; // nothing found
|
||||||
else
|
}
|
||||||
return cur->second;
|
|
||||||
} else
|
return cur->second;
|
||||||
return cur->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScopeBase::find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const
|
bool ScopeBase::find_constant(perm_string by_name, const VType*&typ, Expression*&exp) const
|
||||||
|
|
@ -115,19 +117,12 @@ bool ScopeBase::find_constant(perm_string by_name, const VType*&typ, Expression*
|
||||||
if (cur == cur_constants_.end()) {
|
if (cur == cur_constants_.end()) {
|
||||||
cur = use_constants_.find(by_name);
|
cur = use_constants_.find(by_name);
|
||||||
if (cur == use_constants_.end())
|
if (cur == use_constants_.end())
|
||||||
return false;
|
return false; // nothing found
|
||||||
else {
|
|
||||||
typ = cur->second->typ;
|
|
||||||
exp = cur->second->val;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
typ = cur->second->typ;
|
|
||||||
exp = cur->second->val;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
typ = cur->second->typ;
|
||||||
|
exp = cur->second->val;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Signal* ScopeBase::find_signal(perm_string by_name) const
|
Signal* ScopeBase::find_signal(perm_string by_name) const
|
||||||
|
|
@ -136,12 +131,10 @@ Signal* ScopeBase::find_signal(perm_string by_name) const
|
||||||
if (cur == new_signals_.end()) {
|
if (cur == new_signals_.end()) {
|
||||||
cur = old_signals_.find(by_name);
|
cur = old_signals_.find(by_name);
|
||||||
if (cur == old_signals_.end())
|
if (cur == old_signals_.end())
|
||||||
return 0;
|
return NULL; // nothing found
|
||||||
else
|
|
||||||
return cur->second;
|
|
||||||
} else {
|
|
||||||
return cur->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return cur->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable* ScopeBase::find_variable(perm_string by_name) const
|
Variable* ScopeBase::find_variable(perm_string by_name) const
|
||||||
|
|
@ -150,12 +143,10 @@ Variable* ScopeBase::find_variable(perm_string by_name) const
|
||||||
if (cur == new_variables_.end()) {
|
if (cur == new_variables_.end()) {
|
||||||
cur = old_variables_.find(by_name);
|
cur = old_variables_.find(by_name);
|
||||||
if (cur == old_variables_.end())
|
if (cur == old_variables_.end())
|
||||||
return 0;
|
return 0; // nothing found
|
||||||
else
|
|
||||||
return cur->second;
|
|
||||||
} else {
|
|
||||||
return cur->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return cur->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InterfacePort* ScopeBase::find_param(perm_string) const
|
const InterfacePort* ScopeBase::find_param(perm_string) const
|
||||||
|
|
@ -232,7 +223,6 @@ void ScopeBase::do_use_from(const ScopeBase*that)
|
||||||
use_subprograms_[cur->first] = cur->second;
|
use_subprograms_[cur->first] = cur->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (map<perm_string,const VType*>::const_iterator cur = that->cur_types_.begin()
|
for (map<perm_string,const VType*>::const_iterator cur = that->cur_types_.begin()
|
||||||
; cur != that->cur_types_.end() ; ++ cur) {
|
; cur != that->cur_types_.end() ; ++ cur) {
|
||||||
if (cur->second == 0)
|
if (cur->second == 0)
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ class ComponentBase;
|
||||||
class Package;
|
class Package;
|
||||||
class SubprogramHeader;
|
class SubprogramHeader;
|
||||||
class VType;
|
class VType;
|
||||||
|
class SequentialStmt;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct delete_object{
|
struct delete_object{
|
||||||
|
|
@ -75,6 +76,20 @@ class ScopeBase {
|
||||||
cur_subprograms_[name] = obj;
|
cur_subprograms_[name] = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adds a statement to implicit initializers list
|
||||||
|
// (emitted in a 'initial block).
|
||||||
|
void add_initializer(SequentialStmt* s)
|
||||||
|
{
|
||||||
|
initializers_.push_back(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a statement to implicit finalizers list
|
||||||
|
// (emitted in a 'final' block).
|
||||||
|
void add_finalizer(SequentialStmt* s)
|
||||||
|
{
|
||||||
|
finalizers_.push_back(s);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
|
|
@ -122,6 +137,12 @@ class ScopeBase {
|
||||||
|
|
||||||
std::list<const VTypeEnum*> use_enums_;
|
std::list<const VTypeEnum*> use_enums_;
|
||||||
|
|
||||||
|
// List of statements that should be emitted in a 'initial' block
|
||||||
|
std::list<SequentialStmt*> initializers_;
|
||||||
|
|
||||||
|
// List of statements that should be emitted in a 'final' block
|
||||||
|
std::list<SequentialStmt*> finalizers_;
|
||||||
|
|
||||||
void do_use_from(const ScopeBase*that);
|
void do_use_from(const ScopeBase*that);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -259,7 +259,7 @@ VariableSeqAssignment::~VariableSeqAssignment()
|
||||||
delete rval_;
|
delete rval_;
|
||||||
}
|
}
|
||||||
|
|
||||||
WhileLoopStatement::WhileLoopStatement(perm_string lname, ExpLogical* cond, list<SequentialStmt*>* stmts)
|
WhileLoopStatement::WhileLoopStatement(perm_string lname, Expression* cond, list<SequentialStmt*>* stmts)
|
||||||
: LoopStatement(lname, stmts), cond_(cond)
|
: LoopStatement(lname, stmts), cond_(cond)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -235,14 +235,16 @@ class VariableSeqAssignment : public SequentialStmt {
|
||||||
class WhileLoopStatement : public LoopStatement {
|
class WhileLoopStatement : public LoopStatement {
|
||||||
public:
|
public:
|
||||||
WhileLoopStatement(perm_string loop_name,
|
WhileLoopStatement(perm_string loop_name,
|
||||||
ExpLogical*, list<SequentialStmt*>*);
|
Expression*, list<SequentialStmt*>*);
|
||||||
~WhileLoopStatement();
|
~WhileLoopStatement();
|
||||||
|
|
||||||
int elaborate(Entity*ent, ScopeBase*scope);
|
int elaborate(Entity*ent, ScopeBase*scope);
|
||||||
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
|
void write_to_stream(std::ostream&fd);
|
||||||
void dump(ostream&out, int indent) const;
|
void dump(ostream&out, int indent) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ExpLogical* cond_;
|
Expression* cond_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ForLoopStatement : public LoopStatement {
|
class ForLoopStatement : public LoopStatement {
|
||||||
|
|
@ -295,7 +297,8 @@ class ReportStmt : public SequentialStmt {
|
||||||
|
|
||||||
class AssertStmt : public ReportStmt {
|
class AssertStmt : public ReportStmt {
|
||||||
public:
|
public:
|
||||||
AssertStmt(Expression*condition, const char*message, ReportStmt::severity_t severity = ReportStmt::ERROR);
|
AssertStmt(Expression*condition, const char*message,
|
||||||
|
ReportStmt::severity_t severity = ReportStmt::ERROR);
|
||||||
|
|
||||||
void dump(ostream&out, int indent) const;
|
void dump(ostream&out, int indent) const;
|
||||||
int elaborate(Entity*ent, ScopeBase*scope);
|
int elaborate(Entity*ent, ScopeBase*scope);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
# include "scope.h"
|
# include "scope.h"
|
||||||
# include "library.h"
|
# include "library.h"
|
||||||
# include "subprogram.h"
|
# include "subprogram.h"
|
||||||
|
# include "std_types.h"
|
||||||
|
|
||||||
int SequentialStmt::elaborate(Entity*, ScopeBase*)
|
int SequentialStmt::elaborate(Entity*, ScopeBase*)
|
||||||
{
|
{
|
||||||
|
|
@ -173,13 +174,8 @@ int ProcedureCall::elaborate(Entity*ent, ScopeBase*scope)
|
||||||
if(param_list_) {
|
if(param_list_) {
|
||||||
for(list<named_expr_t*>::iterator cur = param_list_->begin()
|
for(list<named_expr_t*>::iterator cur = param_list_->begin()
|
||||||
; cur != param_list_->end() ; ++cur) {
|
; cur != param_list_->end() ; ++cur) {
|
||||||
const VType*tmp = (*cur)->expr()->probe_type(ent, scope);
|
errors += elaborate_argument((*cur)->expr(), def_, idx, ent, scope);
|
||||||
const VType*param_type = def_ ? def_->peek_param_type(idx) : NULL;
|
++idx;
|
||||||
|
|
||||||
if(!tmp && param_type)
|
|
||||||
tmp = param_type;
|
|
||||||
|
|
||||||
errors += (*cur)->expr()->elaborate_expr(ent, scope, tmp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -208,10 +204,12 @@ int VariableSeqAssignment::elaborate(Entity*ent, ScopeBase*scope)
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WhileLoopStatement::elaborate(Entity*, ScopeBase*)
|
int WhileLoopStatement::elaborate(Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
//TODO:check whether there is any wait statement in the statements (there should be)
|
int errors = 0;
|
||||||
return 0;
|
errors += elaborate_substatements(ent, scope);
|
||||||
|
errors += cond_->elaborate_expr(ent, scope, cond_->probe_type(ent, scope));
|
||||||
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BasicLoopStatement::elaborate(Entity*, ScopeBase*)
|
int BasicLoopStatement::elaborate(Entity*, ScopeBase*)
|
||||||
|
|
@ -221,7 +219,7 @@ int BasicLoopStatement::elaborate(Entity*, ScopeBase*)
|
||||||
|
|
||||||
int AssertStmt::elaborate(Entity*ent, ScopeBase*scope)
|
int AssertStmt::elaborate(Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
return cond_->elaborate_expr(ent, scope, 0);
|
return cond_->elaborate_expr(ent, scope, cond_->probe_type(ent, scope));
|
||||||
}
|
}
|
||||||
|
|
||||||
int WaitForStmt::elaborate(Entity*ent, ScopeBase*scope)
|
int WaitForStmt::elaborate(Entity*ent, ScopeBase*scope)
|
||||||
|
|
|
||||||
|
|
@ -210,12 +210,15 @@ void VariableSeqAssignment::write_to_stream(ostream&fd)
|
||||||
int ProcedureCall::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
int ProcedureCall::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
std::vector<Expression*>params;
|
||||||
|
|
||||||
std::vector<Expression*>params(param_list_->size());
|
if(param_list_) {
|
||||||
int i = 0;
|
params.reserve(param_list_->size());
|
||||||
for(std::list<named_expr_t*>::iterator it = param_list_->begin();
|
|
||||||
it != param_list_->end(); ++it)
|
for(std::list<named_expr_t*>::iterator it = param_list_->begin();
|
||||||
params[i++] = (*it)->expr();
|
it != param_list_->end(); ++it)
|
||||||
|
params.push_back((*it)->expr());
|
||||||
|
}
|
||||||
|
|
||||||
const Package*pkg = dynamic_cast<const Package*> (def_->get_parent());
|
const Package*pkg = dynamic_cast<const Package*> (def_->get_parent());
|
||||||
if (pkg != 0)
|
if (pkg != 0)
|
||||||
|
|
@ -352,6 +355,28 @@ void CaseSeqStmt::CaseStmtAlternative::write_to_stream(ostream&fd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WhileLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
out << "while(";
|
||||||
|
errors += cond_->emit(out, ent, scope);
|
||||||
|
out << ") begin" << endl;
|
||||||
|
errors += emit_substatements(out, ent, scope);
|
||||||
|
out << "end" << endl;
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WhileLoopStatement::write_to_stream(ostream&out)
|
||||||
|
{
|
||||||
|
out << "while(";
|
||||||
|
cond_->write_to_stream(out);
|
||||||
|
out << ") loop" << endl;
|
||||||
|
write_to_stream_substatements(out);
|
||||||
|
out << "end loop;" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
@ -484,7 +509,7 @@ int ReportStmt::emit(ostream&out, Entity*, ScopeBase*)
|
||||||
case UNSPECIFIED: ivl_assert(*this, false); break;
|
case UNSPECIFIED: ivl_assert(*this, false); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
out << msg_;
|
out << ExpString::escape_quot(msg_);
|
||||||
out << " (" << get_fileline() << ")\");";
|
out << " (" << get_fileline() << ")\");";
|
||||||
|
|
||||||
if(severity_ == FAILURE)
|
if(severity_ == FAILURE)
|
||||||
|
|
@ -497,7 +522,7 @@ int ReportStmt::emit(ostream&out, Entity*, ScopeBase*)
|
||||||
|
|
||||||
void ReportStmt::write_to_stream(std::ostream&fd)
|
void ReportStmt::write_to_stream(std::ostream&fd)
|
||||||
{
|
{
|
||||||
fd << "report \"" << msg_ << "\"" << std::endl;
|
fd << "report \"" << ExpString::escape_quot(msg_) << "\"" << std::endl;
|
||||||
|
|
||||||
fd << "severity ";
|
fd << "severity ";
|
||||||
switch(severity_)
|
switch(severity_)
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,78 @@ static class SubprogramSizeCast : public SubprogramHeader {
|
||||||
}
|
}
|
||||||
}*fn_conv_std_logic_vector, *fn_resize;
|
}*fn_conv_std_logic_vector, *fn_resize;
|
||||||
|
|
||||||
|
static class SubprogramReadWrite : public SubprogramBuiltin {
|
||||||
|
public:
|
||||||
|
SubprogramReadWrite(perm_string nam, perm_string newnam)
|
||||||
|
: SubprogramBuiltin(nam, newnam, NULL, NULL) {
|
||||||
|
ports_ = new std::list<InterfacePort*>();
|
||||||
|
ports_->push_back(new InterfacePort(&primitive_STRING, PORT_INOUT));
|
||||||
|
ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR, PORT_INOUT));
|
||||||
|
ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_std() const { return true; }
|
||||||
|
|
||||||
|
// Format types handled by $ivlh_read/write (see vpi/vhdl_textio.c)
|
||||||
|
enum format_t { FORMAT_STD, FORMAT_BOOL, FORMAT_TIME, FORMAT_HEX, FORMAT_STRING };
|
||||||
|
|
||||||
|
int emit_args(const std::vector<Expression*>&argv,
|
||||||
|
std::ostream&out, Entity*ent, ScopeBase*scope) const {
|
||||||
|
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < 2; ++i) {
|
||||||
|
errors += argv[i]->emit(out, ent, scope);
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
const VType*arg_type = argv[1]->probe_type(ent, scope);
|
||||||
|
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(arg_type);
|
||||||
|
const VTypePrimitive*prim = dynamic_cast<const VTypePrimitive*>(arg_type);
|
||||||
|
|
||||||
|
// Pick the right format
|
||||||
|
if(prim && prim->type() == VTypePrimitive::TIME)
|
||||||
|
out << FORMAT_TIME;
|
||||||
|
else if(arg_type && arg_type->type_match(&type_BOOLEAN))
|
||||||
|
out << FORMAT_BOOL;
|
||||||
|
else if((arg_type && arg_type->type_match(&primitive_CHARACTER)) ||
|
||||||
|
(arr && arr->element_type() == &primitive_CHARACTER))
|
||||||
|
out << FORMAT_STRING;
|
||||||
|
else
|
||||||
|
out << FORMAT_STD;
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
}*fn_read, *fn_write;
|
||||||
|
|
||||||
|
static class SubprogramHexReadWrite : public SubprogramBuiltin {
|
||||||
|
public:
|
||||||
|
SubprogramHexReadWrite(perm_string nam, perm_string newnam)
|
||||||
|
: SubprogramBuiltin(nam, newnam, NULL, NULL) {
|
||||||
|
ports_ = new std::list<InterfacePort*>();
|
||||||
|
ports_->push_back(new InterfacePort(&primitive_STRING, PORT_INOUT));
|
||||||
|
ports_->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR, PORT_INOUT));
|
||||||
|
ports_->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_std() const { return true; }
|
||||||
|
|
||||||
|
int emit_args(const std::vector<Expression*>&argv,
|
||||||
|
std::ostream&out, Entity*ent, ScopeBase*scope) const {
|
||||||
|
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < 2; ++i) {
|
||||||
|
errors += argv[i]->emit(out, ent, scope);
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
out << SubprogramReadWrite::FORMAT_HEX;
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
}*fn_hread, *fn_hwrite;
|
||||||
|
|
||||||
static SubprogramBuiltin*fn_std_logic_vector;
|
static SubprogramBuiltin*fn_std_logic_vector;
|
||||||
static SubprogramBuiltin*fn_to_unsigned;
|
static SubprogramBuiltin*fn_to_unsigned;
|
||||||
static SubprogramBuiltin*fn_unsigned;
|
static SubprogramBuiltin*fn_unsigned;
|
||||||
|
|
@ -103,6 +175,13 @@ static SubprogramBuiltin*fn_falling_edge;
|
||||||
static SubprogramBuiltin*fn_and_reduce;
|
static SubprogramBuiltin*fn_and_reduce;
|
||||||
static SubprogramBuiltin*fn_or_reduce;
|
static SubprogramBuiltin*fn_or_reduce;
|
||||||
|
|
||||||
|
static SubprogramBuiltin*fn_file_open;
|
||||||
|
static SubprogramBuiltin*fn_file_close;
|
||||||
|
static SubprogramBuiltin*fn_endfile;
|
||||||
|
|
||||||
|
static SubprogramBuiltin*fn_readline;
|
||||||
|
static SubprogramBuiltin*fn_writeline;
|
||||||
|
|
||||||
void preload_std_funcs(void)
|
void preload_std_funcs(void)
|
||||||
{
|
{
|
||||||
/* numeric_std library
|
/* numeric_std library
|
||||||
|
|
@ -141,7 +220,8 @@ void preload_std_funcs(void)
|
||||||
fn_resize = new SubprogramSizeCast(perm_string::literal("resize"));
|
fn_resize = new SubprogramSizeCast(perm_string::literal("resize"));
|
||||||
std_subprograms[fn_resize->name()] = fn_resize;
|
std_subprograms[fn_resize->name()] = fn_resize;
|
||||||
|
|
||||||
/* function conv_std_logic_vector
|
/* std_logic_arith library
|
||||||
|
* function conv_std_logic_vector(arg: integer; size: integer) return std_logic_vector;
|
||||||
*/
|
*/
|
||||||
fn_conv_std_logic_vector = new SubprogramSizeCast(perm_string::literal("conv_std_logic_vector"));
|
fn_conv_std_logic_vector = new SubprogramSizeCast(perm_string::literal("conv_std_logic_vector"));
|
||||||
std_subprograms[fn_conv_std_logic_vector->name()] = fn_conv_std_logic_vector;
|
std_subprograms[fn_conv_std_logic_vector->name()] = fn_conv_std_logic_vector;
|
||||||
|
|
@ -206,6 +286,86 @@ void preload_std_funcs(void)
|
||||||
perm_string::literal("$ivlh_to_unsigned"),
|
perm_string::literal("$ivlh_to_unsigned"),
|
||||||
fn_to_unsigned_args, &primitive_UNSIGNED);
|
fn_to_unsigned_args, &primitive_UNSIGNED);
|
||||||
std_subprograms[fn_to_unsigned->name()] = fn_to_unsigned;
|
std_subprograms[fn_to_unsigned->name()] = fn_to_unsigned;
|
||||||
|
|
||||||
|
/* procedure file_open (file f: text; filename: in string, file_open_kind: in mode);
|
||||||
|
*/
|
||||||
|
std::list<InterfacePort*>*fn_file_open_args = new std::list<InterfacePort*>();
|
||||||
|
fn_file_open_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
|
||||||
|
fn_file_open_args->push_back(new InterfacePort(&primitive_STRING, PORT_IN));
|
||||||
|
fn_file_open_args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN));
|
||||||
|
fn_file_open = new SubprogramBuiltin(perm_string::literal("file_open"),
|
||||||
|
perm_string::literal("$ivlh_file_open"),
|
||||||
|
fn_file_open_args, NULL);
|
||||||
|
std_subprograms[fn_file_open->name()] = fn_file_open;
|
||||||
|
|
||||||
|
/* std.textio library
|
||||||
|
* procedure file_close (file f: text);
|
||||||
|
*/
|
||||||
|
std::list<InterfacePort*>*fn_file_close_args = new std::list<InterfacePort*>();
|
||||||
|
fn_file_close_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
|
||||||
|
fn_file_close = new SubprogramBuiltin(perm_string::literal("file_close"),
|
||||||
|
perm_string::literal("$fclose"),
|
||||||
|
fn_file_close_args, NULL);
|
||||||
|
std_subprograms[fn_file_close->name()] = fn_file_close;
|
||||||
|
|
||||||
|
/* std.textio library
|
||||||
|
* procedure read (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
|
||||||
|
*/
|
||||||
|
fn_read = new SubprogramReadWrite(perm_string::literal("read"),
|
||||||
|
perm_string::literal("$ivlh_read"));
|
||||||
|
std_subprograms[fn_read->name()] = fn_read;
|
||||||
|
|
||||||
|
/* std.textio library
|
||||||
|
* procedure write (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
|
||||||
|
*/
|
||||||
|
fn_write = new SubprogramReadWrite(perm_string::literal("write"),
|
||||||
|
perm_string::literal("$ivlh_write"));
|
||||||
|
std_subprograms[fn_write->name()] = fn_write;
|
||||||
|
|
||||||
|
/* std.textio library
|
||||||
|
* procedure hread (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
|
||||||
|
*/
|
||||||
|
fn_hread = new SubprogramHexReadWrite(perm_string::literal("hread"),
|
||||||
|
perm_string::literal("$ivlh_read"));
|
||||||
|
std_subprograms[fn_hread->name()] = fn_hread;
|
||||||
|
|
||||||
|
/* std.textio library
|
||||||
|
* procedure hwrite (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
|
||||||
|
*/
|
||||||
|
fn_hwrite = new SubprogramHexReadWrite(perm_string::literal("hwrite"),
|
||||||
|
perm_string::literal("$ivlh_write"));
|
||||||
|
std_subprograms[fn_hwrite->name()] = fn_hwrite;
|
||||||
|
|
||||||
|
/* std.textio library
|
||||||
|
* procedure readline (file f: text; l: inout line);
|
||||||
|
*/
|
||||||
|
std::list<InterfacePort*>*fn_readline_args = new std::list<InterfacePort*>();
|
||||||
|
fn_readline_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
|
||||||
|
fn_readline_args->push_back(new InterfacePort(&primitive_STRING, PORT_OUT));
|
||||||
|
fn_readline = new SubprogramBuiltin(perm_string::literal("readline"),
|
||||||
|
perm_string::literal("$ivlh_readline"),
|
||||||
|
fn_readline_args, NULL);
|
||||||
|
std_subprograms[fn_readline->name()] = fn_readline;
|
||||||
|
|
||||||
|
/* std.textio library
|
||||||
|
* procedure writeline (file f: text; l: inout line);
|
||||||
|
*/
|
||||||
|
std::list<InterfacePort*>*fn_writeline_args = new std::list<InterfacePort*>();
|
||||||
|
fn_writeline_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
|
||||||
|
fn_writeline_args->push_back(new InterfacePort(&primitive_STRING, PORT_IN));
|
||||||
|
fn_writeline = new SubprogramBuiltin(perm_string::literal("writeline"),
|
||||||
|
perm_string::literal("$ivlh_writeline"),
|
||||||
|
fn_writeline_args, NULL);
|
||||||
|
std_subprograms[fn_writeline->name()] = fn_writeline;
|
||||||
|
|
||||||
|
/* function endline (file f: text) return boolean;
|
||||||
|
*/
|
||||||
|
std::list<InterfacePort*>*fn_endfile_args = new std::list<InterfacePort*>();
|
||||||
|
fn_endfile_args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
|
||||||
|
fn_endfile = new SubprogramBuiltin(perm_string::literal("endfile"),
|
||||||
|
perm_string::literal("$feof"),
|
||||||
|
fn_endfile_args, &type_BOOLEAN);
|
||||||
|
std_subprograms[fn_endfile->name()] = fn_endfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete_std_funcs()
|
void delete_std_funcs()
|
||||||
|
|
|
||||||
|
|
@ -21,20 +21,21 @@
|
||||||
#include "std_types.h"
|
#include "std_types.h"
|
||||||
#include "scope.h"
|
#include "scope.h"
|
||||||
|
|
||||||
static std::map<perm_string, VTypeDef*> std_types;
|
static map<perm_string, VTypeDef*> std_types;
|
||||||
// this list contains enums used by typedefs in the std_types map
|
// this list contains enums used by typedefs in the std_types map
|
||||||
static std::list<const VTypeEnum*> std_enums;
|
static list<const VTypeEnum*> std_enums;
|
||||||
|
|
||||||
const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true);
|
const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true);
|
||||||
const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER);
|
const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER);
|
||||||
const VTypePrimitive primitive_NATURAL(VTypePrimitive::NATURAL);
|
const VTypePrimitive primitive_NATURAL(VTypePrimitive::NATURAL);
|
||||||
const VTypePrimitive primitive_REAL(VTypePrimitive::REAL);
|
const VTypePrimitive primitive_REAL(VTypePrimitive::REAL);
|
||||||
const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true);
|
const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true);
|
||||||
const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER);
|
|
||||||
const VTypePrimitive primitive_TIME(VTypePrimitive::TIME);
|
const VTypePrimitive primitive_TIME(VTypePrimitive::TIME);
|
||||||
|
|
||||||
VTypeDef type_BOOLEAN(perm_string::literal("boolean"));
|
VTypeDef type_BOOLEAN(perm_string::literal("boolean"));
|
||||||
|
VTypeDef type_FILE_OPEN_KIND(perm_string::literal("file_open_kind"));
|
||||||
|
|
||||||
|
const VTypeArray primitive_CHARACTER(&primitive_BIT, 7, 0);
|
||||||
const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector<VTypeArray::range_t> (1));
|
const VTypeArray primitive_BIT_VECTOR(&primitive_BIT, vector<VTypeArray::range_t> (1));
|
||||||
const VTypeArray primitive_BOOL_VECTOR(&type_BOOLEAN, vector<VTypeArray::range_t> (1));
|
const VTypeArray primitive_BOOL_VECTOR(&type_BOOLEAN, vector<VTypeArray::range_t> (1));
|
||||||
const VTypeArray primitive_STDLOGIC_VECTOR(&primitive_STDLOGIC, vector<VTypeArray::range_t> (1));
|
const VTypeArray primitive_STDLOGIC_VECTOR(&primitive_STDLOGIC, vector<VTypeArray::range_t> (1));
|
||||||
|
|
@ -45,7 +46,7 @@ const VTypeArray primitive_UNSIGNED(&primitive_STDLOGIC, vector<VTypeArra
|
||||||
void generate_global_types(ActiveScope*res)
|
void generate_global_types(ActiveScope*res)
|
||||||
{
|
{
|
||||||
// boolean
|
// boolean
|
||||||
std::list<perm_string>*enum_BOOLEAN_vals = new std::list<perm_string>;
|
list<perm_string>*enum_BOOLEAN_vals = new list<perm_string>;
|
||||||
enum_BOOLEAN_vals->push_back(perm_string::literal("false"));
|
enum_BOOLEAN_vals->push_back(perm_string::literal("false"));
|
||||||
enum_BOOLEAN_vals->push_back(perm_string::literal("true"));
|
enum_BOOLEAN_vals->push_back(perm_string::literal("true"));
|
||||||
VTypeEnum*enum_BOOLEAN = new VTypeEnum(enum_BOOLEAN_vals);
|
VTypeEnum*enum_BOOLEAN = new VTypeEnum(enum_BOOLEAN_vals);
|
||||||
|
|
@ -53,6 +54,16 @@ void generate_global_types(ActiveScope*res)
|
||||||
std_types[type_BOOLEAN.peek_name()] = &type_BOOLEAN;
|
std_types[type_BOOLEAN.peek_name()] = &type_BOOLEAN;
|
||||||
std_enums.push_back(enum_BOOLEAN);
|
std_enums.push_back(enum_BOOLEAN);
|
||||||
|
|
||||||
|
// file_open_kind
|
||||||
|
list<perm_string>*enum_FILE_OPEN_KIND_vals = new list<perm_string>;
|
||||||
|
enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("read_mode"));
|
||||||
|
enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("write_mode"));
|
||||||
|
enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("append_mode"));
|
||||||
|
VTypeEnum*enum_FILE_OPEN_KIND = new VTypeEnum(enum_FILE_OPEN_KIND_vals);
|
||||||
|
type_FILE_OPEN_KIND.set_definition(enum_FILE_OPEN_KIND);
|
||||||
|
std_types[type_FILE_OPEN_KIND.peek_name()] = &type_FILE_OPEN_KIND;
|
||||||
|
std_enums.push_back(enum_FILE_OPEN_KIND);
|
||||||
|
|
||||||
res->use_name(type_BOOLEAN.peek_name(), &type_BOOLEAN);
|
res->use_name(type_BOOLEAN.peek_name(), &type_BOOLEAN);
|
||||||
res->use_name(perm_string::literal("bit"), &primitive_BIT);
|
res->use_name(perm_string::literal("bit"), &primitive_BIT);
|
||||||
res->use_name(perm_string::literal("bit_vector"), &primitive_BIT_VECTOR);
|
res->use_name(perm_string::literal("bit_vector"), &primitive_BIT_VECTOR);
|
||||||
|
|
|
||||||
|
|
@ -29,17 +29,19 @@ bool is_global_type(perm_string type_name);
|
||||||
void delete_global_types();
|
void delete_global_types();
|
||||||
const VTypeEnum*find_std_enum_name(perm_string name);
|
const VTypeEnum*find_std_enum_name(perm_string name);
|
||||||
|
|
||||||
extern const VTypePrimitive primitive_BOOLEAN;
|
|
||||||
extern const VTypePrimitive primitive_BIT;
|
extern const VTypePrimitive primitive_BIT;
|
||||||
extern const VTypePrimitive primitive_INTEGER;
|
extern const VTypePrimitive primitive_INTEGER;
|
||||||
extern const VTypePrimitive primitive_NATURAL;
|
extern const VTypePrimitive primitive_NATURAL;
|
||||||
extern const VTypePrimitive primitive_REAL;
|
extern const VTypePrimitive primitive_REAL;
|
||||||
extern const VTypePrimitive primitive_STDLOGIC;
|
extern const VTypePrimitive primitive_STDLOGIC;
|
||||||
extern const VTypePrimitive primitive_CHARACTER;
|
|
||||||
extern const VTypePrimitive primitive_TIME;
|
extern const VTypePrimitive primitive_TIME;
|
||||||
|
extern const VTypePrimitive primitive_TEXT;
|
||||||
|
extern const VTypePrimitive primitive_LINE;
|
||||||
|
|
||||||
extern VTypeDef type_BOOLEAN;
|
extern VTypeDef type_BOOLEAN;
|
||||||
|
extern VTypeDef type_FILE_OPEN_KIND;
|
||||||
|
|
||||||
|
extern const VTypeArray primitive_CHARACTER;
|
||||||
extern const VTypeArray primitive_BIT_VECTOR;
|
extern const VTypeArray primitive_BIT_VECTOR;
|
||||||
extern const VTypeArray primitive_BOOL_VECTOR;
|
extern const VTypeArray primitive_BOOL_VECTOR;
|
||||||
extern const VTypeArray primitive_STDLOGIC_VECTOR;
|
extern const VTypeArray primitive_STDLOGIC_VECTOR;
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ const InterfacePort*SubprogramHeader::find_param(perm_string nam) const
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VType*SubprogramHeader::peek_param_type(int idx) const
|
const InterfacePort*SubprogramHeader::peek_param(int idx) const
|
||||||
{
|
{
|
||||||
if(!ports_ || idx < 0 || (size_t)idx >= ports_->size())
|
if(!ports_ || idx < 0 || (size_t)idx >= ports_->size())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -146,7 +146,17 @@ const VType*SubprogramHeader::peek_param_type(int idx) const
|
||||||
std::list<InterfacePort*>::const_iterator p = ports_->begin();
|
std::list<InterfacePort*>::const_iterator p = ports_->begin();
|
||||||
std::advance(p, idx);
|
std::advance(p, idx);
|
||||||
|
|
||||||
return (*p)->type;
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VType*SubprogramHeader::peek_param_type(int idx) const
|
||||||
|
{
|
||||||
|
const InterfacePort*port = peek_param(idx);
|
||||||
|
|
||||||
|
if(port)
|
||||||
|
return port->type;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubprogramHeader::set_parent(const ScopeBase*par)
|
void SubprogramHeader::set_parent(const ScopeBase*par)
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ class SubprogramHeader : public LineInfo {
|
||||||
bool compare_specification(SubprogramHeader*that) const;
|
bool compare_specification(SubprogramHeader*that) const;
|
||||||
|
|
||||||
const InterfacePort*find_param(perm_string nam) const;
|
const InterfacePort*find_param(perm_string nam) const;
|
||||||
|
const InterfacePort*peek_param(int idx) const;
|
||||||
const VType*peek_param_type(int idx) const;
|
const VType*peek_param_type(int idx) const;
|
||||||
const VType*peek_return_type() const { return return_type_; }
|
const VType*peek_return_type() const { return return_type_; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ int SubprogramBody::emit_package(ostream&fd) const
|
||||||
|
|
||||||
for (map<perm_string,Variable*>::const_iterator cur = new_variables_.begin()
|
for (map<perm_string,Variable*>::const_iterator cur = new_variables_.begin()
|
||||||
; cur != new_variables_.end() ; ++cur) {
|
; cur != new_variables_.end() ; ++cur) {
|
||||||
// Workaround to enable reg_flag for variables
|
// Enable reg_flag for variables
|
||||||
cur->second->count_ref_sequ();
|
cur->second->count_ref_sequ();
|
||||||
errors += cur->second->emit(fd, NULL, NULL);
|
errors += cur->second->emit(fd, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,6 @@ void VTypePrimitive::show(ostream&out) const
|
||||||
case BIT:
|
case BIT:
|
||||||
out << "BIT";
|
out << "BIT";
|
||||||
break;
|
break;
|
||||||
case CHARACTER:
|
|
||||||
out << "CHARACTER";
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
out << "INTEGER";
|
out << "INTEGER";
|
||||||
break;
|
break;
|
||||||
|
|
@ -90,9 +87,6 @@ int VTypePrimitive::get_width(ScopeBase*) const
|
||||||
case NATURAL:
|
case NATURAL:
|
||||||
return 32;
|
return 32;
|
||||||
|
|
||||||
case CHARACTER:
|
|
||||||
return 8;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cerr << "sorry: primitive type " << type_ <<
|
std::cerr << "sorry: primitive type " << type_ <<
|
||||||
" has no get_width() implementation." << std::endl;
|
" has no get_width() implementation." << std::endl;
|
||||||
|
|
@ -271,8 +265,8 @@ void VTypeArray::evaluate_ranges(ScopeBase*scope) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VTypeRange::VTypeRange(const VType*base, int64_t end_val, int64_t start_val)
|
VTypeRange::VTypeRange(const VType*base)
|
||||||
: base_(base), end_(end_val), start_(start_val)
|
: base_(base)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,6 +274,28 @@ VTypeRange::~VTypeRange()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VTypeRangeConst::VTypeRangeConst(const VType*base, int64_t start_val, int64_t end_val)
|
||||||
|
: VTypeRange(base), start_(start_val), end_(end_val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VTypeRangeExpr::VTypeRangeExpr(const VType*base, Expression*start_expr,
|
||||||
|
Expression*end_expr, bool downto)
|
||||||
|
: VTypeRange(base), start_(start_expr), end_(end_expr), downto_(downto)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VTypeRangeExpr::~VTypeRangeExpr()
|
||||||
|
{
|
||||||
|
delete start_;
|
||||||
|
delete end_;
|
||||||
|
}
|
||||||
|
|
||||||
|
VType*VTypeRangeExpr::clone() const {
|
||||||
|
return new VTypeRangeExpr(base_type()->clone(), start_->clone(),
|
||||||
|
end_->clone(), downto_);
|
||||||
|
}
|
||||||
|
|
||||||
VTypeEnum::VTypeEnum(const std::list<perm_string>*names)
|
VTypeEnum::VTypeEnum(const std::list<perm_string>*names)
|
||||||
: names_(names->size())
|
: names_(names->size())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ class VTypeERROR : public VType {
|
||||||
class VTypePrimitive : public VType {
|
class VTypePrimitive : public VType {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum type_t { BIT, INTEGER, NATURAL, REAL, STDLOGIC, CHARACTER, TIME };
|
enum type_t { BIT, INTEGER, NATURAL, REAL, STDLOGIC, TIME };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VTypePrimitive(type_t tt, bool packed = false);
|
VTypePrimitive(type_t tt, bool packed = false);
|
||||||
|
|
@ -269,21 +269,52 @@ class VTypeArray : public VType {
|
||||||
class VTypeRange : public VType {
|
class VTypeRange : public VType {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VTypeRange(const VType*base, int64_t end, int64_t start);
|
VTypeRange(const VType*base);
|
||||||
~VTypeRange();
|
virtual ~VTypeRange() = 0;
|
||||||
|
|
||||||
VType*clone() const { return new VTypeRange(base_->clone(), start_, end_); }
|
bool write_std_types(std::ostream&fd) const;
|
||||||
|
int emit_def(std::ostream&out, perm_string name) const;
|
||||||
|
|
||||||
// Get the type that is limited by the range.
|
// Get the type that is limited by the range.
|
||||||
inline const VType* base_type() const { return base_; }
|
inline const VType*base_type() const { return base_; }
|
||||||
|
|
||||||
public: // Virtual methods
|
|
||||||
void write_to_stream(std::ostream&fd) const;
|
|
||||||
int emit_def(std::ostream&out, perm_string name) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const VType*base_;
|
const VType*base_;
|
||||||
int64_t end_, start_;
|
};
|
||||||
|
|
||||||
|
class VTypeRangeConst : public VTypeRange {
|
||||||
|
|
||||||
|
public:
|
||||||
|
VTypeRangeConst(const VType*base, int64_t end, int64_t start);
|
||||||
|
|
||||||
|
VType*clone() const {
|
||||||
|
return new VTypeRangeConst(base_type()->clone(), start_, end_);
|
||||||
|
}
|
||||||
|
|
||||||
|
public: // Virtual methods
|
||||||
|
void write_to_stream(std::ostream&fd) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int64_t start_, end_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VTypeRangeExpr : public VTypeRange {
|
||||||
|
|
||||||
|
public:
|
||||||
|
VTypeRangeExpr(const VType*base, Expression*end, Expression*start, bool downto);
|
||||||
|
~VTypeRangeExpr();
|
||||||
|
|
||||||
|
VType*clone() const;
|
||||||
|
|
||||||
|
public: // Virtual methods
|
||||||
|
void write_to_stream(std::ostream&fd) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Boundaries
|
||||||
|
Expression*start_, *end_;
|
||||||
|
|
||||||
|
// Range direction (downto/to)
|
||||||
|
bool downto_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VTypeEnum : public VType {
|
class VTypeEnum : public VType {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
# include "vtype.h"
|
# include "vtype.h"
|
||||||
# include "expression.h"
|
# include "expression.h"
|
||||||
|
# include "std_types.h"
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
# include <typeinfo>
|
# include <typeinfo>
|
||||||
# include <cassert>
|
# include <cassert>
|
||||||
|
|
@ -66,6 +67,14 @@ int VTypeArray::emit_def(ostream&out, perm_string name) const
|
||||||
if (base) {
|
if (base) {
|
||||||
assert(dimensions() == 1);
|
assert(dimensions() == 1);
|
||||||
|
|
||||||
|
// If this is a string type without any boundaries specified, then
|
||||||
|
// there is a direct counterpart in SV called.. 'string'
|
||||||
|
if(this == &primitive_STRING) {
|
||||||
|
out << "string";
|
||||||
|
emit_name(out, name);
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
base->emit_def(out, empty_perm_string);
|
base->emit_def(out, empty_perm_string);
|
||||||
if (signed_flag_)
|
if (signed_flag_)
|
||||||
out << " signed";
|
out << " signed";
|
||||||
|
|
@ -163,9 +172,6 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const
|
||||||
case REAL:
|
case REAL:
|
||||||
out << "real";
|
out << "real";
|
||||||
break;
|
break;
|
||||||
case CHARACTER:
|
|
||||||
out << "byte";
|
|
||||||
break;
|
|
||||||
case TIME:
|
case TIME:
|
||||||
out << "time";
|
out << "time";
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -161,9 +161,6 @@ void VTypePrimitive::write_to_stream(ostream&fd) const
|
||||||
case STDLOGIC:
|
case STDLOGIC:
|
||||||
fd << "std_logic";
|
fd << "std_logic";
|
||||||
break;
|
break;
|
||||||
case CHARACTER:
|
|
||||||
fd << "character";
|
|
||||||
break;
|
|
||||||
case TIME:
|
case TIME:
|
||||||
fd << "time";
|
fd << "time";
|
||||||
break;
|
break;
|
||||||
|
|
@ -174,21 +171,41 @@ void VTypePrimitive::write_to_stream(ostream&fd) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VTypeRange::write_to_stream(ostream&fd) const
|
bool VTypeRange::write_std_types(ostream&fd) const
|
||||||
{
|
{
|
||||||
// Detect some special cases that can be written as ieee or
|
// Detect some special cases that can be written as ieee or
|
||||||
// standard types.
|
// standard types.
|
||||||
if (const VTypePrimitive*tmp = dynamic_cast<const VTypePrimitive*> (base_)) {
|
if (const VTypePrimitive*tmp = dynamic_cast<const VTypePrimitive*>(base_)) {
|
||||||
if (tmp->type()==VTypePrimitive::NATURAL) {
|
if (tmp->type()==VTypePrimitive::NATURAL) {
|
||||||
fd << "natural";
|
fd << "natural";
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
base_->write_to_stream(fd);
|
return false;
|
||||||
fd << " range " << start_;
|
}
|
||||||
fd << (start_ < end_ ? " to " : " downto ");
|
|
||||||
fd << end_;
|
void VTypeRangeConst::write_to_stream(ostream&fd) const
|
||||||
|
{
|
||||||
|
if(write_std_types(fd))
|
||||||
|
return;
|
||||||
|
|
||||||
|
base_type()->write_to_stream(fd);
|
||||||
|
fd << " range " << start_;
|
||||||
|
fd << (start_ < end_ ? " to " : " downto ");
|
||||||
|
fd << end_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VTypeRangeExpr::write_to_stream(ostream&fd) const
|
||||||
|
{
|
||||||
|
if(write_std_types(fd))
|
||||||
|
return;
|
||||||
|
|
||||||
|
base_type()->write_to_stream(fd);
|
||||||
|
fd << " range ";
|
||||||
|
start_->write_to_stream(fd);
|
||||||
|
fd << (downto_ ? " downto " : " to ");
|
||||||
|
end_->write_to_stream(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VTypeRecord::write_to_stream(ostream&fd) const
|
void VTypeRecord::write_to_stream(ostream&fd) const
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,11 @@ V2009 = v2009_table.o v2009_array.o v2009_enum.o v2009_string.o
|
||||||
|
|
||||||
VHDL_SYS = vhdl_table.o
|
VHDL_SYS = vhdl_table.o
|
||||||
|
|
||||||
|
VHDL_TEXTIO = vhdl_textio.o sys_priv.o
|
||||||
|
|
||||||
VPI_DEBUG = vpi_debug.o
|
VPI_DEBUG = vpi_debug.o
|
||||||
|
|
||||||
all: dep system.vpi va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vpi_debug.vpi $(ALL32)
|
all: dep system.vpi va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vhdl_textio.vpi vpi_debug.vpi $(ALL32)
|
||||||
|
|
||||||
check: all
|
check: all
|
||||||
|
|
||||||
|
|
@ -88,7 +90,7 @@ clean:
|
||||||
rm -f sdf_lexor.c sdf_parse.c sdf_parse.output sdf_parse.h
|
rm -f sdf_lexor.c sdf_parse.c sdf_parse.output sdf_parse.h
|
||||||
rm -f table_mod_parse.c table_mod_parse.h table_mod_parse.output
|
rm -f table_mod_parse.c table_mod_parse.h table_mod_parse.output
|
||||||
rm -f table_mod_lexor.c
|
rm -f table_mod_lexor.c
|
||||||
rm -f va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vpi_debug.vpi
|
rm -f va_math.vpi v2005_math.vpi v2009.vpi vhdl_sys.vpi vhdl_textio.vpi vpi_debug.vpi
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f Makefile config.log
|
rm -f Makefile config.log
|
||||||
|
|
@ -163,6 +165,9 @@ va_math.vpi: $V ../vvp/libvpi.a
|
||||||
vhdl_sys.vpi: $(VHDL_SYS) ../vvp/libvpi.a
|
vhdl_sys.vpi: $(VHDL_SYS) ../vvp/libvpi.a
|
||||||
$(CC) @shared@ -o $@ $(VHDL_SYS) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
$(CC) @shared@ -o $@ $(VHDL_SYS) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
||||||
|
|
||||||
|
vhdl_textio.vpi: $(VHDL_TEXTIO) ../vvp/libvpi.a
|
||||||
|
$(CC) @shared@ -o $@ $(VHDL_TEXTIO) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
||||||
|
|
||||||
vpi_debug.vpi: $(VPI_DEBUG) ../vvp/libvpi.a
|
vpi_debug.vpi: $(VPI_DEBUG) ../vvp/libvpi.a
|
||||||
$(CC) @shared@ -o $@ $(VPI_DEBUG) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
$(CC) @shared@ -o $@ $(VPI_DEBUG) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS)
|
||||||
|
|
||||||
|
|
@ -177,6 +182,7 @@ install: all installdirs \
|
||||||
$(vpidir)/v2005_math.vpi $(vpidir)/v2005_math.sft \
|
$(vpidir)/v2005_math.vpi $(vpidir)/v2005_math.sft \
|
||||||
$(vpidir)/v2009.vpi $(vpidir)/v2009.sft \
|
$(vpidir)/v2009.vpi $(vpidir)/v2009.sft \
|
||||||
$(vpidir)/vhdl_sys.vpi $(vpidir)/vhdl_sys.sft \
|
$(vpidir)/vhdl_sys.vpi $(vpidir)/vhdl_sys.sft \
|
||||||
|
$(vpidir)/vhdl_textio.vpi $(vpidir)/vhdl_textio.sft \
|
||||||
$(vpidir)/vpi_debug.vpi
|
$(vpidir)/vpi_debug.vpi
|
||||||
|
|
||||||
$(vpidir)/system.vpi: ./system.vpi
|
$(vpidir)/system.vpi: ./system.vpi
|
||||||
|
|
@ -209,6 +215,12 @@ $(vpidir)/vhdl_sys.vpi: ./vhdl_sys.vpi
|
||||||
$(vpidir)/vhdl_sys.sft: vhdl_sys.sft
|
$(vpidir)/vhdl_sys.sft: vhdl_sys.sft
|
||||||
$(INSTALL_DATA) $< "$(DESTDIR)$@"
|
$(INSTALL_DATA) $< "$(DESTDIR)$@"
|
||||||
|
|
||||||
|
$(vpidir)/vhdl_textio.vpi: ./vhdl_textio.vpi
|
||||||
|
$(INSTALL_PROGRAM) ./vhdl_textio.vpi "$(DESTDIR)$(vpidir)/vhdl_textio.vpi"
|
||||||
|
|
||||||
|
$(vpidir)/vhdl_textio.sft: vhdl_textio.sft
|
||||||
|
$(INSTALL_DATA) $< "$(DESTDIR)$@"
|
||||||
|
|
||||||
$(vpidir)/vpi_debug.vpi: ./vpi_debug.vpi
|
$(vpidir)/vpi_debug.vpi: ./vpi_debug.vpi
|
||||||
$(INSTALL_PROGRAM) ./vpi_debug.vpi "$(DESTDIR)$(vpidir)/vpi_debug.vpi"
|
$(INSTALL_PROGRAM) ./vpi_debug.vpi "$(DESTDIR)$(vpidir)/vpi_debug.vpi"
|
||||||
|
|
||||||
|
|
@ -226,6 +238,8 @@ uninstall:
|
||||||
rm -f "$(DESTDIR)$(vpidir)/v2009.sft"
|
rm -f "$(DESTDIR)$(vpidir)/v2009.sft"
|
||||||
rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.vpi"
|
rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.vpi"
|
||||||
rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.sft"
|
rm -f "$(DESTDIR)$(vpidir)/vhdl_sys.sft"
|
||||||
|
rm -f "$(DESTDIR)$(vpidir)/vhdl_textio.vpi"
|
||||||
|
rm -f "$(DESTDIR)$(vpidir)/vhdl_textio.sft"
|
||||||
rm -f "$(DESTDIR)$(vpidir)/vpi_debug.vpi"
|
rm -f "$(DESTDIR)$(vpidir)/vpi_debug.vpi"
|
||||||
|
|
||||||
-include $(patsubst %.o, dep/%.d, $O)
|
-include $(patsubst %.o, dep/%.d, $O)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,943 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 CERN
|
||||||
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
|
*
|
||||||
|
* This source code is free software; you can redistribute it
|
||||||
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
* General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 2 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following VPI module implements some of the functions available
|
||||||
|
* in std.textio library.
|
||||||
|
*
|
||||||
|
* Type counterparts:
|
||||||
|
* VHDL SystemVerilog
|
||||||
|
* ------------------------------
|
||||||
|
* LINE string (line of text, in VHDL it is a pointer to string)
|
||||||
|
* TEXT int (file handle)
|
||||||
|
*
|
||||||
|
* Some of functions offered by std.textio library are not implemented here,
|
||||||
|
* as they can be directly replaced with SystemVerilog system functions.
|
||||||
|
*
|
||||||
|
* VHDL SystemVerilog
|
||||||
|
* --------------------------------------
|
||||||
|
* FILE_CLOSE(file F: TEXT) $fclose(fd)
|
||||||
|
* ENDFILE(file F: TEXT) $feof(fd)
|
||||||
|
*
|
||||||
|
* Procedures:
|
||||||
|
* HREAD (L: inout LINE; VALUE: out BIT_VECTOR)
|
||||||
|
* HWRITE (L: inout LINE; VALUE: out BIT_VECTOR)
|
||||||
|
* are handled with $ivlh_read/write() using FORMAT_HEX parameter (see format_t enum).
|
||||||
|
*/
|
||||||
|
|
||||||
|
# include "sys_priv.h"
|
||||||
|
# include "vpi_config.h"
|
||||||
|
# include "vpi_user.h"
|
||||||
|
# include <assert.h>
|
||||||
|
# include <string.h>
|
||||||
|
# include <ctype.h>
|
||||||
|
# include "ivl_alloc.h"
|
||||||
|
|
||||||
|
/* additional parameter values to distinguish between integer, boolean and
|
||||||
|
* time types or to use hex format */
|
||||||
|
enum format_t { FORMAT_STD, FORMAT_BOOL, FORMAT_TIME, FORMAT_HEX, FORMAT_STRING };
|
||||||
|
|
||||||
|
enum file_mode_t { FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND, FILE_MODE_LAST };
|
||||||
|
|
||||||
|
/* bits per vector, in a single s_vpi_vecval struct */
|
||||||
|
static const size_t BPW = 8 * sizeof(PLI_INT32);
|
||||||
|
|
||||||
|
static int is_integer_var(vpiHandle obj)
|
||||||
|
{
|
||||||
|
PLI_INT32 type = vpi_get(vpiType, obj);
|
||||||
|
|
||||||
|
return (type == vpiIntegerVar || type == vpiShortIntVar ||
|
||||||
|
type == vpiIntVar || type == vpiLongIntVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_error_line(vpiHandle callh) {
|
||||||
|
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_warning_line(vpiHandle callh) {
|
||||||
|
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sets a single bit value in a bit/logic vector */
|
||||||
|
static int set_vec_val(s_vpi_vecval* vector, char value, int idx) {
|
||||||
|
s_vpi_vecval*v = &vector[idx / BPW];
|
||||||
|
PLI_INT32 bit = idx % BPW;
|
||||||
|
|
||||||
|
switch(toupper(value)) {
|
||||||
|
case '0':
|
||||||
|
v->bval &= ~(1 << bit);
|
||||||
|
v->aval &= ~(1 << bit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '1':
|
||||||
|
v->bval &= ~(1 << bit);
|
||||||
|
v->aval |= (1 << bit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Z':
|
||||||
|
v->bval |= (1 << bit);
|
||||||
|
v->aval &= ~(1 << bit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'X':
|
||||||
|
v->bval |= (1 << bit);
|
||||||
|
v->aval |= (1 << bit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Converts a string of characters to a vector in s_vpi_value struct.
|
||||||
|
* Returns number of processed characters, 0 in case of failure.
|
||||||
|
* string is the data to be converted.
|
||||||
|
* val is the target s_vpi_value struct.
|
||||||
|
* var is the variable that is converted (to obtain size & type [2/4-state]).
|
||||||
|
*/
|
||||||
|
static int read_vector(const char *string, s_vpi_value *val, vpiHandle var)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
/* It could be easier to simply use val.format = vpiBinStrVal
|
||||||
|
* but there is no way to check if processing went fine */
|
||||||
|
val.format = vpiBinStrVal;
|
||||||
|
val.value.str = string;
|
||||||
|
processed_chars = size;
|
||||||
|
#endif
|
||||||
|
/* Vector size (==1 for scalars) */
|
||||||
|
int size = vpi_get(vpiSize, var);
|
||||||
|
|
||||||
|
/* Number of required s_vpi_vecval structs to store the result */
|
||||||
|
int words = (size + BPW - 1) / BPW; /* == ceil(size / BPW) */
|
||||||
|
int len = strlen(string);
|
||||||
|
|
||||||
|
val->format = vpiVectorVal; /* it also covers scalars */
|
||||||
|
val->value.vector = calloc(words, sizeof(s_vpi_vecval));
|
||||||
|
|
||||||
|
/* Skip spaces in the beginning */
|
||||||
|
int skipped = 0;
|
||||||
|
while(*string && *string == ' ') {
|
||||||
|
--len;
|
||||||
|
++string;
|
||||||
|
++skipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process bits */
|
||||||
|
int p;
|
||||||
|
for(p = 0; p < size && p < len; ++p) {
|
||||||
|
if(set_vec_val(val->value.vector, string[p], size - p - 1)) {
|
||||||
|
free(val->value.vector); /* error */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2-logic variables cannot hold X or Z values, so change them to 0 */
|
||||||
|
if(vpi_get(vpiType, var) == vpiBitVar) {
|
||||||
|
for(int i = 0; i < words; ++i) {
|
||||||
|
val->value.vector[i].aval &= ~val->value.vector[i].bval;
|
||||||
|
val->value.vector[i].bval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p + skipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Converts a string of characters to a time value, stored in vector filed of
|
||||||
|
* s_vpi_value struct.
|
||||||
|
* Returns number of processed characters, 0 in case of failure.
|
||||||
|
* string is the data to be converted.
|
||||||
|
* val is the target s_vpi_value struct.
|
||||||
|
* scope_unit is the time unit used in the scope (-3 for millisecond,
|
||||||
|
* -6 for microsecond, etc.)
|
||||||
|
*/
|
||||||
|
static int read_time(const char *string, s_vpi_value *val, PLI_INT32 scope_unit) {
|
||||||
|
PLI_UINT64 period;
|
||||||
|
char units[2];
|
||||||
|
int time_unit, processed_chars;
|
||||||
|
|
||||||
|
if(sscanf(string, "%ld %2s%n", &period, units, &processed_chars) != 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(!strncasecmp(units, "fs", 2))
|
||||||
|
time_unit = -15;
|
||||||
|
else if(!strncasecmp(units, "ps", 2))
|
||||||
|
time_unit = -12;
|
||||||
|
else if(!strncasecmp(units, "ns", 2))
|
||||||
|
time_unit = -9;
|
||||||
|
else if(!strncasecmp(units, "us", 2))
|
||||||
|
time_unit = -6;
|
||||||
|
else if(!strncasecmp(units, "ms", 2))
|
||||||
|
time_unit = -3;
|
||||||
|
else if(!strncasecmp(units, "s", 1))
|
||||||
|
time_unit = 0;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Scale the time units to the one used in the scope */
|
||||||
|
int scale_diff = time_unit - scope_unit;
|
||||||
|
|
||||||
|
if(scale_diff > 0) {
|
||||||
|
for(int i = 0; i < scale_diff; ++i)
|
||||||
|
period *= 10;
|
||||||
|
} else {
|
||||||
|
for(int i = 0; i < -scale_diff; ++i)
|
||||||
|
period /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vpiTimeVal format is not handled at the moment,
|
||||||
|
* so return the read value as a vector*/
|
||||||
|
val->format = vpiVectorVal;
|
||||||
|
val->value.vector = calloc(2, sizeof(s_vpi_vecval));
|
||||||
|
memset(val->value.vector, 0, 2 * sizeof(s_vpi_vecval));
|
||||||
|
|
||||||
|
val->value.vector[1].aval = (PLI_UINT32) (period >> 32);
|
||||||
|
val->value.vector[0].aval = (PLI_UINT32) period;
|
||||||
|
|
||||||
|
return processed_chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_string(const char *string, s_vpi_value *val) {
|
||||||
|
char buf[1024];
|
||||||
|
int processed_chars;
|
||||||
|
|
||||||
|
if(sscanf(string, "%1024s%n", buf, &processed_chars) != 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
val->format = vpiStringVal;
|
||||||
|
val->value.str = strndup(buf, processed_chars);
|
||||||
|
|
||||||
|
return processed_chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_time(char *string, const s_vpi_value* val,
|
||||||
|
size_t width, PLI_INT32 scope_unit) {
|
||||||
|
char prefix = 0;
|
||||||
|
PLI_UINT64 period;
|
||||||
|
|
||||||
|
switch(val->format) {
|
||||||
|
case vpiIntVal:
|
||||||
|
period = val->value.integer;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiVectorVal:
|
||||||
|
period = val->value.vector[0].aval;
|
||||||
|
|
||||||
|
if(width > BPW)
|
||||||
|
period |= (PLI_UINT64)(val->value.vector[1].aval) << 32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle the case when the time unit base is 10 or 100 */
|
||||||
|
int remainder = scope_unit % -3;
|
||||||
|
if(remainder) {
|
||||||
|
remainder += 3;
|
||||||
|
scope_unit -= remainder;
|
||||||
|
|
||||||
|
while(remainder--)
|
||||||
|
period *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(scope_unit) {
|
||||||
|
case -15: prefix = 'f'; break;
|
||||||
|
case -12: prefix = 'p'; break;
|
||||||
|
case -9: prefix = 'n'; break;
|
||||||
|
case -6: prefix = 'u'; break;
|
||||||
|
case -3: prefix = 'm'; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(prefix)
|
||||||
|
sprintf(string, "%ld %cs", period, prefix);
|
||||||
|
else
|
||||||
|
sprintf(string, "%ld s", period);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* slightly modified sys_fopen_compiletf */
|
||||||
|
static PLI_INT32 ivlh_file_open_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv;
|
||||||
|
assert(callh != 0);
|
||||||
|
|
||||||
|
argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
|
||||||
|
/* Check that there is a file name argument and that it is a string. */
|
||||||
|
if (argv == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s requires a string file name argument.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_integer_var(vpi_scan(argv))) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's first argument has to be an integer variable (file handle).\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_string_obj(vpi_scan(argv))) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's second argument argument must be a string (file name).\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When provided, the type argument must be a string. */
|
||||||
|
if(!vpi_scan(argv)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's third argument must be an integer (open mode).\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there are no extra arguments. */
|
||||||
|
check_for_extra_args(argv, callh, name, "three arguments", 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* procedure FILE_MODE(file F: TEXT; External_Name; in STRING;
|
||||||
|
Open_Kind: in FILE_MODE_KIND := READ_MODE); */
|
||||||
|
/* slightly modified sys_fopen_calltf */
|
||||||
|
static PLI_INT32 ivlh_file_open_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
s_vpi_value val;
|
||||||
|
int mode;
|
||||||
|
char *fname;
|
||||||
|
|
||||||
|
vpiHandle fhandleh = vpi_scan(argv);
|
||||||
|
vpiHandle fnameh = vpi_scan(argv);
|
||||||
|
vpiHandle modeh = vpi_scan(argv);
|
||||||
|
|
||||||
|
/* Get the mode handle */
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(modeh, &val);
|
||||||
|
mode = val.value.integer;
|
||||||
|
vpi_free_object(argv);
|
||||||
|
|
||||||
|
if(mode < 0 || mode >= FILE_MODE_LAST) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's file open mode argument is invalid.\n", name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fname = get_filename(callh, name, fnameh);
|
||||||
|
|
||||||
|
if(fname == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's could not obtain the file name.\n", name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open file and save the handle */
|
||||||
|
switch(mode) {
|
||||||
|
case FILE_MODE_READ:
|
||||||
|
val.value.integer = vpi_fopen(fname, "r");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILE_MODE_WRITE:
|
||||||
|
val.value.integer = vpi_fopen(fname, "w");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILE_MODE_APPEND:
|
||||||
|
val.value.integer = vpi_fopen(fname, "a");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_put_value(fhandleh, &val, 0, vpiNoDelay);
|
||||||
|
free(fname);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLI_INT32 ivlh_readwriteline_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle arg;
|
||||||
|
|
||||||
|
/* Check that there are two arguments and that the first is an
|
||||||
|
integer (file handle) and that the second is string. */
|
||||||
|
if(argv == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s requires two arguments.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg || !is_integer_var(arg)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's first argument must be an integer variable (file handle).\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg || !is_string_obj(arg)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's second argument must be a string.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure there are no extra arguments. */
|
||||||
|
check_for_extra_args(argv, callh, name, "two arguments", 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* procedure READLINE (file F: TEXT; L: inout LINE); */
|
||||||
|
/* slightly modified sys_fgets_calltf */
|
||||||
|
static PLI_INT32 ivlh_readline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle stringh, arg;
|
||||||
|
s_vpi_value val;
|
||||||
|
PLI_UINT32 fd;
|
||||||
|
FILE *fp;
|
||||||
|
char *text;
|
||||||
|
const int BUF_SIZE = 1024;
|
||||||
|
char buf[BUF_SIZE];
|
||||||
|
|
||||||
|
/* Get the file descriptor. */
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(arg, &val);
|
||||||
|
fd = val.value.integer;
|
||||||
|
|
||||||
|
/* Get the string handle. */
|
||||||
|
stringh = vpi_scan(argv);
|
||||||
|
vpi_free_object(argv);
|
||||||
|
|
||||||
|
/* Return zero if this is not a valid fd. */
|
||||||
|
fp = vpi_get_file(fd);
|
||||||
|
if(!fp) {
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("invalid file descriptor (0x%x) given to %s.\n",
|
||||||
|
(unsigned int)fd, name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read in the bytes. Return 0 if there was an error. */
|
||||||
|
if(fgets(buf, BUF_SIZE, fp) == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s reading past the end of file.\n", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = strlen(buf);
|
||||||
|
|
||||||
|
if(len == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s read 0 bytes.\n", name);
|
||||||
|
return 0;
|
||||||
|
} else if(len == BUF_SIZE - 1) {
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("%s has reached the buffer limit, part of the "
|
||||||
|
"processed string might have been skipped.\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the characters to the register. */
|
||||||
|
text = strndup(buf, len - 1); /* skip the newline character */
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
val.value.str = text;
|
||||||
|
vpi_put_value(stringh, &val, 0, vpiNoDelay);
|
||||||
|
free(text);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* procedure WRITELINE (file F: TEXT; L: inout LINE); */
|
||||||
|
/* slightly modified sys_fgets_calltf */
|
||||||
|
static PLI_INT32 ivlh_writeline_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle stringh, arg;
|
||||||
|
s_vpi_value val;
|
||||||
|
PLI_UINT32 fd;
|
||||||
|
FILE *fp;
|
||||||
|
char *empty;
|
||||||
|
|
||||||
|
/* Get the file descriptor. */
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(arg, &val);
|
||||||
|
fd = val.value.integer;
|
||||||
|
|
||||||
|
/* Get the string contents. */
|
||||||
|
stringh = vpi_scan(argv);
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
vpi_get_value(stringh, &val);
|
||||||
|
|
||||||
|
vpi_free_object(argv);
|
||||||
|
|
||||||
|
/* Return zero if this is not a valid fd. */
|
||||||
|
fp = vpi_get_file(fd);
|
||||||
|
if(!fp) {
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("invalid file descriptor (0x%x) given to %s.\n",
|
||||||
|
(unsigned int)fd, name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "%s\n", val.value.str);
|
||||||
|
|
||||||
|
/* Clear the written string */
|
||||||
|
empty = strdup("");
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
val.value.str = empty;
|
||||||
|
vpi_put_value(stringh, &val, 0, vpiNoDelay);
|
||||||
|
free(empty);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLI_INT32 ivlh_read_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle arg;
|
||||||
|
|
||||||
|
if(argv == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s requires three arguments.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg || !is_string_obj(arg)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's first argument must be a string.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg || is_constant_obj(arg)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's second argument must be a variable.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's third argument must be an integer.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Make sure there are no extra arguments. */
|
||||||
|
check_for_extra_args(argv, callh, name, "three arguments", 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* procedure READ (L: inout LINE;
|
||||||
|
VALUE: out BIT/BIT_VECTOR/BOOLEAN/CHARACTER/INTEGER/REAL/STRING/TIME); */
|
||||||
|
static PLI_INT32 ivlh_read_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle stringh, varh, formath;
|
||||||
|
s_vpi_value val;
|
||||||
|
PLI_INT32 type, format;
|
||||||
|
char *string = 0;
|
||||||
|
int processed_chars = 0, fail = 0;
|
||||||
|
|
||||||
|
/* Get the string */
|
||||||
|
stringh = vpi_scan(argv);
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
vpi_get_value(stringh, &val);
|
||||||
|
|
||||||
|
/* Get the destination variable */
|
||||||
|
varh = vpi_scan(argv);
|
||||||
|
type = vpi_get(vpiType, varh);
|
||||||
|
|
||||||
|
if(strlen(val.value.str) == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s cannot read from an empty string.\n", name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string = strdup(val.value.str);
|
||||||
|
|
||||||
|
/* Get the format (see enum format_t) */
|
||||||
|
formath = vpi_scan(argv);
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(formath, &val);
|
||||||
|
format = val.value.integer;
|
||||||
|
vpi_free_object(argv);
|
||||||
|
|
||||||
|
switch(format) {
|
||||||
|
case FORMAT_STD:
|
||||||
|
switch(type) {
|
||||||
|
/* TODO longint is 64-bit, so it has to be handled by vector */
|
||||||
|
/*case vpiLongIntVar:*/
|
||||||
|
case vpiShortIntVar:
|
||||||
|
case vpiIntVar:
|
||||||
|
case vpiByteVar:
|
||||||
|
case vpiIntegerVar:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
if(sscanf(string, "%d%n", &val.value.integer, &processed_chars) != 1)
|
||||||
|
fail = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiBitVar: /* bit, bit vector */
|
||||||
|
case vpiLogicVar: /* ==vpiReg time, logic, logic vector */
|
||||||
|
processed_chars = read_vector(string, &val, varh);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiRealVar:
|
||||||
|
val.format = vpiRealVal;
|
||||||
|
if(sscanf(string, "%lf%n", &val.value.real, &processed_chars) != 1)
|
||||||
|
fail = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiStringVar:
|
||||||
|
processed_chars = read_string(string, &val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fail = 1;
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("%s does not handle such type (%d).\n", name, type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_BOOL:
|
||||||
|
{
|
||||||
|
char buf[5];
|
||||||
|
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
if(sscanf(string, "%5s%n", buf, &processed_chars) == 1)
|
||||||
|
{
|
||||||
|
if(!strncasecmp(buf, "true", 4))
|
||||||
|
val.value.integer = 1;
|
||||||
|
else if(!strncasecmp(buf, "false", 5))
|
||||||
|
val.value.integer = 0;
|
||||||
|
else
|
||||||
|
fail = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_TIME:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
processed_chars = read_time(string, &val, vpi_get(vpiTimeUnit, callh));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_HEX:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
if(sscanf(string, "%x%n", &val.value.integer, &processed_chars) != 1)
|
||||||
|
fail = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_STRING:
|
||||||
|
processed_chars = read_string(string, &val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(processed_chars == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s could not read a valid value.\n", name);
|
||||||
|
fail = 1;
|
||||||
|
} else if(val.format == vpiStringVar && processed_chars == 1024) {
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("%s has reached the buffer limit, part of the "
|
||||||
|
"processed string might have been skipped.\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!fail) {
|
||||||
|
assert(processed_chars > 0);
|
||||||
|
|
||||||
|
/* Store the read value */
|
||||||
|
vpi_put_value(varh, &val, 0, vpiNoDelay);
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
if(val.format == vpiStringVar)
|
||||||
|
free(val.value.str);
|
||||||
|
else if(val.format == vpiVectorVal)
|
||||||
|
free(val.value.vector);
|
||||||
|
|
||||||
|
/* Strip the read token from the string */
|
||||||
|
char* tmp = strdup(&string[processed_chars]);
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
val.value.str = tmp;
|
||||||
|
vpi_put_value(stringh, &val, 0, vpiNoDelay);
|
||||||
|
free(tmp);
|
||||||
|
} else {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s failed.\n", name);
|
||||||
|
/*vpi_control(vpiFinish, 1);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
free(string);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLI_INT32 ivlh_write_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle arg;
|
||||||
|
|
||||||
|
if(argv == 0) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s requires three arguments.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg || !is_string_obj(arg)) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's first argument must be a string.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s requires three arguments.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if(!arg) {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s's third argument must be an integer.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Make sure there are no extra arguments. */
|
||||||
|
check_for_extra_args(argv, callh, name, "three arguments", 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*procedure WRITE (L: inout LINE;
|
||||||
|
VALUE: in BIT/BIT_VECTOR/BOOLEAN/CHARACTER/INTEGER/REAL/STRING/TIME);
|
||||||
|
JUSTIFIED: in SIDE:= RIGHT; FIELD: in WIDTH := 0); */
|
||||||
|
/* JUSTIFIED & FIELD are not handled at the moment */
|
||||||
|
static PLI_INT32 ivlh_write_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle stringh, varh, formath;
|
||||||
|
s_vpi_value val;
|
||||||
|
PLI_INT32 type, format;
|
||||||
|
char *string = 0;
|
||||||
|
int fail = 0, res = 0;
|
||||||
|
const int BUF_SIZE = 1024;
|
||||||
|
char buf[BUF_SIZE];
|
||||||
|
|
||||||
|
/* Get the string */
|
||||||
|
stringh = vpi_scan(argv);
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
vpi_get_value(stringh, &val);
|
||||||
|
string = strdup(val.value.str);
|
||||||
|
|
||||||
|
/* Get the destination variable */
|
||||||
|
varh = vpi_scan(argv);
|
||||||
|
type = vpi_get(vpiType, varh);
|
||||||
|
|
||||||
|
/* Get the format (see enum format_t) */
|
||||||
|
formath = vpi_scan(argv);
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(formath, &val);
|
||||||
|
format = val.value.integer;
|
||||||
|
vpi_free_object(argv);
|
||||||
|
|
||||||
|
/* Convert constant types to variable types */
|
||||||
|
if(type == vpiConstant) {
|
||||||
|
type = vpi_get(vpiConstType, varh);
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case vpiRealConst:
|
||||||
|
type = vpiRealVar;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiStringConst:
|
||||||
|
type = vpiStringVar;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiDecConst:
|
||||||
|
case vpiBinaryConst:
|
||||||
|
case vpiOctConst:
|
||||||
|
case vpiHexConst:
|
||||||
|
type = vpiIntVar;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(format) {
|
||||||
|
case FORMAT_STD:
|
||||||
|
switch(type) {
|
||||||
|
/* TODO longint is 64-bit, so it has to be handled by vector */
|
||||||
|
/*case vpiLongIntVar:*/
|
||||||
|
case vpiShortIntVar:
|
||||||
|
case vpiIntVar:
|
||||||
|
case vpiByteVar:
|
||||||
|
case vpiIntegerVar:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%d", string, val.value.integer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiBitVar: /* bit, bit vector */
|
||||||
|
case vpiLogicVar: /* ==vpiReg time, logic, logic vector */
|
||||||
|
val.format = vpiBinStrVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
|
||||||
|
/* VHDL stores X/Z values uppercase, so follow the rule */
|
||||||
|
for(size_t i = 0; i< strlen(val.value.str); ++i)
|
||||||
|
val.value.str[i] = toupper(val.value.str[i]);
|
||||||
|
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiRealVar:
|
||||||
|
val.format = vpiRealVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%lf", string, val.value.real);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vpiStringVar:
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fail = 1;
|
||||||
|
show_warning_line(callh);
|
||||||
|
vpi_printf("%s does not handle such type (%d).\n", name, type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_BOOL:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%s", string,
|
||||||
|
val.value.integer ? "TRUE" : "FALSE");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_TIME:
|
||||||
|
{
|
||||||
|
char tmp[64];
|
||||||
|
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
|
||||||
|
if(write_time(tmp, &val, vpi_get(vpiSize, varh), vpi_get(vpiTimeUnit, callh))) {
|
||||||
|
fail = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%s", string, tmp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_HEX:
|
||||||
|
val.format = vpiIntVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%X", string, val.value.integer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FORMAT_STRING:
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
vpi_get_value(varh, &val);
|
||||||
|
res = snprintf(buf, BUF_SIZE, "%s%s", string, val.value.str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(res > BUF_SIZE)
|
||||||
|
fail = 1;
|
||||||
|
|
||||||
|
if(!fail) {
|
||||||
|
/* Strip the read token from the string */
|
||||||
|
char* tmp = strndup(buf, BUF_SIZE);
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
val.value.str = tmp;
|
||||||
|
vpi_put_value(stringh, &val, 0, vpiNoDelay);
|
||||||
|
free(tmp);
|
||||||
|
} else {
|
||||||
|
show_error_line(callh);
|
||||||
|
vpi_printf("%s failed.\n", name);
|
||||||
|
/*vpi_control(vpiFinish, 1);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
free(string);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vhdl_register(void)
|
||||||
|
{
|
||||||
|
vpiHandle res;
|
||||||
|
|
||||||
|
s_vpi_systf_data tf_data[] = {
|
||||||
|
{ vpiSysTask, 0, "$ivlh_file_open",
|
||||||
|
ivlh_file_open_calltf, ivlh_file_open_compiletf, 0,
|
||||||
|
"$ivlh_file_open" },
|
||||||
|
|
||||||
|
{ vpiSysTask, 0, "$ivlh_readline",
|
||||||
|
ivlh_readline_calltf, ivlh_readwriteline_compiletf, 0,
|
||||||
|
"$ivlh_readline" },
|
||||||
|
|
||||||
|
{ vpiSysTask, 0, "$ivlh_writeline",
|
||||||
|
ivlh_writeline_calltf, ivlh_readwriteline_compiletf, 0,
|
||||||
|
"$ivlh_writeline" },
|
||||||
|
|
||||||
|
{ vpiSysTask, 0, "$ivlh_read",
|
||||||
|
ivlh_read_calltf, ivlh_read_compiletf, 0,
|
||||||
|
"$ivlh_read" },
|
||||||
|
|
||||||
|
{ vpiSysTask, 0, "$ivlh_write",
|
||||||
|
ivlh_write_calltf, ivlh_write_compiletf, 0,
|
||||||
|
"$ivlh_write" },
|
||||||
|
};
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < sizeof(tf_data) / sizeof(s_vpi_systf_data); ++i) {
|
||||||
|
res = vpi_register_systf(&tf_data[i]);
|
||||||
|
vpip_make_systf_system_defined(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*vlog_startup_routines[])(void) = {
|
||||||
|
vhdl_register,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
$ivlh_file_open vpiSysFuncVoid
|
||||||
|
|
||||||
|
$ivlh_readline vpiSysFuncVoid
|
||||||
|
$ivlh_writeline vpiSysFuncVoid
|
||||||
|
|
||||||
|
$ivlh_read vpiSysFuncVoid
|
||||||
|
$ivlh_write vpiSysFuncVoid
|
||||||
|
$ivlh_hread vpiSysFuncVoid
|
||||||
|
$ivlh_hwrite vpiSysFuncVoid
|
||||||
Loading…
Reference in New Issue