Allow ports to be declared before arrays.
It is possible for the code generator to create .array/port objects before the .array object that the port refereces, so use the resolv_list to arrange for binding during cleanup.
This commit is contained in:
parent
42913e46b8
commit
6632e4c33b
73
vvp/array.cc
73
vvp/array.cc
|
|
@ -35,7 +35,7 @@ static symbol_table_t array_table =0;
|
|||
class vvp_fun_arrayport;
|
||||
static void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
|
||||
|
||||
vvp_array_t array_find(char*label)
|
||||
vvp_array_t array_find(const char*label)
|
||||
{
|
||||
if (array_table == 0)
|
||||
return 0;
|
||||
|
|
@ -667,43 +667,66 @@ void array_word_change(vvp_array_t array, unsigned long addr)
|
|||
cur->check_word_change(addr);
|
||||
}
|
||||
|
||||
void compile_array_port(char*label, char*array, char*addr)
|
||||
class array_port_resolv_list_t : public resolv_list_s {
|
||||
|
||||
public:
|
||||
explicit array_port_resolv_list_t(char*label) : resolv_list_s(label) { }
|
||||
|
||||
vvp_net_t*ptr;
|
||||
bool use_addr;
|
||||
long addr;
|
||||
bool resolve(bool mes);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
bool array_port_resolv_list_t::resolve(bool mes)
|
||||
{
|
||||
vvp_array_t mem = array_find(array);
|
||||
assert(mem);
|
||||
vvp_array_t mem = array_find(label());
|
||||
if (mem == 0) {
|
||||
assert(mem || !mes);
|
||||
return false;
|
||||
}
|
||||
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_fun_arrayport*fun = new vvp_fun_arrayport(mem, ptr);
|
||||
vvp_fun_arrayport*fun;
|
||||
if (use_addr)
|
||||
fun = new vvp_fun_arrayport(mem, ptr, addr);
|
||||
else
|
||||
fun = new vvp_fun_arrayport(mem, ptr);
|
||||
ptr->fun = fun;
|
||||
|
||||
define_functor_symbol(label, ptr);
|
||||
// Connect the port-0 input as the address.
|
||||
input_connect(ptr, 0, addr);
|
||||
|
||||
array_attach_port(mem, fun);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void compile_array_port(char*label, char*array, char*addr)
|
||||
{
|
||||
array_port_resolv_list_t*resolv_mem
|
||||
= new array_port_resolv_list_t(array);
|
||||
|
||||
resolv_mem->ptr = new vvp_net_t;
|
||||
resolv_mem->use_addr = false;
|
||||
define_functor_symbol(label, resolv_mem->ptr);
|
||||
free(label);
|
||||
free(array);
|
||||
// The input_connect arranges for the array string to be free'ed.
|
||||
// Connect the port-0 input as the address.
|
||||
input_connect(resolv_mem->ptr, 0, addr);
|
||||
|
||||
resolv_submit(resolv_mem);
|
||||
}
|
||||
|
||||
void compile_array_port(char*label, char*array, long addr)
|
||||
{
|
||||
vvp_array_t mem = array_find(array);
|
||||
assert(mem);
|
||||
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
vvp_fun_arrayport*fun = new vvp_fun_arrayport(mem, ptr, addr);
|
||||
ptr->fun = fun;
|
||||
|
||||
define_functor_symbol(label, ptr);
|
||||
|
||||
// Other then the array itself, this kind of array port has no
|
||||
// inputs.
|
||||
array_attach_port(mem, fun);
|
||||
array_port_resolv_list_t*resolv_mem
|
||||
= new array_port_resolv_list_t(array);
|
||||
|
||||
resolv_mem->ptr = new vvp_net_t;
|
||||
resolv_mem->use_addr = true;
|
||||
resolv_mem->addr = addr;
|
||||
define_functor_symbol(label, resolv_mem->ptr);
|
||||
free(label);
|
||||
free(array);
|
||||
|
||||
resolv_submit(resolv_mem);
|
||||
}
|
||||
|
||||
void compile_array_alias(char*label, char*name, char*src)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ typedef struct __vpiArray* vvp_array_t;
|
|||
* This function tries to find the array (by label) in the global
|
||||
* table of all the arrays in the design.
|
||||
*/
|
||||
extern vvp_array_t array_find(char*label);
|
||||
extern vvp_array_t array_find(const char*label);
|
||||
extern vpiHandle array_index_iterate(int code, vpiHandle ref);
|
||||
|
||||
extern void array_word_change(vvp_array_t array, unsigned long addr);
|
||||
|
|
|
|||
104
vvp/compile.cc
104
vvp/compile.cc
|
|
@ -321,13 +321,12 @@ vvp_net_t* vvp_net_lookup(const char*label)
|
|||
*/
|
||||
static struct resolv_list_s*resolv_list = 0;
|
||||
|
||||
struct resolv_list_s {
|
||||
virtual ~resolv_list_s() { }
|
||||
struct resolv_list_s*next;
|
||||
virtual bool resolve(bool mes = false) = 0;
|
||||
};
|
||||
resolv_list_s::~resolv_list_s()
|
||||
{
|
||||
free(label_);
|
||||
}
|
||||
|
||||
static void resolv_submit(struct resolv_list_s*cur)
|
||||
void resolv_submit(struct resolv_list_s*cur)
|
||||
{
|
||||
if (cur->resolve()) {
|
||||
delete cur;
|
||||
|
|
@ -346,8 +345,8 @@ static void resolv_submit(struct resolv_list_s*cur)
|
|||
* put net->port[port] into the fan-out list for that node.
|
||||
*/
|
||||
struct vvp_net_resolv_list_s: public resolv_list_s {
|
||||
// node to locate
|
||||
char*source;
|
||||
|
||||
vvp_net_resolv_list_s(char*l) : resolv_list_s(l) { }
|
||||
// port to be driven by the located node.
|
||||
vvp_net_ptr_t port;
|
||||
virtual bool resolve(bool mes);
|
||||
|
|
@ -355,20 +354,18 @@ struct vvp_net_resolv_list_s: public resolv_list_s {
|
|||
|
||||
bool vvp_net_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
vvp_net_t*tmp = vvp_net_lookup(source);
|
||||
vvp_net_t*tmp = vvp_net_lookup(label());
|
||||
|
||||
if (tmp) {
|
||||
// Link the input port to the located output.
|
||||
vvp_net_t*net = port.ptr();
|
||||
net->port[port.port()] = tmp->out;
|
||||
tmp->out = port;
|
||||
|
||||
free(source);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "unresolved vvp_net reference: %s\n", source);
|
||||
fprintf(stderr, "unresolved vvp_net reference: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -376,10 +373,8 @@ bool vvp_net_resolv_list_s::resolve(bool mes)
|
|||
inline static
|
||||
void postpone_functor_input(vvp_net_ptr_t port, char*lab)
|
||||
{
|
||||
struct vvp_net_resolv_list_s*res = new struct vvp_net_resolv_list_s;
|
||||
|
||||
struct vvp_net_resolv_list_s*res = new struct vvp_net_resolv_list_s(lab);
|
||||
res->port = port;
|
||||
res->source = lab;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
|
@ -390,24 +385,22 @@ void postpone_functor_input(vvp_net_ptr_t port, char*lab)
|
|||
*/
|
||||
|
||||
struct functor_gen_resolv_list_s: public resolv_list_s {
|
||||
char*source;
|
||||
explicit functor_gen_resolv_list_s(char*txt) : resolv_list_s(txt) { }
|
||||
vvp_net_t**ref;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool functor_gen_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
vvp_net_t*tmp = vvp_net_lookup(source);
|
||||
vvp_net_t*tmp = vvp_net_lookup(label());
|
||||
|
||||
if (tmp) {
|
||||
*ref = tmp;
|
||||
|
||||
free(source);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "unresolved functor reference: %s\n", source);
|
||||
fprintf(stderr, "unresolved functor reference: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -415,10 +408,9 @@ bool functor_gen_resolv_list_s::resolve(bool mes)
|
|||
void functor_ref_lookup(vvp_net_t**ref, char*lab)
|
||||
{
|
||||
struct functor_gen_resolv_list_s*res =
|
||||
new struct functor_gen_resolv_list_s;
|
||||
new struct functor_gen_resolv_list_s(lab);
|
||||
|
||||
res->ref = ref;
|
||||
res->source = lab;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
|
@ -428,27 +420,27 @@ void functor_ref_lookup(vvp_net_t**ref, char*lab)
|
|||
*/
|
||||
|
||||
struct vpi_handle_resolv_list_s: public resolv_list_s {
|
||||
vpiHandle *handle;
|
||||
char *label;
|
||||
explicit vpi_handle_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
virtual bool resolve(bool mes);
|
||||
vpiHandle *handle;
|
||||
};
|
||||
|
||||
bool vpi_handle_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
symbol_value_t val = sym_get_value(sym_vpi, label);
|
||||
symbol_value_t val = sym_get_value(sym_vpi, label());
|
||||
if (!val.ptr) {
|
||||
// check for thread vector T<base,wid>
|
||||
unsigned base, wid;
|
||||
unsigned n = 0;
|
||||
char ss[32];
|
||||
if (2 <= sscanf(label, "T<%u,%u>%n", &base, &wid, &n)
|
||||
&& n == strlen(label)) {
|
||||
if (2 <= sscanf(label(), "T<%u,%u>%n", &base, &wid, &n)
|
||||
&& n == strlen(label())) {
|
||||
val.ptr = vpip_make_vthr_vector(base, wid, false);
|
||||
sym_set_value(sym_vpi, label, val);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
|
||||
} else if (3 <= sscanf(label, "T<%u,%u,%[su]>%n", &base,
|
||||
} else if (3 <= sscanf(label(), "T<%u,%u,%[su]>%n", &base,
|
||||
&wid, ss, &n)
|
||||
&& n == strlen(label)) {
|
||||
&& n == strlen(label())) {
|
||||
|
||||
bool signed_flag = false;
|
||||
for (char*fp = ss ; *fp ; fp += 1) switch (*fp) {
|
||||
|
|
@ -463,13 +455,13 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
|
|||
}
|
||||
|
||||
val.ptr = vpip_make_vthr_vector(base, wid, signed_flag);
|
||||
sym_set_value(sym_vpi, label, val);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
|
||||
} else if (2 == sscanf(label, "W<%u,%[r]>%n", &base, ss, &n)
|
||||
&& n == strlen(label)) {
|
||||
} else if (2 == sscanf(label(), "W<%u,%[r]>%n", &base, ss, &n)
|
||||
&& n == strlen(label())) {
|
||||
|
||||
val.ptr = vpip_make_vthr_word(base, ss);
|
||||
sym_set_value(sym_vpi, label, val);
|
||||
sym_set_value(sym_vpi, label(), val);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -480,12 +472,11 @@ bool vpi_handle_resolv_list_s::resolve(bool mes)
|
|||
|
||||
if (val.ptr) {
|
||||
*handle = (vpiHandle) val.ptr;
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "unresolved vpi name lookup: %s\n", label);
|
||||
fprintf(stderr, "unresolved vpi name lookup: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -517,10 +508,9 @@ void compile_vpi_lookup(vpiHandle *handle, char*label)
|
|||
}
|
||||
|
||||
struct vpi_handle_resolv_list_s*res
|
||||
= new struct vpi_handle_resolv_list_s;
|
||||
= new struct vpi_handle_resolv_list_s(label);
|
||||
|
||||
res->handle = handle;
|
||||
res->label = label;
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
||||
|
|
@ -529,27 +519,24 @@ void compile_vpi_lookup(vpiHandle *handle, char*label)
|
|||
*/
|
||||
|
||||
struct code_label_resolv_list_s: public resolv_list_s {
|
||||
code_label_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
struct vvp_code_s *code;
|
||||
char *label;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool code_label_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
symbol_value_t val = sym_get_value(sym_codespace, label);
|
||||
symbol_value_t val = sym_get_value(sym_codespace, label());
|
||||
if (val.num) {
|
||||
if (code->opcode == of_FORK)
|
||||
code->cptr2 = reinterpret_cast<vvp_code_t>(val.ptr);
|
||||
else
|
||||
code->cptr = reinterpret_cast<vvp_code_t>(val.ptr);
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr,
|
||||
"unresolved code label: %s\n",
|
||||
label);
|
||||
fprintf(stderr, "unresolved code label: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -557,10 +544,9 @@ bool code_label_resolv_list_s::resolve(bool mes)
|
|||
void code_label_lookup(struct vvp_code_s *code, char *label)
|
||||
{
|
||||
struct code_label_resolv_list_s *res
|
||||
= new struct code_label_resolv_list_s;
|
||||
= new struct code_label_resolv_list_s(label);
|
||||
|
||||
res->code = code;
|
||||
res->label = label;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
|
@ -569,21 +555,20 @@ void code_label_lookup(struct vvp_code_s *code, char *label)
|
|||
* Lookup memories.
|
||||
*/
|
||||
struct memory_resolv_list_s: public resolv_list_s {
|
||||
memory_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
struct vvp_code_s *code;
|
||||
char *label;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool memory_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
code->mem = memory_find(label);
|
||||
code->mem = memory_find(label());
|
||||
if (code->mem != 0) {
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "Memory unresolved: %s\n", label);
|
||||
fprintf(stderr, "Memory unresolved: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -591,41 +576,38 @@ bool memory_resolv_list_s::resolve(bool mes)
|
|||
static void compile_mem_lookup(struct vvp_code_s *code, char *label)
|
||||
{
|
||||
struct memory_resolv_list_s *res
|
||||
= new struct memory_resolv_list_s;
|
||||
= new struct memory_resolv_list_s(label);
|
||||
|
||||
res->code = code;
|
||||
res->label = label;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
||||
struct array_resolv_list_s: public resolv_list_s {
|
||||
struct code_array_resolv_list_s: public resolv_list_s {
|
||||
code_array_resolv_list_s(char*label) : resolv_list_s(label) { }
|
||||
struct vvp_code_s *code;
|
||||
char *label;
|
||||
virtual bool resolve(bool mes);
|
||||
};
|
||||
|
||||
bool array_resolv_list_s::resolve(bool mes)
|
||||
bool code_array_resolv_list_s::resolve(bool mes)
|
||||
{
|
||||
code->array = array_find(label);
|
||||
code->array = array_find(label());
|
||||
if (code->array != 0) {
|
||||
free(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mes)
|
||||
fprintf(stderr, "Array unresolved: %s\n", label);
|
||||
fprintf(stderr, "Array unresolved: %s\n", label());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void compile_array_lookup(struct vvp_code_s*code, char*label)
|
||||
{
|
||||
struct array_resolv_list_s *res
|
||||
= new struct array_resolv_list_s;
|
||||
struct code_array_resolv_list_s *res
|
||||
= new struct code_array_resolv_list_s(label);
|
||||
|
||||
res->code = code;
|
||||
res->label = label;
|
||||
|
||||
resolv_submit(res);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -243,6 +243,41 @@ extern void compile_param_logic(char*label, char*name, char*value,
|
|||
extern void compile_param_real(char*label, char*name, char*value,
|
||||
long file_idx, long lineno);
|
||||
|
||||
/*
|
||||
* The resolv_list_s is the base class for a symbol resolve
|
||||
* action. Some function creates an instance of a resolv_list_s object
|
||||
* that contains the data pertinent to that resolution request, and
|
||||
* executes it with the resolv_submit function. If the operation can
|
||||
* complete, then the resolv_submit deletes the object. Otherwise, it
|
||||
* pushes it onto the resolv_list for later processing.
|
||||
*
|
||||
* Derived classes implement the resolve function to perform the
|
||||
* actual binding or resolution that the instance requires. If the
|
||||
* function succeeds, the resolve method returns true and the object
|
||||
* can be deleted any time.
|
||||
*
|
||||
* The mes parameter of the resolve method tells the resolver that
|
||||
* this call is its last chance. If it cannot complete the operation,
|
||||
* it must print an error message and return false.
|
||||
*/
|
||||
class resolv_list_s {
|
||||
|
||||
public:
|
||||
explicit resolv_list_s(char*lab) : label_(lab) { }
|
||||
virtual ~resolv_list_s();
|
||||
virtual bool resolve(bool mes = false) = 0;
|
||||
|
||||
protected:
|
||||
const char*label() const { return label_; }
|
||||
|
||||
private:
|
||||
friend void ::resolv_submit(struct resolv_list_s*cur);
|
||||
friend void ::compile_cleanup(void);
|
||||
|
||||
char*label_;
|
||||
struct resolv_list_s*next;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function schedules a lookup of an indexed label. The ref
|
||||
* points to the vvp_net_t that receives the result. The result may
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ struct vvp_memory_s
|
|||
|
||||
static symbol_table_t memory_table = 0;
|
||||
|
||||
vvp_memory_t memory_find(char *label)
|
||||
vvp_memory_t memory_find(const char *label)
|
||||
{
|
||||
if (memory_table == 0)
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class vvp_fun_memport : public vvp_net_fun_t {
|
|||
** The memory_create function creates a new memory device with the given
|
||||
** name. It is a fatal error to try to create a device that already exists.
|
||||
*/
|
||||
vvp_memory_t memory_find(char *label);
|
||||
vvp_memory_t memory_find(const char *label);
|
||||
vvp_memory_t memory_create(char *label);
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue