mirror of
https://github.com/YosysHQ/yosys
synced 2026-02-13 04:13:03 +00:00
Merge remote-tracking branch 'origin/main' into icells_not_derived
This commit is contained in:
commit
52845cd82b
1402 changed files with 116443 additions and 39709 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -17,12 +17,9 @@
|
|||
*
|
||||
* ---
|
||||
*
|
||||
* This is the AST frontend library.
|
||||
*
|
||||
* The AST frontend library is not a frontend on it's own but provides a
|
||||
* generic abstract syntax tree (AST) abstraction for HDL code and can be
|
||||
* used by HDL frontends. See "ast.h" for an overview of the API and the
|
||||
* Verilog frontend for an usage example.
|
||||
* The AST frontend library is not a frontend on its own but provides an
|
||||
* abstract syntax tree (AST) abstraction for the open source Verilog frontend
|
||||
* at frontends/verilog.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -31,6 +28,7 @@
|
|||
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/fmt.h"
|
||||
#include "frontends/verilog/verilog_location.h"
|
||||
#include <stdint.h>
|
||||
#include <set>
|
||||
|
||||
|
|
@ -156,6 +154,7 @@ namespace AST
|
|||
AST_MODPORT,
|
||||
AST_MODPORTMEMBER,
|
||||
AST_PACKAGE,
|
||||
AST_IMPORT,
|
||||
|
||||
AST_WIRETYPE,
|
||||
AST_TYPEDEF,
|
||||
|
|
@ -165,12 +164,7 @@ namespace AST
|
|||
AST_BIND
|
||||
};
|
||||
|
||||
struct AstSrcLocType {
|
||||
unsigned int first_line, last_line;
|
||||
unsigned int first_column, last_column;
|
||||
AstSrcLocType() : first_line(0), last_line(0), first_column(0), last_column(0) {}
|
||||
AstSrcLocType(int _first_line, int _first_column, int _last_line, int _last_column) : first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {}
|
||||
};
|
||||
using AstSrcLocType = Location;
|
||||
|
||||
// convert an node type to a string (e.g. for debug output)
|
||||
std::string type2str(AstNodeType type);
|
||||
|
|
@ -180,16 +174,16 @@ namespace AST
|
|||
{
|
||||
// for dict<> and pool<>
|
||||
unsigned int hashidx_;
|
||||
unsigned int hash() const { return hashidx_; }
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
|
||||
// this nodes type
|
||||
AstNodeType type;
|
||||
|
||||
// the list of child nodes for this node
|
||||
std::vector<AstNode*> children;
|
||||
std::vector<std::unique_ptr<AstNode>> children;
|
||||
|
||||
// the list of attributes assigned to this node
|
||||
std::map<RTLIL::IdString, AstNode*> attributes;
|
||||
std::map<RTLIL::IdString, std::unique_ptr<AstNode>> attributes;
|
||||
bool get_bool_attribute(RTLIL::IdString id);
|
||||
|
||||
// node content - most of it is unused in most node types
|
||||
|
|
@ -215,7 +209,7 @@ namespace AST
|
|||
int unpacked_dimensions;
|
||||
|
||||
// this is set by simplify and used during RTLIL generation
|
||||
AstNode *id2ast;
|
||||
AstNode* id2ast;
|
||||
|
||||
// this is used by simplify to detect if basic analysis has been performed already on the node
|
||||
bool basic_prep;
|
||||
|
|
@ -226,7 +220,6 @@ namespace AST
|
|||
// this is the original sourcecode location that resulted in this AST node
|
||||
// it is automatically set by the constructor using AST::current_filename and
|
||||
// the AST::get_line_num() callback function.
|
||||
std::string filename;
|
||||
AstSrcLocType location;
|
||||
|
||||
// are we embedded in an lvalue, param?
|
||||
|
|
@ -237,9 +230,9 @@ namespace AST
|
|||
bool in_param_from_above;
|
||||
|
||||
// creating and deleting nodes
|
||||
AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr);
|
||||
AstNode *clone() const;
|
||||
void cloneInto(AstNode *other) const;
|
||||
AstNode(AstSrcLocType loc, AstNodeType type = AST_NONE, std::unique_ptr<AstNode> child1 = nullptr, std::unique_ptr<AstNode> child2 = nullptr, std::unique_ptr<AstNode> child3 = nullptr, std::unique_ptr<AstNode> child4 = nullptr);
|
||||
std::unique_ptr<AstNode> clone() const;
|
||||
void cloneInto(AstNode &other) const;
|
||||
void delete_children();
|
||||
~AstNode();
|
||||
|
||||
|
|
@ -268,14 +261,14 @@ namespace AST
|
|||
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
|
||||
bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint);
|
||||
void replace_result_wire_name_in_function(const std::string &from, const std::string &to);
|
||||
AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
|
||||
std::unique_ptr<AstNode> readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
|
||||
void expand_genblock(const std::string &prefix);
|
||||
void label_genblks(std::set<std::string>& existing, int &counter);
|
||||
void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
|
||||
dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
|
||||
bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block);
|
||||
bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode* async_block);
|
||||
bool mem2reg_check(pool<AstNode*> &mem2reg_set);
|
||||
void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes);
|
||||
void mem2reg_remove(pool<AstNode*> &mem2reg_set);
|
||||
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
|
||||
bool detect_latch(const std::string &var);
|
||||
const RTLIL::Module* lookup_cell_module();
|
||||
|
|
@ -291,7 +284,7 @@ namespace AST
|
|||
};
|
||||
bool has_const_only_constructs();
|
||||
bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed);
|
||||
AstNode *eval_const_function(AstNode *fcall, bool must_succeed);
|
||||
std::unique_ptr<AstNode> eval_const_function(AstNode *fcall, bool must_succeed);
|
||||
bool is_simple_const_expr();
|
||||
|
||||
// helper for parsing format strings
|
||||
|
|
@ -308,29 +301,30 @@ namespace AST
|
|||
std::vector<RTLIL::Binding *> genBindings() const;
|
||||
|
||||
// used by genRTLIL() for detecting expression width and sign
|
||||
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL);
|
||||
void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL);
|
||||
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = nullptr);
|
||||
void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = nullptr);
|
||||
|
||||
// create RTLIL code for this AST node
|
||||
// for expressions the resulting signal vector is returned
|
||||
// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module
|
||||
RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);
|
||||
RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
|
||||
RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = nullptr);
|
||||
|
||||
// compare AST nodes
|
||||
bool operator==(const AstNode &other) const;
|
||||
bool operator!=(const AstNode &other) const;
|
||||
bool contains(const AstNode *other) const;
|
||||
AstNode operator=(AstNode) = delete;
|
||||
|
||||
// helper functions for creating AST nodes for constants
|
||||
static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
|
||||
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
|
||||
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
|
||||
static AstNode *mkconst_str(const std::vector<RTLIL::State> &v);
|
||||
static AstNode *mkconst_str(const std::string &str);
|
||||
static std::unique_ptr<AstNode> mkconst_int(AstSrcLocType loc, uint32_t v, bool is_signed, int width = 32);
|
||||
static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized);
|
||||
static std::unique_ptr<AstNode> mkconst_bits(AstSrcLocType loc, const std::vector<RTLIL::State> &v, bool is_signed);
|
||||
static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::vector<RTLIL::State> &v);
|
||||
static std::unique_ptr<AstNode> mkconst_str(AstSrcLocType loc, const std::string &str);
|
||||
|
||||
// helper function to create an AST node for a temporary register
|
||||
AstNode *mktemp_logic(const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);
|
||||
std::unique_ptr<AstNode> mktemp_logic(AstSrcLocType loc, const std::string &name, AstNode *mod, bool nosync, int range_left, int range_right, bool is_signed);
|
||||
|
||||
// helper function for creating sign-extended const objects
|
||||
RTLIL::Const bitsAsConst(int width, bool is_signed);
|
||||
|
|
@ -359,12 +353,12 @@ namespace AST
|
|||
|
||||
// helper to clone the node with some of its subexpressions replaced with zero (this is used
|
||||
// to evaluate widths of dynamic ranges)
|
||||
AstNode *clone_at_zero();
|
||||
std::unique_ptr<AstNode> clone_at_zero();
|
||||
|
||||
void set_attribute(RTLIL::IdString key, AstNode *node)
|
||||
void set_attribute(RTLIL::IdString key, std::unique_ptr<AstNode> node)
|
||||
{
|
||||
attributes[key] = node;
|
||||
node->set_in_param_flag(true);
|
||||
attributes[key] = std::move(node);
|
||||
}
|
||||
|
||||
// helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag
|
||||
|
|
@ -380,11 +374,16 @@ namespace AST
|
|||
void fixup_hierarchy_flags(bool force_descend = false);
|
||||
|
||||
// helpers for indexing
|
||||
AstNode *make_index_range(AstNode *node, bool unpacked_range = false);
|
||||
std::unique_ptr<AstNode> make_index_range(AstNode *node, bool unpacked_range = false);
|
||||
AstNode *get_struct_member() const;
|
||||
|
||||
// helper to print errors from simplify/genrtlil code
|
||||
[[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3));
|
||||
[[noreturn]] void formatted_input_error(std::string str) const;
|
||||
template <typename... Args>
|
||||
[[noreturn]] void input_error(FmtString<TypeIdentity<Args>...> fmt, const Args &... args) const
|
||||
{
|
||||
formatted_input_error(fmt.format(args...));
|
||||
}
|
||||
};
|
||||
|
||||
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
|
||||
|
|
@ -394,12 +393,11 @@ namespace AST
|
|||
// parametric modules are supported directly by the AST library
|
||||
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
|
||||
struct AstModule : RTLIL::Module {
|
||||
AstNode *ast;
|
||||
std::unique_ptr<AstNode> ast;
|
||||
bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire;
|
||||
~AstModule() override;
|
||||
RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, bool mayfail) override;
|
||||
RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail) override;
|
||||
std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, AstNode **new_ast_out, bool quiet = false);
|
||||
std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, std::unique_ptr<AstNode>* new_ast_out, bool quiet = false);
|
||||
void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces) override;
|
||||
bool reprocess_if_necessary(RTLIL::Design *design) override;
|
||||
RTLIL::Module *clone() const override;
|
||||
|
|
@ -409,16 +407,19 @@ namespace AST
|
|||
// this must be set by the language frontend before parsing the sources
|
||||
// the AstNode constructor then uses current_filename and get_line_num()
|
||||
// to initialize the filename and linenum properties of new nodes
|
||||
extern std::string current_filename;
|
||||
extern void (*set_line_num)(int);
|
||||
extern int (*get_line_num)();
|
||||
// extern std::string current_filename;
|
||||
// also set by the language frontend to control some AST processing
|
||||
extern bool sv_mode_but_global_and_used_for_literally_one_condition;
|
||||
|
||||
// for stats
|
||||
unsigned long long astnode_count();
|
||||
|
||||
// set set_line_num and get_line_num to internal dummy functions (done by simplify() and AstModule::derive
|
||||
// to control the filename and linenum properties of new nodes not generated by a frontend parser)
|
||||
void use_internal_line_num();
|
||||
|
||||
// call a DPI function
|
||||
AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args);
|
||||
std::unique_ptr<AstNode> dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AstNode>> &args);
|
||||
|
||||
// Helper functions related to handling SystemVerilog interfaces
|
||||
std::pair<std::string,std::string> split_modport_from_type(std::string name_type);
|
||||
|
|
@ -464,7 +465,7 @@ namespace AST_INTERNAL
|
|||
process_and_replace_module(RTLIL::Design *design,
|
||||
RTLIL::Module *old_module,
|
||||
AST::AstNode *new_ast,
|
||||
AST::AstNode *original_ast = nullptr);
|
||||
std::unique_ptr<AST::AstNode> original_ast = nullptr);
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ static ffi_fptr resolve_fn (std::string symbol_name)
|
|||
plugin_name = loaded_plugin_aliases.at(plugin_name);
|
||||
|
||||
if (loaded_plugins.count(plugin_name) == 0)
|
||||
log_error("unable to resolve '%s': can't find plugin `%s'\n", symbol_name.c_str(), plugin_name.c_str());
|
||||
log_error("unable to resolve '%s': can't find plugin `%s'\n", symbol_name, plugin_name);
|
||||
|
||||
void *symbol = dlsym(loaded_plugins.at(plugin_name), real_symbol_name.c_str());
|
||||
|
||||
|
|
@ -61,44 +61,45 @@ static ffi_fptr resolve_fn (std::string symbol_name)
|
|||
if (symbol != nullptr)
|
||||
return (ffi_fptr) symbol;
|
||||
|
||||
log_error("unable to resolve '%s'.\n", symbol_name.c_str());
|
||||
log_error("unable to resolve '%s'.\n", symbol_name);
|
||||
}
|
||||
|
||||
AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args)
|
||||
std::unique_ptr<AST::AstNode> AST::dpi_call(AstSrcLocType loc, const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<std::unique_ptr<AST::AstNode>> &args)
|
||||
{
|
||||
AST::AstNode *newNode = nullptr;
|
||||
union { double f64; float f32; int32_t i32; void *ptr; } value_store [args.size() + 1];
|
||||
ffi_type *types [args.size() + 1];
|
||||
void *values [args.size() + 1];
|
||||
std::unique_ptr<AST::AstNode> newNode = nullptr;
|
||||
union value { double f64; float f32; int32_t i32; void *ptr; };
|
||||
std::vector<value> value_store(args.size() + 1);
|
||||
std::vector<ffi_type *> types(args.size() + 1);
|
||||
std::vector<void *> values(args.size() + 1);
|
||||
ffi_cif cif;
|
||||
int status;
|
||||
|
||||
log("Calling DPI function `%s' and returning `%s':\n", fname.c_str(), rtype.c_str());
|
||||
log("Calling DPI function `%s' and returning `%s':\n", fname, rtype);
|
||||
|
||||
log_assert(GetSize(args) == GetSize(argtypes));
|
||||
for (int i = 0; i < GetSize(args); i++) {
|
||||
if (argtypes[i] == "real") {
|
||||
log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
|
||||
log(" arg %d (%s): %f\n", i, argtypes[i], args[i]->asReal(args[i]->is_signed));
|
||||
value_store[i].f64 = args[i]->asReal(args[i]->is_signed);
|
||||
values[i] = &value_store[i].f64;
|
||||
types[i] = &ffi_type_double;
|
||||
} else if (argtypes[i] == "shortreal") {
|
||||
log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
|
||||
log(" arg %d (%s): %f\n", i, argtypes[i], args[i]->asReal(args[i]->is_signed));
|
||||
value_store[i].f32 = args[i]->asReal(args[i]->is_signed);
|
||||
values[i] = &value_store[i].f32;
|
||||
types[i] = &ffi_type_double;
|
||||
} else if (argtypes[i] == "integer") {
|
||||
log(" arg %d (%s): %lld\n", i, argtypes[i].c_str(), (long long)args[i]->asInt(args[i]->is_signed));
|
||||
log(" arg %d (%s): %lld\n", i, argtypes[i], (long long)args[i]->asInt(args[i]->is_signed));
|
||||
value_store[i].i32 = args[i]->asInt(args[i]->is_signed);
|
||||
values[i] = &value_store[i].i32;
|
||||
types[i] = &ffi_type_sint32;
|
||||
} else if (argtypes[i] == "chandle") {
|
||||
log(" arg %d (%s): %llx\n", i, argtypes[i].c_str(), (unsigned long long)args[i]->asInt(false));
|
||||
log(" arg %d (%s): %llx\n", i, argtypes[i], (unsigned long long)args[i]->asInt(false));
|
||||
value_store[i].ptr = (void *)args[i]->asInt(args[i]->is_signed);
|
||||
values[i] = &value_store[i].ptr;
|
||||
types[i] = &ffi_type_pointer;
|
||||
} else {
|
||||
log_error("invalid argtype '%s' for argument %d.\n", argtypes[i].c_str(), i);
|
||||
log_error("invalid argtype '%s' for argument %d.\n", argtypes[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,20 +116,20 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
|
|||
types[args.size()] = &ffi_type_pointer;
|
||||
values[args.size()] = &value_store[args.size()].ptr;
|
||||
} else {
|
||||
log_error("invalid rtype '%s'.\n", rtype.c_str());
|
||||
log_error("invalid rtype '%s'.\n", rtype);
|
||||
}
|
||||
|
||||
if ((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, args.size(), types[args.size()], types)) != FFI_OK)
|
||||
if ((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, args.size(), types[args.size()], types.data())) != FFI_OK)
|
||||
log_error("ffi_prep_cif failed: status %d.\n", status);
|
||||
|
||||
ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values);
|
||||
ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values.data());
|
||||
|
||||
if (rtype == "real") {
|
||||
newNode = new AstNode(AST_REALVALUE);
|
||||
newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
|
||||
newNode->realvalue = value_store[args.size()].f64;
|
||||
log(" return realvalue: %g\n", newNode->asReal(true));
|
||||
} else if (rtype == "shortreal") {
|
||||
newNode = new AstNode(AST_REALVALUE);
|
||||
newNode = std::make_unique<AstNode>(loc, AST_REALVALUE);
|
||||
newNode->realvalue = value_store[args.size()].f32;
|
||||
log(" return realvalue: %g\n", newNode->asReal(true));
|
||||
} else if (rtype == "chandle") {
|
||||
|
|
@ -136,10 +137,10 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
|
|||
std::vector<RTLIL::State> bits(64);
|
||||
for (int i = 0; i < 64; i++)
|
||||
bits.at(i) = (rawval & (1ULL << i)) ? RTLIL::State::S1 : RTLIL::State::S0;
|
||||
newNode = AstNode::mkconst_bits(bits, false);
|
||||
newNode = AstNode::mkconst_bits(loc, bits, false);
|
||||
log(" return chandle: %llx\n", (unsigned long long)newNode->asInt(false));
|
||||
} else {
|
||||
newNode = AstNode::mkconst_int(value_store[args.size()].i32, false);
|
||||
newNode = AstNode::mkconst_int(loc, value_store[args.size()].i32, false);
|
||||
log(" return integer: %lld\n", (long long)newNode->asInt(true));
|
||||
}
|
||||
|
||||
|
|
@ -152,9 +153,9 @@ YOSYS_NAMESPACE_END
|
|||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
|
||||
std::unique_ptr<AST::AstNode> AST::dpi_call(AstSrcLocType, const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<std::unique_ptr<AST::AstNode>>&)
|
||||
{
|
||||
log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
|
||||
log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname);
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue