Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add condition clause for wait statements

  • Loading branch information...
commit 04b3e9439de04562e985388ec5797021f7356ad3 1 parent 918ca7e
@nickg authored
View
45 src/cgen.c
@@ -1740,7 +1740,7 @@ static void cgen_sched_process(LLVMValueRef after)
LLVMBuildCall(builder, llvm_fn("_sched_process"), args, 1, "");
}
-static void cgen_sched_event(tree_t on)
+static void cgen_sched_event(tree_t on, LLVMValueRef until)
{
if (tree_kind(on) != T_REF) {
// It is possible for constant folding to replace a signal with
@@ -1762,19 +1762,55 @@ static void cgen_sched_event(tree_t on)
LLVMValueRef signal = tree_attr_ptr(decl, sig_struct_i);
LLVMValueRef args[] = {
llvm_void_cast(signal),
- llvm_int32(n)
+ llvm_int32(n),
+ until
};
LLVMBuildCall(builder, llvm_fn("_sched_event"),
args, ARRAY_LEN(args), "");
}
+static LLVMTypeRef cgen_until_func_type(void)
+{
+ return LLVMFunctionType(LLVMInt1Type(), NULL, 0, false);
+}
+
+static LLVMValueRef cgen_until_func(tree_t wait, cgen_ctx_t *ctx)
+{
+ // Generate a function to evaluate a condition clause
+
+ if (!tree_has_value(wait))
+ return LLVMConstNull(LLVMPointerType(cgen_until_func_type(), 0));
+ else {
+ tree_t expr = tree_value(wait);
+
+ char name[128];
+ snprintf(name, sizeof(name), "until_%p", expr);
+
+ LLVMValueRef fn = LLVMAddFunction(module, name,
+ cgen_until_func_type());
+ LLVMSetLinkage(fn, LLVMInternalLinkage);
+
+ LLVMBasicBlockRef bb = LLVMAppendBasicBlock(fn, "body");
+ LLVMBasicBlockRef save = LLVMGetInsertBlock(builder);
+
+ LLVMPositionBuilderAtEnd(builder, bb);
+ LLVMBuildRet(builder, cgen_expr(expr, ctx));
+
+ LLVMPositionBuilderAtEnd(builder, save);
+
+ return fn;
+ }
+}
+
static void cgen_wait(tree_t t, cgen_ctx_t *ctx)
{
if (tree_has_delay(t))
cgen_sched_process(cgen_expr(tree_delay(t), ctx));
+ LLVMValueRef until = cgen_until_func(t, ctx);
+
for (unsigned i = 0; i < tree_triggers(t); i++)
- cgen_sched_event(tree_trigger(t, i));
+ cgen_sched_event(tree_trigger(t, i), until);
// Find the basic block to jump to when the process is next scheduled
struct proc_entry *it;
@@ -2928,7 +2964,8 @@ static void cgen_support_fns(void)
LLVMTypeRef _sched_event_args[] = {
llvm_void_ptr(),
- LLVMInt32Type()
+ LLVMInt32Type(),
+ LLVMPointerType(cgen_until_func_type(), 0)
};
LLVMAddFunction(module, "_sched_event",
LLVMFunctionType(LLVMVoidType(),
View
2  src/lexer.l
@@ -170,6 +170,7 @@ GENERATE {G}{E}{N}{E}{R}{A}{T}{E}
ACCESS {A}{C}{C}{E}{S}{S}
FILE {F}{I}{L}{E}
OPEN {O}{P}{E}{N}
+UNTIL {U}{N}{T}{I}{L}
%%
@@ -254,6 +255,7 @@ OPEN {O}{P}{E}{N}
{ACCESS} { TOKEN(tACCESS); }
{FILE} { TOKEN(tFILE); }
{OPEN} { TOKEN(tOPEN); }
+{UNTIL} { TOKEN(tUNTIL); }
"(" { TOKEN(tLPAREN); }
")" { TOKEN(tRPAREN); }
View
16 src/parse.y
@@ -162,7 +162,7 @@
%type <t> waveform_element seq_stmt_without_label conc_assign_stmt
%type <t> comp_instance_stmt conc_stmt_without_label elsif_list
%type <t> delay_mechanism bit_string_literal block_stmt expr_or_open
-%type <t> conc_select_assign_stmt generate_stmt
+%type <t> conc_select_assign_stmt generate_stmt condition_clause
%type <i> id opt_id selected_id func_name
%type <l> interface_object_decl interface_list
%type <l> port_clause generic_clause interface_decl signal_decl
@@ -200,7 +200,7 @@
%token tWHILE tLOOP tAFTER tALIAS tATTRIBUTE tPROCEDURE tEXIT
%token tWHEN tCASE tBAR tLSQUARE tRSQUARE tINERTIAL tTRANSPORT
%token tREJECT tBITSTRING tBLOCK tWITH tSELECT tGENERATE tACCESS
-%token tFILE tOPEN tREAL
+%token tFILE tOPEN tREAL tUNTIL
%left tAND tOR tNAND tNOR tXOR tXNOR
%left tEQ tNEQ tLT tLE tGT tGE
@@ -1189,13 +1189,14 @@ seq_stmt
;
seq_stmt_without_label
-: tWAIT sensitivity_clause /* [ condition_clause ] */
- timeout_clause tSEMI
+: tWAIT sensitivity_clause condition_clause timeout_clause tSEMI
{
$$ = tree_new(T_WAIT);
tree_set_loc($$, &@$);
if ($3 != NULL)
- tree_set_delay($$, $3);
+ tree_set_value($$, $3);
+ if ($4 != NULL)
+ tree_set_delay($$, $4);
copy_trees($2, tree_add_trigger, $$);
}
| target tASSIGN expr tSEMI
@@ -1495,6 +1496,11 @@ waveform_element
| tNULL { $$ = NULL; }
;
+condition_clause
+: tUNTIL expr { $$ = $2; }
+| /* empty */ { $$ = NULL; }
+;
+
timeout_clause
: tFOR expr { $$ = $2; }
| /* empty */ { $$ = NULL; }
View
58 src/rt/rtkern.c
@@ -38,6 +38,7 @@
#define EXIT_SEVERITY 2
typedef void (*proc_fn_t)(int32_t reset);
+typedef int8_t (*until_fn_t)(void);
struct tmp_chunk_hdr {
struct tmp_chunk *next;
@@ -84,6 +85,7 @@ struct waveform {
struct sens_list {
struct rt_proc *proc;
unsigned wakeup_gen;
+ until_fn_t until;
struct sens_list *next;
};
@@ -283,12 +285,12 @@ void _sched_waveform(void *_sig, int32_t source, int64_t value, int64_t after)
deltaq_insert_driver(after, sig, source, 1);
}
-void _sched_event(void *_sig, int32_t n)
+void _sched_event(void *_sig, int32_t n, until_fn_t until)
{
struct signal *sig = _sig;
- TRACE("_sched_event %s n=%d proc %s", fmt_sig(sig), n,
- istr(tree_ident(active_proc->source)));
+ TRACE("_sched_event %s n=%d until=%p proc %s", fmt_sig(sig), n,
+ until, istr(tree_ident(active_proc->source)));
for (int i = 0; i < n; i++) {
// See if there is already a stale entry in the sensitvity
@@ -301,6 +303,7 @@ void _sched_event(void *_sig, int32_t n)
struct sens_list *node = rt_alloc(sens_list_stack);
node->proc = active_proc;
node->wakeup_gen = active_proc->wakeup_gen;
+ node->until = until;
node->next = sig[i].sensitive;
sig[i].sensitive = node;
@@ -308,6 +311,7 @@ void _sched_event(void *_sig, int32_t n)
else {
// Reuse the stale entry
it->wakeup_gen = active_proc->wakeup_gen;
+ it->until = until;
}
}
}
@@ -671,7 +675,7 @@ static void rt_initial(tree_t top)
rt_run(&procs[i], true /* reset */);
}
-static void rt_wakeup(struct sens_list *sl)
+static bool rt_wakeup(struct sens_list *sl)
{
// To avoid having each process keep a list of the signals it is
// sensitive to, each process has a "wakeup generation" number which
@@ -681,14 +685,27 @@ static void rt_wakeup(struct sens_list *sl)
// generation: these correspond to stale "wait on" statements that
// have already resumed.
+ const char *pstr = NULL;
+ if (unlikely(trace_on))
+ pstr = istr(tree_ident(sl->proc->source));
+
if (sl->wakeup_gen == sl->proc->wakeup_gen) {
- TRACE("wakeup process %s", istr(tree_ident(sl->proc->source)));
- ++(sl->proc->wakeup_gen);
- sl->next = resume;
- resume = sl;
+ if (unlikely((sl->until != NULL) && ((*sl->until)() == 0))) {
+ TRACE("process %s condition check failed", pstr);
+ return false;
+ }
+ else {
+ TRACE("wakeup process %s", pstr);
+ ++(sl->proc->wakeup_gen);
+ sl->next = resume;
+ resume = sl;
+ return true;
+ }
}
- else
+ else {
rt_free(sens_list_stack, sl);
+ return true;
+ }
}
static void rt_alloc_driver(struct signal *sig, int source,
@@ -747,17 +764,9 @@ static void rt_update_signal(struct signal *s, int source, uint64_t value)
const bool first_cycle = (iteration == 0 && now == 0);
if (likely(!first_cycle)) {
new_flags = SIGNAL_F_ACTIVE;
- if (s->resolved != value) {
+ if (s->resolved != value)
new_flags |= SIGNAL_F_EVENT;
- struct sens_list *it, *next;
- for (it = s->sensitive; it != NULL; it = next) {
- next = it->next;
- rt_wakeup(it);
- }
- s->sensitive = NULL;
- }
-
assert(n_active_signals < MAX_ACTIVE_SIGS);
active_signals[n_active_signals++] = s;
}
@@ -781,6 +790,19 @@ static void rt_update_signal(struct signal *s, int source, uint64_t value)
s->resolved = value;
s->flags |= new_flags;
+
+ // Wake up any processes sensitive to this signal
+ if (new_flags & SIGNAL_F_EVENT) {
+ struct sens_list *it, *next, *save = NULL;
+ for (it = s->sensitive; it != NULL; it = next) {
+ next = it->next;
+ if (unlikely(!rt_wakeup(it))) {
+ it->next = save;
+ save = it;
+ }
+ }
+ s->sensitive = save;
+ }
}
static void rt_update_driver(struct signal *s, int source)
View
18 src/sem.c
@@ -2519,13 +2519,27 @@ static bool sem_check_pcall(tree_t t)
static bool sem_check_wait(tree_t t)
{
if (tree_has_delay(t)) {
+ type_t std_time = sem_std_type("TIME");
tree_t delay = tree_delay(t);
- sem_check(delay);
- if (!icmp(type_ident(tree_type(delay)), "STD.STANDARD.TIME"))
+ if (!sem_check_constrained(delay, std_time))
+ return false;
+
+ if (!type_eq(tree_type(delay), std_time))
sem_error(delay, "type of delay must be TIME");
}
+ if (tree_has_value(t)) {
+ type_t std_bool = sem_std_type("BOOLEAN");
+ tree_t value = tree_value(t);
+
+ if (!sem_check_constrained(value, std_bool))
+ return false;
+
+ if (!type_eq(tree_type(value), std_bool))
+ sem_error(value, "type of condition must be BOOLEAN");
+ }
+
return sem_check_sensitivity(t);
}
View
15 src/simp.c
@@ -33,6 +33,7 @@ static int errors = 0;
{ errors++; error_at(tree_loc(t), __VA_ARGS__); return t; }
static tree_t simp_tree(tree_t t, void *context);
+static void simp_build_wait(tree_t ref, void *context);
static bool folded_int(tree_t t, literal_t *l)
{
@@ -484,6 +485,18 @@ static tree_t simp_process(tree_t t)
return t;
}
+static tree_t simp_wait(tree_t t)
+{
+ // LRM 93 section 8.1
+ // If there is no sensitivity list supplied generate one from the
+ // condition clause
+
+ if (tree_has_value(t))
+ tree_visit_only(tree_value(t), simp_build_wait, t, T_REF);
+
+ return t;
+}
+
static tree_t simp_if(tree_t t)
{
bool value_b;
@@ -823,6 +836,8 @@ static tree_t simp_tree(tree_t t, void *context)
return simp_aggregate(t);
case T_SELECT:
return simp_select(t);
+ case T_WAIT:
+ return simp_wait(t);
case T_NULL:
return NULL; // Delete it
default:
View
4 src/tree.c
@@ -25,7 +25,7 @@
#define MAX_CONTEXTS 16
#define MAX_ATTRS 16
-#define FILE_FMT_VER 0x1009
+#define FILE_FMT_VER 0x100a
//#define EXTRA_READ_CHECKS
@@ -216,7 +216,7 @@ struct tree_rd_ctx {
|| IS(t, T_ARRAY_SLICE) || IS(t, T_IF) || IS(t, T_RETURN) \
|| IS(t, T_WHILE) || IS(t, T_ALIAS) || IS(t, T_ATTR_SPEC) \
|| IS(t, T_EXIT) || IS(t, T_COND) || IS(t, T_SELECT) \
- || IS(t, T_IF_GENERATE) || IS(t, T_FILE_DECL))
+ || IS(t, T_IF_GENERATE) || IS(t, T_FILE_DECL) || IS(t, T_WAIT))
#define HAS_CONTEXT(t) \
(IS(t, T_ARCH) || IS(t, T_ENTITY) || IS(t, T_PACKAGE) \
|| IS(t, T_PACK_BODY) || IS(t, T_ELAB))
View
3  test/parse/seq.vhd
@@ -9,6 +9,9 @@ begin
wait on x;
wait on x, y, z(1 downto 0);
wait on w(1) for 2 ns;
+ wait until x = 3;
+ wait until y = x for 5 ns;
+ wait on x until x = 2 for 1 ns;
end process;
-- Blocking assignment
View
1  test/regress/testlist.txt
@@ -70,3 +70,4 @@ elab4 normal
elab5 normal
signal8 normal
ram1 normal
+wait7 normal
View
43 test/regress/wait7.vhd
@@ -0,0 +1,43 @@
+entity wait7 is
+end entity;
+
+architecture test of wait7 is
+ signal state : integer := 0;
+ signal x : integer := 0;
+begin
+
+ wakeup: process is
+ begin
+ wait until x = 1;
+ state <= 1;
+ wait until x = 5;
+ state <= 2;
+ wait until x > 10;
+ state <= 3;
+ wait;
+ end process;
+
+ stim: process is
+ begin
+ x <= -1;
+ wait for 1 ns;
+ assert state = 0;
+ x <= 6;
+ wait for 1 ns;
+ assert state = 0;
+ x <= 1;
+ wait for 1 ns;
+ assert state = 1;
+ x <= 0;
+ wait for 1 ns;
+ assert state = 1;
+ x <= 5;
+ wait for 1 ns;
+ assert state = 2;
+ x <= 50;
+ wait for 1 ns;
+ assert state = 3;
+ wait;
+ end process;
+
+end architecture;
View
10 test/sem/wait.vhd
@@ -39,6 +39,16 @@ begin
x <= y;
wait for 1 ns; -- Not allowed wait
end process;
+
+ -- wait until
+ process is
+ begin
+ wait until true;
+ wait until x = '1';
+ wait until x; -- Not boolean
+ wait until y = x for 1 ns;
+ wait until y = x for x; -- Not time
+ end process;
end architecture;
View
19 test/test_parse.c
@@ -261,7 +261,7 @@ START_TEST(test_seq)
p = tree_stmt(a, 0);
fail_unless(tree_kind(p) == T_PROCESS);
- fail_unless(tree_stmts(p) == 5);
+ fail_unless(tree_stmts(p) == 8);
s = tree_stmt(p, 0);
fail_unless(tree_kind(s) == T_WAIT);
@@ -296,6 +296,23 @@ START_TEST(test_seq)
s = tree_stmt(p, 4);
fail_unless(tree_kind(s) == T_WAIT);
fail_unless(tree_has_delay(s));
+ fail_if(tree_has_value(s));
+
+ s = tree_stmt(p, 5);
+ fail_unless(tree_kind(s) == T_WAIT);
+ fail_if(tree_has_delay(s));
+ fail_unless(tree_has_value(s));
+
+ s = tree_stmt(p, 6);
+ fail_unless(tree_kind(s) == T_WAIT);
+ fail_unless(tree_has_delay(s));
+ fail_unless(tree_has_value(s));
+
+ s = tree_stmt(p, 7);
+ fail_unless(tree_kind(s) == T_WAIT);
+ fail_unless(tree_has_delay(s));
+ fail_unless(tree_has_value(s));
+ fail_unless(tree_triggers(s) == 1);
// Variable assignment
View
2  test/test_sem.c
@@ -395,6 +395,8 @@ START_TEST(test_wait)
{ 23, "name V in sensitivity list is not a signal" },
{ 32, "undefined identifier A" },
{ 37, "wait statement not allowed in process" },
+ { 48, "type of condition must be BOOLEAN" },
+ { 50, "type of delay must be TIME" },
{ -1, NULL }
};
expect_errors(expect);
Please sign in to comment.
Something went wrong with that request. Please try again.