Add compiler and the start of vvp support for ->>

This commit is contained in:
Cary R 2021-02-19 23:21:12 -08:00
parent 753bf516d6
commit 60a77b08d2
31 changed files with 430 additions and 44 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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