diff --git a/design_dump.cc b/design_dump.cc index 897ae9318..c1335fd85 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -232,7 +232,9 @@ ostream& netdarray_t::debug_dump(ostream&o) const ostream& netqueue_t::debug_dump(ostream&fd) const { - fd << "queue of " << *element_type(); + fd << "queue of "; + if (max_idx_ >= 0) fd << "(maximum of " << max_idx_+1 << " elements) "; + fd << *element_type(); return fd; } diff --git a/elab_sig.cc b/elab_sig.cc index c315efba7..290257e5e 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2020 Stephen Williams (steve@icarus.com) * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it @@ -1094,13 +1094,35 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } // Special case: Detect the mark for a QUEUE - // declaration, which is the dimensions [null:]. - if (use_ridx==0 && dynamic_cast(use_lidx)) { + // declaration, which is the dimensions [null:max_idx]. + if (dynamic_cast(use_lidx)) { netvector_t*vec = new netvector_t(packed_dimensions, data_type_); vec->set_signed(get_signed()); packed_dimensions.clear(); ivl_assert(*this, netdarray==0); - netdarray = new netqueue_t(vec); + long max_idx; + if (use_ridx) { + NetExpr*tmp = elab_and_eval(des, array_type_scope, use_ridx, + -1, true); + NetEConst*cv = dynamic_cast(tmp); + if (cv == 0) { + cerr << get_fileline() << ": error: queue '" << name_ + << "' maximum size must be a constant!" << endl; + des->errors += 1; + max_idx = -1; + } else { + verinum res = cv->value(); + max_idx = res.as_long(); + if (max_idx < 0) { + cerr << get_fileline() << ": error: queue '" + << name_ << "' maximum size must be positive (" + << max_idx << ")!" << endl; + des->errors += 1; + max_idx = -1; + } + } + } else max_idx = -1; + netdarray = new netqueue_t(vec, max_idx); continue; } diff --git a/elab_type.cc b/elab_type.cc index f193945ad..de4b4bac9 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2020 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 @@ -252,12 +252,13 @@ ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const } // Special case: if the dimension is null:nil. this is a queue. - if (cur->second==0 && dynamic_cast(cur->first)) { + if (dynamic_cast(cur->first)) { cerr << get_fileline() << ": sorry: " << "SV queues inside classes are not yet supported." << endl; des->errors += 1; - ivl_type_s*res = new netqueue_t(btype); + // FIXME: Need to set the max size if cur->second is defined + ivl_type_s*res = new netqueue_t(btype, -1); return res; } diff --git a/netqueue.cc b/netqueue.cc index a850e3b46..16c1da5e4 100644 --- a/netqueue.cc +++ b/netqueue.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2014-2020 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 @@ -22,8 +22,8 @@ using namespace std; -netqueue_t::netqueue_t(ivl_type_t vec) -: netdarray_t(vec) +netqueue_t::netqueue_t(ivl_type_t vec, long max_idx) +: netdarray_t(vec), max_idx_(max_idx) { } diff --git a/netqueue.h b/netqueue.h index 85526910e..feded7423 100644 --- a/netqueue.h +++ b/netqueue.h @@ -1,7 +1,7 @@ #ifndef IVL__netqueue_H #define IVL__netqueue_H /* - * Copyright (c) 2014-2015 Stephen Williams (steve@icarus.com) + * Copyright (c) 2014-2020 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 @@ -30,7 +30,7 @@ class netqueue_t : public netdarray_t { public: - explicit netqueue_t(ivl_type_t vec); + explicit netqueue_t(ivl_type_t vec, long max_idx); ~netqueue_t(); // This is the "base_type()" virtual method of the @@ -41,10 +41,14 @@ class netqueue_t : public netdarray_t { // A queue may have a type that is signed. inline bool get_signed() const { return element_type()->get_signed(); } + // Use the packed width to pass the maximum index + long packed_width(void) const { return max_idx_; } + std::ostream& debug_dump(std::ostream&) const; private: bool test_compatibility(ivl_type_t that) const; + long max_idx_; }; #endif diff --git a/parse.y b/parse.y index fd43d2a94..7faac773a 100644 --- a/parse.y +++ b/parse.y @@ -2657,6 +2657,16 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ tmp->push_back(index); $$ = tmp; } + | '[' '$' ':' expression ']' + { // SystemVerilog queue with a max size + list *tmp = new list; + pform_range_t index (new PENull,$4); + if (!gn_system_verilog()) { + yyerror("error: Queue declarations require SystemVerilog."); + } + tmp->push_back(index); + $$ = tmp; + } ; variable_lifetime diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index b8503a537..93f05cfbe 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2020 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 @@ -94,9 +94,13 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result, If I don't need to do any evaluating, then skip it as I'll be passing the handle to the signal itself. */ - if (ivl_expr_width(expr) != - ivl_signal_width(ivl_expr_signal(expr))) { + if ((ivl_expr_width(expr) != + ivl_signal_width(ivl_expr_signal(expr))) && + ivl_expr_value(expr) != IVL_VT_DARRAY) { /* This should never happen since we have IVL_EX_SELECT. */ + /* For a queue (type of darray) we return the maximum + size of the queue as the signal width. */ + assert(0); return 0; } else if (signal_is_return_value(ivl_expr_signal(expr))) { diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index a105e7b12..56467f053 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1780,24 +1780,37 @@ static int show_push_frontback_method(ivl_statement_t net, bool is_front) ivl_type_t var_type = ivl_signal_net_type(var); assert(ivl_type_base(var_type)== IVL_VT_QUEUE); + /* The maximum index value is passed as the signal width. */ + long max_size = ivl_signal_width(var) + 1; + assert(max_size >= 0); + int idx = allocate_word(); + assert(idx >= 0); + /* Save the queue maximum index value to an integer register. */ + fprintf(vvp_out, " %%ix/load %u, %ld, 0;\n", idx, max_size); + fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); + ivl_type_t element_type = ivl_type_element(var_type); ivl_expr_t parm1 = ivl_stmt_parm(net,1); switch (ivl_type_base(element_type)) { case IVL_VT_REAL: draw_eval_real(parm1); - fprintf(vvp_out, " %%store/%s/r v%p_0;\n", type_code, var); + fprintf(vvp_out, " %%store/%s/r v%p_0, %u;\n", + type_code, var, idx); break; case IVL_VT_STRING: draw_eval_string(parm1); - fprintf(vvp_out, " %%store/%s/str v%p_0;\n", type_code, var); + fprintf(vvp_out, " %%store/%s/str v%p_0, %u;\n", + type_code, var, idx); break; default: draw_eval_vec4(parm1); - fprintf(vvp_out, " %%store/%s/v v%p_0, %u;\n", - type_code, var, width_of_packed_type(element_type)); + fprintf(vvp_out, " %%store/%s/v v%p_0, %u, %u;\n", + type_code, var, idx, + width_of_packed_type(element_type)); break; } + clr_word(idx); return 0; } diff --git a/vvp/compile.cc b/vvp/compile.cc index 72c14fbdb..512c564d8 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2020 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 @@ -278,12 +278,12 @@ static const struct opcode_table_s opcode_table[] = { { "%store/prop/r", of_STORE_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%store/prop/str",of_STORE_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%store/prop/v", of_STORE_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, - { "%store/qb/r", of_STORE_QB_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, - { "%store/qb/str", of_STORE_QB_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, - { "%store/qb/v", of_STORE_QB_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, - { "%store/qf/r", of_STORE_QF_R, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, - { "%store/qf/str", of_STORE_QF_STR, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, - { "%store/qf/v", of_STORE_QF_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%store/qb/r", of_STORE_QB_R, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%store/qb/str", of_STORE_QB_STR, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%store/qb/v", of_STORE_QB_V, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, + { "%store/qf/r", of_STORE_QF_R, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%store/qf/str", of_STORE_QF_STR, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%store/qf/v", of_STORE_QF_V, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, { "%store/real", of_STORE_REAL, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} }, { "%store/reala", of_STORE_REALA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} }, { "%store/str", of_STORE_STR, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} }, diff --git a/vvp/vthread.cc b/vvp/vthread.cc index c61456411..209c81ec1 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -5702,7 +5702,7 @@ bool of_STORE_PROP_V(vthread_t thr, vvp_code_t cp) } /* - * %store/qb/r + * %store/qb/r , */ bool of_STORE_QB_R(vthread_t, vvp_code_t) { @@ -5711,7 +5711,7 @@ bool of_STORE_QB_R(vthread_t, vvp_code_t) } /* - * %store/qb/str + * %store/qb/str , */ bool of_STORE_QB_STR(vthread_t thr, vvp_code_t cp) { @@ -5719,15 +5719,16 @@ bool of_STORE_QB_STR(vthread_t thr, vvp_code_t cp) string value = thr->pop_str(); vvp_net_t*net = cp->net; + unsigned max_size = thr->words[cp->bit_idx[0]].w_int; vvp_queue*dqueue = get_queue_object(thr, net); assert(dqueue); - dqueue->push_back(value); + dqueue->push_back(value, max_size); return true; } /* - * %store/qb/v , + * %store/qb/v , , */ bool of_STORE_QB_V(vthread_t thr, vvp_code_t cp) { @@ -5735,20 +5736,21 @@ bool of_STORE_QB_V(vthread_t thr, vvp_code_t cp) vvp_vector4_t value = thr->pop_vec4(); vvp_net_t*net = cp->net; - unsigned wid = cp->bit_idx[0]; + unsigned max_size = thr->words[cp->bit_idx[0]].w_int; + unsigned wid = cp->bit_idx[1]; assert(value.size() == wid); vvp_queue*dqueue = get_queue_object(thr, net); assert(dqueue); - dqueue->push_back(value); + dqueue->push_back(value, max_size); return true; } /* - * %store/qf/r + * %store/qf/r , */ bool of_STORE_QF_R(vthread_t, vvp_code_t) { @@ -5757,7 +5759,7 @@ bool of_STORE_QF_R(vthread_t, vvp_code_t) } /* - * %store/qf/str + * %store/qf/str , */ bool of_STORE_QF_STR(vthread_t, vvp_code_t) { @@ -5766,7 +5768,7 @@ bool of_STORE_QF_STR(vthread_t, vvp_code_t) } /* - * %store/qb/v , + * %store/qb/v , , */ bool of_STORE_QF_V(vthread_t thr, vvp_code_t cp) { @@ -5774,13 +5776,14 @@ bool of_STORE_QF_V(vthread_t thr, vvp_code_t cp) vvp_vector4_t value = thr->pop_vec4(); vvp_net_t*net = cp->net; - unsigned wid = cp->bit_idx[0]; + unsigned max_size = thr->words[cp->bit_idx[0]].w_int; + unsigned wid = cp->bit_idx[1]; vvp_queue*dqueue = get_queue_object(thr, net); assert(value.size() == wid); assert(dqueue); - dqueue->push_front(value); + dqueue->push_front(value, max_size); return true; } diff --git a/vvp/vvp_darray.cc b/vvp/vvp_darray.cc index 39222d226..c24952454 100644 --- a/vvp/vvp_darray.cc +++ b/vvp/vvp_darray.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2020 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 @@ -410,32 +410,32 @@ vvp_queue::~vvp_queue() { } -void vvp_queue::push_back(const vvp_vector4_t&) +void vvp_queue::push_back(const vvp_vector4_t&, unsigned) { cerr << "XXXX push_back(vvp_vector4_t) not implemented for " << typeid(*this).name() << endl; } -void vvp_queue::push_front(const vvp_vector4_t&) +void vvp_queue::push_front(const vvp_vector4_t&, unsigned) { cerr << "XXXX push_front(vvp_vector4_t) not implemented for " << typeid(*this).name() << endl; } -void vvp_queue::push_back(double) +void vvp_queue::push_back(double, unsigned) { cerr << "XXXX push_back(double) not implemented for " << typeid(*this).name() << endl; } -void vvp_queue::push_front(double) +void vvp_queue::push_front(double, unsigned) { cerr << "XXXX push_front(double) not implemented for " << typeid(*this).name() << endl; } -void vvp_queue::push_back(const string&) +void vvp_queue::push_back(const string&, unsigned) { cerr << "XXXX push_back(string) not implemented for " << typeid(*this).name() << endl; } -void vvp_queue::push_front(const string&) +void vvp_queue::push_front(const string&, unsigned) { cerr << "XXXX push_front(string) not implemented for " << typeid(*this).name() << endl; } @@ -449,9 +449,10 @@ size_t vvp_queue_string::get_size() const return array_.size(); } -void vvp_queue_string::push_back(const string&val) +void vvp_queue_string::push_back(const string&val, unsigned max_size) { - array_.push_back(val); + if (!max_size || (array_.size() < max_size)) array_.push_back(val); + else cerr << "Warning: value \"" << val << "\" was not added to queue." << endl; } void vvp_queue_string::set_word(unsigned adr, const string&value) @@ -533,13 +534,18 @@ void vvp_queue_vec4::get_word(unsigned adr, vvp_vector4_t&value) value = *cur; } -void vvp_queue_vec4::push_back(const vvp_vector4_t&val) +void vvp_queue_vec4::push_back(const vvp_vector4_t&val, unsigned max_size) { - array_.push_back(val); + if (!max_size || (array_.size() < max_size)) array_.push_back(val); + else cerr << "Warning: value " << val << " was not added to queue." << endl; } -void vvp_queue_vec4::push_front(const vvp_vector4_t&val) +void vvp_queue_vec4::push_front(const vvp_vector4_t&val, unsigned max_size) { + if (max_size && (array_.size() == max_size)) { + cerr << "Warning: value " << array_.back() << " was removed from queue." << endl; + array_.pop_back(); + } array_.push_front(val); } diff --git a/vvp/vvp_darray.h b/vvp/vvp_darray.h index 12760791c..a08df704a 100644 --- a/vvp/vvp_darray.h +++ b/vvp/vvp_darray.h @@ -1,7 +1,7 @@ #ifndef IVL_vvp_darray_H #define IVL_vvp_darray_H /* - * Copyright (c) 2012-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2020 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 @@ -154,14 +154,14 @@ class vvp_queue : public vvp_darray { inline vvp_queue(void) { } ~vvp_queue(); - virtual void push_back(const vvp_vector4_t&value); - virtual void push_front(const vvp_vector4_t&value); + virtual void push_back(const vvp_vector4_t&value, unsigned max_size); + virtual void push_front(const vvp_vector4_t&value, unsigned max_size); - virtual void push_back(double value); - virtual void push_front(double value); + virtual void push_back(double value, unsigned max_size); + virtual void push_front(double value, unsigned max_size); - virtual void push_back(const std::string&value); - virtual void push_front(const std::string&value); + virtual void push_back(const std::string&value, unsigned max_size); + virtual void push_front(const std::string&value, unsigned max_size); virtual void pop_back(void) =0; virtual void pop_front(void)=0; @@ -175,8 +175,8 @@ class vvp_queue_vec4 : public vvp_queue { size_t get_size(void) const; void set_word(unsigned adr, const vvp_vector4_t&value); void get_word(unsigned adr, vvp_vector4_t&value); - void push_back(const vvp_vector4_t&value); - void push_front(const vvp_vector4_t&value); + void push_back(const vvp_vector4_t&value, unsigned max_size); + void push_front(const vvp_vector4_t&value, unsigned max_size); void pop_back(void); void pop_front(void); @@ -193,8 +193,8 @@ class vvp_queue_string : public vvp_queue { size_t get_size(void) const; void set_word(unsigned adr, const std::string&value); void get_word(unsigned adr, std::string&value); - void push_back(const std::string&value); - //void push_front(const std::string&value); + void push_back(const std::string&value, unsigned max_size); + //void push_front(const std::string&value, unsigned max_size); void pop_back(void); void pop_front(void);