Add compiler and the start of vvp support for ->>
This commit is contained in:
parent
753bf516d6
commit
60a77b08d2
15
Statement.cc
15
Statement.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -416,8 +416,8 @@ PReturn::~PReturn()
|
|||
delete expr_;
|
||||
}
|
||||
|
||||
PTrigger::PTrigger(PPackage*pkg, const pform_name_t&e)
|
||||
: package_(pkg), event_(e)
|
||||
PTrigger::PTrigger(PPackage*pkg, const pform_name_t&ev)
|
||||
: package_(pkg), event_(ev)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -425,6 +425,15 @@ PTrigger::~PTrigger()
|
|||
{
|
||||
}
|
||||
|
||||
PNBTrigger::PNBTrigger(const pform_name_t&ev, PExpr*dly)
|
||||
: event_(ev), dly_(dly)
|
||||
{
|
||||
}
|
||||
|
||||
PNBTrigger::~PNBTrigger()
|
||||
{
|
||||
}
|
||||
|
||||
PWhile::PWhile(PExpr*ex, Statement*st)
|
||||
: cond_(ex), statement_(st)
|
||||
{
|
||||
|
|
|
|||
13
Statement.h
13
Statement.h
|
|
@ -590,6 +590,19 @@ class PTrigger : public Statement {
|
|||
pform_name_t event_;
|
||||
};
|
||||
|
||||
class PNBTrigger : public Statement {
|
||||
public:
|
||||
explicit PNBTrigger(const pform_name_t&ev, PExpr*dly);
|
||||
~PNBTrigger();
|
||||
|
||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
|
||||
private:
|
||||
pform_name_t event_;
|
||||
PExpr*dly_;
|
||||
};
|
||||
|
||||
class PWhile : public Statement {
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -1300,6 +1300,13 @@ void NetEvTrig::dump(ostream&o, unsigned ind) const
|
|||
<< "// " << get_fileline() << endl;
|
||||
}
|
||||
|
||||
void NetEvNBTrig::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "->> " ;
|
||||
if (dly_) o << "#" << *dly_ << " ";
|
||||
o << event_->name() << "; " << "// " << get_fileline() << endl;
|
||||
}
|
||||
|
||||
void NetEvWait::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "";
|
||||
|
|
|
|||
32
elaborate.cc
32
elaborate.cc
|
|
@ -5780,6 +5780,38 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const
|
|||
return trig;
|
||||
}
|
||||
|
||||
NetProc* PNBTrigger::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
assert(scope);
|
||||
|
||||
NetNet* sig = 0;
|
||||
const NetExpr*par = 0;
|
||||
NetEvent* eve = 0;
|
||||
|
||||
NetScope*found_in = symbol_search(this, des, scope, event_,
|
||||
sig, par, eve);
|
||||
|
||||
if (found_in == 0) {
|
||||
cerr << get_fileline() << ": error: event <" << event_ << ">"
|
||||
<< " not found." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (eve == 0) {
|
||||
cerr << get_fileline() << ": error: <" << event_ << ">"
|
||||
<< " is not a named event." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*dly = 0;
|
||||
if (dly_) dly = elab_and_eval(des, scope, dly_, -1);
|
||||
NetEvNBTrig*trig = new NetEvNBTrig(eve, dly);
|
||||
trig->set_line(*this);
|
||||
return trig;
|
||||
}
|
||||
|
||||
/*
|
||||
* The while loop is fairly directly represented in the netlist.
|
||||
*/
|
||||
|
|
|
|||
7
emit.cc
7
emit.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -389,6 +389,11 @@ bool NetEvTrig::emit_proc(struct target_t*tgt) const
|
|||
return tgt->proc_trigger(this);
|
||||
}
|
||||
|
||||
bool NetEvNBTrig::emit_proc(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_nb_trigger(this);
|
||||
}
|
||||
|
||||
bool NetEvWait::emit_proc(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_wait(this);
|
||||
|
|
|
|||
|
|
@ -426,6 +426,7 @@ typedef enum ivl_statement_type_e {
|
|||
IVL_ST_FORK_JOIN_ANY = 28,
|
||||
IVL_ST_FORK_JOIN_NONE = 29,
|
||||
IVL_ST_FREE = 26,
|
||||
IVL_ST_NB_TRIGGER = 31,
|
||||
IVL_ST_RELEASE = 17,
|
||||
IVL_ST_REPEAT = 18,
|
||||
IVL_ST_STASK = 19,
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ TU [munpf]
|
|||
"^~" { return K_NXOR; }
|
||||
"~&" { return K_NAND; }
|
||||
"->" { return K_TRIGGER; }
|
||||
"->>" { return K_NB_TRIGGER; }
|
||||
"+:" { return K_PO_POS; }
|
||||
"-:" { return K_PO_NEG; }
|
||||
"<+" { return K_CONTRIBUTE; }
|
||||
|
|
|
|||
35
net_event.cc
35
net_event.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -264,6 +264,39 @@ const NetEvent* NetEvTrig::event() const
|
|||
return event_;
|
||||
}
|
||||
|
||||
NetEvNBTrig::NetEvNBTrig(NetEvent*ev, NetExpr*dly)
|
||||
: event_(ev), dly_(dly)
|
||||
{
|
||||
enext_ = event_->nb_trig_;
|
||||
event_->nb_trig_ = this;
|
||||
}
|
||||
|
||||
NetEvNBTrig::~NetEvNBTrig()
|
||||
{
|
||||
if (event_->nb_trig_ == this) {
|
||||
event_->nb_trig_ = enext_;
|
||||
|
||||
} else {
|
||||
NetEvNBTrig*cur = event_->nb_trig_;
|
||||
while (cur->enext_ != this) {
|
||||
assert(cur->enext_);
|
||||
cur = cur->enext_;
|
||||
}
|
||||
|
||||
cur->enext_ = this->enext_;
|
||||
}
|
||||
}
|
||||
|
||||
const NetExpr* NetEvNBTrig::delay() const
|
||||
{
|
||||
return dly_;
|
||||
}
|
||||
|
||||
const NetEvent* NetEvNBTrig::event() const
|
||||
{
|
||||
return event_;
|
||||
}
|
||||
|
||||
NetEvProbe::NetEvProbe(NetScope*s, perm_string n, NetEvent*tgt,
|
||||
edge_t t, unsigned p)
|
||||
: NetNode(s, n, p), event_(tgt), edge_(t)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2019 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -475,6 +475,11 @@ NexusSet* NetEvTrig::nex_input(bool, bool, bool) const
|
|||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetEvNBTrig::nex_input(bool, bool, bool) const
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetEvWait::nex_input(bool rem_out, bool always_sens, bool nested_func) const
|
||||
{
|
||||
NexusSet*result = new NexusSet;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002-2017 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -134,6 +134,10 @@ void NetEvTrig::nex_output(NexusSet&)
|
|||
{
|
||||
}
|
||||
|
||||
void NetEvNBTrig::nex_output(NexusSet&)
|
||||
{
|
||||
}
|
||||
|
||||
void NetEvWait::nex_output(NexusSet&out)
|
||||
{
|
||||
if (statement_) statement_->nex_output(out);
|
||||
|
|
|
|||
|
|
@ -3260,6 +3260,13 @@ bool NetEvTrig::check_synth(ivl_process_type_t pr_type,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool NetEvNBTrig::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* /* scope */ ) const
|
||||
{
|
||||
print_synth_warning(this, "A non-blocking event trigger", pr_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The delay check above has already marked this as an error.
|
||||
bool NetEvWait::check_synth(ivl_process_type_t pr_type,
|
||||
const NetScope* scope) const
|
||||
|
|
|
|||
35
netlist.h
35
netlist.h
|
|
@ -73,6 +73,7 @@ class NetFuncDef;
|
|||
class NetRamDq;
|
||||
class NetTaskDef;
|
||||
class NetEvTrig;
|
||||
class NetEvNBTrig;
|
||||
class NetEvWait;
|
||||
class PClass;
|
||||
class PExpr;
|
||||
|
|
@ -3346,6 +3347,11 @@ class NetDoWhile : public NetProc {
|
|||
* turn awakens the waiting threads. Each NetEvTrig object references
|
||||
* exactly one event object.
|
||||
*
|
||||
* The NetEvNBTrig class represents non-blocking trigger statements.
|
||||
* Executing this statement causes the referenced event to be triggered
|
||||
* at some time in the future, which in turn awakens the waiting threads.
|
||||
* Each NetEvNBTrig object references exactly one event object.
|
||||
*
|
||||
* The NetEvProbe class is the structural equivalent of the NetEvTrig,
|
||||
* in that it is a node and watches bit values that it receives. It
|
||||
* checks for edges then if appropriate triggers the associated
|
||||
|
|
@ -3358,6 +3364,7 @@ class NetEvent : public LineInfo {
|
|||
friend class NetScope;
|
||||
friend class NetEvProbe;
|
||||
friend class NetEvTrig;
|
||||
friend class NetEvNBTrig;
|
||||
friend class NetEvWait;
|
||||
friend class NetEEvent;
|
||||
|
||||
|
|
@ -3416,6 +3423,9 @@ class NetEvent : public LineInfo {
|
|||
// Use these methods to list the triggers attached to me.
|
||||
NetEvTrig* trig_;
|
||||
|
||||
// Use these methods to list the non-blocking triggers attached to me.
|
||||
NetEvNBTrig* nb_trig_;
|
||||
|
||||
// Use This member to count references by NetEvWait objects.
|
||||
unsigned waitref_;
|
||||
struct wcell_ {
|
||||
|
|
@ -3455,6 +3465,31 @@ class NetEvTrig : public NetProc {
|
|||
NetEvTrig*enext_;
|
||||
};
|
||||
|
||||
class NetEvNBTrig : public NetProc {
|
||||
|
||||
friend class NetEvent;
|
||||
|
||||
public:
|
||||
explicit NetEvNBTrig(NetEvent*tgt, NetExpr*dly);
|
||||
~NetEvNBTrig();
|
||||
|
||||
const NetExpr*delay() const;
|
||||
const NetEvent*event() const;
|
||||
|
||||
virtual NexusSet* nex_input(bool rem_out = true, bool always_sens = false,
|
||||
bool nested_func = false) const;
|
||||
virtual void nex_output(NexusSet&);
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
|
||||
|
||||
private:
|
||||
NetEvent*event_;
|
||||
NetExpr*dly_;
|
||||
// This is used to place me in the NetEvents lists of triggers.
|
||||
NetEvNBTrig*enext_;
|
||||
};
|
||||
|
||||
class NetEvWait : public NetProc {
|
||||
|
||||
public:
|
||||
|
|
|
|||
29
parse.y
29
parse.y
|
|
@ -478,7 +478,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
|
|||
%token K_CONTRIBUTE
|
||||
%token K_PO_POS K_PO_NEG K_POW
|
||||
%token K_PSTAR K_STARP K_DOTSTAR
|
||||
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER K_LEQUIV
|
||||
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER K_NB_TRIGGER K_LEQUIV
|
||||
%token K_SCOPE_RES
|
||||
%token K_edge_descriptor
|
||||
|
||||
|
|
@ -692,7 +692,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
|
|||
|
||||
%token K_TAND
|
||||
%nonassoc K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ
|
||||
%nonassoc K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ
|
||||
%nonassoc K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ K_NB_TRIGGER
|
||||
%right K_TRIGGER K_LEQUIV
|
||||
%right '?' ':' K_inside
|
||||
%left K_LOR
|
||||
|
|
@ -6716,16 +6716,37 @@ statement_item /* This is roughly statement_item in the LRM */
|
|||
}
|
||||
| K_TRIGGER hierarchy_identifier ';'
|
||||
{ PTrigger*tmp = pform_new_trigger(@2, 0, *$2);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete $2;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_TRIGGER PACKAGE_IDENTIFIER K_SCOPE_RES hierarchy_identifier
|
||||
{ PTrigger*tmp = pform_new_trigger(@4, $2, *$4);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete $4;
|
||||
$$ = tmp;
|
||||
}
|
||||
/* FIXME: Does this need support for package resolution like above? */
|
||||
| K_NB_TRIGGER hierarchy_identifier ';'
|
||||
{ PNBTrigger*tmp = pform_new_nb_trigger(@2, 0, *$2);
|
||||
delete $2;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_NB_TRIGGER delay1 hierarchy_identifier ';'
|
||||
{ PNBTrigger*tmp = pform_new_nb_trigger(@3, $2, *$3);
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_NB_TRIGGER event_control hierarchy_identifier ';'
|
||||
{ PNBTrigger*tmp = pform_new_nb_trigger(@3, 0, *$3);
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
yywarn(@1, "Sorry: ->> with event control is not currently supported.");
|
||||
}
|
||||
| K_NB_TRIGGER K_repeat '(' expression ')' event_control hierarchy_identifier ';'
|
||||
{ PNBTrigger*tmp = pform_new_nb_trigger(@7, 0, *$7);
|
||||
delete $7;
|
||||
$$ = tmp;
|
||||
yywarn(@1, "Sorry: ->> with repeat event control is not currently supported.");
|
||||
}
|
||||
|
||||
| procedural_assertion_statement { $$ = $1; }
|
||||
|
||||
|
|
|
|||
18
pform.cc
18
pform.cc
|
|
@ -752,6 +752,24 @@ PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg,
|
|||
return tmp;
|
||||
}
|
||||
|
||||
PNBTrigger* pform_new_nb_trigger(const struct vlltype&loc,
|
||||
const list<PExpr*>*dly,
|
||||
const pform_name_t&name)
|
||||
{
|
||||
if (gn_system_verilog())
|
||||
check_potential_imports(loc, name.front().name, false);
|
||||
|
||||
PExpr*tmp_dly = 0;
|
||||
if (dly) {
|
||||
assert(dly->size() == 1);
|
||||
tmp_dly = dly->front();
|
||||
}
|
||||
|
||||
PNBTrigger*tmp = new PNBTrigger(name, tmp_dly);
|
||||
FILE_NAME(tmp, loc);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
PGenerate* pform_parent_generate(void)
|
||||
{
|
||||
return pform_cur_generate;
|
||||
|
|
|
|||
3
pform.h
3
pform.h
|
|
@ -250,6 +250,9 @@ extern PEIdent* pform_new_ident(const struct vlltype&loc, const pform_name_t&nam
|
|||
|
||||
extern PTrigger* pform_new_trigger(const struct vlltype&loc, PPackage*pkg,
|
||||
const pform_name_t&name);
|
||||
extern PNBTrigger* pform_new_nb_trigger(const struct vlltype&loc,
|
||||
const list<PExpr*>*dly,
|
||||
const pform_name_t&name);
|
||||
|
||||
/*
|
||||
* Enter/exit name scopes. The push_scope function pushes the scope
|
||||
|
|
|
|||
|
|
@ -1263,6 +1263,13 @@ void PTrigger::dump(ostream&out, unsigned ind) const
|
|||
out << setw(ind) << "" << "-> " << event_ << ";" << endl;
|
||||
}
|
||||
|
||||
void PNBTrigger::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "->> ";
|
||||
if (dly_) out << "#" << *dly_ << " ";
|
||||
out << event_ << ";" << endl;
|
||||
}
|
||||
|
||||
void PWhile::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "while (" << *cond_ << ")" << endl;
|
||||
|
|
|
|||
22
t-dll-api.cc
22
t-dll-api.cc
|
|
@ -2834,6 +2834,9 @@ extern "C" ivl_expr_t ivl_stmt_delay_expr(ivl_statement_t net)
|
|||
case IVL_ST_DELAYX:
|
||||
return net->u_.delayx_.expr;
|
||||
|
||||
case IVL_ST_NB_TRIGGER:
|
||||
return net->u_.wait_.delay;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
|
|
@ -2864,12 +2867,15 @@ extern "C" unsigned ivl_stmt_nevent(ivl_statement_t net)
|
|||
case IVL_ST_ASSIGN_NB:
|
||||
return net->u_.assign_.nevent;
|
||||
|
||||
case IVL_ST_WAIT:
|
||||
return net->u_.wait_.nevent;
|
||||
case IVL_ST_NB_TRIGGER:
|
||||
return 1;
|
||||
|
||||
case IVL_ST_TRIGGER:
|
||||
return 1;
|
||||
|
||||
case IVL_ST_WAIT:
|
||||
return net->u_.wait_.nevent;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
|
@ -2887,6 +2893,14 @@ extern "C" ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx)
|
|||
else
|
||||
return net->u_.assign_.events[idx];
|
||||
|
||||
case IVL_ST_NB_TRIGGER:
|
||||
assert(idx == 0);
|
||||
return net->u_.wait_.event;
|
||||
|
||||
case IVL_ST_TRIGGER:
|
||||
assert(idx == 0);
|
||||
return net->u_.wait_.event;
|
||||
|
||||
case IVL_ST_WAIT:
|
||||
assert(idx < net->u_.wait_.nevent);
|
||||
if (net->u_.wait_.nevent == 1)
|
||||
|
|
@ -2894,10 +2908,6 @@ extern "C" ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx)
|
|||
else
|
||||
return net->u_.wait_.events[idx];
|
||||
|
||||
case IVL_ST_TRIGGER:
|
||||
assert(idx == 0);
|
||||
return net->u_.wait_.event;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -825,6 +825,38 @@ bool dll_target::proc_trigger(const NetEvTrig*net)
|
|||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dll_target::proc_nb_trigger(const NetEvNBTrig*net)
|
||||
{
|
||||
assert(stmt_cur_);
|
||||
assert(stmt_cur_->type_ == IVL_ST_NONE);
|
||||
FILE_NAME(stmt_cur_, net);
|
||||
|
||||
stmt_cur_->type_ = IVL_ST_NB_TRIGGER;
|
||||
stmt_cur_->u_.wait_.nevent = 1;
|
||||
stmt_cur_->u_.wait_.delay = 0;
|
||||
|
||||
if (const NetExpr*expr = net->delay()) {
|
||||
assert(expr_ == 0);
|
||||
expr->expr_scan(this);
|
||||
stmt_cur_->u_.wait_.delay = expr_;
|
||||
expr_ = 0;
|
||||
}
|
||||
|
||||
/* Locate the event by name. Save the ivl_event_t in the
|
||||
statement so that the generator can find it easily. */
|
||||
const NetEvent*ev = net->event();
|
||||
ivl_scope_t ev_scope = lookup_scope_(ev->scope());
|
||||
|
||||
for (unsigned idx = 0 ; idx < ev_scope->nevent_ ; idx += 1) {
|
||||
const char*ename = ivl_event_basename(ev_scope->event_[idx]);
|
||||
if (strcmp(ev->name(), ename) == 0) {
|
||||
stmt_cur_->u_.wait_.event = ev_scope->event_[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
4
t-dll.h
4
t-dll.h
|
|
@ -128,6 +128,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
|||
void proc_repeat(const NetRepeat*);
|
||||
void proc_stask(const NetSTask*);
|
||||
bool proc_trigger(const NetEvTrig*);
|
||||
bool proc_nb_trigger(const NetEvNBTrig*);
|
||||
void proc_utask(const NetUTask*);
|
||||
bool proc_wait(const NetEvWait*);
|
||||
void proc_while(const NetWhile*);
|
||||
|
|
@ -863,13 +864,14 @@ struct ivl_statement_s {
|
|||
ivl_scope_t def;
|
||||
} utask_;
|
||||
|
||||
struct { /* IVL_ST_TRIGGER IVL_ST_WAIT */
|
||||
struct { /* IVL_ST_TRIGGER IVL_ST_NB_TRIGGER IVL_ST_WAIT */
|
||||
unsigned needs_t0_trigger;
|
||||
unsigned nevent;
|
||||
union {
|
||||
ivl_event_t event;
|
||||
ivl_event_t*events;
|
||||
};
|
||||
ivl_expr_t delay;
|
||||
ivl_statement_t stmt_;
|
||||
} wait_;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2016 Stephen Williams <steve@icarus.com>
|
||||
* Copyright (c) 1998-2021 Stephen Williams <steve@icarus.com>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -424,6 +424,13 @@ bool target_t::proc_trigger(const NetEvTrig*tr)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool target_t::proc_nb_trigger(const NetEvNBTrig*tr)
|
||||
{
|
||||
cerr << tr->get_fileline() << ": error: target (" << typeid(*this).name()
|
||||
<< "): Unhandled non-blocking event trigger." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_stask(const NetSTask*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
|
|
|
|||
3
target.h
3
target.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_target_H
|
||||
#define IVL_target_H
|
||||
/*
|
||||
* Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -143,6 +143,7 @@ struct target_t {
|
|||
virtual bool proc_release(const NetRelease*);
|
||||
virtual void proc_repeat(const NetRepeat*);
|
||||
virtual bool proc_trigger(const NetEvTrig*);
|
||||
virtual bool proc_nb_trigger(const NetEvNBTrig*);
|
||||
virtual void proc_stask(const NetSTask*);
|
||||
virtual void proc_utask(const NetUTask*);
|
||||
virtual bool proc_wait(const NetEvWait*);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2004-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -271,6 +271,39 @@ static void show_stmt_trigger(ivl_statement_t net, unsigned ind)
|
|||
fprintf(out, ";\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* A non-blocking trigger statement is the "->> name;" syntax in Verilog,
|
||||
* where a non-blocking trigger signal is sent to a named event. The trigger
|
||||
* statement is actually a very simple object.
|
||||
*/
|
||||
static void show_stmt_nb_trigger(ivl_statement_t net, unsigned ind)
|
||||
{
|
||||
unsigned cnt = ivl_stmt_nevent(net);
|
||||
unsigned idx;
|
||||
|
||||
fprintf(out, "%*s->>", ind, "");
|
||||
|
||||
ivl_expr_t delay = ivl_stmt_delay_expr(net);
|
||||
if (delay) {
|
||||
fprintf(out, " #(");
|
||||
show_expression(ivl_stmt_delay_expr(net), ind+4);
|
||||
fprintf(out, ")");
|
||||
}
|
||||
|
||||
for (idx = 0 ; idx < cnt ; idx += 1) {
|
||||
ivl_event_t event = ivl_stmt_events(net, idx);
|
||||
fprintf(out, " %s", ivl_event_basename(event));
|
||||
}
|
||||
|
||||
/* The compiler should make exactly one target event, so if we
|
||||
find more or less, then print some error text. */
|
||||
if (cnt != 1) {
|
||||
fprintf(out, " /* ERROR: Expect one target event, got %u */", cnt);
|
||||
}
|
||||
|
||||
fprintf(out, ";\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* The wait statement contains simply an array of events to wait on,
|
||||
* and a sub-statement to execute when an event triggers.
|
||||
|
|
@ -537,6 +570,10 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
|||
show_stmt_trigger(net, ind);
|
||||
break;
|
||||
|
||||
case IVL_ST_NB_TRIGGER:
|
||||
show_stmt_nb_trigger(net, ind);
|
||||
break;
|
||||
|
||||
case IVL_ST_UTASK:
|
||||
fprintf(out, "%*scall task ...\n", ind, "");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2010-2020 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2010-2021 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -878,6 +878,7 @@ static unsigned has_func_disable(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
case IVL_ST_STASK:
|
||||
case IVL_ST_UTASK: // this will be generated for a SV void function
|
||||
case IVL_ST_TRIGGER:
|
||||
case IVL_ST_NB_TRIGGER:
|
||||
break;
|
||||
/* Look for a disable in each block statement. */
|
||||
case IVL_ST_BLOCK:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2020 Cary R. (cygcary@yahoo.com)
|
||||
* Copyright (C) 2011-2021 Cary R. (cygcary@yahoo.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -1427,6 +1427,26 @@ static void emit_stmt_trigger(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
fprintf(vlog_out, "\n");
|
||||
}
|
||||
|
||||
static void emit_stmt_nb_trigger(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
fprintf(vlog_out, "%*c->> ", get_indent(), ' ');
|
||||
ivl_expr_t delay = ivl_stmt_delay_expr(stmt);
|
||||
if (delay) {
|
||||
fprintf(vlog_out, "#(");
|
||||
emit_scaled_delayx(scope, delay, 1);
|
||||
fprintf(vlog_out, ") ");
|
||||
}
|
||||
assert(ivl_stmt_nevent(stmt) == 1);
|
||||
emit_event(scope, stmt);
|
||||
fprintf(vlog_out, ";");
|
||||
emit_stmt_file_line(stmt);
|
||||
fprintf(vlog_out, "\n");
|
||||
fprintf(stderr, "%s:%u: vlog95 sorry: wait fork is not currently "
|
||||
"translated.\n",
|
||||
ivl_stmt_file(stmt), ivl_stmt_lineno(stmt));
|
||||
vlog_errors += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* A user defined task call with arguments is generated as a block with
|
||||
* input assignments, a simple call and then output assignments. This is
|
||||
|
|
@ -1596,6 +1616,9 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
case IVL_ST_TRIGGER:
|
||||
emit_stmt_trigger(scope, stmt);
|
||||
break;
|
||||
case IVL_ST_NB_TRIGGER:
|
||||
emit_stmt_nb_trigger(scope, stmt);
|
||||
break;
|
||||
case IVL_ST_UTASK:
|
||||
emit_stmt_utask(scope, stmt);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2020 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -1284,21 +1284,8 @@ static int show_stmt_delay(ivl_statement_t net, ivl_scope_t sscope)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* The delayx statement is slightly more complex in that it is
|
||||
* necessary to calculate the delay first. Load the calculated delay
|
||||
* into and index register and use the %delayx instruction to do the
|
||||
* actual delay.
|
||||
*/
|
||||
static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
|
||||
static void draw_expr_into_idx(ivl_expr_t expr, int use_idx)
|
||||
{
|
||||
int rc = 0;
|
||||
ivl_expr_t expr = ivl_stmt_delay_expr(net);
|
||||
ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
|
||||
|
||||
show_stmt_file_line(net, "Delay statement.");
|
||||
|
||||
int use_idx = allocate_word();
|
||||
switch (ivl_expr_value(expr)) {
|
||||
|
||||
case IVL_VT_BOOL:
|
||||
|
|
@ -1317,6 +1304,25 @@ static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
|
|||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The delayx statement is slightly more complex in that it is
|
||||
* necessary to calculate the delay first. Load the calculated delay
|
||||
* into and index register and use the %delayx instruction to do the
|
||||
* actual delay.
|
||||
*/
|
||||
static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
int rc = 0;
|
||||
ivl_expr_t expr = ivl_stmt_delay_expr(net);
|
||||
ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
|
||||
|
||||
show_stmt_file_line(net, "Delay statement.");
|
||||
|
||||
int use_idx = allocate_word();
|
||||
draw_expr_into_idx(expr, use_idx);
|
||||
|
||||
fprintf(vvp_out, " %%delayx %d;\n", use_idx);
|
||||
clr_word(use_idx);
|
||||
|
|
@ -1643,6 +1649,34 @@ static int show_stmt_trigger(ivl_statement_t net)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The non-blocking trigger statement is straight forward. All we have to
|
||||
* do is write a single bit of fake data to the event object.
|
||||
*/
|
||||
static int show_stmt_nb_trigger(ivl_statement_t net)
|
||||
{
|
||||
ivl_event_t ev = ivl_stmt_events(net, 0);
|
||||
assert(ev);
|
||||
|
||||
show_stmt_file_line(net, "Non-blocking event trigger statement.");
|
||||
|
||||
ivl_expr_t expr = ivl_stmt_delay_expr(net);
|
||||
int use_idx = allocate_word();
|
||||
if (expr) {
|
||||
draw_expr_into_idx(expr, use_idx);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%ix/load %d, 0, 0;\n", use_idx);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%event/nb E_%p, %d;\n", ev, use_idx);
|
||||
clr_word(use_idx);
|
||||
// FIXME: VVP needs to be updated to correctly support %event/nb
|
||||
fprintf(stderr, "%s:%u: vvp.tgt sorry: ->> is not currently supported.\n",
|
||||
ivl_stmt_file(net), ivl_stmt_lineno(net));
|
||||
vvp_errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int show_stmt_utask(ivl_statement_t net)
|
||||
{
|
||||
ivl_scope_t task = ivl_stmt_call(net);
|
||||
|
|
@ -2383,6 +2417,10 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
|||
rc += show_stmt_trigger(net);
|
||||
break;
|
||||
|
||||
case IVL_ST_NB_TRIGGER:
|
||||
rc += show_stmt_nb_trigger(net);
|
||||
break;
|
||||
|
||||
case IVL_ST_UTASK:
|
||||
rc += show_stmt_utask(net);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_codes_H
|
||||
#define IVL_codes_H
|
||||
/*
|
||||
* Copyright (c) 2001-2020 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -112,6 +112,7 @@ extern bool of_DUP_REAL(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_DUP_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_END(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVENT(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVENT_NB(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVCTL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVCTLC(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_EVCTLI(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2020 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -167,7 +167,8 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%evctl/c",of_EVCTLC, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%evctl/i",of_EVCTLI, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%evctl/s",of_EVCTLS, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%event", of_EVENT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%event", of_EVENT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%event/nb", of_EVENT_NB, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%flag_get/vec4", of_FLAG_GET_VEC4, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%flag_inv", of_FLAG_INV, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%flag_mov", of_FLAG_MOV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2020 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -517,6 +517,7 @@ that this information has been cleared. You can get an assert if
|
|||
this information is not managed correctly.
|
||||
|
||||
* %event <functor-label>
|
||||
* %event/nb <functor-label>
|
||||
|
||||
This instruction is used to send a pulse to an event object. The
|
||||
<functor-label> is an event variable. This instruction simply writes
|
||||
|
|
|
|||
|
|
@ -892,6 +892,19 @@ void schedule_propagate_vector(vvp_net_t*net,
|
|||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||
}
|
||||
|
||||
// FIXME: This needs to create a non-blocking event, but only one per time slot.
|
||||
// Is schedule_event_ or execution actually filtering since the net is
|
||||
// already X because this is not triggering?
|
||||
void schedule_propagate_event(vvp_net_t*net,
|
||||
vvp_time64_t delay)
|
||||
{
|
||||
vvp_vector4_t tmp (1, BIT4_X);
|
||||
struct propagate_vector4_event_s*cur
|
||||
= new struct propagate_vector4_event_s(tmp);
|
||||
cur->net = net;
|
||||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||
}
|
||||
|
||||
void schedule_assign_array_word(vvp_array_t mem,
|
||||
unsigned word_addr,
|
||||
unsigned off,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_schedule_H
|
||||
#define IVL_schedule_H
|
||||
/*
|
||||
* Copyright (c) 2001-2020 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2021 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -75,9 +75,15 @@ extern void schedule_force_vector(vvp_net_t*net,
|
|||
* Create an event to propagate the output of a net.
|
||||
*/
|
||||
extern void schedule_propagate_vector(vvp_net_t*ptr,
|
||||
vvp_time64_t delay,
|
||||
vvp_time64_t delay,
|
||||
const vvp_vector4_t&val);
|
||||
|
||||
/*
|
||||
* Create an event to propagate the output of an event.
|
||||
*/
|
||||
extern void schedule_propagate_event(vvp_net_t*ptr,
|
||||
vvp_time64_t delay);
|
||||
|
||||
/*
|
||||
* This is very similar to schedule_assign_vector, but generates an
|
||||
* event in the active queue. It is used at link time to assign a
|
||||
|
|
|
|||
|
|
@ -3106,6 +3106,18 @@ bool of_EVENT(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %event/nb <var-label>, <delay>
|
||||
*/
|
||||
bool of_EVENT_NB(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_time64_t delay;
|
||||
|
||||
delay = thr->words[cp->bit_idx[0]].w_uint;
|
||||
schedule_propagate_event(cp->net, delay);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_EVCTL(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
assert(thr->event == 0 && thr->ecount == 0);
|
||||
|
|
|
|||
Loading…
Reference in New Issue