Merge pull request #86 from orsonmmz/files

Basic support for std.textio/ieee.std_logic_textio
This commit is contained in:
Stephen Williams 2015-12-07 10:37:13 -08:00
commit fbeac729af
40 changed files with 1703 additions and 205 deletions

View File

@ -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. */

View File

@ -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;

View File

@ -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

View File

@ -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;
}
} }

View File

@ -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 */

View File

@ -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);
}
} }

View File

@ -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;
} }

View File

@ -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 << "@(";

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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 */

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
} }*/

View File

@ -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 << "\"";
} }

View File

@ -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;

View File

@ -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());

View File

@ -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"), &params);
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"), &params);
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");
} }
; ;

View File

@ -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;
} }

View File

@ -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 */

View File

@ -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)

View File

@ -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);
}; };

View File

@ -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)
{ {
} }

View File

@ -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);

View File

@ -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)

View File

@ -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_)

View File

@ -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()

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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_; }

View File

@ -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);
} }

View File

@ -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())
{ {

View File

@ -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 {

View File

@ -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;

View File

@ -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

View File

@ -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)

943
vpi/vhdl_textio.c Normal file
View File

@ -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
};

9
vpi/vhdl_textio.sft Normal file
View File

@ -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