./PaxHeaders.14238/verilog-0.9.70000644000202500001440000000005012204467056014303 xustar000000000000000020 atime=1376939565 20 ctime=1376939566 verilog-0.9.7/0000755000202500001440000000000012204467056013545 5ustar00steveusers00000000000000verilog-0.9.7/PaxHeaders.14238/t-dll-api.cc0000644000202500001440000000005012204466647016322 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/t-dll-api.cc0000644000202500001440000014051112204466647015646 0ustar00steveusers00000000000000/* * Copyright (c) 2000-2009 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "StringHeap.h" # include "t-dll.h" # include "discipline.h" # include # include # include static StringHeap api_strings; /* THE FOLLOWING ARE FUNCTIONS THAT ARE CALLED FROM THE TARGET. */ extern "C" ivl_island_t ivl_branch_island(ivl_branch_t net) { return net->island; } extern "C" ivl_nexus_t ivl_branch_terminal(ivl_branch_t net, int idx) { assert(idx >= 0); assert( idx < 2); return net->pins[idx]; } extern "C" const char*ivl_design_flag(ivl_design_t des, const char*key) { return des->self->get_flag(key); } extern "C" int ivl_design_process(ivl_design_t des, ivl_process_f func, void*cd) { for (ivl_process_t idx = des->threads_; idx; idx = idx->next_) { int rc = (func)(idx, cd); if (rc != 0) return rc; } return 0; } extern "C" ivl_scope_t ivl_design_root(ivl_design_t des) { cerr << "ANACHRONISM: ivl_design_root called. " "Use ivl_design_roots instead." << endl; assert (des->nroots_); return des->roots_[0]; } extern "C" void ivl_design_roots(ivl_design_t des, ivl_scope_t **scopes, unsigned int *nscopes) { assert (nscopes && scopes); *scopes = &des->roots_[0]; *nscopes = des->nroots_; } extern "C" int ivl_design_time_precision(ivl_design_t des) { return des->time_precision; } extern "C" unsigned ivl_design_consts(ivl_design_t des) { return des->consts.size(); } extern "C" ivl_net_const_t ivl_design_const(ivl_design_t des, unsigned idx) { assert(idx < des->consts.size()); return des->consts[idx]; } extern "C" unsigned ivl_design_disciplines(ivl_design_t des) { assert(des); return des->disciplines.size(); } extern "C" ivl_discipline_t ivl_design_discipline(ivl_design_t des, unsigned idx) { assert(des); assert(idx < des->disciplines.size()); return des->disciplines[idx]; } extern "C" ivl_dis_domain_t ivl_discipline_domain(ivl_discipline_t net) { return net->domain(); } extern "C" ivl_nature_t ivl_discipline_flow(ivl_discipline_t net) { return net->flow(); } extern "C" const char* ivl_discipline_name(ivl_discipline_t net) { return net->name(); } extern "C" ivl_nature_t ivl_discipline_potential(ivl_discipline_t net) { return net->potential(); } extern "C" ivl_expr_type_t ivl_expr_type(ivl_expr_t net) { if (net == 0) return IVL_EX_NONE; return net->type_; } extern "C" const char*ivl_expr_file(ivl_expr_t net) { assert(net); return net->file.str(); } extern "C" unsigned ivl_expr_lineno(ivl_expr_t net) { assert(net); return net->lineno; } inline static const char *basename(ivl_scope_t scope, const char *inst) { inst += strlen(ivl_scope_name(scope)); assert(*inst == '.'); return inst+1; } extern "C" ivl_variable_type_t ivl_const_type(ivl_net_const_t net) { assert(net); return net->type; } extern "C" const char*ivl_const_bits(ivl_net_const_t net) { assert(net); switch (net->type) { case IVL_VT_BOOL: case IVL_VT_LOGIC: if (net->width_ <= sizeof(net->b.bit_)) return net->b.bit_; else return net->b.bits_; default: return 0; } } extern "C" ivl_expr_t ivl_const_delay(ivl_net_const_t net, unsigned transition) { assert(transition < 3); return net->delay[transition]; } extern "C" ivl_nexus_t ivl_const_nex(ivl_net_const_t net) { assert(net); return net->pin_; } extern "C" double ivl_const_real(ivl_net_const_t net) { assert(net); assert(net->type == IVL_VT_REAL); return net->b.real_value; } extern "C" int ivl_const_signed(ivl_net_const_t net) { assert(net); return net->signed_; } extern "C" unsigned ivl_const_width(ivl_net_const_t net) { assert(net); return net->width_; } extern "C" const char* ivl_event_name(ivl_event_t net) { static char*name_buffer = 0; static unsigned name_size = 0; ivl_scope_t scope = net->scope; const char*sn = ivl_scope_name(scope); unsigned need = strlen(sn) + 1 + strlen(net->name) + 1; if (need > name_size) { name_buffer = (char*)realloc(name_buffer, need); name_size = need; } strcpy(name_buffer, sn); char*tmp = name_buffer + strlen(sn); *tmp++ = '.'; strcpy(tmp, net->name); cerr << "ANACHRONISM: Call to anachronistic ivl_event_name." << endl; return name_buffer; } extern "C" const char* ivl_event_basename(ivl_event_t net) { return net->name; } extern "C" ivl_scope_t ivl_event_scope(ivl_event_t net) { return net->scope; } extern "C" unsigned ivl_event_nany(ivl_event_t net) { assert(net); return net->nany; } extern "C" ivl_nexus_t ivl_event_any(ivl_event_t net, unsigned idx) { assert(net); assert(idx < net->nany); return net->pins[idx]; } extern "C" unsigned ivl_event_nneg(ivl_event_t net) { assert(net); return net->nneg; } extern "C" ivl_nexus_t ivl_event_neg(ivl_event_t net, unsigned idx) { assert(net); assert(idx < net->nneg); return net->pins[net->nany + idx]; } extern "C" unsigned ivl_event_npos(ivl_event_t net) { assert(net); return net->npos; } extern "C" ivl_nexus_t ivl_event_pos(ivl_event_t net, unsigned idx) { assert(net); assert(idx < net->npos); return net->pins[net->nany + net->nneg + idx]; } extern "C" const char* ivl_expr_bits(ivl_expr_t net) { assert(net && (net->type_ == IVL_EX_NUMBER)); return net->u_.number_.bits_; } extern "C" ivl_branch_t ivl_expr_branch(ivl_expr_t net) { assert(net && (net->type_ == IVL_EX_BACCESS)); return net->u_.branch_.branch; } extern "C" ivl_scope_t ivl_expr_def(ivl_expr_t net) { assert(net); switch (net->type_) { case IVL_EX_UFUNC: return net->u_.ufunc_.def; default: assert(0); } return 0; } extern "C" uint64_t ivl_expr_delay_val(ivl_expr_t net) { assert(net->type_ == IVL_EX_DELAY); return net->u_.delay_.value; } extern "C" double ivl_expr_dvalue(ivl_expr_t net) { assert(net->type_ == IVL_EX_REALNUM); return net->u_.real_.value; } extern "C" const char* ivl_expr_name(ivl_expr_t net) { switch (net->type_) { case IVL_EX_SFUNC: return net->u_.sfunc_.name_; case IVL_EX_SIGNAL: return net->u_.signal_.sig->name_; default: assert(0); } return 0; } extern "C" ivl_nature_t ivl_expr_nature(ivl_expr_t net) { assert(net && (net->type_ == IVL_EX_BACCESS)); return net->u_.branch_.nature; } extern "C" char ivl_expr_opcode(ivl_expr_t net) { assert(net); switch (net->type_) { case IVL_EX_BINARY: return net->u_.binary_.op_; case IVL_EX_UNARY: return net->u_.unary_.op_; default: assert(0); } return 0; } extern "C" ivl_expr_t ivl_expr_oper1(ivl_expr_t net) { assert(net); switch (net->type_) { case IVL_EX_BINARY: case IVL_EX_SELECT: return net->u_.binary_.lef_; case IVL_EX_UNARY: return net->u_.unary_.sub_; case IVL_EX_MEMORY: return net->u_.memory_.idx_; case IVL_EX_SIGNAL: return net->u_.signal_.word; case IVL_EX_TERNARY: return net->u_.ternary_.cond; default: assert(0); } return 0; } extern "C" ivl_expr_t ivl_expr_oper2(ivl_expr_t net) { assert(net); switch (net->type_) { case IVL_EX_BINARY: case IVL_EX_SELECT: return net->u_.binary_.rig_; case IVL_EX_TERNARY: return net->u_.ternary_.true_e; default: assert(0); } return 0; } extern "C" ivl_expr_t ivl_expr_oper3(ivl_expr_t net) { assert(net); switch (net->type_) { case IVL_EX_TERNARY: return net->u_.ternary_.false_e; default: assert(0); } return 0; } extern "C" ivl_parameter_t ivl_expr_parameter(ivl_expr_t net) { assert(net); switch (net->type_) { case IVL_EX_NUMBER: return net->u_.number_.parameter; case IVL_EX_STRING: return net->u_.string_.parameter; case IVL_EX_REALNUM: return net->u_.real_.parameter; default: return 0; } } extern "C" ivl_expr_t ivl_expr_parm(ivl_expr_t net, unsigned idx) { assert(net); switch (net->type_) { case IVL_EX_CONCAT: assert(idx < net->u_.concat_.parms); return net->u_.concat_.parm[idx]; case IVL_EX_SFUNC: assert(idx < net->u_.sfunc_.parms); return net->u_.sfunc_.parm[idx]; case IVL_EX_UFUNC: assert(idx < net->u_.ufunc_.parms); return net->u_.ufunc_.parm[idx]; default: assert(0); return 0; } } extern "C" unsigned ivl_expr_parms(ivl_expr_t net) { assert(net); switch (net->type_) { case IVL_EX_CONCAT: return net->u_.concat_.parms; case IVL_EX_SFUNC: return net->u_.sfunc_.parms; case IVL_EX_UFUNC: return net->u_.ufunc_.parms; default: assert(0); return 0; } } extern "C" unsigned ivl_expr_repeat(ivl_expr_t net) { assert(net); assert(net->type_ == IVL_EX_CONCAT); return net->u_.concat_.rept; } extern "C" ivl_event_t ivl_expr_event(ivl_expr_t net) { assert(net); assert(net->type_ == IVL_EX_EVENT); return net->u_.event_.event; } extern "C" ivl_scope_t ivl_expr_scope(ivl_expr_t net) { assert(net); assert(net->type_ == IVL_EX_SCOPE); return net->u_.scope_.scope; } extern "C" ivl_signal_t ivl_expr_signal(ivl_expr_t net) { assert(net); switch (net->type_) { case IVL_EX_SIGNAL: case IVL_EX_ARRAY: return net->u_.signal_.sig; default: assert(0); return 0; } } extern "C" int ivl_expr_signed(ivl_expr_t net) { assert(net); return net->signed_; } extern "C" const char* ivl_expr_string(ivl_expr_t net) { assert(net->type_ == IVL_EX_STRING); return net->u_.string_.value_; } extern "C" unsigned long ivl_expr_uvalue(ivl_expr_t net) { switch (net->type_) { case IVL_EX_ULONG: return net->u_.ulong_.value; case IVL_EX_NUMBER: { unsigned long val = 0; for (unsigned long idx = 0 ; idx < net->width_ ; idx += 1) { if (net->u_.number_.bits_[idx] == '1') val |= 1UL << idx; } return val; } default: assert(0); } assert(0); return 0; } extern "C" ivl_variable_type_t ivl_expr_value(ivl_expr_t net) { assert(net); return net->value_; } extern "C" unsigned ivl_expr_width(ivl_expr_t net) { assert(net); return net->width_; } /* * ivl_file_table_index puts entries in the map as needed and returns * the appropriate index. * ivl_file_table_size returns the number of entries in the table. * ivl_file_table_item returns the file name for the given index. */ struct ltstr { bool operator()(const char*s1, const char*s2) const { return strcmp(s1, s2) < 0; } }; static map fn_map; static vector fn_vector; static void ivl_file_table_init() { /* The first two index entries do not depend on a real * file name and are always available. */ fn_vector.push_back("N/A"); fn_map["N/A"] = 0; fn_vector.push_back(""); fn_map[""] = 1; } extern "C" const char* ivl_file_table_item(unsigned idx) { if (fn_vector.empty()) { ivl_file_table_init(); } assert(idx < fn_vector.size()); return fn_vector[idx]; } extern "C" unsigned ivl_file_table_index(const char*name) { if (fn_vector.empty()) { ivl_file_table_init(); } if (name == NULL) return 0; /* The new index is the current map size. This is inserted only * if the file name is not currently in the map. */ pair::iterator, bool> result; result = fn_map.insert(make_pair(name, fn_vector.size())); if (result.second) { fn_vector.push_back(name); } return result.first->second; } extern "C" unsigned ivl_file_table_size() { if (fn_vector.empty()) { ivl_file_table_init(); } return fn_vector.size(); } extern "C" int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value) { if (flag >= net->flags.size()) { if (value == 0) return 0; else net->flags.resize(flag+1, false); } int old_flag = net->flags[flag]; net->flags[flag] = value != 0; return old_flag; } extern "C" int ivl_island_flag_test(ivl_island_t net, unsigned flag) { if (flag >= net->flags.size()) return 0; else return net->flags[flag]; } extern "C" const char* ivl_logic_attr(ivl_net_logic_t net, const char*key) { assert(net); unsigned idx; for (idx = 0 ; idx < net->nattr ; idx += 1) { if (strcmp(net->attr[idx].key, key) == 0) return net->attr[idx].type == IVL_ATT_STR ? net->attr[idx].val.str : 0; } return 0; } extern "C" unsigned ivl_logic_attr_cnt(ivl_net_logic_t net) { return net->nattr; } extern "C" ivl_attribute_t ivl_logic_attr_val(ivl_net_logic_t net, unsigned idx) { assert(idx < net->nattr); return net->attr + idx; } extern "C" ivl_drive_t ivl_logic_drive0(ivl_net_logic_t net) { ivl_nexus_t nex = ivl_logic_pin(net, 0); for (unsigned idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) { ivl_nexus_ptr_t cur = ivl_nexus_ptr(nex, idx); if (ivl_nexus_ptr_log(cur) != net) continue; if (ivl_nexus_ptr_pin(cur) != 0) continue; return ivl_nexus_ptr_drive0(cur); } assert(0); return IVL_DR_STRONG; } extern "C" ivl_drive_t ivl_logic_drive1(ivl_net_logic_t net) { ivl_nexus_t nex = ivl_logic_pin(net, 0); for (unsigned idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) { ivl_nexus_ptr_t cur = ivl_nexus_ptr(nex, idx); if (ivl_nexus_ptr_log(cur) != net) continue; if (ivl_nexus_ptr_pin(cur) != 0) continue; return ivl_nexus_ptr_drive1(cur); } assert(0); return IVL_DR_STRONG; } extern "C" const char* ivl_logic_name(ivl_net_logic_t net) { assert(net); cerr << "ANACHRONISM: Call to anachronistic ivl_logic_name." << endl; return net->name_; } extern "C" const char* ivl_logic_basename(ivl_net_logic_t net) { assert(net); return net->name_; } extern "C" ivl_scope_t ivl_logic_scope(ivl_net_logic_t net) { assert(net); return net->scope_; } extern "C" ivl_logic_t ivl_logic_type(ivl_net_logic_t net) { return net->type_; } extern "C" unsigned ivl_logic_pins(ivl_net_logic_t net) { return net->npins_; } extern "C" ivl_nexus_t ivl_logic_pin(ivl_net_logic_t net, unsigned pin) { assert(pin < net->npins_); return net->pins_[pin]; } extern "C" ivl_udp_t ivl_logic_udp(ivl_net_logic_t net) { assert(net->type_ == IVL_LO_UDP); assert(net->udp); return net->udp; } extern "C" ivl_expr_t ivl_logic_delay(ivl_net_logic_t net, unsigned transition) { assert(transition < 3); return net->delay[transition]; } extern "C" unsigned ivl_logic_width(ivl_net_logic_t net) { assert(net); return net->width_; } extern "C" int ivl_udp_sequ(ivl_udp_t net) { return net->sequ; } extern "C" unsigned ivl_udp_nin(ivl_udp_t net) { return net->nin; } extern "C" unsigned ivl_udp_init(ivl_udp_t net) { return net->init; } extern "C" const char* ivl_udp_row(ivl_udp_t net, unsigned idx) { assert(idx < net->nrows); assert(net->table); assert(net->table[idx]); return net->table[idx]; } extern "C" unsigned ivl_udp_rows(ivl_udp_t net) { return net->nrows; } extern "C" const char* ivl_udp_name(ivl_udp_t net) { assert(net->name); return net->name; } extern "C" const char* ivl_lpm_basename(ivl_lpm_t net) { return net->name; } extern "C" ivl_nexus_t ivl_lpm_async_clr(ivl_lpm_t net) { assert(net); switch(net->type) { case IVL_LPM_FF: return net->u_.ff.aclr; default: assert(0); return 0; } } extern "C" ivl_nexus_t ivl_lpm_sync_clr(ivl_lpm_t net) { assert(net); switch(net->type) { case IVL_LPM_FF: return net->u_.ff.sclr; default: assert(0); return 0; } } extern "C" ivl_expr_t ivl_lpm_delay(ivl_lpm_t net, unsigned transition) { assert(transition < 3); return net->delay[transition]; } extern "C" ivl_nexus_t ivl_lpm_async_set(ivl_lpm_t net) { assert(net); switch(net->type) { case IVL_LPM_FF: return net->u_.ff.aset; default: assert(0); return 0; } } extern "C" ivl_nexus_t ivl_lpm_sync_set(ivl_lpm_t net) { assert(net); switch(net->type) { case IVL_LPM_FF: return net->u_.ff.sset; default: assert(0); return 0; } } extern "C" ivl_signal_t ivl_lpm_array(ivl_lpm_t net) { assert(net); switch (net->type) { case IVL_LPM_ARRAY: return net->u_.array.sig; default: assert(0); return 0; } } extern "C" unsigned ivl_lpm_base(ivl_lpm_t net) { assert(net); switch (net->type) { case IVL_LPM_PART_VP: case IVL_LPM_PART_PV: return net->u_.part.base; default: assert(0); return 0; } } extern "C" ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net) { assert(net); switch (net->type) { case IVL_LPM_FF: return net->u_.ff.clk; default: assert(0); return 0; } } extern "C" ivl_expr_t ivl_lpm_aset_value(ivl_lpm_t net) { assert(net); switch (net->type) { case IVL_LPM_FF: return net->u_.ff.aset_value; default: assert(0); return 0; } } extern "C" ivl_expr_t ivl_lpm_sset_value(ivl_lpm_t net) { assert(net); switch (net->type) { case IVL_LPM_FF: return net->u_.ff.sset_value; default: assert(0); return 0; } } extern "C" ivl_scope_t ivl_lpm_define(ivl_lpm_t net) { assert(net); switch (net->type) { case IVL_LPM_UFUNC: return net->u_.ufunc.def; default: assert(0); return 0; } } extern "C" ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net) { assert(net); switch (net->type) { case IVL_LPM_FF: return net->u_.ff.we; default: assert(0); return 0; } } /* The file name and line number are only set for system functions! */ extern "C" const char* ivl_lpm_file(ivl_lpm_t net) { return net->file.str(); } extern "C" unsigned ivl_lpm_lineno(ivl_lpm_t net) { return net->lineno; } extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) { assert(net); switch (net->type) { case IVL_LPM_ABS: case IVL_LPM_CAST_INT: case IVL_LPM_CAST_REAL: assert(idx == 0); return net->u_.arith.a; case IVL_LPM_ADD: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: case IVL_LPM_CMP_NEE: case IVL_LPM_DIVIDE: case IVL_LPM_MOD: case IVL_LPM_MULT: case IVL_LPM_POW: case IVL_LPM_SUB: assert(idx <= 1); if (idx == 0) return net->u_.arith.a; else return net->u_.arith.b; case IVL_LPM_MUX: assert(idx < net->u_.mux.size); return net->u_.mux.d[idx]; case IVL_LPM_RE_AND: case IVL_LPM_RE_OR: case IVL_LPM_RE_XOR: case IVL_LPM_RE_NAND: case IVL_LPM_RE_NOR: case IVL_LPM_RE_XNOR: case IVL_LPM_SIGN_EXT: assert(idx == 0); return net->u_.reduce.a; case IVL_LPM_SHIFTL: case IVL_LPM_SHIFTR: assert(idx <= 1); if (idx == 0) return net->u_.shift.d; else return net->u_.shift.s; case IVL_LPM_FF: assert(idx == 0); return net->u_.ff.d.pin; case IVL_LPM_CONCAT: assert(idx < net->u_.concat.inputs); return net->u_.concat.pins[idx+1]; case IVL_LPM_PART_VP: case IVL_LPM_PART_PV: assert(idx <= 1); if (idx == 0) return net->u_.part.a; else return net->u_.part.s; case IVL_LPM_REPEAT: assert(idx == 0); return net->u_.repeat.a; case IVL_LPM_SFUNC: // Skip the return port. assert(idx < (net->u_.sfunc.ports-1)); return net->u_.sfunc.pins[idx+1]; case IVL_LPM_UFUNC: // Skip the return port. assert(idx < (net->u_.ufunc.ports-1)); return net->u_.ufunc.pins[idx+1]; default: assert(0); return 0; } } extern "C" ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx) { cerr << "ANACHRONISM: Call to anachronistic ivl_lpm_datab." << endl; assert(net); switch (net->type) { case IVL_LPM_ADD: case IVL_LPM_CMP_EQ: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: case IVL_LPM_DIVIDE: case IVL_LPM_MOD: case IVL_LPM_MULT: case IVL_LPM_POW: case IVL_LPM_SUB: assert(idx == 0); return net->u_.arith.b; default: assert(0); return 0; } } /* * This function returns the hierarchical name for the LPM device. The * name needs to be built up from the scope name and the lpm base * name. * * Anachronism: This function is provided for * compatibility. Eventually, it will be removed. */ extern "C" const char* ivl_lpm_name(ivl_lpm_t net) { static char*name_buffer = 0; static unsigned name_size = 0; ivl_scope_t scope = ivl_lpm_scope(net); const char*sn = ivl_scope_name(scope); unsigned need = strlen(sn) + 1 + strlen(net->name) + 1; if (need > name_size) { name_buffer = (char*)realloc(name_buffer, need); name_size = need; } strcpy(name_buffer, sn); char*tmp = name_buffer + strlen(sn); *tmp++ = '.'; strcpy(tmp, net->name); return name_buffer; } extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx) { assert(net); switch (net->type) { case IVL_LPM_ABS: case IVL_LPM_ADD: case IVL_LPM_CAST_INT: case IVL_LPM_CAST_REAL: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: case IVL_LPM_CMP_EQ: case IVL_LPM_CMP_NE: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_NEE: case IVL_LPM_DIVIDE: case IVL_LPM_MOD: case IVL_LPM_MULT: case IVL_LPM_POW: case IVL_LPM_SUB: assert(idx == 0); return net->u_.arith.q; case IVL_LPM_FF: assert(idx == 0); return net->u_.ff.q.pin; case IVL_LPM_MUX: assert(idx == 0); return net->u_.mux.q; case IVL_LPM_RE_AND: case IVL_LPM_RE_OR: case IVL_LPM_RE_XOR: case IVL_LPM_RE_NAND: case IVL_LPM_RE_NOR: case IVL_LPM_RE_XNOR: case IVL_LPM_SIGN_EXT: assert(idx == 0); return net->u_.reduce.q; case IVL_LPM_SHIFTL: case IVL_LPM_SHIFTR: assert(idx == 0); return net->u_.shift.q; case IVL_LPM_SFUNC: assert(idx == 0); return net->u_.sfunc.pins[0]; case IVL_LPM_UFUNC: assert(idx == 0); return net->u_.ufunc.pins[0]; case IVL_LPM_CONCAT: return net->u_.concat.pins[0]; case IVL_LPM_PART_VP: case IVL_LPM_PART_PV: assert(idx == 0); return net->u_.part.q; case IVL_LPM_REPEAT: assert(idx == 0); return net->u_.repeat.q; case IVL_LPM_ARRAY: assert(idx == 0); return net->u_.array.q; default: assert(0); return 0; } } extern "C" ivl_scope_t ivl_lpm_scope(ivl_lpm_t net) { assert(net); return net->scope; } extern "C" ivl_nexus_t ivl_lpm_select(ivl_lpm_t net) { switch (net->type) { case IVL_LPM_MUX: return net->u_.mux.s; case IVL_LPM_ARRAY: return net->u_.array.a; default: assert(0); return 0; } } extern "C" unsigned ivl_lpm_selects(ivl_lpm_t net) { switch (net->type) { case IVL_LPM_MUX: return net->u_.mux.swid; case IVL_LPM_ARRAY: return net->u_.array.swid; case IVL_LPM_CONCAT: return net->u_.concat.inputs; default: assert(0); return 0; } } extern "C" int ivl_lpm_signed(ivl_lpm_t net) { assert(net); switch (net->type) { case IVL_LPM_FF: case IVL_LPM_MUX: return 0; case IVL_LPM_ABS: case IVL_LPM_ADD: case IVL_LPM_CAST_REAL: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: case IVL_LPM_CMP_NE: case IVL_LPM_CMP_NEE: case IVL_LPM_DIVIDE: case IVL_LPM_MOD: case IVL_LPM_MULT: case IVL_LPM_POW: case IVL_LPM_SUB: return net->u_.arith.signed_flag; case IVL_LPM_RE_AND: case IVL_LPM_RE_OR: case IVL_LPM_RE_XOR: case IVL_LPM_RE_NAND: case IVL_LPM_RE_NOR: case IVL_LPM_RE_XNOR: return 0; case IVL_LPM_SHIFTL: case IVL_LPM_SHIFTR: return net->u_.shift.signed_flag; case IVL_LPM_CAST_INT: case IVL_LPM_SIGN_EXT: // Sign extend is always signed. return 1; case IVL_LPM_SFUNC: return 0; case IVL_LPM_UFUNC: return 0; case IVL_LPM_CONCAT: // Concatenations are always unsigned return 0; case IVL_LPM_PART_VP: case IVL_LPM_PART_PV: return net->u_.part.signed_flag; case IVL_LPM_REPEAT: return 0; case IVL_LPM_ARRAY: // Array ports take the signedness of the array. return net->u_.array.sig->signed_; default: assert(0); return 0; } } extern "C" unsigned ivl_lpm_size(ivl_lpm_t net) { switch (net->type) { case IVL_LPM_MUX: return net->u_.mux.size; case IVL_LPM_SFUNC: return net->u_.sfunc.ports - 1; case IVL_LPM_UFUNC: return net->u_.ufunc.ports - 1; case IVL_LPM_REPEAT: return net->u_.repeat.count; case IVL_LPM_CONCAT: return net->u_.concat.inputs; default: assert(0); return 0; } } extern "C" const char* ivl_lpm_string(ivl_lpm_t net) { assert(net->type == IVL_LPM_SFUNC); return net->u_.sfunc.fun_name; } extern "C" ivl_lpm_type_t ivl_lpm_type(ivl_lpm_t net) { return net->type; } extern "C" unsigned ivl_lpm_width(ivl_lpm_t net) { assert(net); return net->width; } extern "C" ivl_event_t ivl_lpm_trigger(ivl_lpm_t net) { assert(net); switch (net->type) { case IVL_LPM_SFUNC: return net->u_.sfunc.trigger; case IVL_LPM_UFUNC: return net->u_.ufunc.trigger; default: assert(0); return 0; } } extern "C" ivl_expr_t ivl_lval_mux(ivl_lval_t net) { assert(net); if (net->type_ == IVL_LVAL_MUX) return net->idx; return 0x0; } extern "C" ivl_expr_t ivl_lval_idx(ivl_lval_t net) { assert(net); if (net->type_ == IVL_LVAL_ARR) return net->idx; return 0x0; } extern "C" ivl_expr_t ivl_lval_part_off(ivl_lval_t net) { assert(net); return net->loff; } extern "C" unsigned ivl_lval_width(ivl_lval_t net) { assert(net); return net->width_; } extern "C" ivl_signal_t ivl_lval_sig(ivl_lval_t net) { assert(net); switch (net->type_) { case IVL_LVAL_REG: case IVL_LVAL_NET: case IVL_LVAL_MUX: case IVL_LVAL_ARR: return net->n.sig; default: return 0; } } extern "C" const char* ivl_nature_name(ivl_nature_t net) { return net->name(); } /* * The nexus name is rarely needed. (Shouldn't be needed at all!) This * function will calculate the name if it is not already calculated. */ extern "C" const char* ivl_nexus_name(ivl_nexus_t net) { assert(net); if (net->name_ == 0) { char tmp[2 * sizeof(net) + 5]; snprintf(tmp, sizeof tmp, "n%p", net); net->name_ = api_strings.add(tmp); } return net->name_; } extern "C" void* ivl_nexus_get_private(ivl_nexus_t net) { assert(net); return net->private_data; } extern "C" void ivl_nexus_set_private(ivl_nexus_t net, void*data) { assert(net); net->private_data = data; } extern "C" unsigned ivl_nexus_ptrs(ivl_nexus_t net) { assert(net); return net->ptrs_.size(); } extern "C" ivl_nexus_ptr_t ivl_nexus_ptr(ivl_nexus_t net, unsigned idx) { assert(net); assert(idx < net->ptrs_.size()); return & net->ptrs_[idx]; } extern "C" ivl_drive_t ivl_nexus_ptr_drive0(ivl_nexus_ptr_t net) { assert(net); return (ivl_drive_t)(net->drive0); } extern "C" ivl_drive_t ivl_nexus_ptr_drive1(ivl_nexus_ptr_t net) { assert(net); return (ivl_drive_t)(net->drive1); } extern "C" unsigned ivl_nexus_ptr_pin(ivl_nexus_ptr_t net) { assert(net); return net->pin_; } extern "C" ivl_branch_t ivl_nexus_ptr_branch(ivl_nexus_ptr_t net) { if (net == 0) return 0; if (net->type_ != __NEXUS_PTR_BRA) return 0; return net->l.bra; } extern "C" ivl_net_const_t ivl_nexus_ptr_con(ivl_nexus_ptr_t net) { if (net == 0) return 0; if (net->type_ != __NEXUS_PTR_CON) return 0; return net->l.con; } extern "C" ivl_net_logic_t ivl_nexus_ptr_log(ivl_nexus_ptr_t net) { if (net == 0) return 0; if (net->type_ != __NEXUS_PTR_LOG) return 0; return net->l.log; } extern "C" ivl_lpm_t ivl_nexus_ptr_lpm(ivl_nexus_ptr_t net) { if (net == 0) return 0; if (net->type_ != __NEXUS_PTR_LPM) return 0; return net->l.lpm; } extern "C" ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net) { if (net == 0) return 0; if (net->type_ != __NEXUS_PTR_SIG) return 0; return net->l.sig; } extern "C" ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net) { if (net == 0) return 0; if (net->type_ != __NEXUS_PTR_SWI) return 0; return net->l.swi; } extern "C" const char* ivl_parameter_basename(ivl_parameter_t net) { assert(net); return net->basename; } extern "C" ivl_expr_t ivl_parameter_expr(ivl_parameter_t net) { assert(net); return net->value; } extern "C" const char* ivl_parameter_file(ivl_parameter_t net) { assert(net); return net->file.str(); } extern "C" unsigned ivl_parameter_lineno(ivl_parameter_t net) { assert(net); return net->lineno; } extern "C" ivl_scope_t ivl_parameter_scope(ivl_parameter_t net) { assert(net); return net->scope; } extern "C" ivl_nexus_t ivl_path_condit(ivl_delaypath_t obj) { assert(obj); return obj->condit; } extern "C" int ivl_path_is_condit(ivl_delaypath_t obj) { assert(obj); return obj->conditional ? 1 : 0; } extern uint64_t ivl_path_delay(ivl_delaypath_t obj, ivl_path_edge_t edg) { assert(obj); return obj->delay[edg]; } extern ivl_scope_t ivl_path_scope(ivl_delaypath_t obj) { assert(obj); assert(obj->scope); return obj->scope; } extern ivl_nexus_t ivl_path_source(ivl_delaypath_t net) { return net->src; } extern int ivl_path_source_posedge(ivl_delaypath_t net) { return net->posedge ? 1 : 0; } extern int ivl_path_source_negedge(ivl_delaypath_t net) { return net->negedge ? 1 : 0; } extern "C" const char*ivl_process_file(ivl_process_t net) { assert(net); return net->file.str(); } extern "C" unsigned ivl_process_lineno(ivl_process_t net) { assert(net); return net->lineno; } extern "C" ivl_process_type_t ivl_process_type(ivl_process_t net) { return net->type_; } extern "C" int ivl_process_analog(ivl_process_t net) { return net->analog_flag != 0; } extern "C" ivl_scope_t ivl_process_scope(ivl_process_t net) { return net->scope_; } extern "C" ivl_statement_t ivl_process_stmt(ivl_process_t net) { return net->stmt_; } extern "C" unsigned ivl_process_attr_cnt(ivl_process_t net) { return net->nattr; } extern "C" ivl_attribute_t ivl_process_attr_val(ivl_process_t net, unsigned idx) { assert(idx < net->nattr); return net->attr + idx; } extern "C" unsigned ivl_scope_attr_cnt(ivl_scope_t net) { assert(net); return net->nattr; } extern "C" ivl_attribute_t ivl_scope_attr_val(ivl_scope_t net, unsigned idx) { assert(idx < net->nattr); return net->attr + idx; } extern "C" const char* ivl_scope_basename(ivl_scope_t net) { assert(net); return net->name_; } extern "C" int ivl_scope_children(ivl_scope_t net, ivl_scope_f func, void*cd) { for (ivl_scope_t cur = net->child_; cur; cur = cur->sibling_) { int rc = func(cur, cd); if (rc != 0) return rc; } return 0; } extern "C" ivl_statement_t ivl_scope_def(ivl_scope_t net) { assert(net); return net->def; } extern "C" const char*ivl_scope_def_file(ivl_scope_t net) { assert(net); return net->def_file.str(); } extern "C" unsigned ivl_scope_def_lineno(ivl_scope_t net) { assert(net); return net->def_lineno; } extern "C" unsigned ivl_scope_events(ivl_scope_t net) { assert(net); return net->nevent_; } extern "C" ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx) { assert(net); assert(idx < net->nevent_); return net->event_[idx]; } extern "C" const char*ivl_scope_file(ivl_scope_t net) { assert(net); return net->file.str(); } extern "C" unsigned ivl_scope_is_auto(ivl_scope_t net) { assert(net); return net->is_auto; } extern "C" unsigned ivl_scope_is_cell(ivl_scope_t net) { assert(net); return net->is_cell; } extern "C" unsigned ivl_scope_lineno(ivl_scope_t net) { assert(net); return net->lineno; } extern "C" unsigned ivl_scope_logs(ivl_scope_t net) { assert(net); return net->nlog_; } extern "C" ivl_net_logic_t ivl_scope_log(ivl_scope_t net, unsigned idx) { assert(net); assert(idx < net->nlog_); return net->log_[idx]; } extern "C" unsigned ivl_scope_lpms(ivl_scope_t net) { assert(net); return net->nlpm_; } extern "C" ivl_lpm_t ivl_scope_lpm(ivl_scope_t net, unsigned idx) { assert(net); assert(idx < net->nlpm_); return net->lpm_[idx]; } static unsigned scope_name_len(ivl_scope_t net) { unsigned len = 0; for (ivl_scope_t cur = net ; cur ; cur = cur->parent) len += strlen(cur->name_) + 1; return len; } static void push_scope_basename(ivl_scope_t net, char*buf) { if (net->parent == 0) { strcpy(buf, net->name_); return; } push_scope_basename(net->parent, buf); strcat(buf, "."); strcat(buf, net->name_); } extern "C" const char* ivl_scope_name(ivl_scope_t net) { static char*name_buffer = 0; static unsigned name_size = 0; if (net->parent == 0) return net->name_; unsigned needlen = scope_name_len(net); if (name_size < needlen) { name_buffer = (char*)realloc(name_buffer, needlen); name_size = needlen; } push_scope_basename(net, name_buffer); return name_buffer; } extern "C" unsigned ivl_scope_params(ivl_scope_t net) { assert(net); return net->nparam_; } extern "C" ivl_parameter_t ivl_scope_param(ivl_scope_t net, unsigned idx) { assert(net); assert(idx < net->nparam_); return net->param_ + idx; } extern "C" ivl_scope_t ivl_scope_parent(ivl_scope_t net) { assert(net); return net->parent; } extern "C" unsigned ivl_scope_ports(ivl_scope_t net) { assert(net); assert(net->type_ == IVL_SCT_FUNCTION); return net->ports; } extern "C" ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx) { assert(net); assert(net->type_ == IVL_SCT_FUNCTION); assert(idx < net->ports); return net->port[idx]; } extern "C" unsigned ivl_scope_sigs(ivl_scope_t net) { assert(net); return net->nsigs_; } extern "C" ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx) { assert(net); assert(idx < net->nsigs_); return net->sigs_[idx]; } extern "C" unsigned ivl_scope_switches(ivl_scope_t net) { assert(net); return net->switches.size(); } extern "C" ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx) { assert(net); assert(idx < net->switches.size()); return net->switches[idx]; } extern "C" int ivl_scope_time_precision(ivl_scope_t net) { assert(net); return net->time_precision; } extern "C" int ivl_scope_time_units(ivl_scope_t net) { assert(net); return net->time_units; } extern "C" ivl_scope_type_t ivl_scope_type(ivl_scope_t net) { assert(net); return net->type_; } extern "C" const char* ivl_scope_tname(ivl_scope_t net) { assert(net); return net->tname_; } extern "C" int ivl_signal_array_base(ivl_signal_t net) { return net->array_base; } extern "C" unsigned ivl_signal_array_count(ivl_signal_t net) { return net->array_words; } extern "C" unsigned ivl_signal_array_addr_swapped(ivl_signal_t net) { return net->array_addr_swapped; } extern "C" unsigned ivl_signal_dimensions(ivl_signal_t net) { return net->array_dimensions_; } extern "C" ivl_discipline_t ivl_signal_discipline(ivl_signal_t net) { return net->discipline; } extern "C" const char* ivl_signal_attr(ivl_signal_t net, const char*key) { if (net->nattr == 0) return 0; for (unsigned idx = 0 ; idx < net->nattr ; idx += 1) if (strcmp(key, net->attr[idx].key) == 0) return net->attr[idx].type == IVL_ATT_STR ? net->attr[idx].val.str : 0; return 0; } extern "C" unsigned ivl_signal_attr_cnt(ivl_signal_t net) { return net->nattr; } extern "C" ivl_attribute_t ivl_signal_attr_val(ivl_signal_t net, unsigned idx) { assert(idx < net->nattr); return net->attr + idx; } extern "C" const char* ivl_signal_basename(ivl_signal_t net) { return net->name_; } extern "C" const char* ivl_signal_name(ivl_signal_t net) { static char*name_buffer = 0; static unsigned name_size = 0; unsigned needlen = scope_name_len(net->scope_); needlen += strlen(net->name_) + 2; if (name_size < needlen) { name_buffer = (char*)realloc(name_buffer, needlen); name_size = needlen; } push_scope_basename(net->scope_, name_buffer); strcat(name_buffer, "."); strcat(name_buffer, net->name_); return name_buffer; } extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word) { assert(word < net->array_words); if (net->array_words > 1) { if (net->pins) { return net->pins[word]; } else { // net->pins can be NULL for a virtualized reg array. assert(net->type_ == IVL_SIT_REG); return NULL; } } else { return net->pin; } } extern "C" int ivl_signal_msb(ivl_signal_t net) { assert(net->lsb_dist == 1 || net->lsb_dist == -1); return net->lsb_index + net->lsb_dist * (net->width_ - 1); } extern "C" int ivl_signal_lsb(ivl_signal_t net) { return net->lsb_index; } extern "C" unsigned ivl_signal_width(ivl_signal_t net) { return net->width_; } extern "C" ivl_signal_port_t ivl_signal_port(ivl_signal_t net) { return net->port_; } extern "C" int ivl_signal_local(ivl_signal_t net) { return net->local_; } extern "C" int ivl_signal_signed(ivl_signal_t net) { return net->signed_; } extern "C" const char* ivl_signal_file(ivl_signal_t net) { assert(net); return net->file.str(); } extern "C" unsigned ivl_signal_lineno(ivl_signal_t net) { assert(net); return net->lineno; } extern "C" int ivl_signal_integer(ivl_signal_t net) { return net->isint_; } extern "C" ivl_variable_type_t ivl_signal_data_type(ivl_signal_t net) { return net->data_type; } extern "C" unsigned ivl_signal_npath(ivl_signal_t net) { return net->npath; } extern "C" ivl_delaypath_t ivl_signal_path(ivl_signal_t net, unsigned idx) { assert(idx < net->npath); return net->path + idx; } extern "C" ivl_signal_type_t ivl_signal_type(ivl_signal_t net) { return net->type_; } extern "C" ivl_statement_type_t ivl_statement_type(ivl_statement_t net) { return net->type_; } extern "C" const char* ivl_stmt_file(ivl_statement_t net) { return net->file.str(); } extern "C" unsigned ivl_stmt_lineno(ivl_statement_t net) { return net->lineno; } extern "C" ivl_scope_t ivl_stmt_block_scope(ivl_statement_t net) { switch (net->type_) { case IVL_ST_BLOCK: case IVL_ST_FORK: return net->u_.block_.scope; default: assert(0); return 0; } } extern "C" unsigned ivl_stmt_block_count(ivl_statement_t net) { switch (net->type_) { case IVL_ST_BLOCK: case IVL_ST_FORK: return net->u_.block_.nstmt_; default: assert(0); return 0; } } extern "C" ivl_statement_t ivl_stmt_block_stmt(ivl_statement_t net, unsigned i) { switch (net->type_) { case IVL_ST_BLOCK: case IVL_ST_FORK: return net->u_.block_.stmt_ + i; default: assert(0); return 0; } } extern "C" ivl_scope_t ivl_stmt_call(ivl_statement_t net) { switch (net->type_) { case IVL_ST_ALLOC: return net->u_.alloc_.scope; case IVL_ST_DISABLE: return net->u_.disable_.scope; case IVL_ST_FREE: return net->u_.free_.scope; case IVL_ST_UTASK: return net->u_.utask_.def; default: assert(0); return 0; } } extern "C" unsigned ivl_stmt_case_count(ivl_statement_t net) { switch (net->type_) { case IVL_ST_CASE: case IVL_ST_CASER: case IVL_ST_CASEX: case IVL_ST_CASEZ: return net->u_.case_.ncase; default: assert(0); return 0; } } extern "C" ivl_expr_t ivl_stmt_case_expr(ivl_statement_t net, unsigned idx) { switch (net->type_) { case IVL_ST_CASE: case IVL_ST_CASER: case IVL_ST_CASEX: case IVL_ST_CASEZ: assert(idx < net->u_.case_.ncase); return net->u_.case_.case_ex[idx]; default: assert(0); return 0; } } extern "C" ivl_statement_t ivl_stmt_case_stmt(ivl_statement_t net, unsigned idx) { switch (net->type_) { case IVL_ST_CASE: case IVL_ST_CASER: case IVL_ST_CASEX: case IVL_ST_CASEZ: assert(idx < net->u_.case_.ncase); return net->u_.case_.case_st + idx; default: assert(0); return 0; } } extern "C" ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net) { switch (net->type_) { case IVL_ST_ASSIGN_NB: return net->u_.assign_.count; case IVL_ST_CONDIT: return net->u_.condit_.cond_; case IVL_ST_CASE: case IVL_ST_CASER: case IVL_ST_CASEX: case IVL_ST_CASEZ: return net->u_.case_.cond; case IVL_ST_REPEAT: case IVL_ST_WHILE: return net->u_.while_.cond_; default: assert(0); return 0; } } extern "C" ivl_statement_t ivl_stmt_cond_false(ivl_statement_t net) { assert(net->type_ == IVL_ST_CONDIT); if (net->u_.condit_.stmt_[1].type_ == IVL_ST_NONE) return 0; else return net->u_.condit_.stmt_ + 1; } extern "C" ivl_statement_t ivl_stmt_cond_true(ivl_statement_t net) { assert(net->type_ == IVL_ST_CONDIT); if (net->u_.condit_.stmt_[0].type_ == IVL_ST_NONE) return 0; else return net->u_.condit_.stmt_ + 0; } extern "C" ivl_expr_t ivl_stmt_delay_expr(ivl_statement_t net) { switch (net->type_) { case IVL_ST_ASSIGN: case IVL_ST_ASSIGN_NB: return net->u_.assign_.delay; case IVL_ST_DELAYX: return net->u_.delayx_.expr; default: assert(0); return 0; } } extern "C" uint64_t ivl_stmt_delay_val(ivl_statement_t net) { assert(net->type_ == IVL_ST_DELAY); return net->u_.delay_.value; } extern "C" unsigned ivl_stmt_nevent(ivl_statement_t net) { switch (net->type_) { case IVL_ST_ASSIGN_NB: return net->u_.assign_.nevent; case IVL_ST_WAIT: return net->u_.wait_.nevent; case IVL_ST_TRIGGER: return 1; default: assert(0); } return 0; } extern "C" ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx) { switch (net->type_) { case IVL_ST_ASSIGN_NB: assert(idx < net->u_.assign_.nevent); if (net->u_.assign_.nevent == 1) return net->u_.assign_.event; else return net->u_.assign_.events[idx]; case IVL_ST_WAIT: assert(idx < net->u_.wait_.nevent); if (net->u_.wait_.nevent == 1) return net->u_.wait_.event; else return net->u_.wait_.events[idx]; case IVL_ST_TRIGGER: assert(idx == 0); return net->u_.wait_.event; default: assert(0); } return 0; } extern "C" ivl_expr_t ivl_stmt_lexp(ivl_statement_t net) { switch (net->type_) { case IVL_ST_CONTRIB: return net->u_.contrib_.lval; default: assert(0); } return 0; } extern "C" ivl_lval_t ivl_stmt_lval(ivl_statement_t net, unsigned idx) { switch (net->type_) { case IVL_ST_ASSIGN: case IVL_ST_ASSIGN_NB: case IVL_ST_CASSIGN: case IVL_ST_DEASSIGN: case IVL_ST_FORCE: case IVL_ST_RELEASE: assert(idx < net->u_.assign_.lvals_); return net->u_.assign_.lval_ + idx; default: assert(0); } return 0; } extern "C" unsigned ivl_stmt_lvals(ivl_statement_t net) { switch (net->type_) { case IVL_ST_ASSIGN: case IVL_ST_ASSIGN_NB: case IVL_ST_CASSIGN: case IVL_ST_DEASSIGN: case IVL_ST_FORCE: case IVL_ST_RELEASE: return net->u_.assign_.lvals_; default: assert(0); } return 0; } extern "C" unsigned ivl_stmt_lwidth(ivl_statement_t net) { assert((net->type_ == IVL_ST_ASSIGN) || (net->type_ == IVL_ST_ASSIGN_NB) || (net->type_ == IVL_ST_CASSIGN) || (net->type_ == IVL_ST_DEASSIGN) || (net->type_ == IVL_ST_FORCE) || (net->type_ == IVL_ST_RELEASE)); unsigned sum = 0; unsigned nlvals; struct ivl_lval_s*lvals; nlvals = net->u_.assign_.lvals_; lvals = net->u_.assign_.lval_; for (unsigned idx = 0 ; idx < nlvals ; idx += 1) { ivl_lval_t cur = lvals + idx; switch(cur->type_) { case IVL_LVAL_MUX: sum += 1; break; case IVL_LVAL_REG: case IVL_LVAL_ARR: sum += ivl_lval_width(cur); break; default: assert(0); } } return sum; } extern "C" const char* ivl_stmt_name(ivl_statement_t net) { switch (net->type_) { case IVL_ST_STASK: return net->u_.stask_.name_; default: assert(0); } return 0; } extern "C" ivl_expr_t ivl_stmt_parm(ivl_statement_t net, unsigned idx) { switch (net->type_) { case IVL_ST_STASK: assert(idx < net->u_.stask_.nparm_); return net->u_.stask_.parms_[idx]; default: assert(0); } return 0; } extern "C" unsigned ivl_stmt_parm_count(ivl_statement_t net) { switch (net->type_) { case IVL_ST_STASK: return net->u_.stask_.nparm_; default: assert(0); } return 0; } extern "C" ivl_expr_t ivl_stmt_rval(ivl_statement_t net) { switch (net->type_) { case IVL_ST_ASSIGN: case IVL_ST_ASSIGN_NB: case IVL_ST_CASSIGN: case IVL_ST_FORCE: return net->u_.assign_.rval_; case IVL_ST_CONTRIB: return net->u_.contrib_.rval; default: assert(0); } return 0; } extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net) { switch (net->type_) { case IVL_ST_DELAY: return net->u_.delay_.stmt_; case IVL_ST_DELAYX: return net->u_.delayx_.stmt_; case IVL_ST_FOREVER: return net->u_.forever_.stmt_; case IVL_ST_WAIT: return net->u_.wait_.stmt_; case IVL_ST_REPEAT: case IVL_ST_WHILE: return net->u_.while_.stmt_; default: assert(0); } return 0; } extern "C" const char*ivl_switch_basename(ivl_switch_t net) { return net->name; } extern "C" ivl_scope_t ivl_switch_scope(ivl_switch_t net) { return net->scope; } extern "C" ivl_switch_type_t ivl_switch_type(ivl_switch_t net) { return net->type; } extern "C" ivl_nexus_t ivl_switch_a(ivl_switch_t net) { return net->pins[0]; } extern "C" ivl_nexus_t ivl_switch_b(ivl_switch_t net) { return net->pins[1]; } extern "C" ivl_nexus_t ivl_switch_enable(ivl_switch_t net) { return net->pins[2]; } extern "C" unsigned ivl_switch_width(ivl_switch_t net) { return net->width; } extern "C" unsigned ivl_switch_part(ivl_switch_t net) { return net->part; } extern "C" unsigned ivl_switch_offset(ivl_switch_t net) { return net->offset; } extern "C" const char* ivl_switch_file(ivl_switch_t net) { return net->file; } extern "C" ivl_island_t ivl_switch_island(ivl_switch_t net) { return net->island; } extern "C" unsigned ivl_switch_lineno(ivl_switch_t net) { return net->lineno; } verilog-0.9.7/PaxHeaders.14238/emit.cc0000644000202500001440000000005012204466647015475 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/emit.cc0000644000202500001440000002705012204466647015023 0ustar00steveusers00000000000000/* * Copyright (c) 1998-2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include /* * The emit function is called to generate the output required of the * target. */ # include "target.h" # include "netlist.h" # include # include # include bool NetNode::emit_node(struct target_t*tgt) const { cerr << "EMIT: Gate type? " << typeid(*this).name() << endl; return false; } bool NetLogic::emit_node(struct target_t*tgt) const { tgt->logic(this); return true; } bool NetUDP::emit_node(struct target_t*tgt) const { tgt->udp(this); return true; } bool NetAbs::emit_node(struct target_t*tgt) const { tgt->lpm_abs(this); return true; } bool NetAddSub::emit_node(struct target_t*tgt) const { tgt->lpm_add_sub(this); return true; } bool NetArrayDq::emit_node(struct target_t*tgt) const { return tgt->lpm_array_dq(this); } bool NetCaseCmp::emit_node(struct target_t*tgt) const { tgt->net_case_cmp(this); return true; } bool NetCastInt::emit_node(struct target_t*tgt) const { return tgt->lpm_cast_int(this); } bool NetCastReal::emit_node(struct target_t*tgt) const { return tgt->lpm_cast_real(this); } bool NetCLShift::emit_node(struct target_t*tgt) const { tgt->lpm_clshift(this); return true; } bool NetCompare::emit_node(struct target_t*tgt) const { tgt->lpm_compare(this); return true; } bool NetConcat::emit_node(struct target_t*tgt) const { return tgt->concat(this); } bool NetConst::emit_node(struct target_t*tgt) const { return tgt->net_const(this); } bool NetDivide::emit_node(struct target_t*tgt) const { tgt->lpm_divide(this); return true; } bool NetFF::emit_node(struct target_t*tgt) const { tgt->lpm_ff(this); return true; } bool NetLiteral::emit_node(struct target_t*tgt) const { return tgt->net_literal(this); } bool NetModulo::emit_node(struct target_t*tgt) const { tgt->lpm_modulo(this); return true; } bool NetMult::emit_node(struct target_t*tgt) const { tgt->lpm_mult(this); return true; } bool NetMux::emit_node(struct target_t*tgt) const { tgt->lpm_mux(this); return true; } bool NetPartSelect::emit_node(struct target_t*tgt) const { return tgt->part_select(this); } bool NetPow::emit_node(struct target_t*tgt) const { tgt->lpm_pow(this); return true; } bool NetReplicate::emit_node(struct target_t*tgt) const { return tgt->replicate(this); } bool NetSignExtend::emit_node(struct target_t*tgt) const { return tgt->sign_extend(this); } bool NetUReduce::emit_node(struct target_t*tgt) const { return tgt->ureduce(this); } bool NetSysFunc::emit_node(struct target_t*tgt) const { return tgt->net_sysfunction(this); } bool NetUserFunc::emit_node(struct target_t*tgt) const { return tgt->net_function(this); } bool NetTran::emit_node(struct target_t*tgt) const { return tgt->tran(this); } bool NetBUFZ::emit_node(struct target_t*tgt) const { return tgt->bufz(this); } bool NetProcTop::emit(struct target_t*tgt) const { return tgt->process(this); } bool NetAnalogTop::emit(struct target_t*tgt) const { return tgt->process(this); } bool NetProc::emit_proc(struct target_t*tgt) const { cerr << "EMIT: Proc type? " << typeid(*this).name() << endl; return false; } bool NetAlloc::emit_proc(struct target_t*tgt) const { tgt->proc_alloc(this); return true; } bool NetAssign::emit_proc(struct target_t*tgt) const { return tgt->proc_assign(this); } bool NetAssignNB::emit_proc(struct target_t*tgt) const { tgt->proc_assign_nb(this); return true; } bool NetBlock::emit_proc(struct target_t*tgt) const { return tgt->proc_block(this); } bool NetCase::emit_proc(struct target_t*tgt) const { tgt->proc_case(this); return true; } bool NetCAssign::emit_proc(struct target_t*tgt) const { return tgt->proc_cassign(this); } bool NetCondit::emit_proc(struct target_t*tgt) const { return tgt->proc_condit(this); } bool NetContribution::emit_proc(struct target_t*tgt) const { return tgt->proc_contribution(this); } bool NetDeassign::emit_proc(struct target_t*tgt) const { return tgt->proc_deassign(this); } bool NetDisable::emit_proc(struct target_t*tgt) const { return tgt->proc_disable(this); } bool NetForce::emit_proc(struct target_t*tgt) const { return tgt->proc_force(this); } bool NetForever::emit_proc(struct target_t*tgt) const { tgt->proc_forever(this); return true; } bool NetFree::emit_proc(struct target_t*tgt) const { tgt->proc_free(this); return true; } bool NetPDelay::emit_proc(struct target_t*tgt) const { return tgt->proc_delay(this); } bool NetPDelay::emit_proc_recurse(struct target_t*tgt) const { if (statement_) return statement_->emit_proc(tgt); return true; } bool NetRelease::emit_proc(struct target_t*tgt) const { return tgt->proc_release(this); } bool NetRepeat::emit_proc(struct target_t*tgt) const { tgt->proc_repeat(this); return true; } bool NetSTask::emit_proc(struct target_t*tgt) const { tgt->proc_stask(this); return true; } bool NetUTask::emit_proc(struct target_t*tgt) const { tgt->proc_utask(this); return true; } bool NetWhile::emit_proc(struct target_t*tgt) const { tgt->proc_while(this); return true; } void NetBlock::emit_recurse(struct target_t*tgt) const { if (last_ == 0) return; NetProc*cur = last_; do { cur = cur->next_; cur->emit_proc(tgt); } while (cur != last_); } bool NetCondit::emit_recurse_if(struct target_t*tgt) const { if (if_) return if_->emit_proc(tgt); else return true; } bool NetCondit::emit_recurse_else(struct target_t*tgt) const { if (else_) return else_->emit_proc(tgt); else return true; } bool NetEvProbe::emit_node(struct target_t*tgt) const { tgt->net_probe(this); return true; } bool NetEvTrig::emit_proc(struct target_t*tgt) const { return tgt->proc_trigger(this); } bool NetEvWait::emit_proc(struct target_t*tgt) const { return tgt->proc_wait(this); } bool NetEvWait::emit_recurse(struct target_t*tgt) const { if (!statement_) return true; return statement_->emit_proc(tgt); } void NetForever::emit_recurse(struct target_t*tgt) const { if (statement_) statement_->emit_proc(tgt); } void NetRepeat::emit_recurse(struct target_t*tgt) const { if (statement_) statement_->emit_proc(tgt); } void NetScope::emit_scope(struct target_t*tgt) const { tgt->scope(this); for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) tgt->event(cur); for (NetScope*cur = sub_ ; cur ; cur = cur->sib_) cur->emit_scope(tgt); for (signals_map_iter_t cur = signals_map_.begin() ; cur != signals_map_.end() ; cur ++) { tgt->signal(cur->second); } // Run the signals again, but this time to connect the // delay paths. This is done as a second pass because // the paths reference other signals that may be later // in the list. We can do it here because delay paths are // always connected within the scope. for (signals_map_iter_t cur = signals_map_.begin() ; cur != signals_map_.end() ; cur ++) { tgt->signal_paths(cur->second); } } bool NetScope::emit_defs(struct target_t*tgt) const { bool flag = true; switch (type_) { case MODULE: for (NetScope*cur = sub_ ; cur ; cur = cur->sib_) flag &= cur->emit_defs(tgt); break; case FUNC: flag &= tgt->func_def(this); break; case TASK: tgt->task_def(this); break; default: /* BEGIN_END and FORK_JOIN, GENERATE... */ for (NetScope*cur = sub_ ; cur ; cur = cur->sib_) flag &= cur->emit_defs(tgt); break; } return flag; } void NetWhile::emit_proc_recurse(struct target_t*tgt) const { proc_->emit_proc(tgt); } int Design::emit(struct target_t*tgt) const { int rc = 0; if (tgt->start_design(this) == false) return -2; // enumerate the scopes for (list::const_iterator scope = root_scopes_.begin(); scope != root_scopes_.end(); scope++) (*scope)->emit_scope(tgt); // emit nodes bool nodes_rc = true; if (nodes_) { NetNode*cur = nodes_->node_next_; do { nodes_rc = nodes_rc && cur->emit_node(tgt); cur = cur->node_next_; } while (cur != nodes_->node_next_); } bool branches_rc = true; for (NetBranch*cur = branches_ ; cur ; cur = cur->next_) { branches_rc = tgt->branch(cur) && branches_rc; } // emit task and function definitions bool tasks_rc = true; for (list::const_iterator scope = root_scopes_.begin(); scope != root_scopes_.end(); scope++) tasks_rc &= (*scope)->emit_defs(tgt); // emit the processes bool proc_rc = true; for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_) proc_rc &= idx->emit(tgt); for (const NetAnalogTop*idx = aprocs_ ; idx ; idx = idx->next_) proc_rc &= idx->emit(tgt); rc = tgt->end_design(this); if (nodes_rc == false) return -1; if (tasks_rc == false) return -2; if (proc_rc == false) return -3; if (branches_rc == false) return -4; return rc; } void NetEAccess::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_access_func(this); } void NetEBinary::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_binary(this); } void NetEConcat::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_concat(this); } void NetEConst::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_const(this); } void NetEConstParam::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_param(this); } void NetECReal::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_creal(this); } void NetECRealParam::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_rparam(this); } void NetEParam::expr_scan(struct expr_scan_t*tgt) const { cerr << get_fileline() << ":internal error: unexpected NetEParam." << endl; } void NetEEvent::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_event(this); } void NetEScope::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_scope(this); } void NetESelect::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_select(this); } void NetESFunc::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_sfunc(this); } void NetEUFunc::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_ufunc(this); } void NetESignal::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_signal(this); } void NetETernary::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_ternary(this); } void NetEUnary::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_unary(this); } verilog-0.9.7/PaxHeaders.14238/pform.h0000644000202500001440000000005012204466647015524 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/pform.h0000644000202500001440000003323312204466647015052 0ustar00steveusers00000000000000#ifndef __pform_H #define __pform_H /* * Copyright (c) 1998-2011 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "netlist.h" # include "HName.h" # include "named.h" # include "Module.h" # include "Statement.h" # include "AStatement.h" # include "PGate.h" # include "PExpr.h" # include "PTask.h" # include "PUdp.h" # include "PWire.h" # include "verinum.h" # include "discipline.h" # include # include # include # include /* * These classes implement the parsed form (P-form for short) of the * original Verilog source. the parser generates the pform for the * convenience of later processing steps. */ /* * Wire objects represent the named wires (of various flavor) declared * in the source. * * Gate objects are the functional modules that are connected together * by wires. * * Wires and gates, connected by joints, represent a netlist. The * netlist is therefore a representation of the desired circuit. */ class PGate; class PExpr; class PSpecPath; struct vlltype; /* * The min:typ:max expression s selected at parse time using the * enumeration. When the compiler makes a choice, it also prints a * warning if min_typ_max_warn > 0. */ extern enum MIN_TYP_MAX { MIN, TYP, MAX } min_typ_max_flag; extern unsigned min_typ_max_warn; PExpr* pform_select_mtm_expr(PExpr*min, PExpr*typ, PExpr*max); /* * This flag is true if the lexor thinks we are in a library source * file. */ extern bool pform_library_flag; /* * These type are lexical types -- that is, types that are used as * lexical values to decorate the parse tree during parsing. They are * not in any way preserved once parsing is done. */ /* This is information about port name information for named port connections. */ //typedef struct named named_pexpr_t; typedef named named_pexpr_t; struct parmvalue_t { svector*by_order; svector*by_name; }; struct str_pair_t { PGate::strength_t str0, str1; }; struct net_decl_assign_t { perm_string name; PExpr*expr; struct net_decl_assign_t*next; }; /* The lgate is gate instantiation information. */ struct lgate { lgate(int =0) : parms(0), parms_by_name(0), lineno(0) { range[0] = 0; range[1] = 0; } string name; svector*parms; svector*parms_by_name; PExpr*range[2]; const char* file; unsigned lineno; }; /* Use this function to transform the parted form of the attribute list to the attribute map that is used later. */ extern void pform_bind_attributes(map&attributes, svector*attr); /* The lexor calls this function to change the default nettype. */ extern void pform_set_default_nettype(NetNet::Type net, const char*file, unsigned lineno); /* * Look for the given wire in the current lexical scope. If the wire * (including variables of any type) cannot be found in the current * scope, then return 0. */ extern PWire* pform_get_wire_in_scope(perm_string name); /* * The parser uses startmodule and endmodule together to build up a * module as it parses it. The startmodule tells the pform code that a * module has been noticed in the source file and the following events * are to apply to the scope of that module. The endmodule causes the * pform to close up and finish the named module. */ extern void pform_startmodule(const char*, const char*file, unsigned lineno, svector*attr); extern void pform_module_set_ports(vector*); /* This function is used to support the port definition in a port_definition_list. In this case, we have everything needed to define the port, all in one place. */ extern void pform_module_define_port(const struct vlltype&li, perm_string name, NetNet::PortType, NetNet::Type type, bool signed_flag, svector*range, svector*attr); extern Module::port_t* pform_module_port_reference(perm_string name, const char*file, unsigned lineno); extern void pform_endmodule(const char*, bool inside_celldefine, Module::UCDriveType uc_drive_def); extern void pform_make_udp(perm_string name, list*parms, svector*decl, list*table, Statement*init, const char*file, unsigned lineno); extern void pform_make_udp(perm_string name, bool sync_flag, perm_string out_name, PExpr*sync_init, list*parms, list*table, const char*file, unsigned lineno); /* * Enter/exit name scopes. The push_scope function pushes the scope * name string onto the scope hierarchy. The pop pulls it off and * deletes it. Thus, the string pushed must be allocated. */ extern void pform_pop_scope(); extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto); extern PFunction*pform_push_function_scope(const struct vlltype&loc, char*name, bool is_auto); extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt); extern void pform_put_behavior_in_scope(AProcess*proc); extern verinum* pform_verinum_with_size(verinum*s, verinum*val, const char*file, unsigned lineno); /* * This function takes the list of names as new genvars to declare in * the current module or generate scope. */ extern void pform_genvars(const struct vlltype&li, list*names); extern void pform_start_generate_for(const struct vlltype&li, char*ident1, PExpr*init, PExpr*test, char*ident2, PExpr*next); extern void pform_start_generate_if(const struct vlltype&li, PExpr*test); extern void pform_start_generate_else(const struct vlltype&li); extern void pform_start_generate_case(const struct vlltype&lp, PExpr*test); extern void pform_start_generate_nblock(const struct vlltype&lp, char*name); extern void pform_generate_case_item(const struct vlltype&lp, svector*test); extern void pform_generate_block_name(char*name); extern void pform_endgenerate(); /* * The makewire functions announce to the pform code new wires. These * go into a module that is currently opened. */ extern void pform_makewire(const struct vlltype&li, perm_string name, NetNet::Type type, NetNet::PortType pt, ivl_variable_type_t, svector*attr); /* This form handles simple declarations */ extern void pform_makewire(const struct vlltype&li, svector*range, bool signed_flag, list*names, NetNet::Type type, NetNet::PortType, ivl_variable_type_t, svector*attr, PWSRType rt = SR_NET); /* This form handles assignment declarations. */ extern void pform_makewire(const struct vlltype&li, svector*range, bool signed_flag, svector*delay, str_pair_t str, net_decl_assign_t*assign_list, NetNet::Type type, ivl_variable_type_t); extern void pform_make_reginit(const struct vlltype&li, perm_string name, PExpr*expr); /* Look up the names of the wires, and set the port type, i.e. input, output or inout. If the wire does not exist, create it. The second form takes a single name. */ extern void pform_set_port_type(const struct vlltype&li, list*names, svector*range, bool signed_flag, NetNet::PortType, svector*attr); extern void pform_set_port_type(perm_string nm, NetNet::PortType pt, const char*file, unsigned lineno); extern void pform_set_net_range(list*names, svector*, bool signed_flag, ivl_variable_type_t, PWSRType rt = SR_NET); extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); extern void pform_set_reg_time(list*names); /* pform_set_attrib and pform_set_type_attrib exist to support the $attribute syntax, which can only set string values to attributes. The functions keep the value strings that are passed in. */ extern void pform_set_attrib(perm_string name, perm_string key, char*value); extern void pform_set_type_attrib(perm_string name, const string&key, char*value); extern LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag, bool low_open, PExpr*low_expr, bool hig_open, PExpr*hig_expr); extern void pform_set_parameter(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, bool signed_flag, svector*range, PExpr*expr, LexicalScope::range_t*value_range); extern void pform_set_localparam(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, bool signed_flag, svector*range, PExpr*expr); extern void pform_set_defparam(const pform_name_t&name, PExpr*expr); /* * Functions related to specify blocks. */ extern void pform_set_specparam(perm_string name, PExpr*expr); extern PSpecPath*pform_make_specify_path(const struct vlltype&li, list*src, char pol, bool full_flag, list*dst); extern PSpecPath*pform_make_specify_edge_path(const struct vlltype&li, int edge_flag, /*posedge==true */ list*src, char pol, bool full_flag, list*dst, PExpr*data_source_expression); extern PSpecPath*pform_assign_path_delay(PSpecPath*obj, svector*delays); extern void pform_module_specify_path(PSpecPath*obj); /* * pform_make_behavior creates processes that are declared with always * or initial items. */ extern PProcess* pform_make_behavior(ivl_process_type_t, Statement*, svector*attr); extern svector* pform_make_udp_input_ports(list*); extern void pform_make_events(list*names, const char*file, unsigned lineno); /* * Make real datum objects. */ extern void pform_make_reals(list*names, const char*file, unsigned lineno); /* * The makegate function creates a new gate (which need not have a * name) and connects it to the specified wires. */ extern void pform_makegates(PGBuiltin::Type type, struct str_pair_t str, svector*delay, svector*gates, svector*attr); extern void pform_make_modgates(perm_string type, struct parmvalue_t*overrides, svector*gates); /* Make a continuous assignment node, with optional bit- or part- select. */ extern void pform_make_pgassign_list(svector*alist, svector*del, struct str_pair_t str, const char* fn, unsigned lineno); /* Given a port type and a list of names, make a list of wires that can be used as task port information. */ extern svector*pform_make_task_ports(NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, svector*range, list*names, const char* file, unsigned lineno, bool isint = false); /* * These are functions that the outside-the-parser code uses the do * interesting things to the Verilog. The parse function reads and * parses the source file and places all the modules it finds into the * mod list. The dump function dumps a module to the output stream. */ extern void pform_dump(ostream&out, Module*mod); /* * Used to report the original module location when a nested module * (missing endmodule) is found by the parser. */ extern void pform_error_nested_modules(); /* ** pform_discipline.cc * Functions for handling the parse of natures and disciplines. These * functions are in pform_disciplines.cc */ extern void pform_start_nature(const char*name); extern void pform_end_nature(const struct vlltype&loc); extern void pform_nature_access(const struct vlltype&loc, const char*name); extern void pform_start_discipline(const char*name); extern void pform_end_discipline(const struct vlltype&loc); extern void pform_discipline_domain(const struct vlltype&loc, ivl_dis_domain_t use_domain); extern void pform_discipline_potential(const struct vlltype&loc, const char*name); extern void pform_discipline_flow(const struct vlltype&loc, const char*name); extern void pform_attach_discipline(const struct vlltype&loc, ivl_discipline_t discipline, list*names); extern void pform_dump(ostream&out, const ivl_nature_s*); extern void pform_dump(ostream&out, const ivl_discipline_s*); /* ** pform_analog.cc */ extern void pform_make_analog_behavior(const struct vlltype&loc, ivl_process_type_t type, Statement*st); extern AContrib*pform_contribution_statement(const struct vlltype&loc, PExpr*lval, PExpr*rval); extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, char*name, char*n1, char*n2); extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, char*name, char*branch); #endif verilog-0.9.7/PaxHeaders.14238/t-dll-analog.cc0000644000202500001440000000005012204466647017012 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/t-dll-analog.cc0000644000202500001440000000441312204466647016336 0ustar00steveusers00000000000000/* * Copyright (c) 2008-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "config.h" # include # include # include "target.h" # include "ivl_target.h" # include "compiler.h" # include "t-dll.h" # include bool dll_target::process(const NetAnalogTop*net) { bool rc_flag = true; ivl_process_t obj = (struct ivl_process_s*) calloc(1, sizeof(struct ivl_process_s)); obj->type_ = net->type(); obj->analog_flag = 1; FILE_NAME(obj, net); /* Save the scope of the process. */ obj->scope_ = lookup_scope_(net->scope()); obj->nattr = net->attr_cnt(); obj->attr = fill_in_attributes(net); assert(stmt_cur_ == 0); stmt_cur_ = (struct ivl_statement_s*)calloc(1, sizeof*stmt_cur_); assert(stmt_cur_); rc_flag = net->statement()->emit_proc(this) && rc_flag; assert(stmt_cur_); obj->stmt_ = stmt_cur_; stmt_cur_ = 0; /* Save the process in the design. */ obj->next_ = des_.threads_; des_.threads_ = obj; return rc_flag; } bool dll_target::proc_contribution(const NetContribution*net) { assert(stmt_cur_); assert(stmt_cur_->type_ == IVL_ST_NONE); FILE_NAME(stmt_cur_, net); stmt_cur_->type_ = IVL_ST_CONTRIB; assert(expr_ == 0); net->lval()->expr_scan(this); stmt_cur_->u_.contrib_.lval = expr_; expr_ = 0; net->rval()->expr_scan(this); stmt_cur_->u_.contrib_.rval = expr_; expr_ = 0; return true; } verilog-0.9.7/PaxHeaders.14238/elab_anet.cc0000644000202500001440000000005012204466647016451 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/elab_anet.cc0000644000202500001440000001103012204466647015766 0ustar00steveusers00000000000000/* * Copyright (c) 2000-2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" /* * The elaborate_anet methods elaborate expressions that are intended * to be the left side of procedural continuous assignments. */ # include "PExpr.h" # include "netlist.h" # include "netmisc.h" # include NetNet* PExpr::elaborate_anet(Design*des, NetScope*scope) const { cerr << get_line() << ": error: Invalid expression on left side " << "of procedural continuous assignment." << endl; return 0; } NetNet* PEConcat::elaborate_anet(Design*des, NetScope*scope) const { if (repeat_) { cerr << get_line() << ": error: Repeat concatenations make " "no sense in l-value expressions. I refuse." << endl; des->errors += 1; return 0; } svectornets (parms_.count()); unsigned pins = 0; unsigned errors = 0; for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) { if (parms_[idx] == 0) { cerr << get_line() << ": error: Empty expressions " << "not allowed in concatenations." << endl; errors += 1; continue; } nets[idx] = parms_[idx]->elaborate_anet(des, scope); if (nets[idx] == 0) errors += 1; else pins += nets[idx]->pin_count(); } /* If any of the sub expressions failed to elaborate, then delete all those that did and abort myself. */ if (errors) { for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) { if (nets[idx]) delete nets[idx]; } des->errors += 1; return 0; } /* Make the temporary signal that connects to all the operands, and connect it up. Scan the operands of the concat operator from least significant to most significant, which is opposite from how they are given in the list. Allow for a repeat count other than 1 by repeating the connect loop as many times as necessary. */ NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT_REG, pins); /* Assume that all the data types are the same. */ osig->data_type(nets[0]->data_type()); pins = 0; for (unsigned idx = nets.count() ; idx > 0 ; idx -= 1) { NetNet*cur = nets[idx-1]; assert(cur->data_type() == osig->data_type()); for (unsigned pin = 0; pin < cur->pin_count(); pin += 1) { connect(osig->pin(pins), cur->pin(pin)); pins += 1; } } osig->local_flag(true); return osig; } NetNet* PEIdent::elaborate_anet(Design*des, NetScope*scope) const { assert(scope); NetNet* sig = 0; NetMemory* mem = 0; const NetExpr*par = 0; NetEvent* eve = 0; symbol_search(this, des, scope, path_, sig, mem, par, eve); if (mem != 0) { cerr << get_line() << ": error: memories not allowed " << "on left side of procedural continuous " << "assignment." << endl; des->errors += 1; return 0; } if (eve != 0) { cerr << get_line() << ": error: named events not allowed " << "on left side of procedural continuous " << "assignment." << endl; des->errors += 1; return 0; } if (sig == 0) { cerr << get_line() << ": error: reg ``" << path_ << "'' " << "is undefined in this scope." << endl; des->errors += 1; return 0; } switch (sig->type()) { case NetNet::REG: case NetNet::IMPLICIT_REG: break; default: cerr << get_line() << ": error: " << path_ << " is not " << "a reg in this context." << endl; des->errors += 1; return 0; } assert(sig); if (msb_ || lsb_) { cerr << get_line() << ": error: bit/part selects not allowed " << "on left side of procedural continuous assignment." << endl; des->errors += 1; return 0; } return sig; } verilog-0.9.7/PaxHeaders.14238/load_module.cc0000644000202500001440000000005012204466647017023 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/load_module.cc0000644000202500001440000001152612204466647016352 0ustar00steveusers00000000000000/* * Copyright (c) 2001-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "util.h" # include "parse_api.h" # include "compiler.h" # include # include # include # include # include # include # include # include # include /* * The module library items are maps of key names to file name within * the directory. */ struct module_library { char*dir; bool key_case_sensitive; mapname_map; struct module_library*next; }; static struct module_library*library_list = 0; static struct module_library*library_last = 0; const char dir_character = '/'; extern FILE *depend_file; /* * Use the type name as a key, and search the module library for a * file name that has that key. */ bool load_module(const char*type) { char path[4096]; char*ltype = strdup(type); for (char*tmp = ltype ; *tmp ; tmp += 1) *tmp = tolower(*tmp); for (struct module_library*lcur = library_list ; lcur != 0 ; lcur = lcur->next) { const char*key = lcur->key_case_sensitive? type : ltype; map::const_iterator cur; cur = lcur->name_map.find(key); if (cur == lcur->name_map.end()) continue; sprintf(path, "%s%c%s", lcur->dir, dir_character, (*cur).second); if(depend_file) { fprintf(depend_file, "%s\n", path); fflush(depend_file); } if (ivlpp_string) { char*cmdline = (char*)malloc(strlen(ivlpp_string) + strlen(path) + 4); strcpy(cmdline, ivlpp_string); strcat(cmdline, " \""); strcat(cmdline, path); strcat(cmdline, "\""); FILE*file = popen(cmdline, "r"); if (verbose_flag) cerr << "Executing: " << cmdline << endl; pform_parse(path, file); pclose(file); free(cmdline); } else { if (verbose_flag) cerr << "Loading library file " << path << "." << endl; FILE*file = fopen(path, "r"); assert(file); pform_parse(path, file); fclose(file); } return true; } return false; } /* * This function takes the name of a library directory that the caller * passed, and builds a name index for it. */ int build_library_index(const char*path, bool key_case_sensitive) { DIR*dir = opendir(path); if (dir == 0) return -1; if (verbose_flag) { cerr << "Indexing library: " << path << endl; } struct module_library*mlp = new struct module_library; mlp->dir = strdup(path); mlp->key_case_sensitive = key_case_sensitive; /* Scan the director for files. check each file name to see if it has one of the configured suffixes. If it does, then use the root of the name as the key and index the file name. */ while (struct dirent*de = readdir(dir)) { unsigned namsiz = strlen(de->d_name); char*key = 0; for (list::iterator suf = library_suff.begin() ; suf != library_suff.end() ; suf ++ ) { const char*sufptr = *suf; unsigned sufsiz = strlen(sufptr); if (sufsiz >= namsiz) continue; /* If the directory is case insensitive, then so is the suffix. */ if (key_case_sensitive) { if (strcmp(de->d_name + (namsiz-sufsiz), sufptr) != 0) continue; } else { if (strcasecmp(de->d_name + (namsiz-sufsiz), sufptr) != 0) continue; } key = new char[namsiz-sufsiz+1]; strncpy(key, de->d_name, namsiz-sufsiz); key[namsiz-sufsiz] = 0; break; } if (key == 0) continue; /* If the key is not to be case sensitive, then change it to lowercase. */ if (! key_case_sensitive) for (char*tmp = key ; *tmp ; tmp += 1) *tmp = tolower(*tmp); mlp->name_map[key] = strdup(de->d_name); delete[]key; } closedir(dir); if (library_last) { assert(library_list); library_last->next = mlp; mlp->next = 0; library_last = mlp; } else { library_list = mlp; library_last = mlp; mlp->next = 0; } return 0; } verilog-0.9.7/PaxHeaders.14238/ivl.def0000644000202500001440000000005012204466647015502 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/ivl.def0000644000202500001440000001006712204466647015030 0ustar00steveusers00000000000000EXPORTS ivl_branch_island ivl_branch_terminal ivl_design_const ivl_design_consts ivl_design_discipline ivl_design_disciplines ivl_design_flag ivl_design_process ivl_design_root ivl_design_roots ivl_design_time_precision ivl_const_bits ivl_const_delay ivl_const_real ivl_const_signed ivl_const_type ivl_const_width ivl_discipline_domain ivl_discipline_flow ivl_discipline_name ivl_discipline_potential ivl_event_any ivl_event_basename ivl_event_name ivl_event_nany ivl_event_neg ivl_event_nneg ivl_event_npos ivl_event_pos ivl_event_scope ivl_expr_type ivl_expr_bits ivl_expr_branch ivl_expr_def ivl_expr_delay_val ivl_expr_dvalue ivl_expr_event ivl_expr_file ivl_expr_lineno ivl_expr_name ivl_expr_nature ivl_expr_opcode ivl_expr_oper1 ivl_expr_oper2 ivl_expr_oper3 ivl_expr_parameter ivl_expr_parm ivl_expr_parms ivl_expr_repeat ivl_expr_scope ivl_expr_signal ivl_expr_signed ivl_expr_string ivl_expr_uvalue ivl_expr_value ivl_expr_width ivl_file_table_index ivl_file_table_item ivl_file_table_size ivl_island_flag_set ivl_island_flag_test ivl_logic_attr ivl_logic_attr_cnt ivl_logic_attr_val ivl_logic_basename ivl_logic_delay ivl_logic_drive0 ivl_logic_drive1 ivl_logic_name ivl_logic_pin ivl_logic_pins ivl_logic_scope ivl_logic_type ivl_logic_udp ivl_logic_width ivl_lpm_array ivl_lpm_aset_value ivl_lpm_async_clr ivl_lpm_async_set ivl_lpm_base ivl_lpm_basename ivl_lpm_clk ivl_lpm_data ivl_lpm_datab ivl_lpm_define ivl_lpm_delay ivl_lpm_enable ivl_lpm_file ivl_lpm_lineno ivl_lpm_name ivl_lpm_q ivl_lpm_scope ivl_lpm_select ivl_lpm_selects ivl_lpm_signed ivl_lpm_size ivl_lpm_sset_value ivl_lpm_string ivl_lpm_sync_clr ivl_lpm_sync_set ivl_lpm_trigger ivl_lpm_type ivl_lpm_width ivl_lval_idx ivl_lval_mux ivl_lval_part_off ivl_lval_sig ivl_lval_width ivl_nature_name ivl_nexus_get_private ivl_nexus_name ivl_nexus_ptrs ivl_nexus_ptr ivl_nexus_set_private ivl_nexus_ptr_branch ivl_nexus_ptr_con ivl_nexus_ptr_drive0 ivl_nexus_ptr_drive1 ivl_nexus_ptr_pin ivl_nexus_ptr_lpm ivl_nexus_ptr_log ivl_nexus_ptr_sig ivl_nexus_ptr_switch ivl_parameter_basename ivl_parameter_expr ivl_parameter_file ivl_parameter_lineno ivl_path_condit ivl_path_delay ivl_path_is_condit ivl_path_scope ivl_path_source ivl_path_source_negedge ivl_path_source_posedge ivl_scope_attr_cnt ivl_scope_attr_val ivl_scope_basename ivl_scope_children ivl_scope_def ivl_scope_def_file ivl_scope_def_lineno ivl_scope_event ivl_scope_events ivl_scope_file ivl_scope_is_auto ivl_scope_is_cell ivl_scope_lineno ivl_scope_logs ivl_scope_log ivl_scope_lpms ivl_scope_lpm ivl_scope_name ivl_scope_param ivl_scope_params ivl_scope_parent ivl_scope_port ivl_scope_ports ivl_scope_sigs ivl_scope_sig ivl_scope_switch ivl_scope_switches ivl_scope_time_precision ivl_scope_time_units ivl_scope_type ivl_scope_tname ivl_signal_array_addr_swapped ivl_signal_array_base ivl_signal_array_count ivl_signal_attr ivl_signal_attr_cnt ivl_signal_attr_val ivl_signal_basename ivl_signal_data_type ivl_signal_dimensions ivl_signal_discipline ivl_signal_file ivl_signal_integer ivl_signal_lineno ivl_signal_local ivl_signal_lsb ivl_signal_msb ivl_signal_name ivl_signal_nex ivl_signal_npath ivl_signal_path ivl_signal_port ivl_signal_signed ivl_signal_type ivl_signal_width ivl_path_delay ivl_path_source ivl_process_analog ivl_process_attr_cnt ivl_process_attr_val ivl_process_file ivl_process_lineno ivl_process_scope ivl_process_stmt ivl_process_type ivl_statement_type ivl_stmt_block_count ivl_stmt_block_scope ivl_stmt_block_stmt ivl_stmt_call ivl_stmt_case_count ivl_stmt_case_expr ivl_stmt_case_stmt ivl_stmt_cond_expr ivl_stmt_cond_false ivl_stmt_cond_true ivl_stmt_delay_expr ivl_stmt_delay_val ivl_stmt_events ivl_stmt_file ivl_stmt_lineno ivl_stmt_lexp ivl_stmt_lval ivl_stmt_lvals ivl_stmt_lwidth ivl_stmt_name ivl_stmt_nevent ivl_stmt_parm ivl_stmt_parm_count ivl_stmt_rval ivl_stmt_sub_stmt ivl_switch_a ivl_switch_b ivl_switch_basename ivl_switch_enable ivl_switch_file ivl_switch_island ivl_switch_lineno ivl_switch_offset ivl_switch_part ivl_switch_scope ivl_switch_type ivl_switch_width ivl_udp_init ivl_udp_name ivl_udp_nin ivl_udp_row ivl_udp_rows ivl_udp_sequ verilog-0.9.7/PaxHeaders.14238/iverilog-vpi.man.in0000644000202500001440000000005012204466647017746 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/iverilog-vpi.man.in0000644000202500001440000000746312204466647017302 0ustar00steveusers00000000000000.TH iverilog-vpi 1 "April 17th, 2009" "" "Version %M.%m.%n %E" .SH NAME iverilog-vpi - Compile front end for VPI modules .SH SYNOPSIS .B iverilog-vpi [\-\-name=\fIname\fP] \fIsourcefile\fP... .SH DESCRIPTION .PP \fIiverilog\-vpi\fP is a tool to simplify the compilation of VPI modules for use with Icarus Verilog. It takes on the command line a list of C or C++ source files, and generates as output a linked VPI module. See the \fBvvp\fP(1) man page for a description of how the linked module is loaded by a simulation. The output is named after the first source file. For example, if the first source file is named \fIfoo.c\fP, the output becomes \fIfoo.vpi\fP. .SH OPTIONS \fIiverilog\-vpi\fP accepts the following options: .TP 8 .B -l\fIlibrary\fP Include the named library in the link of the VPI module. This allows VPI modules to further reference external libraries. .TP 8 .B -I\fIdirectory\fP Add \fIdirectory\fP to the list of directories that will be search for header files. .TP 8 .B -D\fIdefine\fP Define a macro named \fIdefine\fP. .TP 8 .B --name=\fIname\fP Normally, the output VPI module will be named after the first source file passed to the command. This flag sets the name (without the .vpi suffix) of the output vpi module. .TP 8 .B --install-dir This flag causes the program to print the install directory for VPI modules, then exit. It is a convenience for makefiles or automated plug-in installers. .TP 8 .B --cflags, --ldflags and --ldlibs These flags provide compile time information. .SH "PC-ONLY OPTIONS" The PC port of \fIiverilog\-vpi\fP includes two special flags needed to support the more intractable development environment. These flags help the program locate parts that it needs. .TP 8 .B -mingw=\fIpath\fP Tell the program the root of the Mingw compiler tool suite. The \fBvvp\fP runtime is compiled with this compiler, and this is the compiler that \fIiverilog\-vpi\fP expects to use to compile your source code. This is normally not needed, and if you do use it, it is only needed once. The compiler will save the \fIpath\fP in the registry for use later. .TP 8 .B -ivl=\fIpath\fP Set for the use during compilation the root if the Icarus Verilog install. This is the place where you installed Icarus Verilog when you ran the installer. This flag is also only needed once, and the path is stored in the registry for future use. .SH "UNIX-ONLY OPTIONS" The UNIX version of \fIiverilog\-vpi\fP includes additional flags to let Makefile gurus peek at the configuration of the \fIiverilog\fP installation. This way, Makefiles can be written that handle complex VPI builds natively, and without hard-coding values that depend on the system and installation. If used at all, these options must be used one at a time, and without any other options or directives. .TP 8 .B --cflags Print the compiler flags (CFLAGS or CXXFLAGS) needed to compile source code destined for a VPI module. .TP 8 .B --ldflags Print the linker flags (LDFLAGS) needed to link a VPI module. .TP 8 .B --ldlibs Print the libraries (LDLIBS) needed to link a VPI module. .TP 8 .B -m32 On 64bit systems that support it (and support vvp32) this flag requests a 32bit vpi binary instead of the default 64bit binary. .P Example GNU makefile that takes advantage of these flags: .IP "" 4 CFLAGS = \-Wall \-O $(CFLAGS_$@) .br VPI_CFLAGS := $(shell iverilog-vpi \-\-cflags) .br CFLAGS_messagev.o = $(VPI_CFLAGS) .br CFLAGS_fifo.o = $(VPI_CFLAGS) .br messagev.o fifo.o: transport.h .br messagev.vpi: messagev.o fifo.o .br iverilog-vpi $^ .SH "AUTHOR" .nf Steve Williams (steve@icarus.com) .SH SEE ALSO iverilog(1), vvp(1), .BR "", .BR "", .SH COPYRIGHT .nf Copyright \(co 2002\-2009 Stephen Williams This document can be freely redistributed according to the terms of the GNU General Public License version 2.0 verilog-0.9.7/PaxHeaders.14238/PEvent.h0000644000202500001440000000005012204466647015602 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/PEvent.h0000644000202500001440000000314712204466647015131 0ustar00steveusers00000000000000#ifndef __PEvent_H #define __PEvent_H /* * Copyright (c) 2000-2004 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "LineInfo.h" # include "StringHeap.h" # include class Design; class NetScope; /* * The PEvent class represents event objects. These are things that * are declared in Verilog as ``event foo;'' The name passed to the * constructor is the "foo" part of the declaration. */ class PEvent : public LineInfo { public: // The name is a perm-allocated string. It is the simple name // of the event, without any scope. explicit PEvent(perm_string name); ~PEvent(); perm_string name() const; void elaborate_scope(Design*des, NetScope*scope) const; private: perm_string name_; private: // not implemented PEvent(const PEvent&); PEvent& operator= (const PEvent&); }; #endif verilog-0.9.7/PaxHeaders.14238/ivl_target.h0000644000202500001440000000005012204466647016541 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/ivl_target.h0000644000202500001440000024124112204466647016067 0ustar00steveusers00000000000000#ifndef __ivl_target_H #define __ivl_target_H /* * Copyright (c) 2000-2011 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include #ifdef __cplusplus #define _BEGIN_DECL extern "C" { #define _END_DECL } #else #define _BEGIN_DECL #define _END_DECL #endif #ifndef __GNUC__ # define __attribute__(x) #endif _BEGIN_DECL /* * This header file describes the API for the loadable target * module. The main program can load these modules and access the * functions within the loaded module to implement the backend * behavior. * * The interface is divided into two parts: the entry points within * the core that are called by the module, and the entry points in * the module that are called by the core. It is the latter that * causes the module to be invoked in the first place, but most of the * interesting information about the design is accessed through the * various access functions that the modules calls into the core. */ /* * In order to grab onto data in the design, the core passes cookies * to the various functions of the module. These cookies can in turn * be passed to access functions in the core to get more detailed * information. * * The following typedefs list the various cookies that may be passed * around. * * ivl_array_t * This object represent an array that can be a memory or a net * array. (They are the same from the perspective of ivl_target.h.) * * ivl_branch_t * this object represents an analog branch. * * ivl_design_t * This object represents the entire elaborated design. Various * global properties and methods are available from this. * * ivl_event_t * This object represents an event node. An event node stands for * named events written explicitly in the Verilog, and net events * that are implicit when @ statements are used. * * ivl_expr_t * This object represents a node of an expression. If the * expression has sub-expressions, they can be accessed from * various method described below. The ivl_expr_type method in * particular gets the type of the node in the form of an * ivl_expr_type_t enumeration value. * * Objects of this type represent expressions in * processes. Structural expressions are instead treated as logic * gates. * * ivl_island_t * Certain types of objects may belong to islands. The island that * they belong to is represented by the ivl_island_t cookie. To * know if object belong to the same island, it is sufficient to * compare island cookies. If a==b, then island a is the same as * island b. * * ivl_lpm_t * This object is the base class for all the various LPM type * device nodes. This object carries a few base properties * (including a type) including a handle to the specific type. * * ivl_net_logic_t * This object represents various built in logic devices. In fact, * this includes just about every directional device that has a * single output, including logic gates and nmos, pmos and cmos * devices. There is also the occasional Icarus Verilog creation. * What is common about these devices is that they are * bitwise. That is, when fed a vector, they produce a vector * result where each bit of the output is made only from the same * bits in the vector inputs. * * ivl_nexus_t * Structural links within an elaborated design are connected * together at each bit. The connection point is a nexus, so pins * of devices refer to an ivl_nexus_t. Furthermore, from a nexus * there are backward references to all the device pins that point * to it. * * ivl_parameter_t * Scopes have zero or more parameter objects that represent * parameters that the source defined. The parameter has a value * that is fully elaborated, with defparams and other parameter * overrides taken care of. * * ivl_process_t * A Verilog process is represented by one of these. A process may * be an "initial" or an "always" process. These come from initial * or always statements from the Verilog source. * * ivl_scope_t * Elaborated scopes within a design are represented by this * type. Objects of this type also act as containers for scoped * objects such as signals. * * ivl_statement_t * Statements within processes are represented by one of these. The * ivl_process_t object holds one of these, but a statement may in * turn contain other statements. * * ivl_switch_t * Switches are the tran/tranif devices in the design. * * -- A Note About Bit Sets -- * Some objects hold a value as an array of bits. In these cases there * is some method that retrieves the width of the value and another * that returns a "char*". The latter is a pointer to the least * significant bit value. Bit values are represented by the characters * '0', '1', 'x' and 'z'. Strengths are stored elsewhere. * * -- A Note About Names -- * The names of objects are complete, hierarchical names. That is, * they include the instance name of the module that contains them. * * basenames are the name of the object without the containing * scope. These names are unique within a scope, but not necessarily * throughout the design. */ typedef struct ivl_array_s *ivl_array_t; typedef struct ivl_branch_s *ivl_branch_t; typedef struct ivl_delaypath_s*ivl_delaypath_t; typedef struct ivl_design_s *ivl_design_t; /* clang++ wants this to be class to match the definition, but clang * (the C) compiler needs it to be a struct since class is not defined * in C. They are effecively both pointers to an object so everything * works out. */ #ifdef __cplusplus typedef class ivl_discipline_s*ivl_discipline_t; #else typedef struct ivl_discipline_s*ivl_discipline_t; #endif typedef struct ivl_event_s *ivl_event_t; typedef struct ivl_expr_s *ivl_expr_t; typedef struct ivl_island_s *ivl_island_t; typedef struct ivl_lpm_s *ivl_lpm_t; typedef struct ivl_lval_s *ivl_lval_t; typedef struct ivl_net_const_s*ivl_net_const_t; typedef struct ivl_net_logic_s*ivl_net_logic_t; typedef struct ivl_udp_s *ivl_udp_t; /* See the comments above. */ #ifdef __cplusplus typedef class ivl_nature_s *ivl_nature_t; #else typedef struct ivl_nature_s *ivl_nature_t; #endif typedef struct ivl_net_probe_s*ivl_net_probe_t; typedef struct ivl_nexus_s *ivl_nexus_t; typedef struct ivl_nexus_ptr_s*ivl_nexus_ptr_t; typedef struct ivl_parameter_s*ivl_parameter_t; typedef struct ivl_process_s *ivl_process_t; typedef struct ivl_scope_s *ivl_scope_t; typedef struct ivl_signal_s *ivl_signal_t; typedef struct ivl_switch_s *ivl_switch_t; typedef struct ivl_memory_s *ivl_memory_t; //XXXX __attribute__((deprecated)); typedef struct ivl_statement_s*ivl_statement_t; /* * These are types that are defined as enumerations. These have * explicit values so that the binary API is a bit more resilient to * changes and additions to the enumerations. */ typedef enum ivl_dis_domain_e { IVL_DIS_NONE = 0, IVL_DIS_DISCRETE = 1, IVL_DIS_CONTINUOUS = 2 } ivl_dis_domain_t; typedef enum ivl_drive_e { IVL_DR_HiZ = 0, IVL_DR_SMALL = 1, IVL_DR_MEDIUM = 2, IVL_DR_WEAK = 3, IVL_DR_LARGE = 4, IVL_DR_PULL = 5, IVL_DR_STRONG = 6, IVL_DR_SUPPLY = 7 } ivl_drive_t; /* This is the type of an ivl_expr_t object. The explicit numbers allow additions to the enumeration without causing values to shift and incompatibilities to be introduced. */ typedef enum ivl_expr_type_e { IVL_EX_NONE = 0, IVL_EX_ARRAY = 18, IVL_EX_BACCESS= 19, IVL_EX_BINARY = 2, IVL_EX_CONCAT = 3, IVL_EX_DELAY = 20, IVL_EX_EVENT = 17, IVL_EX_MEMORY = 4, IVL_EX_NUMBER = 5, IVL_EX_SCOPE = 6, IVL_EX_SELECT = 7, IVL_EX_SFUNC = 8, IVL_EX_SIGNAL = 9, IVL_EX_STRING = 10, IVL_EX_TERNARY = 11, IVL_EX_UFUNC = 12, IVL_EX_ULONG = 13, IVL_EX_UNARY = 14, IVL_EX_REALNUM = 16 } ivl_expr_type_t; /* This is the type code for an ivl_net_logic_t object. */ typedef enum ivl_logic_e { IVL_LO_NONE = 0, IVL_LO_AND = 1, IVL_LO_BUF = 2, IVL_LO_BUFIF0 = 3, IVL_LO_BUFIF1 = 4, IVL_LO_BUFZ = 5, IVL_LO_CMOS = 22, IVL_LO_NAND = 6, IVL_LO_NMOS = 7, IVL_LO_NOR = 8, IVL_LO_NOT = 9, IVL_LO_NOTIF0 = 10, IVL_LO_NOTIF1 = 11, IVL_LO_OR = 12, IVL_LO_PULLDOWN = 13, IVL_LO_PULLUP = 14, IVL_LO_RCMOS = 23, IVL_LO_RNMOS = 15, IVL_LO_RPMOS = 16, IVL_LO_PMOS = 17, IVL_LO_XNOR = 18, IVL_LO_XOR = 19, IVL_LO_UDP = 21 } ivl_logic_t; /* This is the type of a ivl_switch_t object */ typedef enum ivl_switch_type_e { IVL_SW_TRAN = 0, IVL_SW_TRANIF0 = 1, IVL_SW_TRANIF1 = 2, IVL_SW_RTRAN = 3, IVL_SW_RTRANIF0 = 4, IVL_SW_RTRANIF1 = 5, IVL_SW_TRAN_VP = 6 } ivl_switch_type_t; /* This is the type of an LPM object. */ typedef enum ivl_lpm_type_e { IVL_LPM_ABS = 32, IVL_LPM_ADD = 0, IVL_LPM_ARRAY = 30, IVL_LPM_CAST_INT = 34, IVL_LPM_CAST_REAL = 33, IVL_LPM_CONCAT = 16, IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */ IVL_LPM_CMP_EQ = 10, IVL_LPM_CMP_GE = 1, IVL_LPM_CMP_GT = 2, IVL_LPM_CMP_NE = 11, IVL_LPM_CMP_NEE= 19, /* Case NE (!==) */ IVL_LPM_DIVIDE = 12, IVL_LPM_FF = 3, IVL_LPM_MOD = 13, IVL_LPM_MULT = 4, IVL_LPM_MUX = 5, /* IVL_LPM_PART_BI= 28, / obsolete */ IVL_LPM_PART_VP= 15, /* part select: vector to part */ IVL_LPM_PART_PV= 17, /* part select: part written to vector */ IVL_LPM_POW = 31, IVL_LPM_RE_AND = 20, IVL_LPM_RE_NAND= 21, IVL_LPM_RE_NOR = 22, IVL_LPM_RE_OR = 23, IVL_LPM_RE_XNOR= 24, IVL_LPM_RE_XOR = 25, IVL_LPM_REPEAT = 26, IVL_LPM_SFUNC = 29, IVL_LPM_SHIFTL = 6, IVL_LPM_SHIFTR = 7, IVL_LPM_SIGN_EXT=27, IVL_LPM_SUB = 8, /* IVL_LPM_RAM = 9, / obsolete */ IVL_LPM_UFUNC = 14 } ivl_lpm_type_t; /* The path edge type is the edge type used to select a specific delay. */ typedef enum ivl_path_edge_e { IVL_PE_01 = 0, IVL_PE_10, IVL_PE_0z, IVL_PE_z1, IVL_PE_1z, IVL_PE_z0, IVL_PE_0x, IVL_PE_x1, IVL_PE_1x, IVL_PE_x0, IVL_PE_xz, IVL_PE_zx, IVL_PE_COUNT } ivl_path_edge_t; /* Processes are initial or always blocks with a statement. This is the type of the ivl_process_t object. */ typedef enum ivl_process_type_e { IVL_PR_INITIAL = 0, IVL_PR_ALWAYS = 1 } ivl_process_type_t; /* These are the sorts of reasons a scope may come to be. These types are properties of ivl_scope_t objects. */ typedef enum ivl_scope_type_e { IVL_SCT_MODULE = 0, IVL_SCT_FUNCTION= 1, IVL_SCT_TASK = 2, IVL_SCT_BEGIN = 3, IVL_SCT_FORK = 4, IVL_SCT_GENERATE= 5 } ivl_scope_type_t; /* Signals (ivl_signal_t) that are ports into the scope that contains them have a port type. Otherwise, they are port IVL_SIP_NONE. */ typedef enum ivl_signal_port_e { IVL_SIP_NONE = 0, IVL_SIP_INPUT = 1, IVL_SIP_OUTPUT= 2, IVL_SIP_INOUT = 3 } ivl_signal_port_t; /* This is the type code for an ivl_signal_t object. Implicit types are resolved by the core compiler, and integers are converted into signed registers. */ typedef enum ivl_signal_type_e { IVL_SIT_NONE = 0, IVL_SIT_REG = 1, IVL_SIT_TRI = 4, IVL_SIT_TRI0 = 5, IVL_SIT_TRI1 = 6, IVL_SIT_TRIAND = 7, IVL_SIT_TRIOR = 8 } ivl_signal_type_t; /* This is the type code for ivl_statement_t objects. */ typedef enum ivl_statement_type_e { IVL_ST_NONE = 0, IVL_ST_NOOP = 1, IVL_ST_ALLOC = 25, IVL_ST_ASSIGN = 2, IVL_ST_ASSIGN_NB = 3, IVL_ST_BLOCK = 4, IVL_ST_CASE = 5, IVL_ST_CASER = 24, /* Case statement with real expressions. */ IVL_ST_CASEX = 6, IVL_ST_CASEZ = 7, IVL_ST_CASSIGN = 8, IVL_ST_CONDIT = 9, IVL_ST_CONTRIB = 27, IVL_ST_DEASSIGN = 10, IVL_ST_DELAY = 11, IVL_ST_DELAYX = 12, IVL_ST_DISABLE = 13, IVL_ST_FORCE = 14, IVL_ST_FOREVER = 15, IVL_ST_FORK = 16, IVL_ST_FREE = 26, IVL_ST_RELEASE = 17, IVL_ST_REPEAT = 18, IVL_ST_STASK = 19, IVL_ST_TRIGGER = 20, IVL_ST_UTASK = 21, IVL_ST_WAIT = 22, IVL_ST_WHILE = 23 } ivl_statement_type_t; /* This is the type of a variable, and also used as the type for an expression. */ typedef enum ivl_variable_type_e { IVL_VT_VOID = 0, /* Not used */ IVL_VT_NO_TYPE = 1, /* Place holder for missing/unknown type. */ IVL_VT_REAL = 2, IVL_VT_BOOL = 3, IVL_VT_LOGIC = 4, IVL_VT_VECTOR = IVL_VT_LOGIC /* For compatibility */ } ivl_variable_type_t; /* This is the type of the function to apply to a process. */ typedef int (*ivl_process_f)(ivl_process_t net, void*cd); /* This is the type of a function to apply to a scope. The ivl_scope_t parameter is the scope, and the cd parameter is client data that the user passes to the scanner. */ typedef int (ivl_scope_f)(ivl_scope_t net, void*cd); /* Attributes, which can be attached to various object types, have this form. */ typedef enum ivl_attribute_type_e { IVL_ATT_VOID = 0, IVL_ATT_STR, IVL_ATT_NUM } ivl_attribute_type_t; struct ivl_attribute_s { const char*key; ivl_attribute_type_t type; union val_ { const char*str; long num; } val; }; typedef const struct ivl_attribute_s*ivl_attribute_t; /* BRANCH * Branches are analog constructs, a pair of terminals that is used in * branch access functions. Terminal-1 is the reference node (The * "ground") for the purposes of the access function that accesses it. * * SEMANTIC NOTES * All the branches in an island are connected by terminals or by * expressions. The island is the connection of branches that must be * solved together. */ /* extern ivl_scope_t ivl_branch_scope(ivl_branch_t obj); */ extern ivl_nexus_t ivl_branch_terminal(ivl_branch_t obj, int idx); extern ivl_island_t ivl_branch_island(ivl_branch_t obj); /* DELAYPATH * Delaypath objects represent delay paths called out by a specify * block in the Verilog source file. The destination signal references * the path object, which in turn points to the source for the path. * * ivl_path_scope * This returns the scope of the delay path. This scope corresponds * to the scope of the specify-block that led to this path. * * ivl_path_source * This returns the nexus that is the source end of the delay * path. Transitions on the source are the start of the delay time * for this path. * * ivl_path_condit * This returns the nexus that tracks the condition for the * delay. If the delay path is unconditional, this returns nil. * ivl_path_is_condit * Is this a conditional structure? Needed for ifnone. * * ivl_path_source_posedge * ivl_path_source_negedge * These functions return true if the source is edge sensitive. */ extern ivl_scope_t ivl_path_scope(ivl_delaypath_t obj); extern ivl_nexus_t ivl_path_source(ivl_delaypath_t obj); extern uint64_t ivl_path_delay(ivl_delaypath_t obj, ivl_path_edge_t pt); extern ivl_nexus_t ivl_path_condit(ivl_delaypath_t obj); extern int ivl_path_is_condit(ivl_delaypath_t obj); extern int ivl_path_source_posedge(ivl_delaypath_t obj); extern int ivl_path_source_negedge(ivl_delaypath_t obj); /* DESIGN * When handed a design (ivl_design_t) there are a few things that you * can do with it. The Verilog program has one design that carries the * entire program. Use the design methods to iterate over the elements * of the design. * * ivl_design_flag * This function returns the string value of a named flag. Flags * come from the "-fkey=value" options to the iverilog command and * are stored in a map for this function. Given the key, this * function returns the value. * * The special key "-o" is the argument to the -o flag of the * command line (or the default if the -o flag is not used) and is * generally how the target learns the name of the output file. * * ivl_design_process * This function scans the processes (threads) in the design. It * calls the user supplied function on each of the processes until * one of the functors returns non-0 or all the processes are * scanned. This function will return 0, or the non-zero value that * was returned from the last scanned process. * * ivl_design_root (ANACHRONISM) * A design has a root named scope that is an instance of the top * level module in the design. This is a hook for naming the * design, or for starting the scope scan. * * ivl_design_roots * A design has some number of root scopes. These are the starting * points for structural elaboration. This function returns to the * caller a pointer to an ivl_scope_t array, and the size of the * array. * * ivl_design_time_precision * A design as a time precision. This is the size in seconds (a * signed power of 10) of a simulation tick. */ extern const char* ivl_design_flag(ivl_design_t des, const char*key); extern int ivl_design_process(ivl_design_t des, ivl_process_f fun, void*cd); extern ivl_scope_t ivl_design_root(ivl_design_t des); extern void ivl_design_roots(ivl_design_t des, ivl_scope_t **scopes, unsigned int *nscopes); extern int ivl_design_time_precision(ivl_design_t des); extern unsigned ivl_design_consts(ivl_design_t des); extern ivl_net_const_t ivl_design_const(ivl_design_t, unsigned idx); extern unsigned ivl_design_disciplines(ivl_design_t des); extern ivl_discipline_t ivl_design_discipline(ivl_design_t des, unsigned idx); /* LITERAL CONSTANTS * Literal constants are nodes with no input and a single constant * output. The form of the output depends on the type of the node. * The output is an array of 4-value bits, using a single char * value for each bit. The bits of the vector are in canonical (lsb * first) order for the width of the constant. * * ivl_const_type * The is the type of the node. * * ivl_const_bits * This returns a pointer to an array of constant characters, * each byte a '0', '1', 'x' or 'z'. The array is *not* nul * terminated. This value is only value if ivl_const_type is * IVL_VT_LOGIC or IVL_VT_BOOL. It returns nil otherwise. * * ivl_const_nex * Return the ivl_nexus_t of the output for the constant. * * ivl_const_signed * Return true (!0) if the constant is a signed value, 0 otherwise. * * ivl_const_width * Return the width, in logical bits, of the constant. * * ivl_const_delay * T0 delay for a transition (0, 1 and Z). * * SEMANTIC NOTES * * The const_type of the literal constant must match the * ivl_signal_data_type if the signals that share the nexus of this * node. The compiler makes sure it is so, converting constant values * as needed. * * - IVL_VT_LOGIC * * - IVL_VT_REAL * Real valued constants have a width of 1. The value emitted to the * output is ivl_const_real. */ extern ivl_variable_type_t ivl_const_type(ivl_net_const_t net); extern const char* ivl_const_bits(ivl_net_const_t net); extern ivl_expr_t ivl_const_delay(ivl_net_const_t net, unsigned transition); extern ivl_nexus_t ivl_const_nex(ivl_net_const_t net); extern int ivl_const_signed(ivl_net_const_t net); extern unsigned ivl_const_width(ivl_net_const_t net); extern double ivl_const_real(ivl_net_const_t net); /* extern ivl_nexus_t ivl_const_pin(ivl_net_const_t net, unsigned idx); */ /* extern unsigned ivl_const_pins(ivl_net_const_t net); */ /* DISCIPLINES * * Disciplines are Verilog-AMS construct. A discipline is a collection * of attributes that can be attached to a signal. * * FUNCTION SUMMARY * * ivl_discipline_name * This is the name of the discipline in the Verilog-AMS source. * * ivl_discipline_domain * This is the domain: continuous or discrete. * * SEMANTIC NOTES * * The discipline domain will not be IVL_DIS_NONE. The "none" domain * is a place-holder internally for incomplete parsing, and is also * available for code generators to use. */ extern const char*ivl_discipline_name(ivl_discipline_t net); extern ivl_dis_domain_t ivl_discipline_domain(ivl_discipline_t net); extern ivl_nature_t ivl_discipline_potential(ivl_discipline_t net); extern ivl_nature_t ivl_discipline_flow(ivl_discipline_t net); extern const char* ivl_nature_name(ivl_nature_t net); /* EVENTS * * Events are a unification of named events and implicit events * generated by the @ statements. * * FUNCTION SUMMARY * * ivl_event_name (Obsolete) * ivl_event_basename * Return the name of the event. The basename is the name within * the scope, as declared by the user or generated by elaboration. * * ivl_event_scope * All events exist within a scope. * * SEMANTICS NOTES * * Named events (i.e. event objects declared by the Verilog * declaration "event foo") are recognized by the fact that they have * no edge sources. The name of the event as given in the Verilog * source is available from the ivl_event_basename function. * * Named events are referenced in trigger statements. * * Edge events are created implicitly by the @(...) Verilog syntax to * watch for the correct type of edge for the functor being * watched. The nodes to watch are collected into groups based on the * type of edge to be watched for on that node. For example, nodes to * be watched for positive edges are accessed via the ivl_event_npos * and ivl_event_pos functions. */ extern const char* ivl_event_name(ivl_event_t net); extern const char* ivl_event_basename(ivl_event_t net); extern ivl_scope_t ivl_event_scope(ivl_event_t net); extern unsigned ivl_event_nany(ivl_event_t net); extern ivl_nexus_t ivl_event_any(ivl_event_t net, unsigned idx); extern unsigned ivl_event_nneg(ivl_event_t net); extern ivl_nexus_t ivl_event_neg(ivl_event_t net, unsigned idx); extern unsigned ivl_event_npos(ivl_event_t net); extern ivl_nexus_t ivl_event_pos(ivl_event_t net, unsigned idx); /* EXPRESSIONS * * These methods operate on expression objects from the * design. Expressions mainly exist in behavioral code. The * ivl_expr_type() function returns the type of the expression node, * and the remaining functions access value bits of the expression. * * ivl_expr_signed * This method returns true (!= 0) if the expression node * represents a signed expression. It is possible for sub- * expressions to be unsigned even if a node is signed, but the * IVL core figures all this out for you. At any rate, this method * can be applied to any expression node. * * ivl_expr_type * Get the type of the expression node. Every expression node has a * type, which can affect how some of the other expression methods * operate on the node * * ivl_expr_value * Get the data type of the expression node. This uses the variable * type enum to express the type of the expression node. * * ivl_expr_width * This method returns the bit width of the expression at this * node. It can be applied to any expression node, and returns the * *output* width of the expression node. * * ivl_expr_parameter * This function returns the ivl_parameter_t object that represents * this object, or 0 (nil) if it is not a parameter value. This * function allows the code generator to detect the case where the * expression is a parameter. This will normally only return a * non-nil value for constants. * * ivl_expr_opcode * IVL_EX_BINARY and IVL_EX_UNARY expression nodes include an * opcode from this table: * & -- AND * A -- NAND (~&) * X -- XNOR (~^) * * -- Multiply * * SEMANTIC NOTES * * - IVL_EX_ARRAY * This expression type is a special case of the IVL_EX_SIGNAL where * the target is an array (ivl_signal_t with an array_count) but there * is no index expression. This is used only in the special situation * where the array is passed to a system task/function. The function * ivl_expr_signal returns the ivl_signal_t of the array object, and * from that all the properties of the array can be determined. * * - IVL_EX_BINARY * * - IVL_EX_SELECT * This expression takes two operands, oper1 is the expression to * select from, and oper2 is the selection base. The ivl_expr_width * value is the width of the bit/part select. The ivl_expr_oper1 value * is the base of a vector. The compiler has already figured out any * conversion from signal units to vector units, so the result of * ivl_expr_oper1 should range from 0 to ivl_expr_width(). * * - IVL_EX_SIGNAL * This expression references a signal vector. The ivl_expr_signal * function gets a handle for the signal that is referenced. The * signal may be an array (see the ivl_signal_array_count function) * that is addressed by the expression returned by the ivl_expr_oper1 * function. This expression returns a *canonical* address. The core * compiler already corrected the expression to account for index * bases. * * The ivl_expr_width function returns the vector width of the signal * word. The ivl_expr_value returns the data type of the word. * * Bit and part selects are not done here. The IVL_EX_SELECT * expression does bit/part selects on the word read from the signal. * * - IVL_EX_STRING * This expression refers to a string constant. The ivl_expr_string * function returns a pointer to the first byte of the string. The * compiler has translated it to a "vvp escaped string" which has * quoting and escapes eliminated. The string may contain octal * escapes (\) so that the string text returned by * ivl_expr_string will only contain graphical characters. It is up to * the target to change the escaped \NNN to the proper byte value when * using this string. No other escape sequences will appear in the * string. Quote (") and slash (\) characters will be delivered in * \NNN form. */ extern ivl_expr_type_t ivl_expr_type(ivl_expr_t net); extern ivl_variable_type_t ivl_expr_value(ivl_expr_t net); extern const char*ivl_expr_file(ivl_expr_t net); extern unsigned ivl_expr_lineno(ivl_expr_t net); /* IVL_EX_NUMBER */ extern const char* ivl_expr_bits(ivl_expr_t net); /* IVL_EX_BACCESS */ extern ivl_branch_t ivl_expr_branch(ivl_expr_t net); /* IVL_EX_UFUNC */ extern ivl_scope_t ivl_expr_def(ivl_expr_t net); /* IVL_EX_DELAY */ extern uint64_t ivl_expr_delay_val(ivl_expr_t net); /* IVL_EX_REALNUM */ extern double ivl_expr_dvalue(ivl_expr_t net); /* IVL_EX_SIGNAL, IVL_EX_SFUNC, IVL_EX_VARIABLE */ extern const char* ivl_expr_name(ivl_expr_t net); /* IVL_EX_BACCESS */ extern ivl_nature_t ivl_expr_nature(ivl_expr_t net); /* IVL_EX_BINARY IVL_EX_UNARY */ extern char ivl_expr_opcode(ivl_expr_t net); /* IVL_EX_BINARY IVL_EX_UNARY, IVL_EX_MEMORY IVL_EX_TERNARY */ extern ivl_expr_t ivl_expr_oper1(ivl_expr_t net); /* IVL_EX_BINARY IVL_EX_TERNARY */ extern ivl_expr_t ivl_expr_oper2(ivl_expr_t net); /* IVL_EX_TERNARY */ extern ivl_expr_t ivl_expr_oper3(ivl_expr_t net); /* and expression */ extern ivl_parameter_t ivl_expr_parameter(ivl_expr_t net); /* IVL_EX_CONCAT IVL_EX_UFUNC */ extern ivl_expr_t ivl_expr_parm(ivl_expr_t net, unsigned idx); /* IVL_EX_CONCAT IVL_EX_SFUNC IVL_EX_UFUNC */ extern unsigned ivl_expr_parms(ivl_expr_t net); /* IVL_EX_CONCAT */ extern unsigned ivl_expr_repeat(ivl_expr_t net); /* IVL_EX_EVENT */ extern ivl_event_t ivl_expr_event(ivl_expr_t net); /* IVL_EX_SCOPE */ extern ivl_scope_t ivl_expr_scope(ivl_expr_t net); /* IVL_EX_SIGNAL */ extern ivl_signal_t ivl_expr_signal(ivl_expr_t net); /* any expression */ extern int ivl_expr_signed(ivl_expr_t net); /* IVL_EX_STRING */ extern const char* ivl_expr_string(ivl_expr_t net); /* IVL_EX_ULONG */ extern unsigned long ivl_expr_uvalue(ivl_expr_t net); /* any expression */ extern unsigned ivl_expr_width(ivl_expr_t net); extern const char* ivl_file_table_item(unsigned idx); extern unsigned ivl_file_table_index(const char *); extern unsigned ivl_file_table_size(void); /* ISLAND * * ivl_island_flag_set * ivl_island_flag_test * Allow the user to test or set a boolean flag associated with the * island. */ extern int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value); extern int ivl_island_flag_test(ivl_island_t net, unsigned flag); /* LOGIC * These types and functions support manipulation of logic gates. The * ivl_logic_t enumeration identifies the various kinds of gates that * the ivl_net_logic_t can represent. The various functions then * provide access to the bits of information for a given logic device. * * The ivl_net_logic_t nodes are bit-slice devices. That means that * the device may have width (and therefore processes vectors) but * each bit slice of the width is independent. * * ivl_logic_type * This method returns the type of logic gate that the node * represents. The logic type implies the meaning of the various pins. * * ivl_logic_name (obsolete) * This method returns the complete name of the logic gate. Every * gate has a complete name (that includes the scope) even if the * Verilog source doesn't include one. The compiler will choose one * if necessary. * * ivl_logic_basename * This is the name of the gate without the scope part. * * ivl_logic_scope * This is the scope that directly contains the logic device. * * ivl_logic_pins * ivl_logic_pin * Return the nexus for the pin. If two pins are connected * together, then these values are the same. Use the nexus * functions to find other pins that are connected to this nexus. * * ivl_logic_width * This returns the width of the logic array. This does not affect * the number of pins, but implies the width of the vector at each * pin. * * ivl_logic_delay * Logic devices have a delay for each transition (0, 1 and Z). * * ivl_logic_attr (obsolete) * Return the value of a specific attribute, given the key name as * a string. If the key is not defined, then return 0 (null). * * ivl_logic_attr_cnt * ivl_logic_attr_val * These support iterating over logic attributes. The _cnt method * returns the number of attributes attached to the gate, and the * ivl_logic_attr_val returns the value of the attribute. * * SEMANTIC NOTES * The ivl_logic_width applies to all the pins of a logic device. If a * logic device has width, that means that it is actually an array of * logic devices that each process a bit slice of the * inputs/output. That implies that the widths of all the inputs and * the output must be identical. * * The ivl_logic_width and ivl_logic_pins are *not* related. A logic * device has a number of pins that is the number of inputs to a logic * array of identical gates, and the ivl_logic_width, is the width of * the vector into each input pin and out of the output pin. * * The output pin is pin-0. The ivl_logic_driveX functions return the * drive strengths for the output pin-0, and match the drive values * stored in the ivl_nexus_ptr_t object for the pin. * * Logic devices have a logic propagation delay. The delay can be any * expression, although the most common expression is an IVL_EX_NUMBER * for a number value. The expression already includes scaling for the * containing module, so the delay value is always taken to be in * simulation clock ticks. * * If the delay is present, then ivl_logic_delay returns a non-nil * object. If any of the three delays is present, then all three are * present, even if they are all the same. The compiler will translate * shorthands into a complete set of delay expressions. * * The ivl_logic_delay expression will always be an IVL_EX_NUMBER, an * IVL_EX_ULONG, or an IVL_EX_SIGNAL. These expressions can easily be * used in structural contexts. The compiler will take care of * elaborating more complex expressions to nets. * * - IVL_LO_PULLUP/IVL_LO_PULLDOWN * These devices are grouped as logic devices with zero inputs because * the outputs have the same characteristics as other logic * devices. They are special only in that they have zero inputs, and * their drivers typically have strength other than strong. * * - IVL_LO_UDP * User defined primitives (UDPs) are like any other logic devices, in * that they are bit-slice devices. If they have a width, then they * are repeated to accommodate that width, and that implies that the * output and all the inputs must have the same width. * * The IVL_LO_UDP represents instantiations of UDP devices. The * ivl_udp_t describes the implementation. */ extern const char* ivl_logic_name(ivl_net_logic_t net); extern const char* ivl_logic_basename(ivl_net_logic_t net); extern ivl_scope_t ivl_logic_scope(ivl_net_logic_t net); extern ivl_logic_t ivl_logic_type(ivl_net_logic_t net); extern ivl_nexus_t ivl_logic_pin(ivl_net_logic_t net, unsigned pin); extern unsigned ivl_logic_pins(ivl_net_logic_t net); extern ivl_udp_t ivl_logic_udp(ivl_net_logic_t net); extern ivl_expr_t ivl_logic_delay(ivl_net_logic_t net, unsigned transition); extern ivl_drive_t ivl_logic_drive0(ivl_net_logic_t net); extern ivl_drive_t ivl_logic_drive1(ivl_net_logic_t net); extern unsigned ivl_logic_width(ivl_net_logic_t net); /* DEPRECATED */ extern const char* ivl_logic_attr(ivl_net_logic_t net, const char*key); extern unsigned ivl_logic_attr_cnt(ivl_net_logic_t net); extern ivl_attribute_t ivl_logic_attr_val(ivl_net_logic_t net, unsigned idx); /* UDP * These methods allow access to the ivl_udp_t definition of a UDP. * The UDP definition is accessed through the ivl_logic_udp method of * an ivl_net_logic_t object. * * ivl_udp_name * This returns the name of the definition of the primitive. * * ivl_udp_nin * This is the number of inputs for the UDP definition. * * ivl_udp_rows * ivl_udp_row * These methods give access to the rows that define the table of * the primitive. * * SEMANTIC NOTES * * - Combinational primitives * These devices have no edge dependencies, and have no table entry * for the current input value. These have ivl_udp_sequ return 0 * (false) and the length of each row is the number of inputs plus 1. * The first N characters correspond to the N inputs of the * device. The next character, the last character, is the output for * that row. * * - Sequential primitives * These devices allow edge transitions, and the rows are 1+N+1 * characters long. The first character is the current output, the * next N characters the current input and the last character is the * new output. * * The ivl_udp_init value is only valid if the device is * sequential. It is the initial value for the output of the storage * element. */ extern int ivl_udp_sequ(ivl_udp_t net); extern unsigned ivl_udp_nin(ivl_udp_t net); extern unsigned ivl_udp_init(ivl_udp_t net); extern const char* ivl_udp_row(ivl_udp_t net, unsigned idx); extern unsigned ivl_udp_rows(ivl_udp_t net); extern const char* ivl_udp_name(ivl_udp_t net); extern const char* ivl_lpm_file(ivl_lpm_t net); extern unsigned ivl_lpm_lineno(ivl_lpm_t net); /* LPM * These functions support access to the properties of LPM * devices. LPM devices are a variety of devices that handle more * complex structural semantics. They are based on EIA LPM standard * devices, but vary to suite the technical situation. * * These are the functions that apply to all LPM devices: * * ivl_lpm_name (Obsolete) * ivl_lpm_basename * Return the name of the device. The name is the name of the * device with the scope part, and the basename is without the scope. * * ivl_lpm_delay * LPM devices have a delay for each transition (0, 1 and Z). * * ivl_lpm_scope * LPM devices exist within a scope. Return the scope that contains * this device. * * ivl_lpm_type * Return the ivl_lpm_type_t of the specific LPM device. * * ivl_lpm_width * Return the width of the LPM device. What this means depends on * the LPM type, but it generally has to do with the width of the * output data path. * * * These functions apply to a subset of the LPM devices, or may have * varying meaning depending on the device: * * ivl_lpm_base * The IVL_LPM_PART objects use this value as the base (first bit) * of the part select. The ivl_lpm_width is the size of the part. * * ivl_lpm_data * Return the input data nexus for device types that have input * vectors. The "idx" parameter selects which data input is selected. * * ivl_lpm_datab (ANACHRONISM) * This is the same as ivl_lpm_data(net,1), in other words the * second data input. Use the ivl_lpm_data method instead. * * ivl_lpm_q * Return the output data nexus for device types that have a single * output vector. This is most devices, it turns out. * * ivl_lpm_selects * This is the size of the select input for a LPM_MUX device, or the * address bus width of an LPM_RAM. * * ivl_lpm_signed * Arithmetic LPM devices may be signed or unsigned if there is a * distinction. For some devices this gives the signedness of the * output, but not all devices. * * ivl_lpm_size * In addition to a width, some devices have a size. The size is * often the number of inputs per out, i.e., the number of inputs * per bit for a MUX. * * ivl_lpm_trigger * SFUNC and UFUNC devices may have a trigger that forces the * function output to be re-evaluated. * * SEMANTIC NOTES * * - Concatenation (IVL_LPM_CONCAT) * These devices take vectors in and combine them to form a single * output the width specified by ivl_lpm_width. * * The ivl_lpm_q nexus is the output from the concatenation. * * The ivl_lpm_data function returns the connections for the inputs to * the concatenation. The ivl_lpm_size function returns the number of * inputs help by the device. * * - Divide (IVL_LPM_DIVIDE) * The divide operators take two inputs and generate an output. The * ivl_lpm_width returns the width of the result. The width of the * inputs are their own. * * - Multiply (IVL_LPM_MULT) * The multiply takes two inputs and generates an output. Unlike other * arithmetic nodes, the width only refers to the output. The inputs * have independent widths, to reflect the arithmetic truth that the * width of a general multiply is the sum of the widths of the * inputs. In fact, the compiler doesn't assure that the widths of the * inputs add up to the width of the output, but the possibility * exists. It is *not* an error for the sum of the input widths to be * more than the width of the output, although the possibility of * overflow exists at run time. * * The inputs are always treated as unsigned. If the expression is * supposed to be signed, elaboration will generate the necessary sign * extension, so the target need not (must not) consider signedness. * * - Power (IVL_LPM_POW) * The power takes two inputs and generates an output. Unlike other * arithmetic nodes, the width only refers to the output. The inputs * have independent widths, to reflect the arithmetic truth that the * width of a general power is the XXXX of the widths of the * inputs. * * Power may be signed. If so, the output should be sign extended * to fill in its result. * * - Part Select (IVL_LPM_PART_VP and IVL_LPM_PART_PV) * There are two part select devices, one that extracts a part from a * vector, and another that writes a part of a vector. The _VP is * Vector-to-Part, and _PV is Part-to-Vector. The _VP form is meant to * model part/bin selects in r-value expressions, where the _PV from * is meant to model part selects in l-value nets. * * In both cases, ivl_lpm_data(0) is the input pin, and ivl_lpm_q is the * output. In the case of the _VP device, the vector is input and the * part is the output. In the case of the _PV device, the part is the * input and the vector is the output. * * If the base of the part select is non-constant, then * ivl_lpm_data(1) is non-nil and is the select, or base, address of * the part. If this pin is nil, then the constant base is used * instead. * * Also in both cases, the width of the device is the width of the * part. In the _VP case, this is obvious as the output nexus has the * part width. In the _PV case, this is a little less obvious, but * still correct. The output being written to the wider vector is * indeed the width of the part, even though it is written to a wider * gate. The target will need to handle this case specially. * * - Bi-directional Part Select (IVL_LPM_PART_BI) * This is not exactly a part select but a bi-directional partial link * of two nexa with different widths. This is used to implement tran * devices and inout ports in certain cases. The device width is the * width of the part. The ivl_lpm_q is the part end, and the * ivl_lpm_data(0) is the non-part end. * * - Comparisons (IVL_LPM_CMP_GT/GE/EQ/NE/EEQ/NEE) * These devices have two inputs, available by the ivl_lpm_data() * function, and one output available by the ivl_lpm_q function. The * output width is always 1, but the ivl_lpm_width() returns the width * of the inputs. Both inputs must have the same width. * * The CMP_GE and CMP_GT nodes may also be signed or unsigned, with * the obvious implications. The widths are matched by the compiler * (so the target need not worry about sign extension) but when doing * magnitude compare, the signedness does matter. In any case, the * result of the compare is always unsigned. * * - Mux Device (IVL_LPM_MUX) * The MUX device has a q output, a select input, and a number of data * inputs. The ivl_lpm_q output and the ivl_lpm_data inputs all have * the width from the ivl_lpm_width() method. The Select input, from * ivl_lpm_select, has the width ivl_lpm_selects(). * * The ivl_lpm_data() method returns the inputs of the MUX device. The * ivl_lpm_size() method returns the number of data inputs there * are. All the data inputs have the same width, the width of the * ivl_lpm_q output. The type of the device is divined from the * inputs and the Q. All the types must be exactly the same. * * - D-FlipFlop (IVL_LPM_FF) * This data is an edge sensitive register. The ivl_lpm_q output and * single ivl_lpm_data input are the same with, ivl_lpm_width. This * device carries a vector like other LPM devices. * * - Memory port (IVL_LPM_RAM) (deprecated in favor of IVL_LPM_ARRAY) * These are structural ports into a memory device. They represent * address/data ports of a memory device that the context can hook to * for read or write. Read devices have an ivl_lpm_q output port that * is the data being read. * * The ivl_lpm_memory function returns the ivl_memory_t for the memory * that the port access. The ivl_lpm_width for the port then must * match the ivl_memory_width of the memory device. * * Read or write, the ivl_lpm_select nexus is the address. The * ivl_lpm_selects function returns the vector width of the * address. The range of the address is always from 0 to the memory * size-1 -- the canonical form. It is up to the compiler to generate * offsets to correct for a range declaration. * * Read ports use the ivl_lpm_q as the data output, and write ports * use the ivl_lpm_data(0) as the input. In either case the width of * the vector matches the width of the memory itself. * * - Reduction operators (IVL_LPM_RE_*) * These devices have one input, a vector, and generate a single bit * result. The width from the ivl_lpm_width is the width of the input * vector. * * - Repeat Node (IVL_LPM_REPEAT) * This node takes as input a single vector, and outputs a single * vector. The ivl_lpm_width if this node is the width of the *output* * vector. The ivl_lpm_size() returns the number of times the input is * repeated to get the desired width. The ivl core assures that the * input vector is exactly ivl_lpm_width() / ivl_lpm_size() bits. * * - Sign Exend (IVL_LPM_SIGN_EXT) * This node takes a single input and generates a single output. The * input must be signed, and the output will be a vector sign extended * to the desired width. The ivl_lpm_width() value is the output * width, the input will be whatever it wants to be. * * - Shifts (IVL_LPM_SHIFTL/SHIFTR) * This node takes two inputs, a vector and a shift distance. The * ivl_lpm_data(0) nexus is the vector input, and the ivl_lpm_data(1) * the shift distance. The vector input is the same width as the * output, but the distance has its own width. * * The ivl_lpm_signed() flag means for IVL_LPM_SHIFTR that the right * shift is *signed*. For SHIFTL, then signed-ness is meaningless. * * - System function call (IVL_LPM_SFUNC) * This device represents a netlist call to a system function. The * inputs to the device are passed to a system function, and the * result is sent via the output. The ivl_lpm_q function returns the * output nexus. * * The ivl_lpm_size function returns the number of arguments, and the * ivl_lpm_data(net,N) returns the nexa for the argument. * * The ivl_lpm_string(net) function returns the name of the system * function (i.e. "$display") that was found in the source code. The * compiler does little checking of that name. * * The ivl_lpm_trigger function retrieves the trigger event that * indicates when the system function needs to be re-evaluated. If * there is no trigger event, the system function only needs to be * re-evaluated when a change is detected on its input ports. * * - User Function Call (IVL_LPM_UFUNC) * This device is special as it represents a call to a user defined * function (behavioral code) within a netlist. The inputs to the * function are connected to the net, as is the output. * * The function definition is associated with a scope, and the * ivl_lpm_define function returns the scope that is that definition. * See the ivl_scope_* functions for how to get at the actual * definition. * * As with many LPM nodes, the ivl_lpm_q function returns the nexus * for the signal function return value. The width of this nexus must * exactly match the width of the device from ivl_lpm_width. * * The ivl_lpm_data function retrieves the nexa for all the input * ports. The ivl_lpm_size function returns the number of inputs for * the device, and the ivl_lpm_data() function index argument selects * the port to retrieve. Each port is sized independently. * * The ivl_lpm_trigger function retrieves the trigger event that * indicates when the user function needs to be re-evaluated. If * there is no trigger event, the user function only needs to be * re-evaluated when a change is detected on its input ports. */ extern const char* ivl_lpm_name(ivl_lpm_t net); /* (Obsolete) */ extern const char* ivl_lpm_basename(ivl_lpm_t net); extern ivl_expr_t ivl_lpm_delay(ivl_lpm_t net, unsigned transition); extern ivl_scope_t ivl_lpm_scope(ivl_lpm_t net); extern int ivl_lpm_signed(ivl_lpm_t net); extern ivl_lpm_type_t ivl_lpm_type(ivl_lpm_t net); extern unsigned ivl_lpm_width(ivl_lpm_t net); extern ivl_event_t ivl_lpm_trigger(ivl_lpm_t net); /* IVL_LPM_FF */ extern ivl_nexus_t ivl_lpm_async_clr(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_async_set(ivl_lpm_t net); extern ivl_expr_t ivl_lpm_aset_value(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_sync_clr(ivl_lpm_t net); extern ivl_nexus_t ivl_lpm_sync_set(ivl_lpm_t net); extern ivl_expr_t ivl_lpm_sset_value(ivl_lpm_t net); /* IVL_LPM_ARRAY */ extern ivl_signal_t ivl_lpm_array(ivl_lpm_t net); /* IVL_LPM_PART */ extern unsigned ivl_lpm_base(ivl_lpm_t net); /* IVL_LPM_FF */ extern ivl_nexus_t ivl_lpm_clk(ivl_lpm_t net); /* IVL_LPM_UFUNC */ extern ivl_scope_t ivl_lpm_define(ivl_lpm_t net); /* IVL_LPM_FF */ extern ivl_nexus_t ivl_lpm_enable(ivl_lpm_t net); /* IVL_LPM_ADD IVL_LPM_CONCAT IVL_LPM_FF IVL_LPM_PART IVL_LPM_MULT IVL_LPM_MUX IVL_LPM_POW IVL_LPM_SHIFTL IVL_LPM_SHIFTR IVL_LPM_SUB IVL_LPM_UFUNC */ extern ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx); /* IVL_LPM_ADD IVL_LPM_MULT IVL_LPM_POW IVL_LPM_SUB */ extern ivl_nexus_t ivl_lpm_datab(ivl_lpm_t net, unsigned idx); /* IVL_LPM_ADD IVL_LPM_FF IVL_LPM_MULT IVL_LPM_PART IVL_LPM_POW IVL_LPM_SUB IVL_LPM_UFUNC */ extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx); /* IVL_LPM_MUX */ extern unsigned ivl_lpm_selects(ivl_lpm_t net); /* IVL_LPM_MUX */ extern ivl_nexus_t ivl_lpm_select(ivl_lpm_t net); /* IVL_LPM_CONCAT IVL_LPM_MUX IVL_LPM_REPEAT IVL_LPM_UFUNC */ extern unsigned ivl_lpm_size(ivl_lpm_t net); /* IVL_LPM_SFUNC */ extern const char*ivl_lpm_string(ivl_lpm_t net); /* LVAL * The l-values of assignments are concatenation of ivl_lval_t * objects. Each lvi_lval_t object is an assignment to a var or a * memory, through a bit select, part select or word select. * * Var lvals are things like assignments to a part select or a bit * select. Assignment to the whole variable is a special case of a * part select, as is a bit select with a constant expression. * * ivl_lval_width * The width of a vector that this lval can receive. This accounts * for the local part selecting I might to in the lval object, as * well as the target object width. * * ivl_lval_mux * If the l-value includes a bit select expression, this method * returns an ivl_expr_t that represents that * expression. Otherwise, it returns 0. * * (Should this be combined with ivl_lval_idx? -Ed) * * ivl_lval_mem (deprecated) * If the l-value is a memory, this method returns an * ivl_memory_t that represents that memory. Otherwise, it * returns 0. * * ivl_lval_sig * If the l-value is a variable, this method returns the signal * object that is the target of the assign. * * ivl_lval_part_off * The part select of the signal is based here. This is the * canonical index of bit-0 of the part select. The return value is * an ivl_expr_t. If the return value is nil, then take the offset * as zero. Otherwise, evaluate the expression to get the offset. * * ivl_lval_idx * If the l-value is a memory, this method returns an * ivl_expr_t that represents the index expression. Otherwise, it * returns 0. * * SEMANTIC NOTES * The ivl_lval_width is not necessarily the same as the width of the * signal or memory word it represents. It is the width of the vector * it receives and assigns. This may be less than the width of the * signal (or even 1) if only a part of the l-value signal is to be * assigned. * * The ivl_lval_part_off is the canonical base of a part or * bit select. * * - Memory words (Replace this with Array words below) * If the l-value is a memory word, the ivl_lval_mem function returns * a non-nil value. The ivl_lval_idx function will return an * expression that calculates an address for the memory. The compiler * will assure that the ivl_lval_width will exactly match the * ivl_memory_width of the memory word. * * - Array words * If the l-value is an array, then ivl_lval_idx function will return * an expression that calculates the address of the array word. If * the referenced signal has more than one word, this expression must * be present. If the signal has exactly one word (it is not an array) * then the ivl_lval_idx expression must *not* be present. * * For array words, the ivl_lval_width is the width of the word. */ extern unsigned ivl_lval_width(ivl_lval_t net); extern ivl_expr_t ivl_lval_mux(ivl_lval_t net); /* XXXX Obsolete? */ extern ivl_expr_t ivl_lval_idx(ivl_lval_t net); extern ivl_expr_t ivl_lval_part_off(ivl_lval_t net); extern ivl_signal_t ivl_lval_sig(ivl_lval_t net); /* NEXUS * connections of signals and nodes is handled by single-bit * nexus. These functions manage the ivl_nexus_t object. They also * manage the ivl_nexus_ptr_t objects that are closely related to the * nexus. * * ivl_nexus_name * Each nexus is given a name, typically derived from the signals * connected to it, but completely made up if need be. The name of * every nexus is unique. * * ivl_nexus_ptrs * This function returns the number of pointers that are held by * the nexus. It should always return at least 1. The pointer * proper is accessed by index. * * ivl_nexus_ptr * Return a nexus pointer given the nexus and an index. * * ivl_nexus_set_private * ivl_nexus_get_private * The target module often needs to associate data with a nexus for * later use when the nexus is encountered associated with a * device. These methods allow the code generator to store to or * retrieve from a nexus a void* of private data. This pointer is * guaranteed to be 0 before the target module is invoked. * * Once an ivl_nexus_ptr_t is selected by the ivl_nexus_ptr method, * the properties of the pointer can be accessed by the following * methods: * * ivl_nexus_ptr_pin * This returns the pin number of the device where this nexus * points. It is the bit within the signal or logic device that is * connected to the nexus. * * If the target is an LPM device, then this value is zero, and it * is up to the application to find the pin that refers to this * nexus. The problem is that LPM devices do not have a pinout per * se, the pins all have specific names. * * ivl_nexus_ptr_con * If this is a pointer to a magic constant device, then this * returns the net_const object. * * ivl_nexus_ptr_drive0 * ivl_nexus_ptr_drive1 * These are the 0 and 1 strength values for the devices. For most * devices, these values are fixed by the description in the * original source, with the default as IVL_DR_STRONG. For pins * that are input only, drive0 and drive1 are both IVL_DR_HiZ. * * The strength of strength-aware devices (such as nmos devices) * does not really matter, as long at the output is not * IVL_DR_HiZ. Testing for HiZ drivers is how code generators * detect inputs. * * ivl_nexus_ptr_log * If the target object is an ivl_net_logic_t, this method returns * the object. Otherwise, this method returns 0. * * ivl_nexus_ptr_lpm * If the target object is an ivl_lpm_t, this method returns the * object. Otherwise, this method returns 0. * * ivl_nexus_ptr_sig * If the target object is an ivl_signal_t, this method returns the * object. If the target is not a signal, this method returns 0. * * SEMANTIC NOTES * All the device pins that connect to a nexus have the same * type. That means, for example, that vector pins have the same * width. The compiler will insure this is so. */ extern const char* ivl_nexus_name(ivl_nexus_t net) __attribute__((deprecated)); extern unsigned ivl_nexus_ptrs(ivl_nexus_t net); extern ivl_nexus_ptr_t ivl_nexus_ptr(ivl_nexus_t net, unsigned idx); extern void ivl_nexus_set_private(ivl_nexus_t net, void*data); extern void* ivl_nexus_get_private(ivl_nexus_t net); extern ivl_drive_t ivl_nexus_ptr_drive0(ivl_nexus_ptr_t net); extern ivl_drive_t ivl_nexus_ptr_drive1(ivl_nexus_ptr_t net); extern unsigned ivl_nexus_ptr_pin(ivl_nexus_ptr_t net); extern ivl_branch_t ivl_nexus_ptr_branch(ivl_nexus_ptr_t net); extern ivl_net_const_t ivl_nexus_ptr_con(ivl_nexus_ptr_t net); extern ivl_net_logic_t ivl_nexus_ptr_log(ivl_nexus_ptr_t net); extern ivl_lpm_t ivl_nexus_ptr_lpm(ivl_nexus_ptr_t net); extern ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net); extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net); /* PARAMETER * Parameters are named constants associated with a scope. The user * may set in the Verilog source the value of parameters, and that * leads to ivl_parameter_t objects contained in the ivl_scope_t * objects. * * Parameters are essentially named constants. These constant values * can be accessed by looking at the scope (using ivl_scope_param) or * they can be discovered when they are used, via the * ivl_expr_parameter function. The fact that a constant has a name * (i.e. is a parameter) does not otherwise impose on the value or * interpretation of the constant expression so far as ivl_target is * concerned. The target may need this information, or may choose to * completely ignore it. * * ivl_parameter_basename * return the name of the parameter. * * ivl_parameter_scope * Return the scope of the parameter. The parameter name is only * unique within its scope. * * ivl_parameter_expr * Return the value of the parameter. This should be a simple * constant expression, an IVL_EX_STRING or IVL_EX_NUMBER. * * ivl_parameter_file * ivl_parameter_lineno * Returns the file and line where this parameter is define */ extern const char* ivl_parameter_basename(ivl_parameter_t net); extern ivl_scope_t ivl_parameter_scope(ivl_parameter_t net); extern ivl_expr_t ivl_parameter_expr(ivl_parameter_t net); extern const char* ivl_parameter_file(ivl_parameter_t net); extern unsigned ivl_parameter_lineno(ivl_parameter_t net); /* SCOPE * Scopes of various sort have these properties. Use these methods to * access them. Scopes come to exist in the elaborated design * generally when a module is instantiated, though they also come from * named blocks, tasks and functions. * * - module instances (IVL_SCT_MODULE) * A module instance scope may contain events, logic gates, lpm * nodes, signals, and possibly children. The children are further * instances, or function/task scopes. Module instances do *not* * contain a definition. * * - function scopes (IVL_SCT_FUNCTION) * These scopes represent functions. A function may not be a root, * so it is contained within a module instance scope. A function is * required to have a definition (in the form of a statement) and a * signal (IVL_SIG_REG) that is its return value. * * A single function scope is created each time the module with the * definition is instantiated. * * * - task scopes (IVL_SCT_TASK) * [...] * * ivl_scope_attr_cnt * ivl_scope_attr_val * A scope may have attributes attached to it. These functions * allow the target to access the attributes values. * * ivl_scope_children * A scope may in turn contain other scopes. This method iterates * through all the child scopes of a given scope. If the function * returns any value other than 0, the iteration stops and the * method returns that value. Otherwise, iteration continues until * the children run out. * * If the scope has no children, this method will return 0 and * otherwise do nothing. * * ivl_scope_def * Task definition scopes carry a task definition, in the form of * a statement. This method accesses that definition. The * ivl_scope_def function must return a statement for scopes that * are type FUNCTION or TASK, and must return nil otherwise. * * ivl_scope_def_file * ivl_scope_def_lineno * Returns the file and line where this scope is defined. * * ivl_scope_event * ivl_scope_events * Scopes have 0 or more event objects in them. * * ivl_scope_file * ivl_scope_lineno * Returns the instantiation file and line for this scope. * * ivl_scope_is_auto * Is the task or function declared to be automatic? * * ivl_scope_is_cell * Is the module defined to be a cell? * * ivl_scope_var * ivl_scope_vars * REMOVED * * ivl_scope_log * ivl_scope_logs * Scopes have 0 or more logic devices in them. A logic device is * represented by ivl_logic_t. * * ivl_scope_lpm * ivl_scope_lpms * Scopes have 0 or more LPM devices in them. These functions access * those devices. * * ivl_scope_name * ivl_scope_basename * Every scope has a hierarchical name. This name is also a prefix * of all the names of objects contained within the scope. The * ivl_scope_basename is the name of the scope without the included * hierarchy. * * ivl_scope_param * ivl_scope_params * A scope has zero or more named parameters. These parameters have * a name and an expression value. * * ivl_scope_parent * If this is a non-root scope, then the parent is the scope that * contains this scope. Otherwise, the parent is nil. * * ivl_scope_port * ivl_scope_ports * Scopes that are functions or tasks have ports defined by * signals. These methods access the ports by name. * * If this scope represents a function, then the ports list * includes the return value, as port 0. The remaining ports are * the input ports in order. * * ivl_scope_sig * ivl_scope_sigs * Scopes have 0 or more signals in them. These signals are * anything that can become and ivl_signal_t, include synthetic * signals generated by the compiler. * * ivl_scope_time_precision * Scopes have their own intrinsic time precision, typically from * the timescale compiler directive. This method returns the * precision as a signed power of 10 value. * * ivl_scope_time_units * Scopes have their own intrinsic time units, typically from the * timescale compiler directive. This method returns the units as a * signed power of 10 value. * * ivl_scope_type * ivl_scope_tname * Scopes have a type and a type name. For example, if a scope is * an instance of module foo, its type is IVL_SCT_MODULE and its * type name is "foo". This is different from the instance name * returned by ivl_scope_name above. */ extern unsigned ivl_scope_attr_cnt(ivl_scope_t net); extern ivl_attribute_t ivl_scope_attr_val(ivl_scope_t net, unsigned idx); extern int ivl_scope_children(ivl_scope_t net, ivl_scope_f func, void*cd); extern ivl_statement_t ivl_scope_def(ivl_scope_t net); extern const char* ivl_scope_def_file(ivl_scope_t net); extern unsigned ivl_scope_def_lineno(ivl_scope_t net); extern unsigned ivl_scope_events(ivl_scope_t net); extern ivl_event_t ivl_scope_event(ivl_scope_t net, unsigned idx); extern const char* ivl_scope_file(ivl_scope_t net); extern unsigned ivl_scope_is_auto(ivl_scope_t net); extern unsigned ivl_scope_is_cell(ivl_scope_t net); extern unsigned ivl_scope_lineno(ivl_scope_t net); extern unsigned ivl_scope_logs(ivl_scope_t net); extern ivl_net_logic_t ivl_scope_log(ivl_scope_t net, unsigned idx); extern unsigned ivl_scope_lpms(ivl_scope_t net); extern ivl_lpm_t ivl_scope_lpm(ivl_scope_t, unsigned idx); extern const char* ivl_scope_name(ivl_scope_t net); extern const char* ivl_scope_basename(ivl_scope_t net); extern unsigned ivl_scope_params(ivl_scope_t net); extern ivl_parameter_t ivl_scope_param(ivl_scope_t net, unsigned idx); extern ivl_scope_t ivl_scope_parent(ivl_scope_t net); extern unsigned ivl_scope_ports(ivl_scope_t net); extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx); extern unsigned ivl_scope_sigs(ivl_scope_t net); extern ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx); extern unsigned ivl_scope_switches(ivl_scope_t net); extern ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx); extern ivl_scope_type_t ivl_scope_type(ivl_scope_t net); extern const char* ivl_scope_tname(ivl_scope_t net); extern int ivl_scope_time_precision(ivl_scope_t net); extern int ivl_scope_time_units(ivl_scope_t net); /* SIGNALS * Signals are named things in the Verilog source, like wires and * regs, and also named things that are created as temporaries during * certain elaboration or optimization steps. A signal may also be a * port of a module or task. * * Signals have a name (obviously) and types. A signal may also be * signed or unsigned. * * ivl_signal_nex * This is the nexus of the signal. This is used for managing * connections to the rest of the net. There is exactly one pin for * each word of a signal. Each word may in turn be a vector. The * word address is the zero-based index for the word. It is up to * the context to translate different bases to the canonical address. * * ivl_signal_array_base * ivl_signal_array_count * ivl_signal_array_addr_swapped * The signal may be arrayed. If so, the array_count is >1. Each * word of the array has its own nexus. The array_base is the * address in the Verilog source for the canonical zero word. This * may be negative, positive or zero. The array addresses may be * reversed/swapped. * * Note that arraying of the signal into words is distinct from the * vectors. The width of a signal is the width of a WORD. * * ivl_signal_dimensions * The signal may be an array (of vectors) in which case this * function returns >0, the number of dimensions of the array. * * ivl_signal_discipline * If the signal has been declared with a domain (Verilog-AMS) then * this function will return a non-nil ivl_discipline_t. * * ivl_signal_msb * ivl_signal_lsb * ivl_signal_width * These functions return the left and right indices, respectively, * of the signal. If the signal is a scalar, both return 0. However, * it doesn't mean that the signal is a scalar if both return 0, one * can have a vector with 0 as both indices. * * ivl_signal_port * If the signal is a port to a module, this function returns the * port direction. If the signal is not a port, it returns * IVL_SIP_NONE. * * ivl_signal_signed * A signal, which is a vector, may be signed. In Verilog 2000, any * net or variable may be signed. This function returns true if the * signal is signed. * * ivl_signal_local * A signal that was generated by the compiler as a place holder is * marked as local. * * ivl_signal_type * Return the type of the signal, i.e., reg, wire, tri0, etc. * * ivl_signal_data_type * Return the data type of the signal, i.e. logic, real, bool, * etc. All the signals connected to a nexus should have the same * data type * * ivl_signal_npath * ivl_signal_path * This function returns the delay path object for the signal. The * delay path has this signal as the output, the source is attached * to the delay path itself. * * ivl_signal_name (DEPRECATED) * This function returns the fully scoped hierarchical name for the * signal. The name refers to the entire vector that is the signal. * * NOTE: This function is deprecated. The hierarchical name is too * vague a construct when escaped names can have . characters in * them. Do no use this function in new code, it will disappear. * * ivl_signal_basename * This function returns the name of the signal, without the scope * information. This is the tail of the signal name. Since Verilog * has an escape syntax, this name can contain any ASCII * characters, except NULL or white space. The leading \ and * trailing ' ' of escaped names in Verilog source are not part of * the name, so not included here. * * ivl_signal_attr * Icarus Verilog supports attaching attributes to signals, with * the attribute value (a string) associated with a key. This * function returns the attribute value for the given key. If the * key does not exist, the function returns 0. * * ivl_signal_file * ivl_signal_lineno * Returns the file and line where this signal is defined. */ extern ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word); extern int ivl_signal_array_base(ivl_signal_t net); extern unsigned ivl_signal_array_count(ivl_signal_t net); extern unsigned ivl_signal_array_addr_swapped(ivl_signal_t net); extern unsigned ivl_signal_dimensions(ivl_signal_t net); extern ivl_discipline_t ivl_signal_discipline(ivl_signal_t net); extern int ivl_signal_msb(ivl_signal_t net); extern int ivl_signal_lsb(ivl_signal_t net); extern unsigned ivl_signal_width(ivl_signal_t net); extern ivl_signal_port_t ivl_signal_port(ivl_signal_t net); extern int ivl_signal_signed(ivl_signal_t net); extern int ivl_signal_integer(ivl_signal_t net); extern int ivl_signal_local(ivl_signal_t net); extern unsigned ivl_signal_npath(ivl_signal_t net); extern ivl_delaypath_t ivl_signal_path(ivl_signal_t net, unsigned idx); extern ivl_signal_type_t ivl_signal_type(ivl_signal_t net); extern ivl_variable_type_t ivl_signal_data_type(ivl_signal_t net); extern const char* ivl_signal_name(ivl_signal_t net); extern const char* ivl_signal_basename(ivl_signal_t net); extern const char* ivl_signal_attr(ivl_signal_t net, const char*key); extern const char* ivl_signal_file(ivl_signal_t net); extern unsigned ivl_signal_lineno(ivl_signal_t net); extern unsigned ivl_signal_attr_cnt(ivl_signal_t net); extern ivl_attribute_t ivl_signal_attr_val(ivl_signal_t net, unsigned idx); /* ivl_nexus_t ivl_signal_pin(ivl_signal_t net, unsigned idx); */ /* unsigned ivl_signal_pins(ivl_signal_t net); */ /* * These functions get information about a process. A process is * an initial or always block within the original Verilog source, that * is translated into a type and a single statement. (The statement * may be a compound statement.) * * ivl_process_type * ivl_process_analog * The ivl_process_type function returns the type of the process, * an "initial" or "always" statement. The ivl_process_analog * returns true if the process is analog. * * ivl_process_scope * A process is placed in a scope. The statement within the process * operates within the scope of the process unless there are calls * outside the scope. * * The ivl_process_stmt function gets the statement that forms the * process. See the statement related functions for how to manipulate * statements. * * Processes can have attributes attached to them. the attr_cnt and * attr_val methods return those attributes. */ extern ivl_process_type_t ivl_process_type(ivl_process_t net); extern int ivl_process_analog(ivl_process_t net); extern ivl_scope_t ivl_process_scope(ivl_process_t net); extern ivl_statement_t ivl_process_stmt(ivl_process_t net); extern unsigned ivl_process_attr_cnt(ivl_process_t net); extern ivl_attribute_t ivl_process_attr_val(ivl_process_t net, unsigned idx); extern const char* ivl_process_file(ivl_process_t net); extern unsigned ivl_process_lineno(ivl_process_t net); /* * These functions manage statements of various type. This includes * all the different kinds of statements (as enumerated in * ivl_statement_type_t) that might occur in behavioral code. * * The ivl_statement_type() function returns the type code for the * statement. This is the major type, and implies which of the later * functions are applicable to the statement. * * the ivl_statement_file() and _lineno() functions return the source * file and line number of the statement in the Verilog source. This * information is useful for diagnostic information. */ extern ivl_statement_type_t ivl_statement_type(ivl_statement_t net); extern const char* ivl_stmt_file(ivl_statement_t net); extern unsigned ivl_stmt_lineno(ivl_statement_t net); /* * The following functions retrieve specific single values from the * statement. These values are the bits of data and parameters that * make up the statement. Many of these functions apply to more than * one type of statement, so the comment in front of them tells which * statement types can be passed to the function. * * FUNCTION SUMMARY: * * ivl_stmt_block_scope * If the block is named, then there is a scope associated with * this. The code generator may need to know this in order to * handle disable statements. * * ivl_stmt_events * ivl_stmt_nevent * Statements that have event arguments (TRIGGER and WAIT) make * those event objects available through these methods. * * ivl_stmt_lval * ivl_stmt_lvals * Return the number of l-values for an assignment statement, or * the specific l-value. If there is more than 1 l-value, then the * l-values are presumed to be vector values concatenated together * from msb (idx==0) to lsb. * * ivl_stmt_rval * Return the rval expression of the assignment. This is the value * that is to be calculated and assigned to the l-value in all the * assignment statements. * * ivl_stmt_sub_stmt * Some statements contain a single, subordinate statement. An * example is the IVL_ST_WAIT, which contains the statement to be * executed after the wait completes. This method retrieves that * sub-statement. * * SEMANTIC NOTES: * * - Assignments: IVL_ST_ASSIGN, IVL_ST_ASSIGN_NB, IVL_CASSIGN, IVL_ST_FORCE * * The assignments support ivl_stmt_rval to get the r-value expression * that is to be assign to the l-value, and ivl_stmt_lval[s] to get * the l-value that receives the value. The compiler has already made * sure that the types (l-value and r-value) are compatible. * * If the l-value is a vector, then the compiler also makes sure the * expression width of the r-values matches. It handles padding or * operator sizing as needed to get the width exactly right. * * The blocking and non-blocking assignments may also have an internal * delay. These are of the form "lval = # rval;" and is * the internal delay expression. (It is internal because it is inside * the statement.) The ivl_stmt_delay_expr function returns the * expression for the delay, or nil if there is no delay expression. * * - IVL_ST_CASSIGN * This reflects a procedural continuous assignment to an l-value. The * l-value is the same as any other assignment (use ivl_stmt_lval). * * The value to be assigned is an ivl_expr_t retrieved by the * ivl_stmt_rval function. The run time is expected to calculate the * value of the expression at the assignment, then continuous assign * that constant value. If the expression is non-constant, the code * generator is supposed to know what to do about that, too. * * - IVL_ST_CONTRIB * This is an analog contribution statement. The ivl_stmt_lexp * function returns the l-value expression which is guaranteed to be a * branch access expression. The ivl_stmt_rval returns the r-value * expression for the assignment. * * - IVL_ST_DELAY, IVL_ST_DELAYX * These statement types are delay statements. They are a way to * attach a delay to a statement. The ivl_stmt_sub_stmt() function * gets the statement to be executed after the delay. If this is * IVL_ST_DELAY, then the ivl_stmt_delay_val function gets the * constant delay. If this is IVL_ST_DELAYX, then the * ivl_stmt_delay_expr gets the expression of the delay. In this case, * the expression is not necessarily constant. * * Whether constant or calculated, the resulting delay is in units of * simulation ticks. The compiler has already taken care of converting * the delay to the time scale/precision of the scope. * * - IVL_ST_FORCE * This is very much like IVL_ST_CASSIGN, but adds that l-values can * include nets (tri, wire, etc). Memory words are restricted from * force l-values, and also non-constant bit or part selects. The * compiler will assure these constraints are met. * * - IVL_ST_TRIGGER * This represents the "-> name" statement that sends a trigger to a * named event. The ivl_stmt_nevent function should always return 1, * and the ivl_stmt_events(net,0) function returns the target event, * as an ivl_event_t. The only behavior of this statement is to send a * "trigger" to the target event. * * - IVL_ST_WAIT * This is the edge sensitive wait (for event) statement. The * statement contains an array of events that are to be tested, and a * single statement that is to be executed when any of the array of * events triggers. * * the ivl_stmt_events function accesses the array of events to wait * for, and the ivl_stmt_sub_stmt function gets the sub-statement, * which may be null, that is to be executed when an event * triggers. The statement waits even if the sub-statement is nul. */ /* IVL_ST_BLOCK, IVL_ST_FORK */ extern unsigned ivl_stmt_block_count(ivl_statement_t net); /* IVL_ST_BLOCK, IVL_ST_FORK */ extern ivl_scope_t ivl_stmt_block_scope(ivl_statement_t net); /* IVL_ST_BLOCK, IVL_ST_FORK */ extern ivl_statement_t ivl_stmt_block_stmt(ivl_statement_t net, unsigned i); /* IVL_ST_UTASK IVL_ST_DISABLE */ extern ivl_scope_t ivl_stmt_call(ivl_statement_t net); /* IVL_ST_CASE,IVL_ST_CASER,IVL_ST_CASEX,IVL_ST_CASEZ */ extern unsigned ivl_stmt_case_count(ivl_statement_t net); /* IVL_ST_CASE,IVL_ST_CASER,IVL_ST_CASEX,IVL_ST_CASEZ */ extern ivl_expr_t ivl_stmt_case_expr(ivl_statement_t net, unsigned i); /* IVL_ST_CASE,IVL_ST_CASER,IVL_ST_CASEX,IVL_ST_CASEZ */ extern ivl_statement_t ivl_stmt_case_stmt(ivl_statement_t net, unsigned i); /* IVL_ST_CONDIT IVL_ST_CASE IVL_ST_REPEAT IVL_ST_WHILE */ extern ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net); /* IVL_ST_CONDIT */ extern ivl_statement_t ivl_stmt_cond_false(ivl_statement_t net); /* IVL_ST_CONDIT */ extern ivl_statement_t ivl_stmt_cond_true(ivl_statement_t net); /* IVL_ST_ASSIGN IVL_ST_ASSIGN_NB IVL_ST_DELAYX */ extern ivl_expr_t ivl_stmt_delay_expr(ivl_statement_t net); /* IVL_ST_DELAY */ extern uint64_t ivl_stmt_delay_val(ivl_statement_t net); /* IVL_ST_WAIT IVL_ST_TRIGGER */ extern unsigned ivl_stmt_nevent(ivl_statement_t net); extern ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx); /* IVL_ST_CONTRIB */ extern ivl_expr_t ivl_stmt_lexp(ivl_statement_t net); /* IVL_ST_ASSIGN IVL_ST_ASSIGN_NB IVL_ST_CASSIGN IVL_ST_DEASSIGN IVL_ST_FORCE IVL_ST_RELEASE */ extern ivl_lval_t ivl_stmt_lval(ivl_statement_t net, unsigned idx); /* IVL_ST_ASSIGN IVL_ST_ASSIGN_NB IVL_ST_CASSIGN IVL_ST_DEASSIGN IVL_ST_FORCE IVL_ST_RELEASE */ extern unsigned ivl_stmt_lvals(ivl_statement_t net); /* IVL_ST_ASSIGN IVL_ST_ASSIGN_NB IVL_ST_CASSIGN */ extern unsigned ivl_stmt_lwidth(ivl_statement_t net); /* IVL_ST_STASK */ extern const char* ivl_stmt_name(ivl_statement_t net); /* IVL_ST_STASK */ extern ivl_expr_t ivl_stmt_parm(ivl_statement_t net, unsigned idx); /* IVL_ST_STASK */ extern unsigned ivl_stmt_parm_count(ivl_statement_t net); /* IVL_ST_ASSIGN IVL_ST_ASSIGN_NB IVL_ST_CASSIGN IVL_ST_CONTRIB IVL_ST_FORCE */ extern ivl_expr_t ivl_stmt_rval(ivl_statement_t net); /* IVL_ST_DELAY, IVL_ST_DELAYX, IVL_ST_FOREVER, IVL_ST_REPEAT IVL_ST_WAIT, IVL_ST_WHILE */ extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net); /* SWITCHES * * The switches represent the tran devices in the design. * * FUNCTION SUMMARY * * ivl_switch_type * Return the enumerated value that is the type of the switch. * * ivl_switch_basename * This is the name given to the device in the source code. * * ivl_switch_a * ivl_switch_b * The a and b ports are the two ports of the switch. * * ivl_switch_enable * If the device has an enable (tranifX) then this is the enable * port. * * SEMANTIC NOTES * The a/b ports can be any type, but the types must exactly * match, including vector widths. The enable must be a scalar. * * The IVL_SW_TRAN_VP is an exception to the above. In this case, * the B side may be a different size, and the a side will have a * a fixed width. The unused bits are padded to Z on the A side. */ extern ivl_switch_type_t ivl_switch_type(ivl_switch_t net); extern ivl_scope_t ivl_switch_scope(ivl_switch_t net); extern const char*ivl_switch_basename(ivl_switch_t net); extern ivl_nexus_t ivl_switch_a(ivl_switch_t net); extern ivl_nexus_t ivl_switch_b(ivl_switch_t net); extern ivl_nexus_t ivl_switch_enable(ivl_switch_t net); extern ivl_island_t ivl_switch_island(ivl_switch_t net); /* These are only support for IVL_SW_TRAN_VP switches. */ extern unsigned ivl_switch_width(ivl_switch_t net); extern unsigned ivl_switch_part(ivl_switch_t net); extern unsigned ivl_switch_offset(ivl_switch_t net); /* Not implemented yet extern unsigned ivl_switch_attr_cnt(ivl_switch_t net); extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx); *** */ extern const char* ivl_switch_file(ivl_switch_t net); extern unsigned ivl_switch_lineno(ivl_switch_t net); #if defined(__MINGW32__) || defined (__CYGWIN32__) # define DLLEXPORT __declspec(dllexport) #else # define DLLEXPORT #endif extern DLLEXPORT int target_design(ivl_design_t des); extern DLLEXPORT const char* target_query(const char*key); /* target_design The "target_design" function is called once after the whole design is processed and available to the target. The target doesn't return from this function until it is finished with the design. The return value of this function should normally be zero. If the code generator detects errors, however, then the code generator returns a positive number to indicate the approximate number of errors detected (before it gave up.) Return values <0 are reserved for system and infrastructure errors. This function is implemented in the loaded target, and not in the ivl core. This function is how the target module is invoked. */ typedef int (*target_design_f)(ivl_design_t des); typedef const char* (*target_query_f) (const char*key); _END_DECL #endif verilog-0.9.7/PaxHeaders.14238/lexor_keyword.h0000644000202500001440000000005012204466647017276 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/lexor_keyword.h0000644000202500001440000000170712204466647016625 0ustar00steveusers00000000000000#ifndef __lexor_keyword_H #define __lexor_keyword_H /* * Copyright (c) 2000 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ extern int lexor_keyword_code (const char*str, unsigned len); #endif verilog-0.9.7/PaxHeaders.14238/nodangle.cc0000644000202500001440000000005012204466647016326 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/nodangle.cc0000644000202500001440000001572212204466647015657 0ustar00steveusers00000000000000/* * Copyright (c) 1999-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" /* * This functor scans the design looking for dangling objects and * excess local signals. These deletions are not necessarily required * for proper functioning of anything, but they can clean up the * appearance of design files that are generated. */ # include "functor.h" # include "netlist.h" # include "compiler.h" class nodangle_f : public functor_t { public: void event(Design*des, NetEvent*ev); void signal(Design*des, NetNet*sig); unsigned iteration; unsigned stotal, etotal; bool scontinue, econtinue; bool scomplete, ecomplete; }; void nodangle_f::event(Design*des, NetEvent*ev) { if (ecomplete) return; /* If there are no references to this event, then go right ahead and delete it. There is no use looking further at it. */ if ((ev->nwait() + ev->ntrig() + ev->nexpr()) == 0) { delete ev; etotal += 1; return; } if (iteration == 0) { /* Try to remove duplicate probes from the event. This is done as a separate initial pass to ensure similar events are detected as soon as possible in subsequent iterations. */ for (unsigned idx = 0 ; idx < ev->nprobe() ; idx += 1) { unsigned jdx = idx + 1; while (jdx < ev->nprobe()) { NetEvProbe*ip = ev->probe(idx); NetEvProbe*jp = ev->probe(jdx); if (ip->edge() != jp->edge()) { jdx += 1; continue; } bool fully_connected = true; for (unsigned jpin = 0; jpin < jp->pin_count(); jpin += 1) { unsigned ipin = 0; bool connected_flag = false; for (ipin = 0 ; ipin < ip->pin_count(); ipin += 1) if (connected(ip->pin(ipin), jp->pin(jpin))) { connected_flag = true; break; } if (!connected_flag) { fully_connected = false; break; } } if (fully_connected) { delete jp; } else { jdx += 1; } } } econtinue = true; } else { /* Postpone examining events in an automatic scope until the third (optional) pass. This will mean similar events are biased towards being stored in static scopes. */ if (ev->scope()->is_auto()) { if (iteration == 1) { econtinue = true; return; } } else { if (iteration == 2) { return; } } /* Try to find all the events that are similar to me, and replace their references with references to me. */ list match; ev->find_similar_event(match); for (list::iterator idx = match.begin() ; idx != match.end() ; idx ++) { NetEvent*tmp = *idx; assert(tmp != ev); tmp ->replace_event(ev); } } } void nodangle_f::signal(Design*des, NetNet*sig) { if (scomplete) return; /* Cannot delete signals referenced in an expression or an l-value. */ if (sig->get_refs() > 0) return; /* Cannot delete the ports of tasks, functions or modules. There are too many places where they are referenced. */ if ((sig->port_type() != NetNet::NOT_A_PORT) && ((sig->scope()->type() == NetScope::TASK) || (sig->scope()->type() == NetScope::FUNC) || (sig->scope()->type() == NetScope::MODULE))) return; /* Can't delete ports of cells. */ if ((sig->port_type() != NetNet::NOT_A_PORT) && (sig->scope()->attribute(perm_string::literal("ivl_synthesis_cell")) != verinum())) return; /* Check to see if the signal is completely unconnected. If all the bits are unlinked, then delete it. */ if (! sig->is_linked()) { delete sig; stotal += 1; return; } /* The remaining things can only be done to synthesized signals, not ones that appear in the original Verilog. */ if (! sig->local_flag()) return; /* Check to see if there is some significant signal connected to every pin of this signal. */ unsigned significant_flags = 0; for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1) { Nexus*nex = sig->pin(idx).nexus(); for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) { if (cur == &sig->pin(idx)) continue; NetNet*cursig = dynamic_cast(cur->get_obj()); if (cursig == 0) continue; if (cursig->local_flag()) continue; significant_flags += 1; break; } if (significant_flags <= idx) break; } /* If every pin is connected to another significant signal, then I can delete this one. */ if (significant_flags == sig->pin_count()) { scontinue = true; delete sig; stotal += 1; } } void nodangle(Design*des) { nodangle_f fun; fun.iteration = 0; fun.stotal = 0; fun.etotal = 0; fun.scomplete = false; fun.ecomplete = false; do { fun.scontinue = false; fun.econtinue = false; des->functor(&fun); fun.iteration += 1; fun.scomplete = !fun.scontinue; fun.ecomplete = !fun.econtinue; if (verbose_flag) { cout << " ... " << fun.iteration << " iterations" << " deleted " << fun.stotal << " dangling signals" << " and " << fun.etotal << " events." << endl; } } while (fun.scontinue || fun.econtinue); } verilog-0.9.7/PaxHeaders.14238/install-sh0000644000202500001440000000005012204466647016231 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/install-sh0000755000202500001440000001123512204466647015560 0ustar00steveusers00000000000000#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 verilog-0.9.7/PaxHeaders.14238/main.cc0000644000202500001440000000005012204466647015463 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/main.cc0000644000202500001440000007312612204466647015016 0ustar00steveusers00000000000000const char COPYRIGHT[] = "Copyright (c) 1998-2011 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "version_base.h" # include "version_tag.h" const char NOTICE[] = " This program is free software; you can redistribute it and/or modify\n" " it under the terms of the GNU General Public License as published by\n" " the Free Software Foundation; either version 2 of the License, or\n" " (at your option) any later version.\n" "\n" " This program is distributed in the hope that it will be useful,\n" " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" " GNU General Public License for more details.\n" "\n" " You should have received a copy of the GNU General Public License along\n" " with this program; if not, write to the Free Software Foundation, Inc.,\n" " 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n" ; # include # include # include # include # include # include # include # include # include #if defined(HAVE_TIMES) # include #endif #if defined(HAVE_GETOPT_H) # include #endif # include "pform.h" # include "parse_api.h" # include "PGenerate.h" # include "netlist.h" # include "target.h" # include "compiler.h" # include "discipline.h" # include "t-dll.h" #if defined(__MINGW32__) && !defined(HAVE_GETOPT_H) extern "C" int getopt(int argc, char*argv[], const char*fmt); extern "C" int optind; extern "C" const char*optarg; #endif #if defined(__CYGWIN32__) && !defined(HAVE_GETOPT_H) extern "C" int getopt(int argc, char*argv[], const char*fmt); extern "C" int optind; extern "C" const char*optarg; #endif /* Count errors detected in flag processing. */ unsigned flag_errors = 0; const char*basedir = strdup("."); /* * These are the language support control flags. These support which * language features (the generation) to support. The generation_flag * is a major mode, and the gn_* flags control specific sub-features. */ generation_t generation_flag = GN_DEFAULT; bool gn_icarus_misc_flag = true; bool gn_cadence_types_flag = true; bool gn_specify_blocks_flag = true; bool gn_io_range_error_flag = true; bool gn_strict_ca_eval_flag = false; bool gn_verilog_ams_flag = false; bool gn_system_verilog_flag = false; map flags; char*vpi_module_list = 0; map missing_modules; map library_file_map; list library_suff; list roots; char*ivlpp_string = 0; char* depfile_name = NULL; FILE *depend_file = NULL; /* * These are the warning enable flags. */ bool warn_implicit = false; bool warn_timescale = false; bool warn_portbinding = false; bool warn_inf_loop = false; bool warn_ob_select = false; bool warn_sens_entire_vec = false; bool warn_sens_entire_arr = false; bool error_implicit = false; /* * Debug message class flags. */ bool debug_scopes = false; bool debug_eval_tree = false; bool debug_elaborate = false; bool debug_elab_pexpr = false; bool debug_synth2 = false; bool debug_optimizer = false; /* * Miscellaneous flags. */ bool disable_virtual_pins = false; unsigned long array_size_limit = 16777216; // Minimum required by IEEE-1364? unsigned recursive_mod_limit = 10; /* * Verbose messages enabled. */ bool verbose_flag = false; unsigned integer_width = 32; int def_ts_units = 0; int def_ts_prec = 0; /* * Keep a heap of identifier strings that I encounter. This is a more * efficient way to allocate those strings. */ StringHeapLex lex_strings; StringHeapLex filename_strings; /* * In library searches, Windows file names are never case sensitive. */ #if defined(__MINGW32__) const bool CASE_SENSITIVE = false; #else const bool CASE_SENSITIVE = true; #endif /* * Are we doing synthesis? */ bool synthesis = false; extern void cprop(Design*des); extern void synth(Design*des); extern void synth2(Design*des); extern void syn_rules(Design*des); extern void nodangle(Design*des); typedef void (*net_func)(Design*); static struct net_func_map { const char*name; void (*func)(Design*); } func_table[] = { { "cprop", &cprop }, { "nodangle",&nodangle }, { "synth", &synth }, { "synth2", &synth2 }, { "syn-rules", &syn_rules }, { 0, 0 } }; queue net_func_queue; net_func name_to_net_func(const string&name) { for (unsigned idx = 0 ; func_table[idx].name ; idx += 1) if (name == func_table[idx].name) return func_table[idx].func; return 0; } const char *net_func_to_name(const net_func func) { for (unsigned idx = 0 ; func_table[idx].name ; idx += 1) if (func == func_table[idx].func) return func_table[idx].name; return "This cannot happen"; } static void process_generation_flag(const char*gen) { if (strcmp(gen,"1") == 0) { // FIXME: Deprecated for 1995 generation_flag = GN_VER1995; } else if (strcmp(gen,"2") == 0) { // FIXME: Deprecated for 2001 generation_flag = GN_VER2001; } else if (strcmp(gen,"2x") == 0) { // FIXME: Deprecated for 2001 generation_flag = GN_VER2001; gn_icarus_misc_flag = true; } else if (strcmp(gen,"1995") == 0) { generation_flag = GN_VER1995; } else if (strcmp(gen,"2001") == 0) { generation_flag = GN_VER2001; } else if (strcmp(gen,"2001-noconfig") == 0) { generation_flag = GN_VER2001_NOCONFIG; } else if (strcmp(gen,"2005") == 0) { generation_flag = GN_VER2005; } else if (strcmp(gen,"icarus-misc") == 0) { gn_icarus_misc_flag = true; } else if (strcmp(gen,"no-icarus-misc") == 0) { gn_icarus_misc_flag = false; } else if (strcmp(gen,"xtypes") == 0) { gn_cadence_types_flag = true; } else if (strcmp(gen,"no-xtypes") == 0) { gn_cadence_types_flag = false; } else if (strcmp(gen,"specify") == 0) { gn_specify_blocks_flag = true; } else if (strcmp(gen,"no-specify") == 0) { gn_specify_blocks_flag = false; } else if (strcmp(gen,"verilog-ams") == 0) { gn_verilog_ams_flag = true; } else if (strcmp(gen,"no-verilog-ams") == 0) { gn_verilog_ams_flag = false; } else if (strcmp(gen,"io-range-error") == 0) { gn_io_range_error_flag = true; } else if (strcmp(gen,"no-io-range-error") == 0) { gn_io_range_error_flag = false; } else if (strcmp(gen,"strict-ca-eval") == 0) { gn_strict_ca_eval_flag = true; } else if (strcmp(gen,"no-strict-ca-eval") == 0) { gn_strict_ca_eval_flag = false; } else if (strcmp(gen,"system-verilog") == 0) { gn_system_verilog_flag = true; } else { } } static void parm_to_flagmap(const string&flag) { string key; const char*value; unsigned off = flag.find('='); if (off > flag.size()) { key = flag; value = strdup(""); } else { key = flag.substr(0, off); value = strdup(flag.substr(off+1).c_str()); } flags[key] = value; } static void find_module_mention(map&check_map, Module*m); static void find_module_mention(map&check_map, PGenerate*s); /* * Convert a string to a time unit or precision. * * Returns true on failure. */ static bool get_ts_const(const char*&cp, int&res, bool is_units) { /* Check for the 1 digit. */ if (*cp != '1') { if (is_units) { cerr << "Error: Invalid +timescale units constant " "(1st digit)." << endl; } else { cerr << "Error: Invalid +timescale precision constant " "(1st digit)." << endl; } return true; } cp += 1; /* Check the number of zeros after the 1. */ res = strspn(cp, "0"); if (res > 2) { if (is_units) { cerr << "Error: Invalid +timescale units constant " "(number of zeros)." << endl; } else { cerr << "Error: Invalid +timescale precision constant " "(number of zeros)." << endl; } return true; } cp += res; /* Now process the scaling string. */ if (strncmp("s", cp, 1) == 0) { res -= 0; cp += 1; return false; } else if (strncmp("ms", cp, 2) == 0) { res -= 3; cp += 2; return false; } else if (strncmp("us", cp, 2) == 0) { res -= 6; cp += 2; return false; } else if (strncmp("ns", cp, 2) == 0) { res -= 9; cp += 2; return false; } else if (strncmp("ps", cp, 2) == 0) { res -= 12; cp += 2; return false; } else if (strncmp("fs", cp, 2) == 0) { res -= 15; cp += 2; return false; } if (is_units) { cerr << "Error: Invalid +timescale units scale." << endl; } else { cerr << "Error: Invalid +timescale precision scale." << endl; } return true; } /* * Process a string with the following form (no space allowed): * * num = < '1' | '10' | '100' > * scale = < 's' | 'ms' | 'us' | 'ns' | 'ps' | 'fs' > * * " '/' * * and set the default time units and precision if successful. * * Return true if we have an error processing the timescale string. */ static bool set_default_timescale(const char*ts_string) { /* Because this came from a command file we can not have embedded * space in this string. */ const char*cp = ts_string; int units = 0; int prec = 0; /* Get the time units. */ if (get_ts_const(cp, units, true)) return true; /* Skip the '/'. */ if (*cp != '/') { cerr << "Error: +timescale separator '/' is missing." << endl; return true; } cp += 1; /* Get the time precision. */ if (get_ts_const(cp, prec, false)) return true; /* The time unit must be greater than or equal to the precision. */ if (units < prec) { cerr << "Error: +timescale unit must not be less than the " "precision." << endl; return true; } /* We have valid units and precision so set the global defaults. */ def_ts_units = units; def_ts_prec = prec; return false; } /* * Read the contents of a config file. This file is a temporary * configuration file made by the compiler driver to carry the bulky * flags generated from the user. This reduces the size of the command * line needed to invoke ivl. * * Each line of the iconfig file has the format: * * : * * The is all the text after the ':' and up to but not * including the end of the line. Thus, white spaces and ':' * characters may appear here. * * The valid keys are: * * -y: * -yl: * -Y: * * -T: * Select which expression to use. * * -t: (obsolete) * Usually, "-t:dll" * * basedir: * Location to look for installed sub-components * * debug: * Activate a class of debug messages. * * depfile: * Give the path to an output dependency file. * * flag:= * Generic compiler flag strings. * * functor: * Append a named functor to the processing path. * * generation:<1|2|2x|xtypes|no-xtypes|specify|no-specify> * This is the generation flag * * ivlpp: * This specifies the ivlpp command line used to process * library modules as I read them in. * * iwidth: * This specifies the width of integer variables. (that is, * variables declared using the "integer" keyword.) * * library_file: * This marks that a source file with the given path is a * library. Any modules in that file are marked as library * modules. * * module: * Load a VPI module. * * out: * Path to the output file. * * sys_func: * Path to a system functions descriptor table * * root: * Specify a root module. There may be multiple of this. * * warnings: * Warning flag letters. */ bool had_timescale = false; static void read_iconfig_file(const char*ipath) { char buf[8*1024]; FILE*ifile = fopen(ipath, "r"); if (ifile == 0) { cerr << "ERROR: Unable to read config file: " << ipath << endl; return; } while (fgets(buf, sizeof buf, ifile) != 0) { if (buf[0] == '#') continue; char*cp = strchr(buf, ':'); if (cp == 0) continue; *cp++ = 0; char*ep = cp + strlen(cp); while (ep > cp) { ep -= 1; switch (*ep) { case '\r': case '\n': case ' ': case '\t': *ep = 0; break; default: ep = cp; } } if (strcmp(buf, "basedir") == 0) { free((void *)basedir); basedir = strdup(cp); } else if (strcmp(buf, "debug") == 0) { if (strcmp(cp, "scopes") == 0) { debug_scopes = true; cerr << "debug: Enable scopes debug" << endl; } else if (strcmp(cp,"eval_tree") == 0) { debug_eval_tree = true; cerr << "debug: Enable eval_tree debug" << endl; } else if (strcmp(cp,"elaborate") == 0) { debug_elaborate = true; cerr << "debug: Enable elaborate debug" << endl; } else if (strcmp(cp,"elab_pexpr") == 0) { debug_elab_pexpr = true; cerr << "debug: Enable elaborate-pexpr debug" << endl; } else if (strcmp(cp,"synth2") == 0) { debug_synth2 = true; cerr << "debug: Enable synth2 debug" << endl; } else if (strcmp(cp,"optimizer") == 0) { debug_optimizer = true; cerr << "debug: Enable optimizer debug" << endl; } else { } } else if (strcmp(buf, "depfile") == 0) { depfile_name = strdup(cp); } else if (strcmp(buf, "flag") == 0) { string parm = cp; parm_to_flagmap(parm); } else if (strcmp(buf,"functor") == 0) { if (strncmp(cp, "synth", 5) == 0) { synthesis = true; // We are doing synthesis. } net_func tmp = name_to_net_func(cp); if (tmp == 0) { cerr << "No such design transform function ``" << cp << "''." << endl; flag_errors += 1; break; } net_func_queue.push(tmp); } else if (strcmp(buf, "generation") == 0) { process_generation_flag(cp); } else if (strcmp(buf, "ivlpp") == 0) { ivlpp_string = strdup(cp); } else if (strcmp(buf, "iwidth") == 0) { integer_width = strtoul(cp,0,10); } else if (strcmp(buf, "library_file") == 0) { perm_string path = filename_strings.make(cp); library_file_map[path] = true; } else if (strcmp(buf,"module") == 0) { if (vpi_module_list == 0) { vpi_module_list = strdup(cp); } else { char*tmp = (char*)realloc(vpi_module_list, strlen(vpi_module_list) + strlen(cp) + 2); strcat(tmp, ","); strcat(tmp, cp); vpi_module_list = tmp; } flags["VPI_MODULE_LIST"] = vpi_module_list; } else if (strcmp(buf, "out") == 0) { free((void *)flags["-o"]); flags["-o"] = strdup(cp); } else if (strcmp(buf, "sys_func") == 0) { load_sys_func_table(cp); } else if (strcmp(buf, "root") == 0) { roots.push_back(lex_strings.make(cp)); } else if (strcmp(buf,"warnings") == 0) { /* Scan the warnings enable string for warning flags. */ for ( ; *cp ; cp += 1) switch (*cp) { case 'i': warn_implicit = true; break; case 'l': warn_inf_loop = true; break; case 's': warn_ob_select = true; break; case 'p': warn_portbinding = true; break; case 't': warn_timescale = true; break; case 'v': warn_sens_entire_vec = true; break; case 'a': warn_sens_entire_arr = true; break; default: break; } } else if (strcmp(buf, "-y") == 0) { build_library_index(cp, CASE_SENSITIVE); } else if (strcmp(buf, "-yl") == 0) { build_library_index(cp, false); } else if (strcmp(buf, "-Y") == 0) { library_suff.push_back(strdup(cp)); } else if (strcmp(buf,"-t") == 0) { // NO LONGER USED } else if (strcmp(buf,"-T") == 0) { if (strcmp(cp,"min") == 0) { min_typ_max_flag = MIN; min_typ_max_warn = 0; } else if (strcmp(cp,"typ") == 0) { min_typ_max_flag = TYP; min_typ_max_warn = 0; } else if (strcmp(cp,"max") == 0) { min_typ_max_flag = MAX; min_typ_max_warn = 0; } else { cerr << "Invalid argument (" << optarg << ") to -T flag." << endl; flag_errors += 1; } } else if (strcmp(buf, "timescale") == 0) { if (had_timescale) { cerr << "Command File: Warning: default timescale " "is being set multiple times." << endl; cerr << " : using the last valid " "+timescale found." << endl; } if (set_default_timescale(cp)) { cerr << " : with +timescale+" << cp << "+" << endl; flag_errors += 1; } else had_timescale = true; } } fclose(ifile); } extern Design* elaborate(list root); #if defined(HAVE_TIMES) static double cycles_diff(struct tms *a, struct tms *b) { clock_t aa = a->tms_utime + a->tms_stime + a->tms_cutime + a->tms_cstime; clock_t bb = b->tms_utime + b->tms_stime + b->tms_cutime + b->tms_cstime; return (aa-bb)/(double)sysconf(_SC_CLK_TCK); } #else // ! defined(HAVE_TIMES) // Provide dummies struct tms { int x; }; inline static void times(struct tms *) { } inline static double cycles_diff(struct tms *, struct tms *) { return 0; } #endif // ! defined(HAVE_TIMES) static void EOC_cleanup(void) { cleanup_sys_func_table(); for (list::iterator suf = library_suff.begin() ; suf != library_suff.end() ; suf ++ ) { free((void *)*suf); } library_suff.clear(); free((void *) basedir); free(ivlpp_string); free(depfile_name); for (map::iterator flg = flags.begin() ; flg != flags.end() ; flg ++ ) { free((void *)flg->second); } flags.clear(); lex_strings.cleanup(); filename_strings.cleanup(); } int main(int argc, char*argv[]) { bool help_flag = false; bool times_flag = false; bool version_flag = false; const char* net_path = 0; const char* pf_path = 0; int opt; struct tms cycles[5]; library_suff.push_back(strdup(".v")); vpi_module_list = strdup("system"); flags["VPI_MODULE_LIST"] = vpi_module_list; flags["-o"] = strdup("a.out"); min_typ_max_flag = TYP; min_typ_max_warn = 10; while ((opt = getopt(argc, argv, "C:f:hN:P:p:Vv")) != EOF) switch (opt) { case 'C': read_iconfig_file(optarg); break; case 'f': parm_to_flagmap(optarg); break; case 'h': help_flag = true; break; case 'N': net_path = optarg; break; case 'P': pf_path = optarg; break; case 'p': parm_to_flagmap(optarg); break; case 'v': verbose_flag = true; # if defined(HAVE_TIMES) times_flag = true; # endif break; case 'V': version_flag = true; break; default: flag_errors += 1; break; } if (flag_errors) return flag_errors; if (version_flag) { cout << "\nIcarus Verilog Parser/Elaborator version " << VERSION << " (" << VERSION_TAG << ")" << endl << endl; cout << COPYRIGHT << endl << endl; cout << NOTICE << endl; dll_target_obj.test_version(flags["DLL"]); return 0; } if (help_flag) { cout << "Icarus Verilog Parser/Elaborator version " << VERSION << " (" << VERSION_TAG << ")" << endl << "usage: ivl \n" "options:\n" "\t-C Config file from driver.\n" "\t-h Print usage information, and exit.\n" "\t-N Dump the elaborated netlist to .\n" "\t-P Write the parsed input to .\n" "\t-p Set a parameter value.\n" "\t-v Print progress indications" #if defined(HAVE_TIMES) " and execution times" #endif ".\n" "\t-V Print version and copyright information, and exit.\n" ; return 0; } if (optind == argc) { cerr << "No input files." << endl; return 1; } if( depfile_name ) { depend_file = fopen(depfile_name, "a"); if(! depend_file) { perror(depfile_name); } } lexor_keyword_mask = 0; switch (generation_flag) { case GN_VER1995: lexor_keyword_mask |= GN_KEYWORDS_1364_1995; break; case GN_VER2001: lexor_keyword_mask |= GN_KEYWORDS_1364_2001_CONFIG; case GN_VER2001_NOCONFIG: lexor_keyword_mask |= GN_KEYWORDS_1364_1995; lexor_keyword_mask |= GN_KEYWORDS_1364_2001; break; case GN_VER2005: lexor_keyword_mask |= GN_KEYWORDS_1364_1995; lexor_keyword_mask |= GN_KEYWORDS_1364_2001; lexor_keyword_mask |= GN_KEYWORDS_1364_2001_CONFIG; lexor_keyword_mask |= GN_KEYWORDS_1364_2005; break; } if (gn_cadence_types_flag) lexor_keyword_mask |= GN_KEYWORDS_ICARUS; if (gn_system_verilog_flag) lexor_keyword_mask |= GN_KEYWORDS_1800_2005; if (gn_verilog_ams_flag) lexor_keyword_mask |= GN_KEYWORDS_VAMS_2_3; if (verbose_flag) { if (times_flag) times(cycles+0); cout << "Using language generation: "; switch (generation_flag) { case GN_VER1995: cout << "IEEE1364-1995"; break; case GN_VER2001_NOCONFIG: cout << "IEEE1364-2001-noconfig"; break; case GN_VER2001: cout << "IEEE1364-2001"; break; case GN_VER2005: cout << "IEEE1364-2005"; break; } if (gn_verilog_ams_flag) cout << ",verilog-ams"; if (gn_specify_blocks_flag) cout << ",specify"; else cout << ",no-specify"; if (gn_cadence_types_flag) cout << ",xtypes"; else cout << ",no-xtypes"; if (gn_icarus_misc_flag) cout << ",icarus-misc"; else cout << ",no-icarus-misc"; cout << endl << "PARSING INPUT" << endl; } const char *flag_tmp = flags["DISABLE_VIRTUAL_PINS"]; if (flag_tmp) disable_virtual_pins = strcmp(flag_tmp,"true")==0; flag_tmp = flags["ARRAY_SIZE_LIMIT"]; if (flag_tmp) array_size_limit = strtoul(flag_tmp,NULL,0); flag_tmp = flags["RECURSIVE_MOD_LIMIT"]; if (flag_tmp) recursive_mod_limit = strtoul(flag_tmp,NULL,0); /* Parse the input. Make the pform. */ pform_set_timescale(def_ts_units, def_ts_prec, 0, 0); int rc = pform_parse(argv[optind]); if (pf_path) { ofstream out (pf_path); out << "PFORM DUMP NATURES:" << endl; for (map::iterator cur = natures.begin() ; cur != natures.end() ; cur ++ ) { pform_dump(out, (*cur).second); } out << "PFORM DUMP DISCIPLINES:" << endl; for (map::iterator cur = disciplines.begin() ; cur != disciplines.end() ; cur ++ ) { pform_dump(out, (*cur).second); } out << "PFORM DUMP MODULES:" << endl; for (map::iterator mod = pform_modules.begin() ; mod != pform_modules.end() ; mod ++ ) { pform_dump(out, (*mod).second); } out << "PFORM DUMP PRIMITIVES:" << endl; for (map::iterator idx = pform_primitives.begin() ; idx != pform_primitives.end() ; idx ++ ) { (*idx).second->dump(out); } } if (rc) { return rc; } /* If the user did not give specific module(s) to start with, then look for modules that are not instantiated anywhere. */ if (roots.empty()) { map mentioned_p; map::iterator mod; if (verbose_flag) cout << "LOCATING TOP-LEVEL MODULES" << endl << " "; for (mod = pform_modules.begin() ; mod != pform_modules.end() ; mod++) { find_module_mention(mentioned_p, mod->second); } for (mod = pform_modules.begin() ; mod != pform_modules.end() ; mod++) { /* Don't choose library modules. */ if ((*mod).second->library_flag) continue; /* Don't choose modules instantiated in other modules. */ if (mentioned_p[(*mod).second->mod_name()]) continue; /* What's left might as well be chosen as a root. */ if (verbose_flag) cout << " " << (*mod).second->mod_name(); roots.push_back((*mod).second->mod_name()); } if (verbose_flag) cout << endl; } /* If there is *still* no guess for the root module, then give up completely, and complain. */ if (roots.empty()) { cerr << "No top level modules, and no -s option." << endl; return 1; } if (verbose_flag) { if (times_flag) { times(cycles+1); cerr<<" ... done, " <errors > 0)) { if (des != 0) { cerr << des->errors << " error(s) during elaboration." << endl; if (net_path) { ofstream out (net_path); des->dump(out); } } else { cerr << "Elaboration failed" << endl; } goto errors_summary; } des->set_flags(flags); /* Done with all the pform data. Delete the modules. */ for (map::iterator idx = pform_modules.begin() ; idx != pform_modules.end() ; idx ++) { delete (*idx).second; (*idx).second = 0; } if (verbose_flag) { if (times_flag) { times(cycles+2); cerr<<" ... done, " <join_islands(); if (net_path) { if (verbose_flag) cerr<<" dumping netlist to " <dump(out); } if (des->errors) { cerr << des->errors << " error(s) in post-elaboration processing." << endl; return des->errors; } if (verbose_flag) { if (times_flag) { times(cycles+3); cerr<<" ... done, " <emit(&dll_target_obj)) { if (emit_rc > 0) { cerr << "error: Code generation had " << emit_rc << " errors." << endl; return 1; } if (emit_rc < 0) { cerr << "error: Code generator failure: " << emit_rc << endl; return -1; } assert(emit_rc); } if (verbose_flag) { if (times_flag) { times(cycles+4); cerr<<" ... done, " <::const_iterator idx; for (idx = missing_modules.begin() ; idx != missing_modules.end() ; idx ++) cerr << " " << (*idx).first << " referenced " << (*idx).second << " times."<< endl; cerr << "***" << endl; } return des? des->errors : 1; } static void find_module_mention(map&check_map, Module*mod) { list gates = mod->get_gates(); list::const_iterator gate; for (gate = gates.begin(); gate != gates.end(); gate++) { PGModule*tmp = dynamic_cast(*gate); if (tmp) { // Note that this module has been instantiated check_map[tmp->get_type()] = true; } } list::const_iterator cur; for (cur = mod->generate_schemes.begin() ; cur != mod->generate_schemes.end() ; cur ++) { find_module_mention(check_map, *cur); } } static void find_module_mention(map&check_map, PGenerate*schm) { list::const_iterator gate; for (gate = schm->gates.begin(); gate != schm->gates.end(); gate++) { PGModule*tmp = dynamic_cast(*gate); if (tmp) { // Note that this module has been instantiated check_map[tmp->get_type()] = true; } } list::const_iterator cur; for (cur = schm->generate_schemes.begin() ; cur != schm->generate_schemes.end() ; cur ++) { find_module_mention(check_map, *cur); } } verilog-0.9.7/PaxHeaders.14238/verinum.cc0000644000202500001440000000005012204466647016224 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/verinum.cc0000644000202500001440000011170312204466647015551 0ustar00steveusers00000000000000/* * Copyright (c) 1998-2011 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "verinum.h" # include # include # include // Needed to get pow for as_double(). # include // Needed to get snprintf for as_string(). #if !defined(HAVE_LROUND) /* * If the system doesn't provide the lround function, then we provide * it ourselves here. It is simply the nearest integer, rounded away * from zero. */ extern "C" long int lround(double x) { if (x >= 0.0) return (long)floor(x+0.5); else return (long)ceil(x-0.5); } #endif static verinum::V add_with_carry(verinum::V l, verinum::V r, verinum::V&c); verinum::verinum() : bits_(0), nbits_(0), has_len_(false), has_sign_(false), string_flag_(false) { } verinum::verinum(const V*bits, unsigned nbits, bool has_len__) : has_len_(has_len__), has_sign_(false), string_flag_(false) { nbits_ = nbits; bits_ = new V [nbits]; for (unsigned idx = 0 ; idx < nbits ; idx += 1) { bits_[idx] = bits[idx]; } } static string process_verilog_string_quotes(const string&str) { string res; int idx = 0; int str_len = str.length(); while (idx < str_len) { if (str[idx] == '\\') { idx += 1; assert(idx < str_len); switch (str[idx]) { case 'n': res = res + '\n'; idx += 1; break; case 't': res = res + '\t'; idx += 1; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { char byte_val = 0; int odx = 0; while (odx < 3 && idx+odx < str_len && str[idx+odx] >= '0' && str[idx+odx] <= '7') { byte_val = 8*byte_val + str[idx+odx]-'0'; odx += 1; } idx += odx; res = res + byte_val; break; } default: res = res + str[idx]; idx += 1; break; } } else { res = res + str[idx]; idx += 1; } } return res; } verinum::verinum(const string&s) : has_len_(true), has_sign_(false), string_flag_(true) { string str = process_verilog_string_quotes(s); nbits_ = str.length() * 8; // Special case: The string "" is 8 bits of 0. if (nbits_ == 0) { nbits_ = 8; bits_ = new V [nbits_]; bits_[0] = V0; bits_[1] = V0; bits_[2] = V0; bits_[3] = V0; bits_[4] = V0; bits_[5] = V0; bits_[6] = V0; bits_[7] = V0; return; } bits_ = new V [nbits_]; unsigned idx, cp; V*bp = bits_+nbits_; for (idx = nbits_, cp = 0 ; idx > 0 ; idx -= 8, cp += 1) { char ch = str[cp]; *(--bp) = (ch&0x80) ? V1 : V0; *(--bp) = (ch&0x40) ? V1 : V0; *(--bp) = (ch&0x20) ? V1 : V0; *(--bp) = (ch&0x10) ? V1 : V0; *(--bp) = (ch&0x08) ? V1 : V0; *(--bp) = (ch&0x04) ? V1 : V0; *(--bp) = (ch&0x02) ? V1 : V0; *(--bp) = (ch&0x01) ? V1 : V0; } } verinum::verinum(verinum::V val, unsigned n, bool h) : has_len_(h), has_sign_(false), string_flag_(false) { nbits_ = n; bits_ = new V[nbits_]; for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) bits_[idx] = val; } verinum::verinum(uint64_t val, unsigned n) : has_len_(true), has_sign_(false), string_flag_(false) { nbits_ = n; bits_ = new V[nbits_]; for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) { bits_[idx] = (val&1) ? V1 : V0; val >>= (uint64_t)1; } } /* The second argument is not used! It is there to make this * constructor unique. */ verinum::verinum(double val, bool dummy) : has_len_(false), has_sign_(true), string_flag_(false) { bool is_neg = false; double fraction; int exponent; const unsigned BITS_IN_LONG = 8*sizeof(long); /* We return `bx for a NaN or +/- infinity. */ if (val != val || (val && (val == 0.5*val))) { nbits_ = 1; bits_ = new V[nbits_]; bits_[0] = Vx; return; } /* Convert to a positive result. */ if (val < 0.0) { is_neg = true; val = -val; } /* Get the exponent and fractional part of the number. */ fraction = frexp(val, &exponent); nbits_ = exponent+1; bits_ = new V[nbits_]; const verinum const_one(1); /* If the value is small enough just use lround(). */ if (nbits_ <= BITS_IN_LONG) { long sval = lround(val); if (is_neg) sval = -sval; for (unsigned idx = 0; idx < nbits_; idx += 1) { bits_[idx] = (sval&1) ? V1 : V0; sval >>= 1; } /* Trim the result. */ signed_trim(); return; } unsigned nwords = (exponent-1)/BITS_IN_LONG; fraction = ldexp(fraction, (exponent-1) % BITS_IN_LONG + 1); if (nwords == 0) { unsigned long bits = (unsigned long) fraction; fraction = fraction - (double) bits; for (unsigned idx = 0; idx < nbits_; idx += 1) { bits_[idx] = (bits&1) ? V1 : V0; bits >>= 1; } if (fraction >= 0.5) *this = *this + const_one; } else { for (int wd = nwords; wd >= 0; wd -= 1) { unsigned long bits = (unsigned long) fraction; fraction = fraction - (double) bits; unsigned max = (wd+1)*BITS_IN_LONG; if (max > nbits_) max = nbits_; for (unsigned idx = wd*BITS_IN_LONG; idx < max; idx += 1) { bits_[idx] = (bits&1) ? V1 : V0; bits >>= 1; } fraction = ldexp(fraction, BITS_IN_LONG); } if (fraction >= ldexp(0.5, BITS_IN_LONG)) *this = *this + const_one; } /* Convert a negative number if needed. */ if (is_neg) { *this = v_not(*this) + const_one; } /* Trim the result. */ signed_trim(); } /* This is used by the double constructor above. It is needed to remove * extra sign bits that can occur when calculating a negative value. */ void verinum::signed_trim() { /* Do we have any extra digits? */ unsigned tlen = nbits_-1; verinum::V sign = bits_[tlen]; while ((tlen > 0) && (bits_[tlen] == sign)) tlen -= 1; /* tlen now points to the first digit that is not the sign. * or bit 0. Set the length to include this bit and one proper * sign bit if needed. */ if (bits_[tlen] != sign) tlen += 1; tlen += 1; /* Trim the bits if needed. */ if (tlen < nbits_) { V* tbits = new V[tlen]; for (unsigned idx = 0; idx < tlen; idx += 1) tbits[idx] = bits_[idx]; delete[] bits_; bits_ = tbits; nbits_ = tlen; } } verinum::verinum(const verinum&that) { string_flag_ = that.string_flag_; nbits_ = that.nbits_; bits_ = new V[nbits_]; has_len_ = that.has_len_; has_sign_ = that.has_sign_; for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) bits_[idx] = that.bits_[idx]; } verinum::verinum(const verinum&that, unsigned nbits) { string_flag_ = false; nbits_ = nbits; bits_ = new V[nbits_]; has_len_ = true; has_sign_ = that.has_sign_; unsigned copy = nbits; if (copy > that.nbits_) copy = that.nbits_; for (unsigned idx = 0 ; idx < copy ; idx += 1) bits_[idx] = that.bits_[idx]; if (copy < nbits_) { if (has_sign_) { for (unsigned idx = copy ; idx < nbits_ ; idx += 1) bits_[idx] = bits_[idx-1]; } else { for (unsigned idx = copy ; idx < nbits_ ; idx += 1) bits_[idx] = verinum::V0; } } } verinum::verinum(int64_t that) : has_len_(false), has_sign_(true), string_flag_(false) { int64_t tmp; if (that < 0) tmp = (that+1)/2; else tmp = that/2; nbits_ = 1; while (tmp != 0) { nbits_ += 1; tmp /= 2; } nbits_ += 1; bits_ = new V[nbits_]; for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) { bits_[idx] = (that & 1)? V1 : V0; that >>= 1; } } verinum::~verinum() { delete[]bits_; } verinum& verinum::operator= (const verinum&that) { if (this == &that) return *this; delete[]bits_; nbits_ = that.nbits_; bits_ = new V[that.nbits_]; for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) bits_[idx] = that.bits_[idx]; has_len_ = that.has_len_; has_sign_ = that.has_sign_; string_flag_ = that.string_flag_; return *this; } verinum::V verinum::get(unsigned idx) const { assert(idx < nbits_); return bits_[idx]; } verinum::V verinum::set(unsigned idx, verinum::V val) { assert(idx < nbits_); return bits_[idx] = val; } unsigned long verinum::as_ulong() const { if (nbits_ == 0) return 0; if (!is_defined()) return 0; unsigned top = nbits_; if (top >= (8 * sizeof(unsigned long))) top = 8 * sizeof(unsigned long); unsigned long val = 0; unsigned long mask = 1; for (unsigned idx = 0 ; idx < top ; idx += 1, mask <<= 1) if (bits_[idx] == V1) val |= mask; return val; } uint64_t verinum::as_ulong64() const { if (nbits_ == 0) return 0; if (!is_defined()) return 0; unsigned top = nbits_; if (top >= (8 * sizeof(uint64_t))) top = 8 * sizeof(uint64_t); uint64_t val = 0; uint64_t mask = 1; for (unsigned idx = 0 ; idx < top ; idx += 1, mask <<= 1) if (bits_[idx] == V1) val |= mask; return val; } /* * This function returns the native long integer that represents the * value of this object. It accounts for sign extension if the value * is signed. * * If the value is undefined, return 0. * * This function presumes that the native format is 2s complement * (pretty safe these days) and masks/sets bits accordingly. If the * value is too large for the native form, it truncates the high bits. */ signed long verinum::as_long() const { #define IVLLBITS (8 * sizeof(long) - 1) if (nbits_ == 0) return 0; if (!is_defined()) return 0; signed long val = 0; unsigned diag_top = 0; unsigned top = nbits_; if (top > IVLLBITS) { diag_top = top; top = IVLLBITS; } int lost_bits=0; if (has_sign_ && (bits_[nbits_-1] == V1)) { val = -1; signed long mask = ~1L; for (unsigned idx = 0 ; idx < top ; idx += 1) { if (bits_[idx] == V0) val &= mask; mask = (mask << 1) | 1L; } if (diag_top) { for (unsigned idx = top; idx < diag_top; idx += 1) { if (bits_[idx] == V0) lost_bits=1; } } } else { signed long mask = 1; for (unsigned idx = 0 ; idx < top ; idx += 1, mask <<= 1) { if (bits_[idx] == V1) val |= mask; } if (diag_top) { for (unsigned idx = top; idx < diag_top; idx += 1) { if (bits_[idx] == V1) lost_bits=1; } } } if (lost_bits) cerr << "warning: verinum::as_long() truncated " << diag_top << " bits to " << IVLLBITS << ", returns " << val << endl; return val; #undef IVLLBITS } double verinum::as_double() const { if (nbits_ == 0) return 0.0; double val = 0.0; /* Do we have/want a signed value? */ if (has_sign_ && bits_[nbits_-1] == V1) { V carry = V1; for (unsigned idx = 0; idx < nbits_; idx += 1) { V sum = add_with_carry(~bits_[idx], V0, carry); if (sum == V1) val += pow(2.0, (double)idx); } val *= -1.0; } else { for (unsigned idx = 0; idx < nbits_; idx += 1) { if (bits_[idx] == V1) val += pow(2.0, (double)idx); } } return val; } string verinum::as_string() const { assert( nbits_%8 == 0 ); if (nbits_ == 0) return ""; string res; for (unsigned idx = nbits_ ; idx > 0 ; idx -= 8) { char char_val = 0; V*bp = bits_+idx; if (*(--bp) == V1) char_val |= 0x80; if (*(--bp) == V1) char_val |= 0x40; if (*(--bp) == V1) char_val |= 0x20; if (*(--bp) == V1) char_val |= 0x10; if (*(--bp) == V1) char_val |= 0x08; if (*(--bp) == V1) char_val |= 0x04; if (*(--bp) == V1) char_val |= 0x02; if (*(--bp) == V1) char_val |= 0x01; if (char_val == '"' || char_val == '\\') { char tmp[5]; snprintf(tmp, sizeof tmp, "\\%03o", char_val); res = res + tmp; } else if (isprint(char_val)) { res = res + char_val; } else { char tmp[5]; snprintf(tmp, sizeof tmp, "\\%03o", (unsigned char)char_val); res = res + tmp; } } return res; } bool verinum::is_before(const verinum&that) const { if (that.nbits_ > nbits_) return true; if (that.nbits_ < nbits_) return false; for (unsigned idx = nbits_ ; idx > 0 ; idx -= 1) { if (bits_[idx-1] < that.bits_[idx-1]) return true; if (bits_[idx-1] > that.bits_[idx-1]) return false; } return false; } bool verinum::is_defined() const { for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) { if (bits_[idx] == Vx) return false; if (bits_[idx] == Vz) return false; } return true; } bool verinum::is_zero() const { for (unsigned idx = 0 ; idx < nbits_ ; idx += 1) if (bits_[idx] != V0) return false; return true; } bool verinum::is_negative() const { return (bits_[nbits_-1] == V1) && has_sign(); } verinum pad_to_width(const verinum&that, unsigned width) { if (that.len() >= width) return that; if (that.len() == 0) { verinum val (verinum::V0, width, that.has_len()); val.has_sign(that.has_sign()); return val; } verinum::V pad = that[that.len()-1]; if (pad==verinum::V1 && !that.has_sign()) pad = verinum::V0; if (that.has_len() && !that.has_sign()) { if (pad==verinum::Vx) pad = verinum::V0; if (pad==verinum::Vz) pad = verinum::V0; } verinum val(pad, width, that.has_len()); for (unsigned idx = 0 ; idx < that.len() ; idx += 1) val.set(idx, that[idx]); val.has_sign(that.has_sign()); if (that.is_string() && (width % 8) == 0) { val = verinum(val.as_string()); } return val; } /* * This function returns a version of the verinum that has only as * many bits as are needed to accurately represent the value. It takes * into account the signedness of the value. * * If the input value has a definite length, then that value is just * returned as is. */ verinum trim_vnum(const verinum&that) { unsigned tlen; if (that.has_len()) return that; if (that.len() < 2) return that; if (that.has_sign()) { unsigned top = that.len()-1; verinum::V sign = that.get(top); while ((top > 0) && (that.get(top) == sign)) top -= 1; /* top points to the first digit that is not the sign. Set the length to include this and one proper sign bit. */ if (that.get(top) != sign) top += 1; tlen = top+1; } else { /* If the result is unsigned and has an indefinite length, then trim off all but one leading zero. */ unsigned top = that.len()-1; while ((top > 0) && (that.get(top) == verinum::V0)) top -= 1; /* Now top is the index of the highest non-zero bit. If that turns out to the highest bit in the vector, then there is no trimming possible. */ if (top+1 == that.len()) return that; /* Make tlen wide enough to include the highest non-zero bit, plus one extra 0 bit. */ tlen = top+2; /* This can only happen when the verinum is all zeros, so make it a single bit wide. */ if (that.get(top) == verinum::V0) tlen -= 1; } verinum tmp (verinum::V0, tlen, false); tmp.has_sign(that.has_sign()); for (unsigned idx = 0 ; idx < tmp.len() ; idx += 1) tmp.set(idx, that.get(idx)); return tmp; } ostream& operator<< (ostream&o, verinum::V v) { switch (v) { case verinum::V0: o << "0"; break; case verinum::V1: o << "1"; break; case verinum::Vx: o << "x"; break; case verinum::Vz: o << "z"; break; } return o; } /* * This operator is used by various dumpers to write the Verilog * number in a Verilog format. */ ostream& operator<< (ostream&o, const verinum&v) { if (v.is_string()) { o << "\"" << v.as_string() << "\""; return o; } /* If the verinum number has a fixed length, dump all the bits literally. This is how we express the fixed length in the output. */ if (v.has_len()) { o << v.len(); } /* If the number is fully defined (no x or z) then print it out as a decimal number. */ if (v.is_defined() && v.len() < 8*sizeof(long)) { if (v.has_sign()) o << "'sd" << v.as_long(); else o << "'d" << v.as_ulong(); return o; } /* Oh, well. Print the minimum to get the value properly displayed. */ if (v.has_sign()) o << "'sb"; else o << "'b"; if (v.len() == 0) { o << "0"; return o; } verinum::V trim_left = v.get(v.len()-1); unsigned idx; if (v.has_sign()) { for (idx = v.len()-1; idx > 0; idx -= 1) if (trim_left != v.get(idx-1)) break; o << trim_left; } else { idx = v.len(); } while (idx > 0) { o << v.get(idx-1); idx -= 1; } return o; } verinum::V operator == (const verinum&left, const verinum&right) { verinum::V left_pad = verinum::V0; verinum::V right_pad = verinum::V0; if (left.has_sign() && right.has_sign()) { left_pad = left.get(left.len()-1); right_pad = right.get(right.len()-1); if (left_pad == verinum::V1 && right_pad == verinum::V0) return verinum::V0; if (left_pad == verinum::V0 && right_pad == verinum::V1) return verinum::V0; } unsigned max_len = left.len(); if (right.len() > max_len) max_len = right.len(); for (unsigned idx = 0 ; idx < max_len ; idx += 1) { verinum::V left_bit = idx < left.len() ? left[idx] : left_pad; verinum::V right_bit = idx < right.len()? right[idx] : right_pad; if (left_bit != right_bit) return verinum::V0; } return verinum::V1; } verinum::V operator <= (const verinum&left, const verinum&right) { verinum::V left_pad = verinum::V0; verinum::V right_pad = verinum::V0; bool signed_calc = left.has_sign() && right.has_sign(); if (signed_calc) { left_pad = left.get(left.len()-1); right_pad = right.get(right.len()-1); if (left_pad == verinum::V1 && right_pad == verinum::V0) return verinum::V1; if (left_pad == verinum::V0 && right_pad == verinum::V1) return verinum::V0; } unsigned idx; for (idx = left.len() ; idx > right.len() ; idx -= 1) { if (left[idx-1] != right_pad) { // A change of padding for a negative left argument // denotes the left value is less than the right. return (signed_calc && (left_pad == verinum::V1)) ? verinum::V1 : verinum::V0; } } for (idx = right.len() ; idx > left.len() ; idx -= 1) { if (right[idx-1] != left_pad) { // A change of padding for a negative right argument // denotes the left value is not less than the right. return (signed_calc && (right_pad == verinum::V1)) ? verinum::V0 : verinum::V1; } } idx = right.len(); if (left.len() < idx) idx = left.len(); while (idx > 0) { if (left[idx-1] == verinum::Vx) return verinum::Vx; if (left[idx-1] == verinum::Vz) return verinum::Vx; if (right[idx-1] == verinum::Vx) return verinum::Vx; if (right[idx-1] == verinum::Vz) return verinum::Vx; if (left[idx-1] > right[idx-1]) return verinum::V0; if (left[idx-1] < right[idx-1]) return verinum::V1; idx -= 1; } return verinum::V1; } verinum::V operator < (const verinum&left, const verinum&right) { verinum::V left_pad = verinum::V0; verinum::V right_pad = verinum::V0; bool signed_calc = left.has_sign() && right.has_sign(); if (signed_calc) { left_pad = left.get(left.len()-1); right_pad = right.get(right.len()-1); if (left_pad == verinum::V1 && right_pad == verinum::V0) return verinum::V1; if (left_pad == verinum::V0 && right_pad == verinum::V1) return verinum::V0; } unsigned idx; for (idx = left.len() ; idx > right.len() ; idx -= 1) { if (left[idx-1] != right_pad) { // A change of padding for a negative left argument // denotes the left value is less than the right. return (signed_calc && (left_pad == verinum::V1)) ? verinum::V1 : verinum::V0; } } for (idx = right.len() ; idx > left.len() ; idx -= 1) { if (right[idx-1] != left_pad) { // A change of padding for a negative right argument // denotes the left value is not less than the right. return (signed_calc && (right_pad == verinum::V1)) ? verinum::V0 : verinum::V1; } } while (idx > 0) { if (left[idx-1] == verinum::Vx) return verinum::Vx; if (left[idx-1] == verinum::Vz) return verinum::Vx; if (right[idx-1] == verinum::Vx) return verinum::Vx; if (right[idx-1] == verinum::Vz) return verinum::Vx; if (left[idx-1] > right[idx-1]) return verinum::V0; if (left[idx-1] < right[idx-1]) return verinum::V1; idx -= 1; } return verinum::V0; } static verinum::V add_with_carry(verinum::V l, verinum::V r, verinum::V&c) { unsigned sum = 0; switch (c) { case verinum::Vx: case verinum::Vz: c = verinum::Vx; return verinum::Vx; case verinum::V0: break; case verinum::V1: sum += 1; } switch (l) { case verinum::Vx: case verinum::Vz: c = verinum::Vx; return verinum::Vx; case verinum::V0: break; case verinum::V1: sum += 1; break; } switch (r) { case verinum::Vx: case verinum::Vz: c = verinum::Vx; return verinum::Vx; case verinum::V0: break; case verinum::V1: sum += 1; break; } if (sum & 2) c = verinum::V1; else c = verinum::V0; if (sum & 1) return verinum::V1; else return verinum::V0; } verinum v_not(const verinum&left) { verinum val = left; for (unsigned idx = 0 ; idx < val.len() ; idx += 1) switch (val[idx]) { case verinum::V0: val.set(idx, verinum::V1); break; case verinum::V1: val.set(idx, verinum::V0); break; default: val.set(idx, verinum::Vx); break; } return val; } /* * Addition works a bit at a time, from the least significant up to * the most significant. The result is signed only if both of the * operands are signed. The result is also expanded as needed to * prevent overflow. It is up to the caller to shrink the result back * down if that is the desire. */ verinum operator + (const verinum&left, const verinum&right) { unsigned min = left.len(); if (right.len() < min) min = right.len(); unsigned max = left.len(); if (right.len() > max) max = right.len(); bool signed_flag = left.has_sign() && right.has_sign(); verinum::V*val_bits = new verinum::V[max+1]; verinum::V carry = verinum::V0; for (unsigned idx = 0 ; idx < min ; idx += 1) val_bits[idx] = add_with_carry(left[idx], right[idx], carry); verinum::V rpad = signed_flag? right[right.len()-1] : verinum::V0; verinum::V lpad = signed_flag? left[left.len()-1] : verinum::V0; if (left.len() > right.len()) { for (unsigned idx = min ; idx < left.len() ; idx += 1) val_bits[idx] = add_with_carry(left[idx], rpad, carry); } else { for (unsigned idx = min ; idx < right.len() ; idx += 1) val_bits[idx] = add_with_carry(lpad, right[idx], carry); } val_bits[max] = add_with_carry(lpad, rpad, carry); #if 0 if (signed_flag) { if (val_bits[max] != val_bits[max-1]) max += 1; } #endif verinum val (val_bits, max+1, false); val.has_sign(signed_flag); delete[]val_bits; return val; } verinum operator - (const verinum&left, const verinum&right) { unsigned min = left.len(); if (right.len() < min) min = right.len(); unsigned max = left.len(); if (right.len() > max) max = right.len(); bool signed_flag = left.has_sign() && right.has_sign(); verinum::V*val_bits = new verinum::V[max+1]; verinum::V carry = verinum::V1; for (unsigned idx = 0 ; idx < min ; idx += 1) val_bits[idx] = add_with_carry(left[idx], ~right[idx], carry); verinum::V rpad = signed_flag? ~right[right.len()-1] : verinum::V1; verinum::V lpad = signed_flag? left[left.len()-1] : verinum::V0; if (left.len() > right.len()) { for (unsigned idx = min ; idx < left.len() ; idx += 1) val_bits[idx] = add_with_carry(left[idx], rpad, carry); } else { for (unsigned idx = min ; idx < right.len() ; idx += 1) val_bits[idx] = add_with_carry(lpad, ~right[idx], carry); } if (signed_flag) { val_bits[max] = add_with_carry(lpad, rpad, carry); if (val_bits[max] != val_bits[max-1]) max += 1; } verinum val (val_bits, max, false); val.has_sign(signed_flag); delete[]val_bits; return val; } /* * This multiplies two verinum numbers together into a verinum * result. The resulting number is as large as the sum of the sizes of * the operand. * * The algorithm used is successive shift and add operations, * implemented as the nested loops. * * If either value is not completely defined, then the result is not * defined either. */ verinum operator * (const verinum&left, const verinum&right) { const bool has_len_flag = left.has_len() && right.has_len(); /* If either operand is not fully defined, then the entire result is undefined. Create a result that is the right size and is filled with 'bx bits. */ if (! (left.is_defined() && right.is_defined())) { verinum result (verinum::Vx, left.len()+right.len(), has_len_flag); result.has_sign(left.has_sign() || right.has_sign()); return result; } verinum result(verinum::V0, left.len() + right.len(), has_len_flag); result.has_sign(left.has_sign() || right.has_sign()); verinum::V r_sign = sign_bit(right); for (unsigned rdx = 0 ; rdx < result.len() ; rdx += 1) { verinum::V r_bit = rdx < right.len()? right.get(rdx) : r_sign; if (r_bit == verinum::V0) continue; verinum::V l_sign = sign_bit(left); verinum::V carry = verinum::V0; for (unsigned ldx = 0 ; ldx < result.len()-rdx ; ldx += 1) { verinum::V l_bit = ldx < left.len()? left[ldx] : l_sign; result.set(ldx+rdx, add_with_carry(l_bit, result[rdx+ldx], carry)); } } return trim_vnum(result); } verinum pow(const verinum&left, const verinum&right) { verinum result = left; long pow_count = right.as_long(); // We need positive and negative one in a few places. unsigned len = left.len(); // Positive one must be at least two bits wide! verinum one (verinum::V0, (len<2) ? 2 : len, left.has_len()); one.has_sign(left.has_sign()); one.set(0, verinum::V1); verinum m_one (verinum::V1, len, left.has_len()); m_one.has_sign(true); // If either the right or left values are undefined we return 'bx. if (!right.is_defined() || !left.is_defined()) { result = verinum(verinum::Vx, len, left.has_len()); result.has_sign(left.has_sign()); // If the right value is zero we need to set the result to 1. } else if (pow_count == 0) { result = one; } else if (pow_count < 0) { // 0 ** is 'bx. if (left.is_zero()) { result = verinum(verinum::Vx, len, left.has_len()); result.has_sign(left.has_sign()); // 1 ** is 1. } else if (left == one) { result = one; // -1 ** is 1 or -1. } else if (left.has_sign() && left == m_one) { if (pow_count%2 == 0) { result = one; } else { result = m_one; } // Everything else is 0. } else { result = verinum(verinum::V0, len, left.has_len()); result.has_sign(left.has_sign()); } } for (long idx = 1 ; idx < pow_count ; idx += 1) result = result * left; return result; } verinum operator << (const verinum&that, unsigned shift) { verinum result(verinum::V0, that.len() + shift, that.has_len()); for (unsigned idx = 0 ; idx < that.len() ; idx += 1) result.set(idx+shift, that.get(idx)); return result; } verinum operator >> (const verinum&that, unsigned shift) { if (shift >= that.len()) { if (that.has_sign()) { verinum result (that.get(that.len()-1), 1); result.has_sign(true); return result; } else { verinum result(verinum::V0, 1); return result; } } verinum result(that.has_sign()? that.get(that.len()-1) : verinum::V0, that.len() - shift, that.has_len()); for (unsigned idx = shift ; idx < that.len() ; idx += 1) result.set(idx-shift, that.get(idx)); return result; } static verinum unsigned_divide(verinum num, verinum den, bool signed_result) { unsigned nwid = num.len(); while (nwid > 0 && (num.get(nwid-1) == verinum::V0)) nwid -= 1; unsigned dwid = den.len(); while (dwid > 0 && (den.get(dwid-1) == verinum::V0)) dwid -= 1; if (dwid > nwid) return verinum(verinum::V0, 1); den = den << (nwid-dwid); unsigned idx = nwid - dwid + 1; verinum result (verinum::V0, signed_result ? idx + 1 : idx); if (signed_result) { result.set(idx, verinum::V0); result.has_sign(true); } while (idx > 0) { if (den <= num) { verinum dif = num - den; num = dif; result.set(idx-1, verinum::V1); } den = den >> 1; idx -= 1; } return result; } static verinum unsigned_modulus(verinum num, verinum den) { unsigned nwid = num.len(); while (nwid > 0 && (num.get(nwid-1) == verinum::V0)) nwid -= 1; unsigned dwid = den.len(); while (dwid > 0 && (den.get(dwid-1) == verinum::V0)) dwid -= 1; if (dwid > nwid) return num; den = den << (nwid-dwid); unsigned idx = nwid - dwid + 1; while (idx > 0) { if (den <= num) { verinum dif = num - den; num = dif; } den = den >> 1; idx -= 1; } return num; } /* * This operator divides the left number by the right number. If * either value is signed, the result is signed. If both values have a * defined length, then the result has a defined length. */ verinum operator / (const verinum&left, const verinum&right) { const bool has_len_flag = left.has_len() && right.has_len(); unsigned use_len = left.len(); /* If either operand is not fully defined, then the entire result is undefined. Create a result that is the right size and is filled with 'bx bits. */ if (! (left.is_defined() && right.is_defined())) { verinum result (verinum::Vx, use_len, has_len_flag); result.has_sign(left.has_sign() || right.has_sign()); return result; } /* If the right expression is a zero value, then the result is filled with 'bx bits. */ if (right.is_zero()) { verinum result (verinum::Vx, use_len, has_len_flag); result.has_sign(left.has_sign() || right.has_sign()); return result; } verinum result(verinum::Vz, use_len, has_len_flag); result.has_sign(left.has_sign() || right.has_sign()); /* do the operation differently, depending on whether the result is signed or not. */ if (result.has_sign()) { if (use_len <= (8*sizeof(long) - 1)) { long l = left.as_long(); long r = right.as_long(); long v = l / r; for (unsigned idx = 0 ; idx < use_len ; idx += 1) { result.set(idx, (v & 1)? verinum::V1 : verinum::V0); v >>= 1; } } else { verinum use_left, use_right; verinum zero(verinum::V0, 1, false); zero.has_sign(true); bool negative = false; if (left < zero) { use_left = zero - left; negative = !negative; } else { use_left = left; } if (right < zero) { use_right = zero - right; negative = !negative; } else { use_right = right; } result = unsigned_divide(use_left, use_right, true); if (negative) result = zero - result; } } else { if (use_len <= 8 * sizeof(unsigned long)) { /* Use native unsigned division to do the work. */ unsigned long l = left.as_ulong(); unsigned long r = right.as_ulong(); unsigned long v = l / r; for (unsigned idx = 0 ; idx < use_len ; idx += 1) { result.set(idx, (v & 1)? verinum::V1 : verinum::V0); v >>= 1; } } else { result = unsigned_divide(left, right, false); } } return trim_vnum(result); } verinum operator % (const verinum&left, const verinum&right) { const bool has_len_flag = left.has_len() && right.has_len(); unsigned use_len = left.len(); /* If either operand is not fully defined, then the entire result is undefined. Create a result that is the right size and is filled with 'bx bits. */ if (! (left.is_defined() && right.is_defined())) { verinum result (verinum::Vx, use_len, has_len_flag); result.has_sign(left.has_sign() || right.has_sign()); return result; } /* If the right expression is a zero value, then the result is filled with 'bx bits. */ if (right.as_ulong() == 0) { verinum result (verinum::Vx, use_len, has_len_flag); result.has_sign(left.has_sign() || right.has_sign()); return result; } verinum result(verinum::Vz, use_len, has_len_flag); result.has_sign(left.has_sign() || right.has_sign()); if (result.has_sign()) { if (use_len <= 8*sizeof(long)) { /* Use native signed modulus to do the work. */ long l = left.as_long(); long r = right.as_long(); long v = l % r; for (unsigned idx = 0 ; idx < use_len ; idx += 1) { result.set(idx, (v & 1)? verinum::V1 : verinum::V0); v >>= 1; } } else { verinum use_left, use_right; verinum zero(verinum::V0, 1, false); zero.has_sign(true); bool negative = false; if (left < zero) { use_left = zero - left; negative = true; } else { use_left = left; } if (right < zero) { use_right = zero - right; } else { use_right = right; } result = unsigned_modulus(use_left, use_right); result.has_sign(true); if (negative) result = zero - result; } } else { if (use_len <= 8*sizeof(unsigned long)) { /* Use native unsigned modulus to do the work. */ unsigned long l = left.as_ulong(); unsigned long r = right.as_ulong(); unsigned long v = l % r; for (unsigned idx = 0 ; idx < use_len ; idx += 1) { result.set(idx, (v & 1)? verinum::V1 : verinum::V0); v >>= 1; } } else { result = unsigned_modulus(left, right); } } return trim_vnum(result); } verinum concat(const verinum&left, const verinum&right) { if (left.is_string() && right.is_string()) { std::string tmp = left.as_string() + right.as_string(); verinum res (tmp); return res; } verinum res (verinum::V0, left.len() + right.len()); for (unsigned idx = 0 ; idx < right.len() ; idx += 1) res.set(idx, right.get(idx)); for (unsigned idx = 0 ; idx < left.len() ; idx += 1) res.set(idx+right.len(), left.get(idx)); return res; } verinum::V operator ~ (verinum::V l) { switch (l) { case verinum::V0: return verinum::V1; case verinum::V1: return verinum::V0; default: return verinum::Vx; } } verinum::V operator | (verinum::V l, verinum::V r) { if (l == verinum::V1) return verinum::V1; if (r == verinum::V1) return verinum::V1; if (l != verinum::V0) return verinum::Vx; if (r != verinum::V0) return verinum::Vx; return verinum::V0; } verinum::V operator & (verinum::V l, verinum::V r) { if (l == verinum::V0) return verinum::V0; if (r == verinum::V0) return verinum::V0; if (l != verinum::V1) return verinum::Vx; if (r != verinum::V1) return verinum::Vx; return verinum::V1; } verinum::V operator ^ (verinum::V l, verinum::V r) { if (l == verinum::V0) return bit4_z2x(r); if (r == verinum::V0) return bit4_z2x(l); if ((l == verinum::V1) && (r == verinum::V1)) return verinum::V0; return verinum::Vx; } verilog-0.9.7/PaxHeaders.14238/parse_api.h0000644000202500001440000000005012204466647016344 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/parse_api.h0000644000202500001440000000352112204466647015667 0ustar00steveusers00000000000000#ifndef __parse_api_H #define __parse_api_H /* * Copyright (c) 2001-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include # include "StringHeap.h" # include # include class Module; class PUdp; /* * These are maps of the modules and primitives parsed from the * Verilog source into pform for elaboration. The parser adds modules * to these maps as it compiles modules in the Verilog source. */ extern map pform_modules; extern map pform_primitives; /* * This code actually invokes the parser to make modules. The first * parameter is the name of the file that is to be parsed. The * optional second parameter is the opened descriptor for the file. If * the descriptor is 0 (or skipped) then the function will attempt to * open the file on its own. */ extern int pform_parse(const char*path, FILE*file =0); extern string vl_file; extern void pform_set_timescale(int units, int prec, const char*file, unsigned lineno); extern int def_ts_units; extern int def_ts_prec; #endif verilog-0.9.7/PaxHeaders.14238/PEvent.cc0000644000202500001440000000005012204466647015740 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/PEvent.cc0000644000202500001440000000177212204466647015271 0ustar00steveusers00000000000000/* * Copyright (c) 2004 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "PEvent.h" PEvent::PEvent(perm_string n) : name_(n) { } PEvent::~PEvent() { } perm_string PEvent::name() const { return name_; } verilog-0.9.7/PaxHeaders.14238/synth.cc0000644000202500001440000000005012204466647015704 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/synth.cc0000644000202500001440000000750612204466647015236 0ustar00steveusers00000000000000/* * Copyright (c) 1999-2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "functor.h" # include "netlist.h" /* * This functor scans the behavioral code, looking for expressions to * synthesize. Although it uses the proc_match_t class, it doesn't * actually match anything, but transforms expressions into structural * netlists. The product of this should be a process where all the * expressions have been reduced to a signal ident, which references * the NetNet of the now synthesized expression. */ class do_expr : public proc_match_t { public: do_expr(Design*d, NetScope*s) : des_(d), scope_(s) { } private: Design*des_; NetScope*scope_; virtual int assign(NetAssign*); virtual int assign_nb(NetAssignNB*); virtual int event_wait(NetEvWait*); virtual int condit(NetCondit*); }; int do_expr::assign(NetAssign*stmt) { if (dynamic_cast(stmt->rval())) return 0; NetNet*tmp = stmt->rval()->synthesize(des_, scope_, stmt->rval()); if (tmp == 0) return 0; NetESignal*tmpe = new NetESignal(tmp); stmt->set_rval(tmpe); return 0; } int do_expr::assign_nb(NetAssignNB*stmt) { if (dynamic_cast(stmt->rval())) return 0; NetNet*tmp = stmt->rval()->synthesize(des_, scope_, stmt->rval()); if (tmp == 0) return 0; NetESignal*tmpe = new NetESignal(tmp); stmt->set_rval(tmpe); return 0; } int do_expr::condit(NetCondit*stmt) { /* synthesize the condition expression, if necessary. */ if (! dynamic_cast(stmt->expr())) { NetNet*tmp = stmt->expr()->synthesize(des_, scope_, stmt->expr()); if (tmp) { NetESignal*tmpe = new NetESignal(tmp); stmt->set_expr(tmpe); } } /* Now recurse through the if and else clauses. */ if (NetProc*tmp = stmt->if_clause()) tmp->match_proc(this); if (NetProc*tmp = stmt->else_clause()) tmp->match_proc(this); return 0; } int do_expr::event_wait(NetEvWait*stmt) { NetProc*tmp = stmt->statement(); if (tmp) return tmp->match_proc(this); else return 0; } class synth_f : public functor_t { public: void process(class Design*, class NetProcTop*); private: void proc_always_(class Design*); void proc_initial_(class Design*); NetProcTop*top_; }; /* * Look at a process, and divide the problem into always and initial * threads. */ void synth_f::process(class Design*des, class NetProcTop*top) { top_ = top; switch (top->type()) { case IVL_PR_ALWAYS: proc_always_(des); break; case IVL_PR_INITIAL: proc_initial_(des); break; } } void synth_f::proc_always_(class Design*des) { do_expr expr_pat(des, top_->scope()); top_->statement()->match_proc(&expr_pat); } void synth_f::proc_initial_(class Design*des) { do_expr expr_pat(des, top_->scope()); top_->statement()->match_proc(&expr_pat); } void synth(Design*des) { synth_f synth_obj; des->functor(&synth_obj); } verilog-0.9.7/PaxHeaders.14238/functor.h0000644000202500001440000000005012204466647016061 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/functor.h0000644000202500001440000000727712204466647015420 0ustar00steveusers00000000000000#ifndef __functor_H #define __functor_H /* * Copyright (c) 1999-2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * The functor is an object that can be applied to a design to * transform it. This is different from the target_t, which can only * scan the design but not transform it in any way. * * When a functor it scanning a process, signal or node, the functor * is free to manipulate the list by deleting items, including the * node being scanned. The Design class scanner knows how to handle * the situation. However, if objects are added to the netlist, there * is no guarantee that object will be scanned unless the functor is * rerun. */ class Design; class NetNet; class NetProcTop; struct functor_t { virtual ~functor_t(); /* Events are scanned here. */ virtual void event(class Design*des, class NetEvent*); /* This is called once for each signal in the design. */ virtual void signal(class Design*des, class NetNet*); /* This method is called for each process in the design. */ virtual void process(class Design*des, class NetProcTop*); /* This method is called for each structural abs(). */ virtual void lpm_abs(class Design*des, class NetAbs*); /* This method is called for each structural adder. */ virtual void lpm_add_sub(class Design*des, class NetAddSub*); /* This method is called for each structural comparator. */ virtual void lpm_compare(class Design*des, class NetCompare*); /* This method is called for each structural constant. */ virtual void lpm_const(class Design*des, class NetConst*); /* This method is called for each structural constant. */ virtual void lpm_divide(class Design*des, class NetDivide*); /* Constant literals. */ virtual void lpm_literal(class Design*des, class NetLiteral*); /* This method is called for each structural constant. */ virtual void lpm_modulo(class Design*des, class NetModulo*); /* This method is called for each FF in the design. */ virtual void lpm_ff(class Design*des, class NetFF*); /* Handle LPM combinational logic devices. */ virtual void lpm_logic(class Design*des, class NetLogic*); /* This method is called for each multiplier. */ virtual void lpm_mult(class Design*des, class NetMult*); /* This method is called for each MUX. */ virtual void lpm_mux(class Design*des, class NetMux*); /* This method is called for each power. */ virtual void lpm_pow(class Design*des, class NetPow*); /* This method is called for each unary reduction gate. */ virtual void lpm_ureduce(class Design*des, class NetUReduce*); virtual void sign_extend(class Design*des, class NetSignExtend*); }; struct proc_match_t { virtual ~proc_match_t(); virtual int assign(class NetAssign*); virtual int assign_nb(class NetAssignNB*); virtual int condit(class NetCondit*); virtual int event_wait(class NetEvWait*); virtual int block(class NetBlock*); }; #endif verilog-0.9.7/PaxHeaders.14238/tgt-vhdl0000644000202500001440000000005012204466647015704 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/0000755000202500001440000000000012204466647015303 5ustar00steveusers00000000000000verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl_element.cc0000644000202500001440000000005012204466647020736 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl_element.cc0000644000202500001440000001074412204466647020266 0ustar00steveusers00000000000000/* * VHDL abstract syntax elements. * * Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_element.hh" #include #include #include #include #include #include using namespace std; static const int VHDL_INDENT = 2; // Spaces to indent int indent(int level) { return level + VHDL_INDENT; } std::string nl_string(int level) { std::ostringstream ss; newline(ss, level); return ss.str(); } /* * Emit a newline and indent to the correct level. */ void newline(std::ostream &of, int level) { of << std::endl; while (level--) of << ' '; } void blank_line(std::ostream &of, int level) { of << std::endl; newline(of, level); } // The array of all vhdl_elements allocated so we can quickly // clean them up just before the code generator exits vector vhdl_element::allocated_; // Just a counter of total bytes allocated for statistics size_t vhdl_element::total_alloc_(0); void vhdl_element::set_comment(std::string comment) { comment_ = comment; } /* * Draw the comment for any element. The comment is either on * a line before the element (end_of_line is false) or at the * end of the line containing the element (end_of_line is true). */ void vhdl_element::emit_comment(std::ostream &of, int level, bool end_of_line) const { if (comment_.size() > 0) { if (end_of_line) of << " "; of << "-- " << comment_; if (!end_of_line) newline(of, level); } } void vhdl_element::print() const { emit(std::cout, 0); std::cout << std::endl; } // Trap allocations of vhdl_element subclasses. // This records the pointer allocated in a static field of vhdl_element // so we can delete it just before the code generator exits. void* vhdl_element::operator new(size_t size) throw (bad_alloc) { // Let the default new handle the allocation void* ptr = ::operator new(size); // Remember this element so we can delete it later vhdl_element* elem = static_cast(ptr); allocated_.push_back(elem); total_alloc_ += size; return ptr; } // Explicitly delete a vhdl_element object. // This just sets the corresponding pointer in vhdl_element::allocated_ // to NULL (since it's safe to delete a NULL pointer). void vhdl_element::operator delete(void* ptr) { // Let the default delete handle the deallocation ::operator delete(ptr); // Remember that we've already deleted this pointer so we don't // delete it again in the call to free_all_objects vector::iterator it = find(allocated_.begin(), allocated_.end(), static_cast(ptr)); if (it != allocated_.end()) { *it = NULL; // It's safe to delete a NULL pointer and much cheaper // than removing an element from the middle of a vector } else { // This shouldn't really happen but it's harmless cerr << "??? vhdl_element::operator delete called on an object not " << "allocated by vhdl_element::operator new" << endl; } } // Return the total number of bytes our custom operator new has seen. size_t vhdl_element::total_allocated() { return total_alloc_; } // Free every object derived from vhdl_element that has not yet been // explicitly deallocated. // Any pointers to vhdl_elements will be invalid after this call! // Returns the number of objects freed. int vhdl_element::free_all_objects() { for (vector::iterator it = allocated_.begin(); it != allocated_.end(); ++it) { if (*it) ::operator delete(*it); // Explicitly use the default delete } int freed = allocated_.size(); // Just in case we want to allocated any more vhdl_element objects allocated_.clear(); return freed; } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/lpm.cc0000644000202500001440000000005012204466647017060 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/lpm.cc0000644000202500001440000002417412204466647016412 0ustar00steveusers00000000000000/* * VHDL code generation for LPM devices. * * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_target.h" #include "state.hh" #include #include /* * Return the base of a part select. */ static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_expr *off; ivl_nexus_t base = ivl_lpm_data(lpm, 1); if (base != NULL) off = readable_ref(scope, base); else off = new vhdl_const_int(ivl_lpm_base(lpm)); // Array indexes must be integers vhdl_type integer(VHDL_TYPE_INTEGER); return off->cast(&integer); } static vhdl_expr *concat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_type *result_type = vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0); vhdl_binop_expr *expr = new vhdl_binop_expr(VHDL_BINOP_CONCAT, result_type); for (int i = ivl_lpm_size(lpm) - 1; i >= 0; i--) { vhdl_expr *e = readable_ref(scope, ivl_lpm_data(lpm, i)); if (NULL == e) { delete expr; return NULL; } expr->add_expr(e); } return expr; } static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op) { unsigned out_width = ivl_lpm_width(lpm); vhdl_type *result_type = vhdl_type::type_for(out_width, ivl_lpm_signed(lpm) != 0); vhdl_binop_expr *expr = new vhdl_binop_expr(op, result_type); for (int i = 0; i < 2; i++) { vhdl_expr *e = readable_ref(scope, ivl_lpm_data(lpm, i)); if (NULL == e) { delete expr; return NULL; } expr->add_expr(e->cast(result_type)); } if (op == VHDL_BINOP_MULT) { // Need to resize the output to the desired size, // as this does not happen automatically in VHDL vhdl_fcall *resize = new vhdl_fcall("Resize", vhdl_type::nsigned(out_width)); resize->add_expr(expr); resize->add_expr(new vhdl_const_int(out_width)); return resize; } else return expr; } static vhdl_expr *rel_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op) { vhdl_binop_expr *expr = new vhdl_binop_expr(op, vhdl_type::boolean()); for (int i = 0; i < 2; i++) { vhdl_expr *e = readable_ref(scope, ivl_lpm_data(lpm, i)); if (NULL == e) { delete expr; return NULL; } expr->add_expr(e); } // Need to make sure output is std_logic rather than Boolean vhdl_type std_logic(VHDL_TYPE_STD_LOGIC); return expr->cast(&std_logic); } static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_var_ref *selfrom = readable_ref(scope, ivl_lpm_data(lpm, 0)); if (NULL == selfrom) return NULL; vhdl_expr *off = part_select_base(scope, lpm);; if (NULL == off) return NULL; if (selfrom->get_type()->get_width() > 1) selfrom->set_slice(off, ivl_lpm_width(lpm) - 1); return selfrom; } static vhdl_expr *part_select_pv_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { return readable_ref(scope, ivl_lpm_data(lpm, 0)); } static vhdl_expr *ufunc_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { ivl_scope_t f_scope = ivl_lpm_define(lpm); vhdl_fcall *fcall = new vhdl_fcall(ivl_scope_basename(f_scope), NULL); for (unsigned i = 0; i < ivl_lpm_size(lpm); i++) { vhdl_var_ref *ref = readable_ref(scope, ivl_lpm_data(lpm, i)); if (NULL == ref) { delete fcall; return NULL; } fcall->add_expr(ref); } return fcall; } static vhdl_expr *reduction_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, support_function_t f, bool invert) { vhdl_var_ref *ref = readable_ref(scope, ivl_lpm_data(lpm, 0)); if (NULL == ref) return NULL; vhdl_expr *result; if (ref->get_type()->get_name() == VHDL_TYPE_STD_LOGIC) result = ref; else { require_support_function(f); vhdl_fcall *fcall = new vhdl_fcall(support_function::function_name(f), vhdl_type::std_logic()); vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); fcall->add_expr(ref->cast(&std_logic_vector)); result = fcall; } if (invert) return new vhdl_unaryop_expr (VHDL_UNARYOP_NOT, result, vhdl_type::std_logic()); else return result; } static vhdl_expr *sign_extend_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_expr *ref = readable_ref(scope, ivl_lpm_data(lpm, 0)); if (ref) return ref->resize(ivl_lpm_width(lpm)); else return NULL; } static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { ivl_signal_t array = ivl_lpm_array(lpm); if (!seen_signal_before(array)) return NULL; const char *renamed = get_renamed_signal(array).c_str(); vhdl_decl *adecl = scope->get_decl(renamed); assert(adecl); vhdl_type *atype = new vhdl_type(*adecl->get_type()); vhdl_expr *select = readable_ref(scope, ivl_lpm_select(lpm)); if (NULL == select) { delete atype; return NULL; } vhdl_var_ref *ref = new vhdl_var_ref(renamed, atype); vhdl_type integer(VHDL_TYPE_INTEGER); ref->set_slice(select->cast(&integer)); return ref; } static vhdl_expr *shift_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t shift_op) { vhdl_expr *lhs = readable_ref(scope, ivl_lpm_data(lpm, 0)); vhdl_expr *rhs = readable_ref(scope, ivl_lpm_data(lpm, 1)); if (!lhs || !rhs) return NULL; // The RHS must be an integer vhdl_type integer(VHDL_TYPE_INTEGER); vhdl_expr *r_cast = rhs->cast(&integer); vhdl_type *rtype = new vhdl_type(*lhs->get_type()); return new vhdl_binop_expr(lhs, shift_op, r_cast, rtype); } static vhdl_expr *repeat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_expr *in = readable_ref(scope, ivl_lpm_data(lpm, 0)); return new vhdl_bit_spec_expr(NULL, in); } static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { switch (ivl_lpm_type(lpm)) { case IVL_LPM_ADD: return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_ADD); case IVL_LPM_SUB: return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_SUB); case IVL_LPM_MULT: return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MULT); case IVL_LPM_DIVIDE: return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_DIV); case IVL_LPM_MOD: return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MOD); case IVL_LPM_CONCAT: return concat_lpm_to_expr(scope, lpm); case IVL_LPM_CMP_GE: return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_GEQ); case IVL_LPM_CMP_GT: return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_GT); case IVL_LPM_CMP_NE: case IVL_LPM_CMP_NEE: return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_NEQ); case IVL_LPM_CMP_EQ: case IVL_LPM_CMP_EEQ: return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_EQ); case IVL_LPM_PART_VP: return part_select_vp_lpm_to_expr(scope, lpm); case IVL_LPM_PART_PV: return part_select_pv_lpm_to_expr(scope, lpm); case IVL_LPM_UFUNC: return ufunc_lpm_to_expr(scope, lpm); case IVL_LPM_RE_AND: return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, false); case IVL_LPM_RE_NAND: return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, true); case IVL_LPM_RE_NOR: return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, true); case IVL_LPM_RE_OR: return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, false); case IVL_LPM_RE_XOR: return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, false); case IVL_LPM_RE_XNOR: return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, true); case IVL_LPM_SIGN_EXT: return sign_extend_lpm_to_expr(scope, lpm); case IVL_LPM_ARRAY: return array_lpm_to_expr(scope, lpm); case IVL_LPM_SHIFTL: return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SL); case IVL_LPM_SHIFTR: return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SR); case IVL_LPM_REPEAT: return repeat_lpm_to_expr(scope, lpm); default: error("Unsupported LPM type: %d", ivl_lpm_type(lpm)); return NULL; } } static int draw_mux_lpm(vhdl_arch *arch, ivl_lpm_t lpm) { int nselects = ivl_lpm_selects(lpm); if (nselects > 1) { error("Only 1 LPM select bit supported at the moment"); return 1; } vhdl_scope *scope = arch->get_scope(); vhdl_expr *s0 = readable_ref(scope, ivl_lpm_data(lpm, 0)); vhdl_expr *s1 = readable_ref(scope, ivl_lpm_data(lpm, 1)); vhdl_expr *sel = readable_ref(scope, ivl_lpm_select(lpm)); vhdl_expr *b1 = new vhdl_const_bit('1'); vhdl_expr *t1 = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, b1, vhdl_type::boolean()); vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0)); // Make sure s0 and s1 have the same type as the output s0 = s0->cast(out->get_type()); s1 = s1->cast(out->get_type()); vhdl_cassign_stmt *s = new vhdl_cassign_stmt(out, s0); s->add_condition(s1, t1); arch->add_stmt(s); return 0; } int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) { if (ivl_lpm_type(lpm) == IVL_LPM_MUX) return draw_mux_lpm(arch, lpm); vhdl_expr *f = lpm_to_expr(arch->get_scope(), lpm); if (NULL == f) return 1; vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) { vhdl_expr *off = part_select_base(arch->get_scope(), lpm); assert(off); out->set_slice(off, ivl_lpm_width(lpm) - 1); } arch->add_stmt(new vhdl_cassign_stmt(out, f->cast(out->get_type()))); return 0; } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/expr.cc0000644000202500001440000000005012204466647017246 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/expr.cc0000644000202500001440000005353012204466647016576 0ustar00steveusers00000000000000/* * VHDL code generation for expressions. * * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_target.h" #include "support.hh" #include "state.hh" #include #include #include /* * Change the signedness of a vector. */ static vhdl_expr *change_signedness(vhdl_expr *e, bool issigned) { int msb = e->get_type()->get_msb(); int lsb = e->get_type()->get_lsb(); vhdl_type u(issigned ? VHDL_TYPE_SIGNED : VHDL_TYPE_UNSIGNED, msb, lsb); return e->cast(&u); } /* * Generate code to ensure that the VHDL expression vhd_e has the * same signedness as the Verilog expression vl_e. */ static vhdl_expr *correct_signedness(vhdl_expr *vhd_e, ivl_expr_t vl_e) { bool should_be_signed = ivl_expr_signed(vl_e) != 0; if (vhd_e->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) { //operand->print(); //std::cout << "^ should be signed but is not" << std::endl; return change_signedness(vhd_e, true); } else if (vhd_e->get_type()->get_name() == VHDL_TYPE_SIGNED && !should_be_signed) { //operand->print(); //std::cout << "^ should be unsigned but is not" << std::endl; return change_signedness(vhd_e, false); } else return vhd_e; } /* * Convert a constant Verilog string to a constant VHDL string. */ static vhdl_expr *translate_string(ivl_expr_t e) { // TODO: May need to inspect or escape parts of this const char *str = ivl_expr_string(e); return new vhdl_const_string(str); } /* * A reference to a signal in an expression. It's assumed that the * signal has already been defined elsewhere. */ static vhdl_var_ref *translate_signal(ivl_expr_t e) { ivl_signal_t sig = ivl_expr_signal(e); const vhdl_scope *scope = find_scope_for_signal(sig); assert(scope); const char *renamed = get_renamed_signal(sig).c_str(); vhdl_decl *decl = scope->get_decl(renamed); assert(decl); // Make sure we can read from this declaration // E.g. if this is an `out' port then we need to make it a buffer decl->ensure_readable(); // Can't generate a constant initialiser for this signal // later as it has already been read if (scope->initializing()) decl->set_initial(NULL); vhdl_var_ref *ref = new vhdl_var_ref(renamed, new vhdl_type(*decl->get_type())); ivl_expr_t off; if (ivl_signal_array_count(sig) > 0 && (off = ivl_expr_oper1(e))) { // Select from an array vhdl_expr *vhd_off = translate_expr(off); if (NULL == vhd_off) { delete ref; return NULL; } vhdl_type integer(VHDL_TYPE_INTEGER); ref->set_slice(vhd_off->cast(&integer)); } return ref; } /* * A numeric literal ends up as std_logic bit string. */ static vhdl_expr *translate_number(ivl_expr_t e) { if (ivl_expr_width(e) == 1) return new vhdl_const_bit(ivl_expr_bits(e)[0]); else return new vhdl_const_bits(ivl_expr_bits(e), ivl_expr_width(e), ivl_expr_signed(e) != 0); } static vhdl_expr *translate_ulong(ivl_expr_t e) { return new vhdl_const_int(ivl_expr_uvalue(e)); } static vhdl_expr *translate_delay(ivl_expr_t e) { return scale_time(get_active_entity(), ivl_expr_delay_val(e)); } static vhdl_expr *translate_reduction(support_function_t f, bool neg, vhdl_expr *operand) { vhdl_expr *result; if (operand->get_type()->get_name() == VHDL_TYPE_STD_LOGIC) result = operand; else { require_support_function(f); vhdl_fcall *fcall = new vhdl_fcall(support_function::function_name(f), vhdl_type::std_logic()); vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); fcall->add_expr(operand->cast(&std_logic_vector)); result = fcall; } if (neg) return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, result, vhdl_type::std_logic()); else return result; } static vhdl_expr *translate_unary(ivl_expr_t e) { vhdl_expr *operand = translate_expr(ivl_expr_oper1(e)); if (NULL == operand) return NULL; operand = correct_signedness(operand, e); char opcode = ivl_expr_opcode(e); switch (opcode) { case '!': case '~': return new vhdl_unaryop_expr (VHDL_UNARYOP_NOT, operand, new vhdl_type(*operand->get_type())); case '-': operand = change_signedness(operand, true); return new vhdl_unaryop_expr (VHDL_UNARYOP_NEG, operand, new vhdl_type(*operand->get_type())); case 'N': // NOR return translate_reduction(SF_REDUCE_OR, true, operand); case '|': return translate_reduction(SF_REDUCE_OR, false, operand); case 'A': // NAND return translate_reduction(SF_REDUCE_AND, true, operand); case '&': return translate_reduction(SF_REDUCE_AND, false, operand); case '^': // XOR return translate_reduction(SF_REDUCE_XOR, false, operand); case 'X': // XNOR return translate_reduction(SF_REDUCE_XNOR, false, operand); default: error("No translation for unary opcode '%c'\n", ivl_expr_opcode(e)); delete operand; return NULL; } } /* * Translate a numeric binary operator (+, -, etc.) to * a VHDL equivalent using the numeric_std package. */ static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs, vhdl_binop_t op) { // May need to make either side Boolean for operators // to work vhdl_type boolean(VHDL_TYPE_BOOLEAN); if (lhs->get_type()->get_name() == VHDL_TYPE_BOOLEAN) rhs = rhs->cast(&boolean); else if (rhs->get_type()->get_name() == VHDL_TYPE_BOOLEAN) lhs = lhs->cast(&boolean); vhdl_type *rtype; if (op == VHDL_BINOP_MULT) rtype = new vhdl_type(lhs->get_type()->get_name(), (lhs->get_type()->get_width()*2) - 1, 0); else rtype = new vhdl_type(*lhs->get_type()); return new vhdl_binop_expr(lhs, op, rhs, rtype); } static vhdl_expr *translate_relation(vhdl_expr *lhs, vhdl_expr *rhs, vhdl_binop_t op) { // Generate any necessary casts // Arbitrarily, the RHS is casted to the type of the LHS vhdl_expr *r_cast = rhs->cast(lhs->get_type()); return new vhdl_binop_expr(lhs, op, r_cast, vhdl_type::boolean()); } /* * Like translate_relation but both operands must be Boolean. */ static vhdl_expr *translate_logical(vhdl_expr *lhs, vhdl_expr *rhs, vhdl_binop_t op) { vhdl_type boolean(VHDL_TYPE_BOOLEAN); return translate_relation(lhs->cast(&boolean), rhs->cast(&boolean), op); } static vhdl_expr *translate_shift(vhdl_expr *lhs, vhdl_expr *rhs, vhdl_binop_t op) { // The RHS must be an integer vhdl_type integer(VHDL_TYPE_INTEGER); vhdl_expr *r_cast = rhs->cast(&integer); vhdl_type *rtype = new vhdl_type(*lhs->get_type()); // The sra operator is not defined on numeric_std types until // VHDL-2006 which is not well supported. Instead we can use // the shift_right function which does the same thing and // exists in earlier versions of numeric_std. if (op == VHDL_BINOP_SRA) { vhdl_fcall *sra = new vhdl_fcall("shift_right", rtype); sra->add_expr(lhs); sra->add_expr(r_cast); return sra; } else return new vhdl_binop_expr(lhs, op, r_cast, rtype); } /* * The exponentiation operator in VHDL is not defined for numeric_std * types. We can get around this by converting the operands to integers, * performing the operation, then converting the result back to the * original type. This will work OK in simulation but certainly will not * synthesise unless the operands are constant. * * However, even this does not work quite correctly. The Integer type in * VHDL is signed and usually only 32 bits, therefore any result larger * than this will overflow and raise an exception. I can't see a way * around this at the moment. */ static vhdl_expr *translate_power(ivl_expr_t e, vhdl_expr *lhs, vhdl_expr *rhs) { vhdl_type integer(VHDL_TYPE_INTEGER); vhdl_expr *lhs_int = lhs->cast(&integer); vhdl_expr *rhs_int = rhs->cast(&integer); vhdl_expr *result = new vhdl_binop_expr(lhs_int, VHDL_BINOP_POWER, rhs_int, vhdl_type::integer()); int width = ivl_expr_width(e); const char *func = ivl_expr_signed(e) ? "To_Signed" : "To_Unsigned"; vhdl_type *type = ivl_expr_signed(e) ? vhdl_type::nsigned(width) : vhdl_type::nunsigned(width); vhdl_fcall *conv = new vhdl_fcall(func, type); conv->add_expr(result); conv->add_expr(new vhdl_const_int(width)); return conv; } static vhdl_expr *translate_binary(ivl_expr_t e) { vhdl_expr *lhs = translate_expr(ivl_expr_oper1(e)); if (NULL == lhs) return NULL; vhdl_expr *rhs = translate_expr(ivl_expr_oper2(e)); if (NULL == rhs) return NULL; int lwidth = lhs->get_type()->get_width(); int rwidth = rhs->get_type()->get_width(); int result_width = ivl_expr_width(e); // For === and !== we need to compare std_logic_vectors // rather than signeds vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, result_width-1, 0); vhdl_type_name_t ltype = lhs->get_type()->get_name(); vhdl_type_name_t rtype = rhs->get_type()->get_name(); bool vectorop = (ltype == VHDL_TYPE_SIGNED || ltype == VHDL_TYPE_UNSIGNED) && (rtype == VHDL_TYPE_SIGNED || rtype == VHDL_TYPE_UNSIGNED); // May need to resize the left or right hand side or change the // signedness if (vectorop) { if (lwidth < rwidth) lhs = lhs->resize(rwidth); else if (rwidth < lwidth) rhs = rhs->resize(lwidth); lhs = correct_signedness(lhs, ivl_expr_oper1(e)); rhs = correct_signedness(rhs, ivl_expr_oper2(e)); } vhdl_expr *result; switch (ivl_expr_opcode(e)) { case '+': result = translate_numeric(lhs, rhs, VHDL_BINOP_ADD); break; case '-': result = translate_numeric(lhs, rhs, VHDL_BINOP_SUB); break; case '*': result = translate_numeric(lhs, rhs, VHDL_BINOP_MULT); break; case '/': result = translate_numeric(lhs, rhs, VHDL_BINOP_DIV); break; case '%': result = translate_numeric(lhs, rhs, VHDL_BINOP_MOD); break; case 'e': result = translate_relation(lhs, rhs, VHDL_BINOP_EQ); break; case 'E': if (vectorop) result = translate_relation(lhs->cast(&std_logic_vector), rhs->cast(&std_logic_vector), VHDL_BINOP_EQ); else result = translate_relation(lhs, rhs, VHDL_BINOP_EQ); break; case 'n': result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ); break; case 'N': if (vectorop) result = translate_relation(lhs->cast(&std_logic_vector), rhs->cast(&std_logic_vector), VHDL_BINOP_NEQ); else result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ); break; case '&': // Bitwise AND result = translate_numeric(lhs, rhs, VHDL_BINOP_AND); break; case 'a': // Logical AND result = translate_logical(lhs, rhs, VHDL_BINOP_AND); break; case 'A': // Bitwise NAND result = translate_numeric(lhs, rhs, VHDL_BINOP_NAND); break; case 'O': // Bitwise NOR result = translate_numeric(lhs, rhs, VHDL_BINOP_NOR); break; case 'X': // Bitwise XNOR result = translate_numeric(lhs, rhs, VHDL_BINOP_XNOR); break; case '|': // Bitwise OR result = translate_numeric(lhs, rhs, VHDL_BINOP_OR); break; case 'o': // Logical OR result = translate_logical(lhs, rhs, VHDL_BINOP_OR); break; case '<': result = translate_relation(lhs, rhs, VHDL_BINOP_LT); break; case 'L': result = translate_relation(lhs, rhs, VHDL_BINOP_LEQ); break; case '>': result = translate_relation(lhs, rhs, VHDL_BINOP_GT); break; case 'G': result = translate_relation(lhs, rhs, VHDL_BINOP_GEQ); break; case 'l': result = translate_shift(lhs, rhs, VHDL_BINOP_SL); break; case 'r': result = translate_shift(lhs, rhs, VHDL_BINOP_SR); break; case 'R': // Arithmetic right shift // Verilog only actually performs a signed shift if the // argument being shifted is signed, otherwise it defaults // to a normal shift if (ivl_expr_signed(ivl_expr_oper1(e))) result = translate_shift(lhs, rhs, VHDL_BINOP_SRA); else result = translate_shift(lhs, rhs, VHDL_BINOP_SR); break; case '^': result = translate_numeric(lhs, rhs, VHDL_BINOP_XOR); break; case 'p': // Power result = translate_power(e, lhs, rhs); break; default: error("No translation for binary opcode '%c'\n", ivl_expr_opcode(e)); delete lhs; delete rhs; return NULL; } if (NULL == result) return NULL; if (vectorop) { result = correct_signedness(result, e); int actual_width = result->get_type()->get_width(); if (actual_width != result_width) { //result->print(); //std::cout << "^ should be " << result_width << " but is " << actual_width << std::endl; } } return result; } static vhdl_expr *translate_select(ivl_expr_t e) { vhdl_expr *from = translate_expr(ivl_expr_oper1(e)); if (NULL == from) return NULL; ivl_expr_t o2 = ivl_expr_oper2(e); if (o2) { vhdl_expr *base = translate_expr(ivl_expr_oper2(e)); if (NULL == base) return NULL; vhdl_var_ref *from_var_ref = dynamic_cast(from); if (NULL == from_var_ref) { // We can't directly select bits from something that's not // a variable reference in VHDL, but we can emulate the // effect with a shift and a resize return new vhdl_binop_expr(from, VHDL_BINOP_SR, base->to_integer(), new vhdl_type(*from->get_type())); } else if (from_var_ref->get_type()->get_name() != VHDL_TYPE_STD_LOGIC) { // We can use the more idiomatic VHDL slice notation on a // single variable reference vhdl_type integer(VHDL_TYPE_INTEGER); from_var_ref->set_slice(base->cast(&integer), ivl_expr_width(e) - 1); return from_var_ref; } else { // Make sure we're not trying to select more than one bit // from a std_logic (this shouldn't actually happen) if (ivl_expr_width(e) > 1) { error("%s:%d: trying to select more than one bit from a std_logic", ivl_expr_file(e), ivl_expr_lineno(e)); return NULL; } else return from_var_ref; } } else return from->resize(ivl_expr_width(e)); } template static T *translate_parms(T *t, ivl_expr_t e) { int nparams = ivl_expr_parms(e); for (int i = 0; i < nparams; i++) { vhdl_expr *param = translate_expr(ivl_expr_parm(e, i)); if (NULL == param) return NULL; t->add_expr(param); } return t; } static vhdl_expr *translate_ufunc(ivl_expr_t e) { ivl_scope_t defscope = ivl_expr_def(e); ivl_scope_t parentscope = ivl_scope_parent(defscope); assert(ivl_scope_type(parentscope) == IVL_SCT_MODULE); // A function is always declared in a module, which should have // a corresponding entity by this point: so we can get type // information, etc. from the declaration vhdl_entity *parent_ent = find_entity(parentscope); assert(parent_ent); const char *funcname = ivl_scope_tname(defscope); vhdl_type *rettype = vhdl_type::type_for(ivl_expr_width(e), ivl_expr_signed(e) != 0); vhdl_fcall *fcall = new vhdl_fcall(funcname, rettype); int nparams = ivl_expr_parms(e); for (int i = 0; i < nparams; i++) { vhdl_expr *param = translate_expr(ivl_expr_parm(e, i)); if (NULL == param) { delete fcall; return NULL; } // Ensure the parameter has the correct VHDL type // Parameter number is i + 1 since 0th parameter is return value ivl_signal_t param_sig = ivl_scope_port(defscope, i + 1); vhdl_type *param_type = vhdl_type::type_for(ivl_signal_width(param_sig), ivl_signal_signed(param_sig) != 0); fcall->add_expr(param->cast(param_type)); delete param_type; } return fcall; } static vhdl_expr *translate_ternary(ivl_expr_t e) { support_function_t sf; int width = ivl_expr_width(e); bool issigned = ivl_expr_signed(e) != 0; if (width == 1) sf = SF_TERNARY_LOGIC; else if (issigned) sf = SF_TERNARY_SIGNED; else sf = SF_TERNARY_UNSIGNED; require_support_function(sf); vhdl_expr *test = translate_expr(ivl_expr_oper1(e)); vhdl_expr *true_part = translate_expr(ivl_expr_oper2(e)); vhdl_expr *false_part = translate_expr(ivl_expr_oper3(e)); if (!test || !true_part || !false_part) return NULL; vhdl_type boolean(VHDL_TYPE_BOOLEAN); test = test->cast(&boolean); vhdl_fcall *fcall = new vhdl_fcall(support_function::function_name(sf), vhdl_type::type_for(width, issigned)); fcall->add_expr(test); fcall->add_expr(true_part); fcall->add_expr(false_part); return fcall; } static vhdl_expr *translate_concat(ivl_expr_t e) { vhdl_type *rtype = vhdl_type::type_for(ivl_expr_width(e), ivl_expr_signed(e) != 0); vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, rtype); int nrepeat = ivl_expr_repeat(e); while (nrepeat--) translate_parms(concat, e); return concat; } vhdl_expr *translate_sfunc_time(ivl_expr_t e) { cerr << "warning: no translation for $time (returning 0)" << endl; vhdl_expr *result = new vhdl_const_int(0); result->set_comment("$time not supported, returned 0 instead!"); return result; } vhdl_expr *translate_sfunc_stime(ivl_expr_t e) { cerr << "warning: no translation for $stime (returning 0)" << endl; vhdl_expr *result = new vhdl_const_int(0); result->set_comment("$stime not supported, returned 0 instead!"); return result; } vhdl_expr *translate_sfunc_simtime(ivl_expr_t e) { cerr << "warning: no translation for $simtime (returning 0)" << endl; vhdl_expr *result = new vhdl_const_int(0); result->set_comment("$simtime not supported, returned 0 instead!"); return result; } vhdl_expr *translate_sfunc_random(ivl_expr_t e) { cerr << "warning: no translation for $random (returning 0)" << endl; vhdl_expr *result = new vhdl_const_int(0); result->set_comment("$random not supported, returned 0 instead!"); return result; } vhdl_expr *translate_sfunc_fopen(ivl_expr_t e) { cerr << "warning: no translation for $fopen (returning 0)" << endl; vhdl_expr *result = new vhdl_const_int(0); result->set_comment("$fopen not supported, returned 0 instead!"); return result; } vhdl_expr *translate_sfunc(ivl_expr_t e) { const char *name = ivl_expr_name(e); if (strcmp(name, "$time") == 0) return translate_sfunc_time(e); else if (strcmp(name, "$stime") == 0) return translate_sfunc_stime(e); else if (strcmp(name, "$simtime") == 0) return translate_sfunc_simtime(e); else if (strcmp(name, "$random") == 0) return translate_sfunc_random(e); else if (strcmp(name, "$fopen") == 0) return translate_sfunc_random(e); else { error("No translation for system function %s", name); return NULL; } } /* * Generate a VHDL expression from a Verilog expression. */ vhdl_expr *translate_expr(ivl_expr_t e) { assert(e); ivl_expr_type_t type = ivl_expr_type(e); switch (type) { case IVL_EX_STRING: return translate_string(e); case IVL_EX_SIGNAL: return translate_signal(e); case IVL_EX_NUMBER: return translate_number(e); case IVL_EX_ULONG: return translate_ulong(e); case IVL_EX_UNARY: return translate_unary(e); case IVL_EX_BINARY: return translate_binary(e); case IVL_EX_SELECT: return translate_select(e); case IVL_EX_UFUNC: return translate_ufunc(e); case IVL_EX_TERNARY: return translate_ternary(e); case IVL_EX_CONCAT: return translate_concat(e); case IVL_EX_SFUNC: return translate_sfunc(e); case IVL_EX_DELAY: return translate_delay(e); case IVL_EX_REALNUM: error("No VHDL translation for real expression at %s:%d", ivl_expr_file(e), ivl_expr_lineno(e)); return NULL; default: error("No VHDL translation for expression at %s:%d (type = %d)", ivl_expr_file(e), ivl_expr_lineno(e), type); return NULL; } } /* * Translate an expression into a time. This is achieved simply * by multiplying the expression by 1ns. */ vhdl_expr *translate_time_expr(ivl_expr_t e) { vhdl_expr *time = translate_expr(e); if (NULL == time) return NULL; if (time->get_type()->get_name() != VHDL_TYPE_TIME) { vhdl_type integer(VHDL_TYPE_INTEGER); time = time->cast(&integer); vhdl_expr *ns1 = scale_time(get_active_entity(), 1); return new vhdl_binop_expr(time, VHDL_BINOP_MULT, ns1, vhdl_type::time()); } else // Translating IVL_EX_DELAY will always return a time type return time; } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/stmt.cc0000644000202500001440000000005012204466647017257 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/stmt.cc0000644000202500001440000014624312204466647016613 0ustar00steveusers00000000000000/* * VHDL code generation for statements. * * Copyright (C) 2008-2011 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_target.h" #include "state.hh" #include #include #include #include #include #include #include #include /* * VHDL has no real equivalent of Verilog's $finish task. The * current solution is to use `assert false ...' to terminate * the simulator. This isn't great, as the simulator will * return a failure exit code when in fact it completed * successfully. * * An alternative is to use the VHPI interface supported by * some VHDL simulators and implement the $finish functionality * in C. This function can be enabled with the flag * -puse-vhpi-finish=1. */ static int draw_stask_finish(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { const char *use_vhpi = ivl_design_flag(get_vhdl_design(), "use-vhpi-finish"); if (strcmp(use_vhpi, "1") == 0) { //get_active_entity()->requires_package("work.Verilog_Support"); container->add_stmt(new vhdl_pcall_stmt("work.Verilog_Support.Finish")); } else { container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED")); } return 0; } /* * Generate VHDL for system tasks (like $display). Not all of * these are supported. */ static int draw_stask(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { const char *name = ivl_stmt_name(stmt); if (strcmp(name, "$display") == 0) return draw_stask_display(proc, container, stmt, true); else if (strcmp(name, "$write") == 0) return draw_stask_display(proc, container, stmt, false); else if (strcmp(name, "$finish") == 0) return draw_stask_finish(proc, container, stmt); else { vhdl_seq_stmt *result = new vhdl_null_stmt(); ostringstream ss; ss << "Unsupported system task " << name << " omitted here (" << ivl_stmt_file(stmt) << ":" << ivl_stmt_lineno(stmt) << ")"; result->set_comment(ss.str()); container->add_stmt(result); cerr << "Warning: no VHDL translation for system task " << name << endl; return 0; } } /* * Generate VHDL for a block of Verilog statements. If this block * doesn't have its own scope then this function does nothing, other * than recursively translate the block's statements and add them * to the process. This is OK as the stmt_container class behaves * like a Verilog block. * * If this block has its own scope with local variables then these * are added to the process as local variables and the statements * are generated as above. */ static int draw_block(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool is_last) { ivl_scope_t block_scope = ivl_stmt_block_scope(stmt); if (block_scope) { int nsigs = ivl_scope_sigs(block_scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(block_scope, i); remember_signal(sig, proc->get_scope()); vhdl_type* type = vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig)); proc->get_scope()->add_decl (new vhdl_var_decl(make_safe_name(sig), type)); } } int count = ivl_stmt_block_count(stmt); for (int i = 0; i < count; i++) { ivl_statement_t stmt_i = ivl_stmt_block_stmt(stmt, i); if (draw_stmt(proc, container, stmt_i, is_last && i == count - 1) != 0) return 1; } return 0; } /* * A no-op statement. This corresponds to a `null' statement in VHDL. */ static int draw_noop(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { container->add_stmt(new vhdl_null_stmt()); return 0; } /* * The VHDL code generator inserts `wait for 0 ns' after each * not-last-in-block blocking assignment. * If this is immediately followed by another `wait for ...' then * we might as well not emit the first zero-time wait. */ void prune_wait_for_0(stmt_container *container) { vhdl_wait_stmt *wait0; stmt_container::stmt_list_t &stmts = container->get_stmts(); while (stmts.size() > 0 && (wait0 = dynamic_cast(stmts.back()))) { if (wait0->get_type() == VHDL_WAIT_FOR0) { delete wait0; stmts.pop_back(); } else break; } } static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope) { ivl_signal_t sig = ivl_lval_sig(lval); if (!sig) { error("Only signals as lvals supported at the moment"); return NULL; } vhdl_expr *base = NULL; ivl_expr_t e_off = ivl_lval_part_off(lval); if (NULL == e_off) e_off = ivl_lval_idx(lval); if (e_off) { if ((base = translate_expr(e_off)) == NULL) return NULL; vhdl_type integer(VHDL_TYPE_INTEGER); base = base->cast(&integer); } unsigned lval_width = ivl_lval_width(lval); string signame(get_renamed_signal(sig)); vhdl_decl *decl = scope->get_decl(signame); assert(decl); // Verilog allows assignments to elements that are constant in VHDL: // function parameters, for example // To work around this we generate a local variable to shadow the // constant and assign to that if (decl->assignment_type() == vhdl_decl::ASSIGN_CONST) { const string shadow_name = signame + "_Shadow"; vhdl_var_decl* shadow_decl = new vhdl_var_decl(shadow_name, decl->get_type()); shadow_decl->set_initial (new vhdl_var_ref(signame, decl->get_type())); scope->add_decl(shadow_decl); // Make sure all future references to this signal use the // shadow variable rename_signal(sig, shadow_name); // ...and use this new variable as the assignment LHS decl = shadow_decl; } vhdl_type *ltype = new vhdl_type(*decl->get_type()); vhdl_var_ref *lval_ref = new vhdl_var_ref(decl->get_name(), ltype); if (base) { if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY) lval_ref->set_slice(base, 0); else if (ivl_signal_width(sig) > 1) lval_ref->set_slice(base, lval_width - 1); } return lval_ref; } static bool assignment_lvals(ivl_statement_t stmt, vhdl_procedural *proc, list &lvals) { int nlvals = ivl_stmt_lvals(stmt); for (int i = 0; i < nlvals; i++) { ivl_lval_t lval = ivl_stmt_lval(stmt, i); vhdl_var_ref *lhs = make_assign_lhs(lval, proc->get_scope()); if (NULL == lhs) return false; lvals.push_back(lhs); } return true; } /* * Generate the right sort of assignment statement for assigning * `lhs' to `rhs'. */ static vhdl_abstract_assign_stmt * assign_for(vhdl_decl::assign_type_t atype, vhdl_var_ref *lhs, vhdl_expr *rhs) { switch (atype) { case vhdl_decl::ASSIGN_BLOCK: case vhdl_decl::ASSIGN_CONST: return new vhdl_assign_stmt(lhs, rhs); case vhdl_decl::ASSIGN_NONBLOCK: return new vhdl_nbassign_stmt(lhs, rhs); } assert(false); return NULL; } /* * Check that this assignment type is valid within the context of `proc'. * For example, a <= assignment is not valid within a function. */ bool check_valid_assignment(vhdl_decl::assign_type_t atype, vhdl_procedural *proc, ivl_statement_t stmt) { if (atype == vhdl_decl::ASSIGN_NONBLOCK && !proc->get_scope()->allow_signal_assignment()) { error("Unable to translate assignment at %s:%d\n" " Translating this would require generating a non-blocking (<=)\n" " assignment in a VHDL context where this is disallowed (e.g.\n" " a function).", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt)); return false; } else return true; } // Generate an assignment of type T for the Verilog statement stmt. // If a statement was generated then `assign_type' will contain the // type of assignment that was generated; this should be initialised // to some sensible default. void make_assignment(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool blocking, vhdl_decl::assign_type_t& assign_type) { list lvals; if (!assignment_lvals(stmt, proc, lvals)) return; vhdl_expr *rhs, *rhs2 = NULL; ivl_expr_t rval = ivl_stmt_rval(stmt); if (ivl_expr_type(rval) == IVL_EX_TERNARY) { rhs = translate_expr(ivl_expr_oper2(rval)); rhs2 = translate_expr(ivl_expr_oper3(rval)); if (rhs2 == NULL) return; } else rhs = translate_expr(rval); if (rhs == NULL) return; if (lvals.size() == 1) { vhdl_var_ref *lhs = lvals.front(); rhs = rhs->cast(lhs->get_type()); ivl_expr_t i_delay; vhdl_expr *after = NULL; if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) after = translate_time_expr(i_delay); // Find the declaration of the LHS so we know what type // of assignment statement to generate (is it a signal, // a variable, etc?) vhdl_decl *decl = proc->get_scope()->get_decl(lhs->get_name()); assign_type = decl->assignment_type(); // A small optimisation is to expand ternary RHSs into an // if statement (eliminates a function call and produces // more idiomatic code) if (ivl_expr_type(rval) == IVL_EX_TERNARY) { rhs2 = rhs2->cast(lhs->get_type()); vhdl_var_ref *lhs2 = make_assign_lhs(ivl_stmt_lval(stmt, 0), proc->get_scope()); vhdl_expr *test = translate_expr(ivl_expr_oper1(rval)); if (NULL == test) return; if (!check_valid_assignment(decl->assignment_type(), proc, stmt)) return; vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); // True part { vhdl_abstract_assign_stmt *a = assign_for(decl->assignment_type(), lhs, rhs); if (after) a->set_after(after); vhdif->get_then_container()->add_stmt(a); } // False part { vhdl_abstract_assign_stmt *a = assign_for(decl->assignment_type(), lhs2, rhs2); if (after) a->set_after(translate_time_expr(i_delay)); vhdif->get_else_container()->add_stmt(a); } container->add_stmt(vhdif); return; } // Where possible, move constant assignments into the // declaration as initialisers. This optimisation is only // performed on assignments of constant values to prevent // ordering problems. // This also has another application: If this is an `initial' // process and we haven't yet generated a `wait' statement then // moving the assignment to the initialization preserves the // expected Verilog behaviour: VHDL does not distinguish // `initial' and `always' processes so an `always' process might // be activated before an `initial' process at time 0. The // `always' process may then use the uninitialised signal value. // The second test ensures that we only try to initialise // internal signals not ports ivl_lval_t lval = ivl_stmt_lval(stmt, 0); if (proc->get_scope()->initializing() && ivl_signal_port(ivl_lval_sig(lval)) == IVL_SIP_NONE && !decl->has_initial() && rhs->constant() && decl->get_type()->get_name() != VHDL_TYPE_ARRAY) { // If this assignment is not in the top-level container // it will not be made on all paths through the code // This precludes any future extraction of an initialiser if (container != proc->get_container()) decl->set_initial(NULL); // Default initial value else { decl->set_initial(rhs); delete lhs; return; } } if (!check_valid_assignment(decl->assignment_type(), proc, stmt)) return; vhdl_abstract_assign_stmt *a = assign_for(decl->assignment_type(), lhs, rhs); container->add_stmt(a); if (after != NULL) a->set_after(after); } else { // Multiple lvals are implemented by first assigning the complete // RHS to a temporary, and then assigning each lval in turn as // bit-selects of the temporary static int tmp_count = 0; ostringstream ss; ss << "Verilog_Assign_Tmp_" << tmp_count++; vhdl_decl* tmp_decl = new vhdl_var_decl(ss.str(), rhs->get_type()); proc->get_scope()->add_decl(tmp_decl); container->add_stmt(new vhdl_assign_stmt(tmp_decl->make_ref(), rhs)); list::iterator it; int width_so_far = 0; for (it = lvals.begin(); it != lvals.end(); ++it) { vhdl_var_ref *tmp_rhs = tmp_decl->make_ref(); int lval_width = (*it)->get_type()->get_width(); vhdl_expr *slice_base = new vhdl_const_int(width_so_far); tmp_rhs->set_slice(slice_base, lval_width - 1); ivl_expr_t i_delay; vhdl_expr *after = NULL; if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) after = translate_time_expr(i_delay); // Find the declaration of the LHS so we know what type // of assignment statement to generate (is it a signal, // a variable, etc?) vhdl_decl *decl = proc->get_scope()->get_decl((*it)->get_name()); assign_type = decl->assignment_type(); if (!check_valid_assignment(decl->assignment_type(), proc, stmt)) return; vhdl_abstract_assign_stmt *a = assign_for(decl->assignment_type(), *it, tmp_rhs); if (after) a->set_after(after); container->add_stmt(a); width_so_far += lval_width; } } return; } /* * A non-blocking assignment inside a process. The semantics for * this are essentially the same as VHDL's non-blocking signal * assignment. */ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { assert(proc->get_scope()->allow_signal_assignment()); vhdl_decl::assign_type_t ignored; make_assignment(proc, container, stmt, false, ignored); return 0; } static int draw_assign(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool is_last) { vhdl_decl::assign_type_t assign_type = vhdl_decl::ASSIGN_NONBLOCK; if (proc->get_scope()->allow_signal_assignment()) { // Blocking assignment is implemented as non-blocking assignment // followed by a zero-time wait // This follows the Verilog semantics fairly closely. make_assignment(proc, container, stmt, false, assign_type); // Don't generate a zero-wait if either: // a) this is the last statement in the process // c) a blocking assignment was generated if (!is_last && assign_type == vhdl_decl::ASSIGN_NONBLOCK) { prune_wait_for_0(container); container->add_stmt (new vhdl_wait_stmt(VHDL_WAIT_FOR0)); proc->added_wait_stmt(); } } else make_assignment(proc, container, stmt, true, assign_type); return 0; } /* * Delay statements are equivalent to the `wait for' form of the * VHDL wait statement. */ static int draw_delay(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { // This currently ignores the time units and precision // of the enclosing scope // A neat way to do this would be to make these values // constants in the scope (type is Time), and have the // VHDL wait statement compute the value from that. // The other solution is to add them as parameters to // the vhdl_process class vhdl_expr *time; if (ivl_statement_type(stmt) == IVL_ST_DELAY) { uint64_t value = ivl_stmt_delay_val(stmt); time = scale_time(get_active_entity(), value); } else { time = translate_time_expr(ivl_stmt_delay_expr(stmt)); if (NULL == time) return 1; } prune_wait_for_0(container); ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_FOR, time); // Remember that we needed a wait statement so if this is // a process it cannot have a sensitivity list proc->added_wait_stmt(); container->add_stmt(wait); // Expand the sub-statement as well // Often this would result in a useless `null' statement which // is caught here instead if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP) draw_stmt(proc, container, sub_stmt); // Any further assignments occur after simulation time 0 // so they cannot be used to initialise signal declarations // (if this scope is an initial process) proc->get_scope()->set_initializing(false); return 0; } /* * Build a set of all the nexuses referenced by signals in `expr'. */ static void get_nexuses_from_expr(ivl_expr_t expr, set &out) { switch (ivl_expr_type(expr)) { case IVL_EX_SIGNAL: out.insert(ivl_signal_nex(ivl_expr_signal(expr), 0)); break; case IVL_EX_TERNARY: get_nexuses_from_expr(ivl_expr_oper3(expr), out); case IVL_EX_BINARY: get_nexuses_from_expr(ivl_expr_oper2(expr), out); case IVL_EX_UNARY: get_nexuses_from_expr(ivl_expr_oper1(expr), out); break; default: break; } } /* * Attempt to identify common forms of wait statements and produce * more idiomatic VHDL than would be produced by the generic * draw_wait function. The main application of this is a input to * synthesis tools that don't synthesise the full VHDL language. * If none of these patterns are matched, the function returns false * and the default draw_wait is used. * * Current patterns: * always @(posedge A or posedge B) * if (A) * ... * else * ... * * This is assumed to be the template for a FF with asynchronous * reset. A is assumed to be the reset as it is dominant. This will * produce the following VHDL: * * process (A, B) is * begin * if A = '1' then * ... * else if rising_edge(B) then * ... * end if; * end process; */ static bool draw_synthesisable_wait(vhdl_process *proc, stmt_container *container, ivl_statement_t stmt) { // At the moment this only detects FFs with an asynchronous reset // All other code will fall back on the default draw_wait // Store a set of the edge triggered signals // The second item is true if this is positive-edge set edge_triggered; const int nevents = ivl_stmt_nevent(stmt); for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); if (ivl_event_nany(event) > 0) return false; int npos = ivl_event_npos(event); for (int j = 0; j < npos; j++) edge_triggered.insert(ivl_event_pos(event, j)); int nneg = ivl_event_nneg(event); for (int j = 0; j < nneg; j++) edge_triggered.insert(ivl_event_neg(event, j)); } // If we're edge-sensitive to less than two signals this doesn't // match the expected template, so use the default draw_wait if (edge_triggered.size() < 2) return false; // Now check to see if the immediately embedded statement is an `if' ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); if (ivl_statement_type(sub_stmt) != IVL_ST_CONDIT) return false; // The if should have two branches: one is the reset branch and // one is the clocked branch if (ivl_stmt_cond_false(sub_stmt) == NULL) return false; // Check the first branch of the if statement // If it matches exactly one of the edge-triggered signals then assume // this is the (dominant) reset branch set test_nexuses; get_nexuses_from_expr(ivl_stmt_cond_expr(sub_stmt), test_nexuses); // Now subtracting this set from the set of edge triggered events // should leave just one nexus, which is hopefully the clock. // If not, then we fall back on the default draw_wait set clock_net; set_difference(edge_triggered.begin(), edge_triggered.end(), test_nexuses.begin(), test_nexuses.end(), inserter(clock_net, clock_net.begin())); if (clock_net.size() != 1) return false; // Build a VHDL `if' statement to model this vhdl_expr *reset_test = translate_expr(ivl_stmt_cond_expr(sub_stmt)); vhdl_if_stmt *body = new vhdl_if_stmt(reset_test); // Draw the reset branch draw_stmt(proc, body->get_then_container(), ivl_stmt_cond_true(sub_stmt)); // Build a test for the clock event vhdl_fcall *edge = NULL; ivl_nexus_t the_clock_net = *clock_net.begin(); for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); const unsigned npos = ivl_event_npos(event); for (unsigned j = 0; j < npos; j++) { if (ivl_event_pos(event, j) == the_clock_net) edge = new vhdl_fcall("rising_edge", vhdl_type::boolean()); } const unsigned nneg = ivl_event_nneg(event); for (unsigned j = 0; j < nneg; j++) if (ivl_event_neg(event, j) == the_clock_net) edge = new vhdl_fcall("falling_edge", vhdl_type::boolean()); } assert(edge); edge->add_expr(nexus_to_var_ref(proc->get_scope(), *clock_net.begin())); // Draw the clocked branch // For an asynchronous reset we just want this around the else branch, stmt_container *else_container = body->add_elsif(edge); draw_stmt(proc, else_container, ivl_stmt_cond_false(sub_stmt)); if (proc->contains_wait_stmt()) { // Expanding the body produced a `wait' statement which can't // be included in a sensitised process so undo all this work // and fall back on the default draw_wait delete body; return false; } else container->add_stmt(body); // Add all the edge triggered signals to the sensitivity list for (set::const_iterator it = edge_triggered.begin(); it != edge_triggered.end(); ++it) { // Get the signal that represents this nexus in this scope vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), *it); proc->add_sensitivity(ref->get_name()); // Don't need the reference any more delete ref; } // Don't bother with the default draw_wait return true; } /* * A wait statement waits for a level change on a @(..) list of * signals. The logic here might seem a little bit convoluted, * it attempts to always produce something that will simulate * correctly, and tries to produce something that will also * synthesise correctly (although not at the expense of simulation * accuracy). * * The difficulty stems from VHDL's restriction that a process with * a sensitivity list may not contain any `wait' statements: we need * to generate these to accurately model some Verilog statements. * * The steps followed are: * 1) Determine whether this is the top-level statement in the process * 2) If this is top-level, call draw_synthesisable_wait to see if the * process and wait statement match any templates for which we know * how to produce good, idiomatic synthesisable VHDL (e.g. FF with * async reset) * 3) Determine whether the process is combinatorial (purely level * sensitive), or sequential (edge sensitive) * 4) Draw all of the statements in the body * 5) One of the following will be true: * A) The process is combinatorial, top-level, and there are * no `wait' statements in the body: add all the level-sensitive * signals to the VHDL sensitivity list * B) The process is combinatorial, and there *are* `wait' * statements in the body or it is not top-level: generate * a VHDL `wait-on' statement at the end of the body containing * the level-sensitive signals * C) The process is sequential, top-level, and there are * no `wait' statements in the body: build an `if' statement * with the edge-detecting expression and wrap the process * in it. * D) The process is sequential, there *are* `wait' statements * in the body, or it is not top-level: generate a VHDL * `wait-until' with the edge-detecting expression and add * it before the body of the wait event. */ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, ivl_statement_t stmt) { // Wait statements only occur in processes vhdl_process *proc = dynamic_cast(_proc); assert(proc); // Catch not process // If this container is the top-level statement (i.e. it is the // first thing inside a process) then we can extract these // events out into the sensitivity list bool is_top_level = container == proc->get_container() && container->empty(); // See if this can be implemented in a more idiomatic way before we // fall back on the generic translation if (is_top_level && draw_synthesisable_wait(proc, container, stmt)) return 0; int nevents = ivl_stmt_nevent(stmt); bool combinatorial = true; // True if no negedge/posedge events for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); if (ivl_event_npos(event) > 0 || ivl_event_nneg(event) > 0) combinatorial = false; } if (combinatorial) { // If the process has no wait statement in its body then // add all the events to the sensitivity list, otherwise // build a wait-on statement at the end of the process draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt), true); vhdl_wait_stmt *wait = NULL; if (proc->contains_wait_stmt() || !is_top_level) wait = new vhdl_wait_stmt(VHDL_WAIT_ON); for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); int nany = ivl_event_nany(event); for (int j = 0; j < nany; j++) { ivl_nexus_t nexus = ivl_event_any(event, j); vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); if (wait) wait->add_sensitivity(ref->get_name()); else proc->add_sensitivity(ref->get_name()); delete ref; } } if (wait) container->add_stmt(wait); } else { // Build a test expression to represent the edge event // If this process contains no `wait' statements and this // is the top-level container then we // wrap it in an `if' statement with this test and add the // edge triggered signals to the sensitivity, otherwise // build a `wait until' statement at the top of the process vhdl_binop_expr *test = new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean()); stmt_container tmp_container; draw_stmt(proc, &tmp_container, ivl_stmt_sub_stmt(stmt), true); for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); int nany = ivl_event_nany(event); for (int j = 0; j < nany; j++) { ivl_nexus_t nexus = ivl_event_any(event, j); vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); ref->set_name(ref->get_name() + "'Event"); test->add_expr(ref); if (!proc->contains_wait_stmt() && is_top_level) proc->add_sensitivity(ref->get_name()); } int nneg = ivl_event_nneg(event); for (int j = 0; j < nneg; j++) { ivl_nexus_t nexus = ivl_event_neg(event, j); vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); vhdl_fcall *detect = new vhdl_fcall("falling_edge", vhdl_type::boolean()); detect->add_expr(ref); test->add_expr(detect); if (!proc->contains_wait_stmt() && is_top_level) proc->add_sensitivity(ref->get_name()); } int npos = ivl_event_npos(event); for (int j = 0; j < npos; j++) { ivl_nexus_t nexus = ivl_event_pos(event, j); vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); vhdl_fcall *detect = new vhdl_fcall("rising_edge", vhdl_type::boolean()); detect->add_expr(ref); test->add_expr(detect); if (!proc->contains_wait_stmt() && is_top_level) proc->add_sensitivity(ref->get_name()); } } if (proc->contains_wait_stmt() || !is_top_level) { container->add_stmt(new vhdl_wait_stmt(VHDL_WAIT_UNTIL, test)); container->move_stmts_from(&tmp_container); } else { // Wrap the whole process body in an `if' statement to detect // the edge event vhdl_if_stmt *edge_detect = new vhdl_if_stmt(test); // Move all the statements from the process body into the `if' // statement edge_detect->get_then_container()->move_stmts_from(&tmp_container); container->add_stmt(edge_detect); } } return 0; } static int draw_if(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool is_last) { vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); if (NULL == test) return 1; vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); ivl_statement_t cond_true_stmt = ivl_stmt_cond_true(stmt); if (cond_true_stmt) draw_stmt(proc, vhdif->get_then_container(), cond_true_stmt, is_last); ivl_statement_t cond_false_stmt = ivl_stmt_cond_false(stmt); if (cond_false_stmt) draw_stmt(proc, vhdif->get_else_container(), cond_false_stmt, is_last); container->add_stmt(vhdif); return 0; } static vhdl_var_ref *draw_case_test(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); if (NULL == test) return NULL; // VHDL case expressions are required to be quite simple: variable // references or slices. So we may need to create a temporary // variable to hold the result of the expression evaluation if (typeid(*test) != typeid(vhdl_var_ref)) { const char *tmp_name = "Verilog_Case_Ex"; vhdl_type *test_type = new vhdl_type(*test->get_type()); if (!proc->get_scope()->have_declared(tmp_name)) { proc->get_scope()->add_decl (new vhdl_var_decl(tmp_name, new vhdl_type(*test_type))); } vhdl_var_ref *tmp_ref = new vhdl_var_ref(tmp_name, NULL); container->add_stmt(new vhdl_assign_stmt(tmp_ref, test)); return new vhdl_var_ref(tmp_name, test_type); } else return dynamic_cast(test); } static int draw_case(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool is_last) { vhdl_var_ref *test = draw_case_test(proc, container, stmt); if (NULL == test) return 1; vhdl_case_stmt *vhdlcase = new vhdl_case_stmt(test); container->add_stmt(vhdlcase); // VHDL is more strict than Verilog about covering every // possible case. So make sure we add an 'others' branch // if there isn't a default one. bool have_others = false; int nbranches = ivl_stmt_case_count(stmt); for (int i = 0; i < nbranches; i++) { vhdl_expr *when; ivl_expr_t net = ivl_stmt_case_expr(stmt, i); if (net) { when = translate_expr(net)->cast(test->get_type()); if (NULL == when) return 1; } else { when = new vhdl_var_ref("others", NULL); have_others = true; } vhdl_case_branch *branch = new vhdl_case_branch(when); vhdlcase->add_branch(branch); ivl_statement_t stmt_i = ivl_stmt_case_stmt(stmt, i); draw_stmt(proc, branch->get_container(), stmt_i, is_last); } if (!have_others) { vhdl_case_branch *others = new vhdl_case_branch(new vhdl_var_ref("others", NULL)); others->get_container()->add_stmt(new vhdl_null_stmt()); vhdlcase->add_branch(others); } return 0; } /* * Check to see if the given number (expression) can be represented * accurately in a long value. */ static bool number_is_long(ivl_expr_t expr) { ivl_expr_type_t type = ivl_expr_type(expr); assert(type == IVL_EX_NUMBER || type == IVL_EX_ULONG); // Make sure the ULONG can be represented correctly in a long. if (type == IVL_EX_ULONG) { unsigned long val = ivl_expr_uvalue(expr); if (val > static_cast(numeric_limits::max())) { return false; } return true; } // Check to see if the number actually fits in a long. unsigned nbits = ivl_expr_width(expr); if (nbits >= 8*sizeof(long)) { const char*bits = ivl_expr_bits(expr); char pad_bit = bits[nbits-1]; for (unsigned idx = 8*sizeof(long); idx < nbits; idx++) { if (bits[idx] != pad_bit) return false; } } return true; } /* * Return the given number (expression) as a signed long value. * * Make sure to call number_is_long() first to verify that the number * can be represented accurately in a long value. */ static long get_number_as_long(ivl_expr_t expr) { long imm = 0; switch (ivl_expr_type(expr)) { case IVL_EX_ULONG: imm = ivl_expr_uvalue(expr); break; case IVL_EX_NUMBER: { const char*bits = ivl_expr_bits(expr); unsigned nbits = ivl_expr_width(expr); if (nbits > 8*sizeof(long)) nbits = 8*sizeof(long); for (unsigned idx = 0; idx < nbits; idx++) { switch (bits[idx]) { case '0': break; case '1': imm |= 1L << idx; break; default: assert(0); } if (ivl_expr_signed(expr) && bits[nbits-1] == '1' && nbits < 8*sizeof(long)) imm |= -1L << nbits; } break; } default: assert(0); } return imm; } /* * Build a check against a constant 'x'. This is for an out of range * or undefined select. */ static void check_against_x(vhdl_binop_expr *all, vhdl_var_ref *test, ivl_expr_t expr, unsigned width, unsigned base, bool is_casez) { if (is_casez) { // For a casez we need to check against 'x'. for (unsigned i = 0; i < ivl_expr_width(expr); i++) { vhdl_binop_expr *sub_expr = new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean()); vhdl_type *type; vhdl_var_ref *ref; // Check if the test bit is 'z'. type = vhdl_type::nunsigned(width); ref = new vhdl_var_ref(test->get_name().c_str(), type); ref->set_slice(new vhdl_const_int(i+base)); vhdl_binop_expr *cmp = new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean()); cmp->add_expr(ref); cmp->add_expr(new vhdl_const_bit('z')); sub_expr->add_expr(cmp); // Compare the test bit against a constant 'x'. type = vhdl_type::nunsigned(width); ref = new vhdl_var_ref(test->get_name().c_str(), type); ref->set_slice(new vhdl_const_int(i+base)); cmp = new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean()); cmp->add_expr(ref); cmp->add_expr(new vhdl_const_bit('x')); sub_expr->add_expr(cmp); all->add_expr(sub_expr); } } else { // For a casex 'x' is a don't care, so just put 'true'. all->add_expr(new vhdl_const_bool(true)); } } /* * Build the test signal to constant bits check. */ static void process_number(vhdl_binop_expr *all, vhdl_var_ref *test, ivl_expr_t expr, unsigned width, unsigned base, bool is_casez) { const char *bits = ivl_expr_bits(expr); bool just_dont_care = true; for (unsigned i = 0; i < ivl_expr_width(expr); i++) { switch (bits[i]) { case 'x': if (is_casez) break; case '?': case 'z': continue; // Ignore these. } vhdl_binop_expr *sub_expr = new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean()); vhdl_type *type; vhdl_var_ref *ref; // Check if the test bit is 'z'. type = vhdl_type::nunsigned(width); ref = new vhdl_var_ref(test->get_name().c_str(), type); ref->set_slice(new vhdl_const_int(i+base)); vhdl_binop_expr *cmp = new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean()); cmp->add_expr(ref); cmp->add_expr(new vhdl_const_bit('z')); sub_expr->add_expr(cmp); // If this is a casex statement check if the test bit is 'x'. if (!is_casez) { type = vhdl_type::nunsigned(width); ref = new vhdl_var_ref(test->get_name().c_str(), type); ref->set_slice(new vhdl_const_int(i+base)); cmp = new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean()); cmp->add_expr(ref); cmp->add_expr(new vhdl_const_bit('x')); sub_expr->add_expr(cmp); } // Compare the bit against the constant value. type = vhdl_type::nunsigned(width); ref = new vhdl_var_ref(test->get_name().c_str(), type); ref->set_slice(new vhdl_const_int(i+base)); cmp = new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean()); cmp->add_expr(ref); cmp->add_expr(new vhdl_const_bit(bits[i])); sub_expr->add_expr(cmp); all->add_expr(sub_expr); just_dont_care = false; } // If there are no bits comparisons then just put a True if (just_dont_care) { all->add_expr(new vhdl_const_bool(true)); } } /* * Build the test signal to label signal check. */ static bool process_signal(vhdl_binop_expr *all, vhdl_var_ref *test, ivl_expr_t expr, unsigned width, unsigned base, bool is_casez, unsigned swid, long sbase) { // If the word or dimensions are not zero then we have an array. if (ivl_expr_oper1(expr) != 0 || ivl_signal_dimensions(ivl_expr_signal(expr)) != 0) { error("Sorry, array selects are not currently allowed in this " "context."); return true; } unsigned ewid = ivl_expr_width(expr); if (sizeof(unsigned) >= sizeof(long)) { // Since we will be casting i (constrained by swid) to a long make sure // it will fit into a long. This is actually off by one, but this is the // best we can do since on 32 bit machines an unsigned and long are the // same size. assert(swid <= static_cast(numeric_limits::max())); // We are also going to cast ewid to long so check it as well. assert(ewid <= static_cast(numeric_limits::max())); } for (unsigned i = 0; i < swid; i++) { // Generate a comparison for this bit position vhdl_binop_expr *cmp; vhdl_type *type; vhdl_var_ref *ref; // Check if this is an out of bounds access. If this is a casez // then check against a constant 'x' for the out of bound bits // otherwise skip the check (casex). if (static_cast(i) + sbase >= static_cast(ewid) || static_cast(i) + sbase < 0) { if (is_casez) { // Get the current test bit. type = vhdl_type::nunsigned(width); ref = new vhdl_var_ref(test->get_name().c_str(), type); ref->set_slice(new vhdl_const_int(i+base)); // Compare the bit against 'x'. cmp = new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean()); cmp->add_expr(ref); cmp->add_expr(new vhdl_const_bit('x')); all->add_expr(cmp); continue; } else { // The compiler replaces a completely out of range select // with a constant so we know there will be at least one // valid bit here. We don't need a just_dont_care test. continue; } } vhdl_binop_expr *sub_expr = new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean()); vhdl_var_ref *bit; // Get the current expression bit. // Why can we reuse the expression bit, but not the condition bit? type = vhdl_type::nunsigned(ivl_expr_width(expr)); bit = new vhdl_var_ref(ivl_expr_name(expr), type); bit->set_slice(new vhdl_const_int(i+sbase)); // Check if the expression bit is 'z'. cmp = new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean()); cmp->add_expr(bit); cmp->add_expr(new vhdl_const_bit('z')); sub_expr->add_expr(cmp); // If this is a casex statement check if the expression bit is 'x'. if (!is_casez) { cmp = new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean()); cmp->add_expr(bit); cmp->add_expr(new vhdl_const_bit('x')); sub_expr->add_expr(cmp); } // Check if the test bit is 'z'. type = vhdl_type::nunsigned(width); ref = new vhdl_var_ref(test->get_name().c_str(), type); ref->set_slice(new vhdl_const_int(i+base)); cmp = new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean()); cmp->add_expr(ref); cmp->add_expr(new vhdl_const_bit('z')); sub_expr->add_expr(cmp); // If this is a casex statement check if the test bit is 'x'. if (!is_casez) { type = vhdl_type::nunsigned(width); ref = new vhdl_var_ref(test->get_name().c_str(), type); ref->set_slice(new vhdl_const_int(i+base)); cmp = new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean()); cmp->add_expr(ref); cmp->add_expr(new vhdl_const_bit('x')); sub_expr->add_expr(cmp); } // Next check if the test and expression bits are equal. type = vhdl_type::nunsigned(width); ref = new vhdl_var_ref(test->get_name().c_str(), type); ref->set_slice(new vhdl_const_int(i+base)); cmp = new vhdl_binop_expr(VHDL_BINOP_EQ, vhdl_type::boolean()); cmp->add_expr(ref); cmp->add_expr(bit); sub_expr->add_expr(cmp); all->add_expr(sub_expr); } return false; } /* * These are the constructs that we allow in a casex/z label * expression. Returns true on failure. */ static bool process_expr_bits(vhdl_binop_expr *all, vhdl_var_ref *test, ivl_expr_t expr, unsigned width, unsigned base, bool is_casez) { assert(ivl_expr_width(expr)+base <= width); switch (ivl_expr_type(expr)) { case IVL_EX_CONCAT: // Loop repeat number of times processing each sub element. for (unsigned repeat = 0; repeat < ivl_expr_repeat(expr); repeat++) { unsigned nparms = ivl_expr_parms(expr) - 1; for (unsigned parm = 0; parm <= nparms; parm++) { ivl_expr_t pexpr = ivl_expr_parm(expr, nparms-parm); if (process_expr_bits(all, test, pexpr, width, base, is_casez)) return true; base += ivl_expr_width(pexpr); } } break; case IVL_EX_NUMBER: process_number(all, test, expr, width, base, is_casez); break; case IVL_EX_SIGNAL: if (process_signal(all, test, expr, width, base, is_casez, ivl_expr_width(expr), 0)) return true; break; case IVL_EX_SELECT: { ivl_expr_t bexpr = ivl_expr_oper2(expr); if (ivl_expr_type(bexpr) != IVL_EX_NUMBER && ivl_expr_type(bexpr) != IVL_EX_ULONG) { error("Sorry, only constant bit/part selects are currently allowed " "in this context."); return true; } // If the number is out of bounds or an 'x' then check against 'x'. if (!number_is_long(bexpr)) { check_against_x(all, test, expr, width, base, is_casez); } else if (process_signal(all, test, ivl_expr_oper1(expr), width, base, is_casez, ivl_expr_width(expr), get_number_as_long(bexpr))) return true; break; } default: error("Sorry, expression type %d is not currently supported.", ivl_expr_type(expr)); return true; break; } return false; } /* * A casex/z statement cannot be directly translated to a VHDL case * statement as VHDL does not treat the don't-care bit as special. * The solution here is to generate an if statement from the casex/z * which compares only the non-don't-care bit positions. */ int draw_casezx(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool is_last) { vhdl_var_ref *test = draw_case_test(proc, container, stmt); if (NULL == test) return 1; vhdl_if_stmt *result = NULL; int nbranches = ivl_stmt_case_count(stmt); bool is_casez = ivl_statement_type(stmt) == IVL_ST_CASEZ; for (int i = 0; i < nbranches; i++) { stmt_container *where = NULL; ivl_expr_t net = ivl_stmt_case_expr(stmt, i); if (net) { vhdl_binop_expr *all = new vhdl_binop_expr(VHDL_BINOP_AND, vhdl_type::boolean()); // The net must be something we can generate a comparison for. if (process_expr_bits(all, test, net, ivl_expr_width(net), 0, is_casez)) { error("%s:%d: Sorry, only case%s statements with simple " "expression labels can be translated to VHDL", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), (is_casez ? "z" : "x")); delete all; return 1; } if (result) where = result->add_elsif(all); else { result = new vhdl_if_stmt(all); where = result->get_then_container(); } } else { // This the default case and therefore the `else' branch assert(result); where = result->get_else_container(); } // `where' now points to a branch of an if statement which // corresponds to this casex/z branch assert(where); draw_stmt(proc, where, ivl_stmt_case_stmt(stmt, i), is_last); } // Add a comment to say that this corresponds to a casex/z statement // as this may not be obvious ostringstream ss; ss << "Generated from case" << (is_casez ? 'z' : 'x') << " statement at " << ivl_stmt_file(stmt) << ":" << ivl_stmt_lineno(stmt); result->set_comment(ss.str()); container->add_stmt(result); // We don't actually use the generated `test' expression delete test; return 0; } int draw_while(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { // Generate the body inside a temporary container before // generating the test // The reason for this is that some of the signals in the // test might be renamed while expanding the body (e.g. if // we need to generate an assignment to a constant signal) stmt_container tmp_container; int rc = draw_stmt(proc, &tmp_container, ivl_stmt_sub_stmt(stmt)); if (rc != 0) return 1; vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); if (NULL == test) return 1; // The test must be a Boolean (and std_logic and (un)signed types // must be explicitly cast unlike in Verilog) vhdl_type boolean(VHDL_TYPE_BOOLEAN); test = test->cast(&boolean); vhdl_while_stmt *loop = new vhdl_while_stmt(test); draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt)); container->add_stmt(loop); return 0; } int draw_forever(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { vhdl_loop_stmt *loop = new vhdl_loop_stmt; container->add_stmt(loop); draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt)); return 0; } int draw_repeat(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { vhdl_expr *times = translate_expr(ivl_stmt_cond_expr(stmt)); if (NULL == times) return 1; vhdl_type integer(VHDL_TYPE_INTEGER); times = times->cast(&integer); const char *it_name = "Verilog_Repeat"; vhdl_for_stmt *loop = new vhdl_for_stmt(it_name, new vhdl_const_int(1), times); container->add_stmt(loop); draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt)); return 0; } /* * Tasks are difficult to translate to VHDL since they allow things * not allowed by VHDL's corresponding procedures (e.g. updating * global variables. The solution here is to expand tasks in-line. */ int draw_utask(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { ivl_scope_t tscope = ivl_stmt_call(stmt); // TODO: adding some comments to the output would be helpful // TOOD: this completely ignores parameters! draw_stmt(proc, container, ivl_scope_def(tscope), false); return 0; } /* * Generate VHDL statements for the given Verilog statement and * add them to the given VHDL process. The container is the * location to add statements: e.g. the process body, a branch * of an if statement, etc. * * The flag is_last should be set if this is the final statement * in a block or process. It avoids generating useless `wait for 0ns' * statements if the next statement would be a wait anyway. */ int draw_stmt(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool is_last) { assert(stmt); switch (ivl_statement_type(stmt)) { case IVL_ST_STASK: return draw_stask(proc, container, stmt); case IVL_ST_BLOCK: return draw_block(proc, container, stmt, is_last); case IVL_ST_NOOP: return draw_noop(proc, container, stmt); case IVL_ST_ASSIGN: return draw_assign(proc, container, stmt, is_last); case IVL_ST_ASSIGN_NB: return draw_nbassign(proc, container, stmt); case IVL_ST_DELAY: case IVL_ST_DELAYX: return draw_delay(proc, container, stmt); case IVL_ST_WAIT: return draw_wait(proc, container, stmt); case IVL_ST_CONDIT: return draw_if(proc, container, stmt, is_last); case IVL_ST_CASE: return draw_case(proc, container, stmt, is_last); case IVL_ST_WHILE: return draw_while(proc, container, stmt); case IVL_ST_FOREVER: return draw_forever(proc, container, stmt); case IVL_ST_REPEAT: return draw_repeat(proc, container, stmt); case IVL_ST_UTASK: return draw_utask(proc, container, stmt); case IVL_ST_FORCE: case IVL_ST_RELEASE: error("force/release statements cannot be translated to VHDL"); return 1; case IVL_ST_DISABLE: error("disable statement cannot be translated to VHDL"); return 1; case IVL_ST_CASEX: case IVL_ST_CASEZ: return draw_casezx(proc, container, stmt, is_last); case IVL_ST_FORK: error("fork statement cannot be translated to VHDL"); return 1; case IVL_ST_CASSIGN: case IVL_ST_DEASSIGN: error("continuous procedural assignment cannot be translated to VHDL"); return 1; default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), ivl_statement_type(stmt)); return 1; } } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/state.cc0000644000202500001440000000005012204466647017410 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/state.cc0000644000202500001440000001747712204466647016752 0ustar00steveusers00000000000000/* * Managing global state for the VHDL code generator. * * Copyright (C) 2009 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "state.hh" #include "vhdl_syntax.hh" #include "vhdl_target.h" #include #include #include #include #include using namespace std; /* * This file stores all the global state required during VHDL code * generation. At present we store the following: * * - A mapping from Verilog signals to the VHDL scope (entity, etc.) * where it is found, and the name of the corresponding VHDL signal. * This allows us to support renaming invalid Verilog signal names * to valid VHDL ones. * * - The set of all VHDL entities generated. * * - The currently active entity. "Active" here means that we are * currently generating code for a process inside the corresponding * scope. This is useful, for example, if a statement or expression * in a process needs to add are referencing something in the containing * architecture object. */ /* * Maps a signal to the scope it is defined within. Also * provides a mechanism for renaming signals -- i.e. when * an output has the same name as register: valid in Verilog * but not in VHDL, so two separate signals need to be * defined. */ struct signal_defn_t { std::string renamed; // The name of the VHDL signal vhdl_scope *scope; // The scope where it is defined }; // All entities to emit. // These are stored in a list rather than a set so the first // entity added will correspond to the first (top) Verilog module // encountered and hence it will appear first in the output file. static entity_list_t g_entities; // Store the mapping of ivl scope names to entity names typedef map scope_name_map_t; static scope_name_map_t g_scope_names; typedef std::map signal_defn_map_t; static signal_defn_map_t g_known_signals; static vhdl_entity *g_active_entity = NULL; // Set of scopes that are treated as the default examples of // that type. Any other scopes of the same type are ignored. typedef set default_scopes_t; static default_scopes_t g_default_scopes; // True if signal `sig' has already been encountered by the code // generator. This means we have already assigned it to a VHDL code // object and possibly renamed it. bool seen_signal_before(ivl_signal_t sig) { return g_known_signals.find(sig) != g_known_signals.end(); } // Remember the association of signal to a VHDL code object (typically // an entity). void remember_signal(ivl_signal_t sig, vhdl_scope *scope) { assert(!seen_signal_before(sig)); signal_defn_t defn = { ivl_signal_basename(sig), scope }; g_known_signals[sig] = defn; } // Change the VHDL name of a Verilog signal. void rename_signal(ivl_signal_t sig, const std::string &renamed) { assert(seen_signal_before(sig)); g_known_signals[sig].renamed = renamed; } // Given a Verilog signal, return the VHDL code object where it should // be defined. Note that this can return a NULL pointer if `sig' hasn't // be encountered yet. vhdl_scope *find_scope_for_signal(ivl_signal_t sig) { if (seen_signal_before(sig)) return g_known_signals[sig].scope; else return NULL; } // Get the name of the VHDL signal corresponding to Verilog signal `sig'. const std::string &get_renamed_signal(ivl_signal_t sig) { assert(seen_signal_before(sig)); return g_known_signals[sig].renamed; } // TODO: Can we dispose of this??? // -> This is only used in logic.cc to get the type of a signal connected // to a logic device -> we should be able to get this from the nexus ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope) { signal_defn_map_t::const_iterator it; for (it = g_known_signals.begin(); it != g_known_signals.end(); ++it) { if (((*it).second.scope == scope || (*it).second.scope == scope->get_parent()) && (*it).second.renamed == name) return (*it).first; } assert(false); return NULL; } // Compare the name of an entity against a string struct cmp_ent_name { cmp_ent_name(const string& n) : name_(n) {} bool operator()(const vhdl_entity* ent) const { return ent->get_name() == name_; } const string& name_; }; // Find an entity given its name. vhdl_entity* find_entity(const string& name) { entity_list_t::const_iterator it = find_if(g_entities.begin(), g_entities.end(), cmp_ent_name(name)); if (it != g_entities.end()) return *it; else return NULL; } // Find a VHDL entity given a Verilog module scope. The VHDL entity // name should be the same as the Verilog module type name. // Note that this will return NULL if no entity has been recorded // for this scope type. vhdl_entity* find_entity(ivl_scope_t scope) { // Skip over generate scopes while (ivl_scope_type(scope) == IVL_SCT_GENERATE) scope = ivl_scope_parent(scope); assert(ivl_scope_type(scope) == IVL_SCT_MODULE); scope_name_map_t::iterator it = g_scope_names.find(ivl_scope_tname(scope)); if (it != g_scope_names.end()) return find_entity((*it).second); else return NULL; } // Add an entity/architecture pair to the list of entities to emit. void remember_entity(vhdl_entity* ent, ivl_scope_t scope) { g_entities.push_back(ent); g_scope_names[ivl_scope_tname(scope)] = ent->get_name(); } // Print all VHDL entities, in order, to the specified output stream. void emit_all_entities(std::ostream& os, int max_depth) { for (entity_list_t::iterator it = g_entities.begin(); it != g_entities.end(); ++it) { if ((max_depth == 0 || (*it)->depth < max_depth)) (*it)->emit(os); } } // Release all memory for the VHDL objects. No vhdl_element pointers // will be valid after this call. void free_all_vhdl_objects() { int freed = vhdl_element::free_all_objects(); debug_msg("Deallocated %d VHDL syntax objects", freed); size_t total = vhdl_element::total_allocated(); debug_msg("%d total bytes used for VHDL syntax objects", total); g_entities.clear(); } // Return the currently active entity vhdl_entity *get_active_entity() { return g_active_entity; } // Change the currently active entity void set_active_entity(vhdl_entity *ent) { g_active_entity = ent; } /* * True if two scopes have the same type name. */ static bool same_scope_type_name(ivl_scope_t a, ivl_scope_t b) { return strcmp(ivl_scope_tname(a), ivl_scope_tname(b)) == 0; } /* * True if we have already seen a scope with this type before. * If the result is `false' then s is stored in the set of seen * scopes. */ bool seen_this_scope_type(ivl_scope_t s) { if (find_if(g_default_scopes.begin(), g_default_scopes.end(), bind1st(ptr_fun(same_scope_type_name), s)) == g_default_scopes.end()) { g_default_scopes.insert(s); return false; } else return true; } /* * True if this scope is the default example of this scope type. * All other instances of this scope type are ignored. */ bool is_default_scope_instance(ivl_scope_t s) { return find(g_default_scopes.begin(), g_default_scopes.end(), s) != g_default_scopes.end(); } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl_syntax.hh0000644000202500001440000000005012204466647020645 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl_syntax.hh0000644000202500001440000005501012204466647020170 0ustar00steveusers00000000000000/* * VHDL abstract syntax elements. * * Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef INC_VHDL_SYNTAX_HH #define INC_VHDL_SYNTAX_HH #include #include #include "vhdl_element.hh" #include "vhdl_type.hh" using namespace std; class vhdl_scope; class vhdl_entity; class vhdl_arch; class vhdl_expr : public vhdl_element { public: vhdl_expr(const vhdl_type* type, bool isconst=false) : type_(type), isconst_(isconst) {} virtual ~vhdl_expr(); const vhdl_type *get_type() const { return type_; } bool constant() const { return isconst_; } vhdl_expr *cast(const vhdl_type *to); virtual vhdl_expr *resize(int newwidth); virtual vhdl_expr *to_boolean(); virtual vhdl_expr *to_integer(); virtual vhdl_expr *to_std_logic(); virtual vhdl_expr *to_vector(vhdl_type_name_t name, int w); protected: const vhdl_type *type_; bool isconst_; }; /* * A scalar or array variable reference. */ class vhdl_var_ref : public vhdl_expr { public: vhdl_var_ref(const string& name, const vhdl_type *type, vhdl_expr *slice = NULL) : vhdl_expr(type), name_(name), slice_(slice) {} ~vhdl_var_ref(); void emit(std::ostream &of, int level) const; const std::string &get_name() const { return name_; } void set_name(const std::string &name) { name_ = name; } void set_slice(vhdl_expr *s, int w=0); private: std::string name_; vhdl_expr *slice_; unsigned slice_width_; }; enum vhdl_binop_t { VHDL_BINOP_AND = 0, VHDL_BINOP_OR, VHDL_BINOP_EQ, VHDL_BINOP_NEQ, VHDL_BINOP_ADD, VHDL_BINOP_SUB, VHDL_BINOP_MULT, VHDL_BINOP_LT, VHDL_BINOP_GT, VHDL_BINOP_LEQ, VHDL_BINOP_GEQ, VHDL_BINOP_SL, VHDL_BINOP_SR, VHDL_BINOP_XOR, VHDL_BINOP_CONCAT, VHDL_BINOP_NAND, VHDL_BINOP_NOR, VHDL_BINOP_XNOR, VHDL_BINOP_DIV, VHDL_BINOP_MOD, VHDL_BINOP_POWER, VHDL_BINOP_SRA }; /* * A binary expression contains a list of operands rather * than just two: this is to model n-input gates and the * like. A second constructor is provided to handle the * common case of a true binary expression. */ class vhdl_binop_expr : public vhdl_expr { public: vhdl_binop_expr(vhdl_binop_t op, vhdl_type *type) : vhdl_expr(type), op_(op) {} vhdl_binop_expr(vhdl_expr *left, vhdl_binop_t op, vhdl_expr *right, vhdl_type *type); ~vhdl_binop_expr(); void add_expr(vhdl_expr *e); void emit(std::ostream &of, int level) const; private: std::list operands_; vhdl_binop_t op_; }; enum vhdl_unaryop_t { VHDL_UNARYOP_NOT, VHDL_UNARYOP_NEG }; class vhdl_unaryop_expr : public vhdl_expr { public: vhdl_unaryop_expr(vhdl_unaryop_t op, vhdl_expr *operand, vhdl_type *type) : vhdl_expr(type), op_(op), operand_(operand) {} ~vhdl_unaryop_expr(); void emit(std::ostream &of, int level) const; private: vhdl_unaryop_t op_; vhdl_expr *operand_; }; /* * An expression like (0 => '1', 2 => '0', others => 'Z') */ class vhdl_bit_spec_expr : public vhdl_expr { public: vhdl_bit_spec_expr(vhdl_type *type, vhdl_expr *others) : vhdl_expr(type), others_(others) {} ~vhdl_bit_spec_expr(); void add_bit(int bit, vhdl_expr *e); void emit(std::ostream &of, int level) const; private: vhdl_expr *others_; struct bit_map { int bit; vhdl_expr *e; }; std::list bits_; }; class vhdl_const_string : public vhdl_expr { public: vhdl_const_string(const char *value) : vhdl_expr(vhdl_type::string(), true), value_(value) {} void emit(std::ostream &of, int level) const; private: std::string value_; }; class vhdl_const_bits : public vhdl_expr { public: vhdl_const_bits(const char *value, int width, bool issigned, bool qualify=false); void emit(std::ostream &of, int level) const; const std::string &get_value() const { return value_; } vhdl_expr *to_integer(); vhdl_expr *to_std_logic(); vhdl_expr *to_vector(vhdl_type_name_t name, int w); vhdl_expr *resize(int w); private: int64_t bits_to_int() const; char sign_bit() const; bool has_meta_bits() const; std::string value_; bool qualified_, signed_; }; class vhdl_const_bit : public vhdl_expr { public: vhdl_const_bit(char bit) : vhdl_expr(vhdl_type::std_logic(), true), bit_(bit) {} void emit(std::ostream &of, int level) const; vhdl_expr *to_boolean(); vhdl_expr *to_integer(); vhdl_expr *to_vector(vhdl_type_name_t name, int w); private: char bit_; }; enum time_unit_t { TIME_UNIT_PS, TIME_UNIT_NS, TIME_UNIT_US, TIME_UNIT_MS }; class vhdl_const_time : public vhdl_expr { public: vhdl_const_time(uint64_t value, time_unit_t units = TIME_UNIT_NS) : vhdl_expr(vhdl_type::time(), true), value_(value), units_(units) {} void emit(std::ostream &of, int level) const; private: uint64_t value_; time_unit_t units_; }; class vhdl_const_int : public vhdl_expr { public: vhdl_const_int(int64_t value) : vhdl_expr(vhdl_type::integer(), true), value_(value) {} void emit(std::ostream &of, int level) const; vhdl_expr *to_vector(vhdl_type_name_t name, int w); private: int64_t value_; }; class vhdl_const_bool : public vhdl_expr { public: vhdl_const_bool(bool value) : vhdl_expr(vhdl_type::boolean(), true), value_(value) {} void emit(std::ostream &of, int level) const; private: bool value_; }; class vhdl_expr_list : public vhdl_element { public: ~vhdl_expr_list(); void emit(std::ostream &of, int level) const; bool empty() const { return exprs_.empty(); } void add_expr(vhdl_expr *e); private: std::list exprs_; }; /* * A function call within an expression. */ class vhdl_fcall : public vhdl_expr { public: vhdl_fcall(const char *name, vhdl_type *rtype) : vhdl_expr(rtype), name_(name) {}; ~vhdl_fcall() {} void add_expr(vhdl_expr *e) { exprs_.add_expr(e); } void emit(std::ostream &of, int level) const; private: std::string name_; vhdl_expr_list exprs_; }; /* * A concurrent statement appears in architecture bodies/ */ class vhdl_conc_stmt : public vhdl_element { public: virtual ~vhdl_conc_stmt() {} }; typedef std::list conc_stmt_list_t; /* * A ' when ' clause that appears in several * statement types. */ struct when_part_t { vhdl_expr *value, *cond, *delay; }; typedef std::list when_list_t; /* * A concurrent signal assignment (i.e. not part of a process). * Can have any number of `when' clauses, in which case the original * rhs becomes the `else' part. */ class vhdl_cassign_stmt : public vhdl_conc_stmt { public: vhdl_cassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) : lhs_(lhs), rhs_(rhs), after_(NULL) {} ~vhdl_cassign_stmt(); void emit(std::ostream &of, int level) const; void add_condition(vhdl_expr *value, vhdl_expr *cond); void set_after(vhdl_expr *a) { after_ = a; } private: vhdl_var_ref *lhs_; vhdl_expr *rhs_; vhdl_expr *after_; when_list_t whens_; }; class vhdl_with_select_stmt : public vhdl_conc_stmt { public: vhdl_with_select_stmt(vhdl_expr *test, vhdl_var_ref *out) : test_(test), out_(out), others_(NULL) {} ~vhdl_with_select_stmt(); void emit(std::ostream &of, int level) const; void add_condition(vhdl_expr *value, vhdl_expr *cond, vhdl_expr *delay=NULL); void add_default(vhdl_expr* value); private: vhdl_expr *test_; vhdl_var_ref *out_; when_list_t whens_; vhdl_expr* others_; }; /* * Any sequential statement in a process. */ class vhdl_seq_stmt : public vhdl_element { public: virtual ~vhdl_seq_stmt() {} }; /* * A list of sequential statements. For example inside a * process, loop, or if statement. */ class stmt_container { public: ~stmt_container(); void add_stmt(vhdl_seq_stmt *stmt); void move_stmts_from(stmt_container *other); void emit(std::ostream &of, int level, bool newline=true) const; bool empty() const { return stmts_.empty(); } typedef std::list stmt_list_t; stmt_list_t &get_stmts() { return stmts_; } private: stmt_list_t stmts_; }; /* * Shared between blocking and non-blocking assignment. */ class vhdl_abstract_assign_stmt : public vhdl_seq_stmt { public: vhdl_abstract_assign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) : lhs_(lhs), rhs_(rhs), after_(NULL) {} virtual ~vhdl_abstract_assign_stmt(); void set_after(vhdl_expr *after) { after_ = after; } protected: vhdl_var_ref *lhs_; vhdl_expr *rhs_, *after_; }; /* * Similar to Verilog non-blocking assignment, except the LHS * must be a signal not a variable. */ class vhdl_nbassign_stmt : public vhdl_abstract_assign_stmt { public: vhdl_nbassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) : vhdl_abstract_assign_stmt(lhs, rhs) {} void emit(std::ostream &of, int level) const; }; class vhdl_assign_stmt : public vhdl_abstract_assign_stmt { public: vhdl_assign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) : vhdl_abstract_assign_stmt(lhs, rhs) {} void emit(std::ostream &of, int level) const; }; enum vhdl_wait_type_t { VHDL_WAIT_INDEF, // Suspend indefinitely VHDL_WAIT_FOR, // Wait for a constant amount of time VHDL_WAIT_FOR0, // Special wait for zero time VHDL_WAIT_UNTIL, // Wait on an expression VHDL_WAIT_ON // Wait on a sensitivity list }; /* * Delay simulation indefinitely, until an event, or for a * specified time. */ class vhdl_wait_stmt : public vhdl_seq_stmt { public: vhdl_wait_stmt(vhdl_wait_type_t type = VHDL_WAIT_INDEF, vhdl_expr *expr = NULL) : type_(type), expr_(expr) {} ~vhdl_wait_stmt(); void emit(std::ostream &of, int level) const; void add_sensitivity(const std::string &s) { sensitivity_.push_back(s); } vhdl_wait_type_t get_type() const { return type_; } private: vhdl_wait_type_t type_; vhdl_expr *expr_; string_list_t sensitivity_; }; class vhdl_null_stmt : public vhdl_seq_stmt { public: void emit(std::ostream &of, int level) const; }; class vhdl_assert_stmt : public vhdl_seq_stmt { public: vhdl_assert_stmt(const char *reason) : reason_(reason) {} void emit(std::ostream &of, int level) const; private: std::string reason_; }; class vhdl_if_stmt : public vhdl_seq_stmt { public: vhdl_if_stmt(vhdl_expr *test); ~vhdl_if_stmt(); stmt_container *get_then_container() { return &then_part_; } stmt_container *get_else_container() { return &else_part_; } stmt_container *add_elsif(vhdl_expr *test); void emit(std::ostream &of, int level) const; private: struct elsif { vhdl_expr *test; stmt_container *container; }; vhdl_expr *test_; stmt_container then_part_, else_part_; std::list elsif_parts_; }; /* * A single branch in a case statement consisting of an * expression part and a statement container. */ class vhdl_case_branch : public vhdl_element { public: vhdl_case_branch(vhdl_expr *when) : when_(when) {} ~vhdl_case_branch(); stmt_container *get_container() { return &stmts_; } void emit(std::ostream &of, int level) const; private: vhdl_expr *when_; stmt_container stmts_; }; typedef std::list case_branch_list_t; class vhdl_case_stmt : public vhdl_seq_stmt { public: vhdl_case_stmt(vhdl_expr *test) : test_(test) {} ~vhdl_case_stmt(); void add_branch(vhdl_case_branch *b) { branches_.push_back(b); } void emit(std::ostream &of, int level) const; private: vhdl_expr *test_; case_branch_list_t branches_; }; class vhdl_loop_stmt : public vhdl_seq_stmt { public: virtual ~vhdl_loop_stmt() {} stmt_container *get_container() { return &stmts_; } void emit(std::ostream &of, int level) const; private: stmt_container stmts_; }; class vhdl_while_stmt : public vhdl_loop_stmt { public: vhdl_while_stmt(vhdl_expr *test) : test_(test) {} ~vhdl_while_stmt(); void emit(std::ostream &of, int level) const; private: vhdl_expr *test_; }; class vhdl_for_stmt : public vhdl_loop_stmt { public: vhdl_for_stmt(const char *lname, vhdl_expr *from, vhdl_expr *to) : lname_(lname), from_(from), to_(to) {} ~vhdl_for_stmt(); void emit(std::ostream &of, int level) const; private: const char *lname_; vhdl_expr *from_, *to_; }; /* * A procedure call. Which is a statement, unlike a function * call which is an expression. */ class vhdl_pcall_stmt : public vhdl_seq_stmt { public: vhdl_pcall_stmt(const char *name) : name_(name) {} void emit(std::ostream &of, int level) const; void add_expr(vhdl_expr *e) { exprs_.add_expr(e); } private: std::string name_; vhdl_expr_list exprs_; }; /* * A declaration of some sort (variable, component, etc.). * Declarations have names, which is the identifier of the variable, * constant, etc. not the type. */ class vhdl_decl : public vhdl_element { public: vhdl_decl(const string& name, const vhdl_type *type = NULL, vhdl_expr *initial = NULL) : name_(name), type_(type), initial_(initial), has_initial_(initial != NULL) {} virtual ~vhdl_decl(); const std::string &get_name() const { return name_; } const vhdl_type *get_type() const; void set_type(vhdl_type *t) { type_ = t; } void set_initial(vhdl_expr *initial); bool has_initial() const { return has_initial_; } // Return a new reference to this declaration vhdl_var_ref* make_ref() const; // The different sorts of assignment statement // ASSIGN_CONST is used to generate a variable to shadow a // constant that cannot be assigned to (e.g. a function parameter) enum assign_type_t { ASSIGN_BLOCK, ASSIGN_NONBLOCK, ASSIGN_CONST }; // Get the sort of assignment statement to generate for // assignments to this declaration // For some sorts of declarations it doesn't make sense // to assign to it so calling assignment_type just raises // an assertion failure virtual assign_type_t assignment_type() const { assert(false); return ASSIGN_BLOCK; } // True if this declaration can be read from virtual bool is_readable() const { return true; } // Modify this declaration so it can be read from // This does nothing for most declaration types virtual void ensure_readable() {} protected: std::string name_; const vhdl_type *type_; vhdl_expr *initial_; bool has_initial_; }; typedef std::list decl_list_t; /* * A forward declaration of a component. At the moment it is assumed * that components declarations will only ever be for entities * generated by this code generator. This is enforced by making the * constructor private (use component_decl_for instead). */ class vhdl_component_decl : public vhdl_decl { public: static vhdl_component_decl *component_decl_for(vhdl_entity *ent); void emit(std::ostream &of, int level) const; private: vhdl_component_decl(const char *name); decl_list_t ports_; }; class vhdl_type_decl : public vhdl_decl { public: vhdl_type_decl(const string& name, const vhdl_type *base) : vhdl_decl(name, base) {} void emit(std::ostream &of, int level) const; }; /* * A variable declaration inside a process (although this isn't * enforced here). */ class vhdl_var_decl : public vhdl_decl { public: vhdl_var_decl(const string& name, const vhdl_type *type) : vhdl_decl(name, type) {} void emit(std::ostream &of, int level) const; assign_type_t assignment_type() const { return ASSIGN_BLOCK; } }; /* * A signal declaration in architecture. */ class vhdl_signal_decl : public vhdl_decl { public: vhdl_signal_decl(const string& name, const vhdl_type* type) : vhdl_decl(name, type) {} virtual void emit(std::ostream &of, int level) const; assign_type_t assignment_type() const { return ASSIGN_NONBLOCK; } }; /* * A parameter to a function. */ class vhdl_param_decl : public vhdl_decl { public: vhdl_param_decl(const char *name, vhdl_type *type) : vhdl_decl(name, type) {} void emit(std::ostream &of, int level) const; assign_type_t assignment_type() const { return ASSIGN_CONST; } }; enum vhdl_port_mode_t { VHDL_PORT_IN, VHDL_PORT_OUT, VHDL_PORT_INOUT, VHDL_PORT_BUFFER }; /* * A port declaration is like a signal declaration except * it has a direction and appears in the entity rather than * the architecture. */ class vhdl_port_decl : public vhdl_decl { public: vhdl_port_decl(const char *name, vhdl_type *type, vhdl_port_mode_t mode) : vhdl_decl(name, type), mode_(mode) {} void emit(std::ostream &of, int level) const; vhdl_port_mode_t get_mode() const { return mode_; } void set_mode(vhdl_port_mode_t m) { mode_ = m; } assign_type_t assignment_type() const { return ASSIGN_NONBLOCK; } void ensure_readable(); bool is_readable() const; private: vhdl_port_mode_t mode_; }; /* * A mapping from port name to an expression. */ struct port_map_t { std::string name; vhdl_expr *expr; }; typedef std::list port_map_list_t; /* * Instantiation of component. This is really only a placeholder * at the moment until the port mappings are worked out. */ class vhdl_comp_inst : public vhdl_conc_stmt { public: vhdl_comp_inst(const char *inst_name, const char *comp_name); ~vhdl_comp_inst(); void emit(std::ostream &of, int level) const; void map_port(const string& name, vhdl_expr *expr); const std::string &get_comp_name() const { return comp_name_; } const std::string &get_inst_name() const { return inst_name_; } private: std::string comp_name_, inst_name_; port_map_list_t mapping_; }; /* * Contains a list of declarations in a hierarchy. * A scope can be `initializing' where assignments automatically * create initial values for declarations. */ class vhdl_scope { public: vhdl_scope(); ~vhdl_scope(); void add_decl(vhdl_decl *decl); void add_forward_decl(vhdl_decl *decl); vhdl_decl *get_decl(const std::string &name) const; bool have_declared(const std::string &name) const; bool name_collides(const string& name) const; bool contained_within(const vhdl_scope *other) const; vhdl_scope *get_parent() const; bool empty() const { return decls_.empty(); } const decl_list_t &get_decls() const { return decls_; } void set_parent(vhdl_scope *p) { parent_ = p; } bool initializing() const { return init_; } void set_initializing(bool i); void set_allow_signal_assignment(bool b) { sig_assign_ = b; } bool allow_signal_assignment() const { return sig_assign_; } private: decl_list_t decls_; vhdl_scope *parent_; bool init_, sig_assign_; }; /* * Any sort of procedural element: process, function, or * procedure. Roughly these map onto Verilog's processes, * functions, and tasks. */ class vhdl_procedural { public: vhdl_procedural() : contains_wait_stmt_(false) {} virtual ~vhdl_procedural() {} virtual stmt_container *get_container() { return &stmts_; } virtual vhdl_scope *get_scope() { return &scope_; } void added_wait_stmt() { contains_wait_stmt_ = true; } bool contains_wait_stmt() const { return contains_wait_stmt_; } protected: stmt_container stmts_; vhdl_scope scope_; // If this is true then the body contains a `wait' statement // embedded in it somewhere // If this is the case then we can't use a sensitivity list for // the process bool contains_wait_stmt_; }; class vhdl_function : public vhdl_decl, public vhdl_procedural { friend class vhdl_forward_fdecl; public: vhdl_function(const char *name, vhdl_type *ret_type); virtual void emit(std::ostream &of, int level) const; vhdl_scope *get_scope() { return &variables_; } void add_param(vhdl_param_decl *p) { scope_.add_decl(p); } private: vhdl_scope variables_; }; class vhdl_forward_fdecl : public vhdl_decl { public: vhdl_forward_fdecl(const vhdl_function *f) : vhdl_decl((f->get_name() + "_Forward").c_str()), f_(f) {} void emit(std::ostream &of, int level) const; private: const vhdl_function *f_; }; class vhdl_process : public vhdl_conc_stmt, public vhdl_procedural { public: vhdl_process(const char *name = "") : name_(name) {} void emit(std::ostream &of, int level) const; void add_sensitivity(const std::string &name); private: std::string name_; string_list_t sens_; }; /* * An architecture which implements an entity. */ class vhdl_arch : public vhdl_element { public: vhdl_arch(const string& entity, const string& name) : name_(name), entity_(entity) {} virtual ~vhdl_arch(); void emit(std::ostream &of, int level=0) const; void add_stmt(vhdl_process *proc); void add_stmt(vhdl_conc_stmt *stmt); vhdl_scope *get_scope() { return &scope_; } private: conc_stmt_list_t stmts_; vhdl_scope scope_; std::string name_, entity_; }; /* * An entity defines the ports, parameters, etc. of a module. Each * entity is associated with a single architecture (although * technically this need not be the case). Entities are `derived' * from instantiations of Verilog module scopes in the hierarchy. */ class vhdl_entity : public vhdl_element { public: vhdl_entity(const string& name, vhdl_arch *arch, int depth=0); virtual ~vhdl_entity(); void emit(std::ostream &of, int level=0) const; void add_port(vhdl_port_decl *decl); vhdl_arch *get_arch() const { return arch_; } const std::string &get_name() const { return name_; } vhdl_scope *get_scope() { return &ports_; } void set_time_units(int units, int precision); friend vhdl_const_time* scale_time(const vhdl_entity* ent, uint64_t t); // Each entity has an associated depth which is how deep in // the Verilog module hierarchy it was found // This is used to limit the maximum depth of modules emitted const int depth; private: std::string name_; vhdl_arch *arch_; // Entity may only have a single architecture vhdl_scope ports_; // Entities have an associated VHDL time unit // This is used to implement the Verilog timescale directive time_unit_t time_unit_; }; typedef std::list entity_list_t; #endif verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl_type.cc0000644000202500001440000000005012204466647020266 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl_type.cc0000644000202500001440000001035312204466647017612 0ustar00steveusers00000000000000/* * VHDL variable and signal types. * * Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_type.hh" #include #include #include vhdl_type *vhdl_type::std_logic() { return new vhdl_type(VHDL_TYPE_STD_LOGIC); } vhdl_type *vhdl_type::string() { return new vhdl_type(VHDL_TYPE_STRING); } vhdl_type *vhdl_type::line() { return new vhdl_type(VHDL_TYPE_LINE); } vhdl_type *vhdl_type::boolean() { return new vhdl_type(VHDL_TYPE_BOOLEAN); } vhdl_type *vhdl_type::integer() { return new vhdl_type(VHDL_TYPE_INTEGER); } vhdl_type *vhdl_type::nunsigned(int width, int lsb) { return new vhdl_type(VHDL_TYPE_UNSIGNED, width-1+lsb, lsb); } vhdl_type *vhdl_type::nsigned(int width, int lsb) { return new vhdl_type(VHDL_TYPE_SIGNED, width-1+lsb, lsb); } vhdl_type *vhdl_type::time() { return new vhdl_type(VHDL_TYPE_TIME); } vhdl_type *vhdl_type::get_base() const { assert(name_ == VHDL_TYPE_ARRAY); return base_; } /* * This is just the name of the type, without any parameters. */ std::string vhdl_type::get_string() const { switch (name_) { case VHDL_TYPE_STD_LOGIC: return std::string("std_logic"); case VHDL_TYPE_STD_LOGIC_VECTOR: return std::string("std_logic_vector"); case VHDL_TYPE_STRING: return std::string("String"); case VHDL_TYPE_LINE: return std::string("Line"); case VHDL_TYPE_FILE: return std::string("File"); case VHDL_TYPE_INTEGER: return std::string("Integer"); case VHDL_TYPE_BOOLEAN: return std::string("Boolean"); case VHDL_TYPE_SIGNED: return std::string("signed"); case VHDL_TYPE_UNSIGNED: return std::string("unsigned"); case VHDL_TYPE_ARRAY: // Each array has its own type declaration return array_name_; default: return std::string("BadType"); } } /* * The is the qualified name of the type. */ std::string vhdl_type::get_decl_string() const { switch (name_) { case VHDL_TYPE_STD_LOGIC_VECTOR: case VHDL_TYPE_UNSIGNED: case VHDL_TYPE_SIGNED: { std::ostringstream ss; ss << get_string() << "(" << msb_; ss << " downto " << lsb_ << ")"; return ss.str(); } default: return get_string(); } } /* * Like get_decl_string but completely expands array declarations. */ std::string vhdl_type::get_type_decl_string() const { switch (name_) { case VHDL_TYPE_ARRAY: { std::ostringstream ss; ss << "array (" << msb_ << " downto " << lsb_ << ") of " << base_->get_decl_string(); return ss.str(); } default: return get_decl_string(); } } void vhdl_type::emit(std::ostream &of, int level) const { of << get_decl_string(); } vhdl_type::vhdl_type(const vhdl_type &other) : name_(other.name_), msb_(other.msb_), lsb_(other.lsb_), array_name_(other.array_name_) { if (other.base_ != NULL) base_ = new vhdl_type(*other.base_); else base_ = NULL; } vhdl_type::~vhdl_type() { if (base_ != NULL) delete base_; } vhdl_type *vhdl_type::std_logic_vector(int msb, int lsb) { return new vhdl_type(VHDL_TYPE_STD_LOGIC_VECTOR, msb, lsb); } vhdl_type *vhdl_type::type_for(int width, bool issigned, int lsb) { if (width == 1) return vhdl_type::std_logic(); else if (issigned) return vhdl_type::nsigned(width, lsb); else return vhdl_type::nunsigned(width, lsb); } vhdl_type *vhdl_type::array_of(vhdl_type *b, std::string &n, int m, int l) { return new vhdl_type(b, n, m, l); } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl_helper.hh0000644000202500001440000000005012204466647020576 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl_helper.hh0000644000202500001440000000352612204466647020126 0ustar00steveusers00000000000000/* * Helper functions for VHDL syntax elements. * * Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef INC_VHDL_HELPER_HH #define INC_VHDL_HELPER_HH #include #include #include template void emit_children(std::ostream &of, const std::list &children, int level, const char *delim = "", bool trailing_newline = true) { // Don't indent if there are no children if (children.size() == 0) newline(of, level); else { typename std::list::const_iterator it; int sz = children.size(); for (it = children.begin(); it != children.end(); ++it) { newline(of, indent(level)); (*it)->emit(of, indent(level)); if (--sz > 0) of << delim; } if (trailing_newline) newline(of, level); } } static inline char vl_to_vhdl_bit(char bit) { switch (bit) { case '0': case 'Z': case '1': return bit; case 'z': return 'Z'; case 'x': case 'X': return 'U'; case '?': return '-'; } assert(false); } #endif verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl-s.conf0000644000202500001440000000005012204466647020025 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl-s.conf0000644000202500001440000000014712204466647017351 0ustar00steveusers00000000000000functor:synth2 functor:synth functor:syn-rules functor:cprop functor:nodangle -t:dll flag:DLL=vhdl.tgt verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl_syntax.cc0000644000202500001440000000005012204466647020633 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl_syntax.cc0000644000202500001440000005372312204466647020167 0ustar00steveusers00000000000000/* * VHDL abstract syntax elements. * * Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_syntax.hh" #include "vhdl_helper.hh" #include #include #include #include #include #include using namespace std; vhdl_scope::vhdl_scope() : parent_(NULL), init_(false), sig_assign_(true) { } vhdl_scope::~vhdl_scope() { } void vhdl_scope::set_initializing(bool i) { init_ = i; if (parent_) parent_->set_initializing(i); } void vhdl_scope::add_decl(vhdl_decl *decl) { decls_.push_back(decl); } void vhdl_scope::add_forward_decl(vhdl_decl *decl) { decls_.push_front(decl); } vhdl_decl *vhdl_scope::get_decl(const std::string &name) const { decl_list_t::const_iterator it; for (it = decls_.begin(); it != decls_.end(); ++it) { if (strcasecmp((*it)->get_name().c_str(), name.c_str()) == 0) return *it; } return parent_ ? parent_->get_decl(name) : NULL; } bool vhdl_scope::have_declared(const std::string &name) const { return get_decl(name) != NULL; } // True if `name' differs in all but case from another declaration bool vhdl_scope::name_collides(const string& name) const { const vhdl_decl* decl = get_decl(name); if (decl) return decl->get_name() != name; else return false; } bool vhdl_scope::contained_within(const vhdl_scope *other) const { if (this == other) return true; else if (NULL == parent_) return false; else return parent_->contained_within(other); } vhdl_scope *vhdl_scope::get_parent() const { assert(parent_); return parent_; } vhdl_entity::vhdl_entity(const string& name, vhdl_arch *arch, int depth__) : depth(depth__), name_(name), arch_(arch), time_unit_(TIME_UNIT_NS) { arch->get_scope()->set_parent(&ports_); } vhdl_entity::~vhdl_entity() { } void vhdl_entity::add_port(vhdl_port_decl *decl) { ports_.add_decl(decl); } void vhdl_entity::emit(std::ostream &of, int level) const { // Pretty much every design will use std_logic so we // might as well include it by default of << "library ieee;" << std::endl; of << "use ieee.std_logic_1164.all;" << std::endl; of << "use ieee.numeric_std.all;" << std::endl; of << "use std.textio.all;" << std::endl; of << std::endl; emit_comment(of, level); of << "entity " << name_ << " is"; if (!ports_.empty()) { newline(of, indent(level)); of << "port ("; emit_children(of, ports_.get_decls(), indent(level), ";"); of << ");"; } newline(of, level); of << "end entity; "; blank_line(of, level); // Extra blank line after entities arch_->emit(of, level); } // Return a VHDL time constant scaled to the correct time scale // for this entity vhdl_const_time* scale_time(const vhdl_entity* ent, uint64_t t) { return new vhdl_const_time(t, ent->time_unit_); } // Work out the best VHDL units to use given the Verilog timescale void vhdl_entity::set_time_units(int units, int precision) { int vhdl_units = std::min(units, precision); if (vhdl_units >= -3) time_unit_ = TIME_UNIT_MS; else if (vhdl_units >= -6) time_unit_ = TIME_UNIT_US; else if (vhdl_units >= -9) time_unit_ = TIME_UNIT_NS; else time_unit_ = TIME_UNIT_PS; } vhdl_arch::~vhdl_arch() { } void vhdl_arch::add_stmt(vhdl_process *proc) { proc->get_scope()->set_parent(&scope_); stmts_.push_back(proc); } void vhdl_arch::add_stmt(vhdl_conc_stmt *stmt) { stmts_.push_back(stmt); } void vhdl_arch::emit(std::ostream &of, int level) const { emit_comment(of, level); of << "architecture " << name_ << " of " << entity_; of << " is"; emit_children(of, scope_.get_decls(), level); of << "begin"; emit_children(of, stmts_, level); of << "end architecture;"; blank_line(of, level); // Extra blank line after architectures; } void vhdl_process::add_sensitivity(const std::string &name) { sens_.push_back(name); } void vhdl_process::emit(std::ostream &of, int level) const { // If there are no statements in the body, this process // can't possibly do anything, so don't bother to emit it if (stmts_.empty()) { of << "-- Removed one empty process"; newline(of, level); return; } newline(of, level); emit_comment(of, level); if (name_.size() > 0) of << name_ << ": "; of << "process "; int num_sens = sens_.size(); if (num_sens > 0) { of << "("; string_list_t::const_iterator it; for (it = sens_.begin(); it != sens_.end(); ++it) { of << *it; if (--num_sens > 0) of << ", "; } of << ") "; } of << "is"; emit_children(of, scope_.get_decls(), level); of << "begin"; stmts_.emit(of, level); of << "end process;"; } stmt_container::~stmt_container() { } void stmt_container::add_stmt(vhdl_seq_stmt *stmt) { // Add a statement at the end of the block stmts_.push_back(stmt); } /* * Move all the statements from one container into another. * This is useful, for example, if we want to wrap a container * in an `if' statement. */ void stmt_container::move_stmts_from(stmt_container *other) { copy(other->stmts_.begin(), other->stmts_.end(), back_inserter(stmts_)); other->stmts_.clear(); } void stmt_container::emit(std::ostream &of, int level, bool newline) const { emit_children(of, stmts_, level, "", newline); } vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) : comp_name_(comp_name), inst_name_(inst_name) { } vhdl_comp_inst::~vhdl_comp_inst() { } void vhdl_comp_inst::map_port(const string& name, vhdl_expr *expr) { port_map_t pmap = { name, expr }; mapping_.push_back(pmap); } void vhdl_comp_inst::emit(std::ostream &of, int level) const { newline(of, level); emit_comment(of, level); of << inst_name_ << ": " << comp_name_; // If there are no ports or generics we don't need to mention them... if (mapping_.size() > 0) { newline(of, indent(level)); of << "port map ("; int sz = mapping_.size(); port_map_list_t::const_iterator it; for (it = mapping_.begin(); it != mapping_.end(); ++it) { newline(of, indent(indent(level))); of << (*it).name << " => "; (*it).expr->emit(of, level); if (--sz > 0) of << ","; } newline(of, indent(level)); of << ")"; } of << ";"; } vhdl_component_decl::vhdl_component_decl(const char *name) : vhdl_decl(name) { } /* * Create a component declaration for the given entity. */ vhdl_component_decl *vhdl_component_decl::component_decl_for(vhdl_entity *ent) { assert(ent != NULL); vhdl_component_decl *decl = new vhdl_component_decl (ent->get_name().c_str()); decl->ports_ = ent->get_scope()->get_decls(); return decl; } void vhdl_component_decl::emit(std::ostream &of, int level) const { newline(of, level); emit_comment(of, level); of << "component " << name_ << " is"; if (ports_.size() > 0) { newline(of, indent(level)); of << "port ("; emit_children(of, ports_, indent(level), ";"); of << ");"; } newline(of, level); of << "end component;"; } vhdl_wait_stmt::~vhdl_wait_stmt() { } void vhdl_wait_stmt::emit(std::ostream &of, int level) const { of << "wait"; switch (type_) { case VHDL_WAIT_INDEF: break; case VHDL_WAIT_FOR: assert(expr_); of << " for "; expr_->emit(of, level); break; case VHDL_WAIT_FOR0: of << " for 0 ns"; break; case VHDL_WAIT_UNTIL: assert(expr_); of << " until "; expr_->emit(of, level); break; case VHDL_WAIT_ON: { of << " on "; string_list_t::const_iterator it = sensitivity_.begin(); while (it != sensitivity_.end()) { of << *it; if (++it != sensitivity_.end()) of << ", "; } } break; } of << ";"; } vhdl_decl::~vhdl_decl() { } // Make a reference object to this declaration vhdl_var_ref* vhdl_decl::make_ref() const { return new vhdl_var_ref(name_, type_); } const vhdl_type *vhdl_decl::get_type() const { assert(type_); return type_; } void vhdl_decl::set_initial(vhdl_expr *initial) { if (!has_initial_) { assert(initial_ == NULL); initial_ = initial; has_initial_ = true; } } void vhdl_port_decl::emit(std::ostream &of, int level) const { of << name_ << " : "; switch (mode_) { case VHDL_PORT_IN: of << "in "; break; case VHDL_PORT_OUT: of << "out "; break; case VHDL_PORT_INOUT: of << "inout "; break; case VHDL_PORT_BUFFER: of << "buffer "; break; } type_->emit(of, level); } // If this is an `out' port make it a `buffer' so we can read from it void vhdl_port_decl::ensure_readable() { if (mode_ == VHDL_PORT_OUT) mode_ = VHDL_PORT_BUFFER; } // A port is readable if it is not `out'. // We also make `buffer' ports not readable for these purposes since // buffers cannot be directly mapped to outputs without an intermediate // signal. bool vhdl_port_decl::is_readable() const { return mode_ != VHDL_PORT_OUT && mode_ != VHDL_PORT_BUFFER; } void vhdl_var_decl::emit(std::ostream &of, int level) const { of << "variable " << name_ << " : "; type_->emit(of, level); if (initial_) { of << " := "; initial_->emit(of, level); } of << ";"; emit_comment(of, level, true); } void vhdl_signal_decl::emit(std::ostream &of, int level) const { of << "signal " << name_ << " : "; type_->emit(of, level); if (initial_) { of << " := "; initial_->emit(of, level); } of << ";"; emit_comment(of, level, true); } void vhdl_type_decl::emit(std::ostream &of, int level) const { of << "type " << name_ << " is "; of << type_->get_type_decl_string() << ";"; emit_comment(of, level, true); } vhdl_expr::~vhdl_expr() { } void vhdl_expr_list::add_expr(vhdl_expr *e) { exprs_.push_back(e); } vhdl_expr_list::~vhdl_expr_list() { } void vhdl_expr_list::emit(std::ostream &of, int level) const { of << "("; int size = exprs_.size(); std::list::const_iterator it; for (it = exprs_.begin(); it != exprs_.end(); ++it) { (*it)->emit(of, level); if (--size > 0) of << ", "; } of << ")"; } void vhdl_pcall_stmt::emit(std::ostream &of, int level) const { of << name_; if (!exprs_.empty()) exprs_.emit(of, level); of << ";"; } vhdl_var_ref::~vhdl_var_ref() { } void vhdl_var_ref::set_slice(vhdl_expr *s, int w) { assert(type_); slice_ = s; slice_width_ = w; vhdl_type_name_t tname = type_->get_name(); if (tname == VHDL_TYPE_ARRAY) { type_ = type_->get_base(); } else { assert(tname == VHDL_TYPE_UNSIGNED || tname == VHDL_TYPE_SIGNED); if (w > 0) type_ = new vhdl_type(tname, w); else type_ = vhdl_type::std_logic(); } } void vhdl_var_ref::emit(std::ostream &of, int level) const { of << name_; if (slice_) { of << "("; if (slice_width_ > 0) { slice_->emit(of, level); of << " + " << slice_width_ << " downto "; } slice_->emit(of, level); of << ")"; } } void vhdl_const_string::emit(std::ostream &of, int level) const { // In some instances a string literal can be ambiguous between // a String type and some other types (e.g. std_logic_vector) // The explicit cast to String removes this ambiguity (although // isn't always strictly necessary) of << "String'(\"" << value_ << "\")"; } void vhdl_null_stmt::emit(std::ostream &of, int level) const { of << "null;"; emit_comment(of, level, true); } void vhdl_fcall::emit(std::ostream &of, int level) const { of << name_; exprs_.emit(of, level); } vhdl_abstract_assign_stmt::~vhdl_abstract_assign_stmt() { } void vhdl_nbassign_stmt::emit(std::ostream &of, int level) const { lhs_->emit(of, level); of << " <= "; rhs_->emit(of, level); if (after_) { of << " after "; after_->emit(of, level); } of << ";"; } void vhdl_assign_stmt::emit(std::ostream &of, int level) const { lhs_->emit(of, level); of << " := "; rhs_->emit(of, level); of << ";"; } vhdl_const_bits::vhdl_const_bits(const char *value, int width, bool issigned, bool qualify) : vhdl_expr(issigned ? vhdl_type::nsigned(width) : vhdl_type::nunsigned(width), true), qualified_(qualify), signed_(issigned) { // Can't rely on value being NULL-terminated while (width--) value_.push_back(*value++); } // True if char is not '1' or '0' static bool is_meta_bit(char c) { return c != '1' && c != '0'; } // True if the bit strings contains characters other than '1' and '0' bool vhdl_const_bits::has_meta_bits() const { return find_if(value_.begin(), value_.end(), is_meta_bit) != value_.end(); } void vhdl_const_bits::emit(std::ostream &of, int level) const { if (qualified_) of << (signed_ ? "signed" : "unsigned") << "'("; // If it's a width we can write in hex, prefer that over binary size_t bits = value_.size(); int64_t ival = bits_to_int(); if ((!signed_ || ival >= 0) && !has_meta_bits() && bits <= 64 && bits % 4 == 0) { of << "X\"" << hex << setfill('0') << setw(bits / 4) << ival; } else { of << "\""; std::string::const_reverse_iterator it; for (it = value_.rbegin(); it != value_.rend(); ++it) of << vl_to_vhdl_bit(*it); } of << (qualified_ ? "\")" : "\""); } void vhdl_const_bit::emit(std::ostream &of, int level) const { of << "'" << vl_to_vhdl_bit(bit_) << "'"; } void vhdl_const_int::emit(std::ostream &of, int level) const { of << dec << value_; // We need to find a way to display a comment, since $time, etc. add one. } void vhdl_const_bool::emit(std::ostream &of, int level) const { of << (value_ ? "True" : "False"); } void vhdl_const_time::emit(std::ostream &of, int level) const { of << dec << value_; switch (units_) { case TIME_UNIT_PS: of << " ps"; break; case TIME_UNIT_NS: of << " ns"; break; case TIME_UNIT_US: of << " us"; break; case TIME_UNIT_MS: of << " ms"; break; } } vhdl_cassign_stmt::~vhdl_cassign_stmt() { } void vhdl_cassign_stmt::add_condition(vhdl_expr *value, vhdl_expr *cond) { when_part_t when = { value, cond, NULL }; whens_.push_back(when); } void vhdl_cassign_stmt::emit(std::ostream &of, int level) const { lhs_->emit(of, level); of << " <= "; if (!whens_.empty()) { for (std::list::const_iterator it = whens_.begin(); it != whens_.end(); ++it) { (*it).value->emit(of, level); of << " when "; (*it).cond->emit(of, level); of << " "; } of << "else "; } rhs_->emit(of, level); if (after_) { of << " after "; after_->emit(of, level); } of << ";"; } void vhdl_assert_stmt::emit(std::ostream &of, int level) const { of << "assert false"; // TODO: Allow arbitrary expression of << " report \"" << reason_ << "\" severity failure;"; } vhdl_if_stmt::vhdl_if_stmt(vhdl_expr *test) { // Need to ensure that the expression is Boolean vhdl_type boolean(VHDL_TYPE_BOOLEAN); test_ = test->cast(&boolean); } vhdl_if_stmt::~vhdl_if_stmt() { } stmt_container *vhdl_if_stmt::add_elsif(vhdl_expr *test) { elsif ef = { test, new stmt_container }; elsif_parts_.push_back(ef); return ef.container; } void vhdl_if_stmt::emit(std::ostream &of, int level) const { emit_comment(of, level); of << "if "; test_->emit(of, level); of << " then"; then_part_.emit(of, level); std::list::const_iterator it; for (it = elsif_parts_.begin(); it != elsif_parts_.end(); ++it) { of << "elsif "; (*it).test->emit(of, level); of << " then"; (*it).container->emit(of, level); } if (!else_part_.empty()) { of << "else"; else_part_.emit(of, level); } of << "end if;"; } vhdl_unaryop_expr::~vhdl_unaryop_expr() { } void vhdl_unaryop_expr::emit(std::ostream &of, int level) const { of << "("; switch (op_) { case VHDL_UNARYOP_NOT: of << "not "; break; case VHDL_UNARYOP_NEG: of << "-"; break; } operand_->emit(of, level); of << ")"; } vhdl_binop_expr::vhdl_binop_expr(vhdl_expr *left, vhdl_binop_t op, vhdl_expr *right, vhdl_type *type) : vhdl_expr(type), op_(op) { add_expr(left); add_expr(right); } vhdl_binop_expr::~vhdl_binop_expr() { } void vhdl_binop_expr::add_expr(vhdl_expr *e) { operands_.push_back(e); } void vhdl_binop_expr::emit(std::ostream &of, int level) const { // Expressions are fully parenthesised to remove any // ambiguity in the output of << "("; assert(operands_.size() > 0); std::list::const_iterator it = operands_.begin(); (*it)->emit(of, level); while (++it != operands_.end()) { const char* ops[] = { "and", "or", "=", "/=", "+", "-", "*", "<", ">", "<=", ">=", "sll", "srl", "xor", "&", "nand", "nor", "xnor", "/", "mod", "**", "sra", NULL }; of << " " << ops[op_] << " "; (*it)->emit(of, level); } of << ")"; } vhdl_bit_spec_expr::~vhdl_bit_spec_expr() { } void vhdl_bit_spec_expr::add_bit(int bit, vhdl_expr *e) { bit_map bm = { bit, e }; bits_.push_back(bm); } void vhdl_bit_spec_expr::emit(std::ostream &of, int level) const { of << "("; std::list::const_iterator it; it = bits_.begin(); while (it != bits_.end()) { of << (*it).bit << " => "; (*it).e->emit(of, level); if (++it != bits_.end()) of << ", "; } if (others_) { of << (bits_.empty() ? "" : ", ") << "others => "; others_->emit(of, level); } of << ")"; } vhdl_case_branch::~vhdl_case_branch() { } void vhdl_case_branch::emit(std::ostream &of, int level) const { of << "when "; when_->emit(of, level); of << " =>"; stmts_.emit(of, indent(level), false); } vhdl_case_stmt::~vhdl_case_stmt() { } void vhdl_case_stmt::emit(std::ostream &of, int level) const { of << "case "; test_->emit(of, level); of << " is"; newline(of, indent(level)); case_branch_list_t::const_iterator it; int n = branches_.size(); for (it = branches_.begin(); it != branches_.end(); ++it) { (*it)->emit(of, level); if (--n > 0) newline(of, indent(level)); else newline(of, level); } of << "end case;"; } vhdl_while_stmt::~vhdl_while_stmt() { } void vhdl_while_stmt::emit(std::ostream &of, int level) const { of << "while "; test_->emit(of, level); of << " "; vhdl_loop_stmt::emit(of, level); } void vhdl_loop_stmt::emit(std::ostream &of, int level) const { of << "loop"; stmts_.emit(of, level); of << "end loop;"; } vhdl_for_stmt::~vhdl_for_stmt() { } void vhdl_for_stmt::emit(std::ostream &of, int level) const { of << "for " << lname_ << " in "; from_->emit(of, level); of << " to "; to_->emit(of, level); of << " "; vhdl_loop_stmt::emit(of, level); } vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type) : vhdl_decl(name, ret_type) { // A function contains two scopes: // scope_ = The parameters // variables_ = Local variables // A call to get_scope returns variables_ whose parent is scope_ variables_.set_parent(&scope_); } void vhdl_function::emit(std::ostream &of, int level) const { newline(of, level); emit_comment(of, level); of << "function " << name_ << " ("; emit_children(of, scope_.get_decls(), level, ";"); of << ") "; newline(of, level); of << "return " << type_->get_string() << " is"; emit_children(of, variables_.get_decls(), level); of << "begin"; stmts_.emit(of, level); of << " return " << name_ << "_Result;"; newline(of, level); of << "end function;"; } void vhdl_forward_fdecl::emit(std::ostream &of, int level) const { of << "function " << f_->get_name() << " ("; emit_children(of, f_->scope_.get_decls(), level, ";"); of << ") "; newline(of, level); of << "return " << f_->type_->get_string() << ";"; newline(of, level); } void vhdl_param_decl::emit(std::ostream &of, int level) const { of << name_ << " : "; type_->emit(of, level); } vhdl_with_select_stmt::~vhdl_with_select_stmt() { } void vhdl_with_select_stmt::emit(std::ostream &of, int level) const { of << "with "; test_->emit(of, level); of << " select"; emit_comment(of, level, true); newline(of, indent(level)); out_->emit(of, level); of << " <= "; when_list_t::const_iterator it = whens_.begin(); while (it != whens_.end()) { (*it).value->emit(of, level); if ((*it).delay) { of << " after "; (*it).delay->emit(of, level); } of << " when "; (*it).cond->emit(of, level); if (++it != whens_.end() || others_ != NULL) { of << ","; newline(of, indent(level)); } else of << ";"; } if (others_) { others_->emit(of, level); of << " when others;"; } } void vhdl_with_select_stmt::add_condition(vhdl_expr *value, vhdl_expr *cond, vhdl_expr *delay) { when_part_t when = { value, cond, delay }; whens_.push_back(when); } void vhdl_with_select_stmt::add_default(vhdl_expr* value) { others_ = value; } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/Makefile.in0000644000202500001440000000005012204466647020026 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/Makefile.in0000644000202500001440000000550412204466647017354 0ustar00steveusers00000000000000# # This source code is free software; you can redistribute it # and/or modify it in source code form under the terms of the GNU # Library General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # SHELL = /bin/sh suffix = @install_suffix@ prefix = @prefix@ prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ VPATH = $(srcdir) bindir = @bindir@ libdir = @libdir@ includedir = $(prefix)/include CXX = @CXX@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ CPPFLAGS = -I. -I.. -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@ CXXFLAGS = @WARNING_FLAGS@ @CXXFLAGS@ LDFLAGS = @LDFLAGS@ all: dep vhdl.tgt vhdl.conf vhdl-s.conf dep: mkdir dep %.o: %.cc vhdl_config.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep O = vhdl.o state.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \ stmt.o expr.o lpm.o display.o support.o cast.o logic.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl TGTDEPLIBS=../libivl.a else TGTLDFLAGS= TGTDEPLIBS= endif vhdl.tgt: $O $(TGTDEPLIBS) $(CXX) @shared@ -o $@ $O $(LDFLAGS) $(TGTLDFLAGS) Makefile: $(srcdir)/Makefile.in ../config.status cd ..; ./config.status --file=tgt-vhdl/$@ stamp-vhdl_config-h: $(srcdir)/vhdl_config.h.in ../config.status @rm -f $@ cd ..; ./config.status --header=tgt-vhdl/vhdl_config.h vhdl_config.h: stamp-vhdl_config-h clean: rm -rf $(O) dep vhdl.tgt distclean: clean rm -f Makefile config.log rm -f stamp-vhdl_config-h vhdl_config.h check: all install: all installdirs $(libdir)/ivl$(suffix)/vhdl.tgt $(libdir)/ivl$(suffix)/vhdl.conf \ $(libdir)/ivl$(suffix)/vhdl-s.conf $(libdir)/ivl$(suffix)/vhdl.tgt: ./vhdl.tgt $(INSTALL_PROGRAM) ./vhdl.tgt "$(DESTDIR)$(libdir)/ivl$(suffix)/vhdl.tgt" $(libdir)/ivl$(suffix)/vhdl.conf: vhdl.conf $(INSTALL_DATA) $< "$(DESTDIR)$(libdir)/ivl$(suffix)/vhdl.conf" $(libdir)/ivl$(suffix)/vhdl-s.conf: vhdl-s.conf $(INSTALL_DATA) $< "$(DESTDIR)$(libdir)/ivl$(suffix)/vhdl-s.conf" installdirs: $(srcdir)/../mkinstalldirs $(srcdir)/../mkinstalldirs "$(DESTDIR)$(libdir)/ivl$(suffix)" uninstall: rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/vhdl.tgt" "$(DESTDIR)$(libdir)/ivl$(suffix)/vhdl.conf" "$(DESTDIR)$(libdir)/ivl$(suffix)/vhdl-s.conf" -include $(patsubst %.o, dep/%.d, $O) verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/logic.cc0000644000202500001440000000005012204466647017365 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/logic.cc0000644000202500001440000002151112204466647016707 0ustar00steveusers00000000000000/* * VHDL code generation for logic devices. * * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_target.h" #include "vhdl_element.hh" #include "state.hh" #include #include #include /* * Convert the inputs of a logic gate to a binary expression. */ static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op, ivl_net_logic_t log) { // Not always std_logic but this is probably OK since // the program has already been type checked vhdl_binop_expr *gate = new vhdl_binop_expr(op, vhdl_type::std_logic()); int npins = ivl_logic_pins(log); for (int i = 1; i < npins; i++) { ivl_nexus_t input = ivl_logic_pin(log, i); gate->add_expr(readable_ref(scope, input)); } return gate; } /* * Convert a gate input to an unary expression. */ static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op, ivl_net_logic_t log) { ivl_nexus_t input = ivl_logic_pin(log, 1); assert(input); vhdl_expr *operand = readable_ref(scope, input); return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic()); } static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) { ivl_nexus_t output = ivl_logic_pin(log, 0); vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output); assert(lhs); vhdl_expr *val = readable_ref(arch->get_scope(), ivl_logic_pin(log, 1)); vhdl_expr *sel = readable_ref(arch->get_scope(), ivl_logic_pin(log, 2)); vhdl_expr *cmp; if (ivl_logic_width(log) == 1) { vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1'); cmp = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, on, NULL); } else { vhdl_expr *zero = (new vhdl_const_int(0))->cast(sel->get_type()); vhdl_binop_t op = if0 ? VHDL_BINOP_EQ : VHDL_BINOP_NEQ; cmp = new vhdl_binop_expr(sel, op, zero, NULL); } ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope()); char zbit; switch (ivl_signal_type(sig)) { case IVL_SIT_TRI0: zbit = '0'; break; case IVL_SIT_TRI1: zbit = '1'; break; case IVL_SIT_TRI: default: zbit = 'Z'; } vhdl_expr *z = new vhdl_const_bit(zbit); if (ivl_logic_width(log) > 1) z = new vhdl_bit_spec_expr(NULL, z); vhdl_cassign_stmt *cass = new vhdl_cassign_stmt(lhs, z); cass->add_condition(val, cmp); arch->add_stmt(cass); } static void comb_udp_logic(vhdl_arch *arch, ivl_net_logic_t log) { ivl_udp_t udp = ivl_logic_udp(log); // As with regular case statements, the expression in a // `with .. select' statement must be "locally static". // This is achieved by first combining the inputs into // a temporary ostringstream ss; ss << ivl_logic_basename(log) << "_Tmp"; int msb = ivl_udp_nin(udp) - 1; vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0); vhdl_signal_decl *tmp_decl = new vhdl_signal_decl(ss.str().c_str(), tmp_type); arch->get_scope()->add_decl(tmp_decl); int nin = ivl_udp_nin(udp); vhdl_expr *tmp_rhs; if (nin == 1) { tmp_rhs = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1)); tmp_rhs = tmp_rhs->cast(tmp_type); } else tmp_rhs = inputs_to_expr(arch->get_scope(), VHDL_BINOP_CONCAT, log); ss.str(""); ss << "Input to " << ivl_logic_basename(log) << " " << ivl_udp_name(udp) << " UDP"; tmp_decl->set_comment(ss.str()); vhdl_var_ref *tmp_ref = new vhdl_var_ref(tmp_decl->get_name().c_str(), NULL); arch->add_stmt(new vhdl_cassign_stmt(tmp_ref, tmp_rhs)); // Now we can implement the UDP as a `with .. select' statement // by reading values out of the table ivl_nexus_t output_nex = ivl_logic_pin(log, 0); vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), output_nex); vhdl_with_select_stmt *ws = new vhdl_with_select_stmt(new vhdl_var_ref(*tmp_ref), out); // Ensure the select statement completely covers the input space // or some strict VHDL compilers will complain ws->add_default(new vhdl_const_bit('X')); int nrows = ivl_udp_rows(udp); for (int i = 0; i < nrows; i++) { const char *row = ivl_udp_row(udp, i); vhdl_expr *value = new vhdl_const_bit(row[nin]); vhdl_expr *cond = new vhdl_const_bits(row, nin, false); ivl_expr_t delay_ex = ivl_logic_delay(log, 1); vhdl_expr *delay = NULL; if (delay_ex) delay = translate_time_expr(delay_ex); ws->add_condition(value, cond, delay); } ss.str(""); ss << "UDP " << ivl_udp_name(udp); ws->set_comment(ss.str()); arch->add_stmt(ws); } static void seq_udp_logic(vhdl_arch *arch, ivl_net_logic_t log) { ivl_udp_t udp = ivl_logic_udp(log); // These will be translated to a process with a single // case statement vhdl_process *proc = new vhdl_process(ivl_logic_basename(log)); ostringstream ss; ss << "Generated from UDP " << ivl_udp_name(udp); proc->set_comment(ss.str().c_str()); // Create a variable to hold the concatenation of the inputs int msb = ivl_udp_nin(udp) - 1; vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0); proc->get_scope()->add_decl(new vhdl_var_decl("UDP_Inputs", tmp_type)); // Concatenate the inputs into a single expression that can be // used as the test in a case statement (this can't be inserted // directly into the case statement due to the requirement that // the test expression be "locally static") int nin = ivl_udp_nin(udp); vhdl_expr *tmp_rhs = NULL; if (nin == 1) { vhdl_var_ref *ref = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1)); tmp_rhs = ref->cast(tmp_type); proc->add_sensitivity(ref->get_name()); } else { vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, NULL); for (int i = 1; i < nin; i++) { vhdl_var_ref *ref = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, i)); concat->add_expr(ref); proc->add_sensitivity(ref->get_name()); } tmp_rhs = concat; } proc->get_container()->add_stmt (new vhdl_assign_stmt(new vhdl_var_ref("UDP_Inputs", NULL), tmp_rhs)); arch->add_stmt(proc); } static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) { if (ivl_udp_sequ(ivl_logic_udp(log))) seq_udp_logic(arch, log); else comb_udp_logic(arch, log); } static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log) { switch (ivl_logic_type(log)) { case IVL_LO_NOT: return input_to_expr(scope, VHDL_UNARYOP_NOT, log); case IVL_LO_AND: return inputs_to_expr(scope, VHDL_BINOP_AND, log); case IVL_LO_OR: return inputs_to_expr(scope, VHDL_BINOP_OR, log); case IVL_LO_NAND: return inputs_to_expr(scope, VHDL_BINOP_NAND, log); case IVL_LO_NOR: return inputs_to_expr(scope, VHDL_BINOP_NOR, log); case IVL_LO_XOR: return inputs_to_expr(scope, VHDL_BINOP_XOR, log); case IVL_LO_XNOR: return inputs_to_expr(scope, VHDL_BINOP_XNOR, log); case IVL_LO_BUF: case IVL_LO_BUFZ: return nexus_to_var_ref(scope, ivl_logic_pin(log, 1)); case IVL_LO_PULLUP: return new vhdl_const_bit('1'); case IVL_LO_PULLDOWN: return new vhdl_const_bit('0'); default: error("Don't know how to translate logic type = %d to expression", ivl_logic_type(log)); return NULL; } } void draw_logic(vhdl_arch *arch, ivl_net_logic_t log) { switch (ivl_logic_type(log)) { case IVL_LO_BUFIF0: bufif_logic(arch, log, true); break; case IVL_LO_BUFIF1: bufif_logic(arch, log, false); break; case IVL_LO_UDP: udp_logic(arch, log); break; default: { // The output is always pin zero ivl_nexus_t output = ivl_logic_pin(log, 0); vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output); vhdl_expr *rhs = translate_logic_inputs(arch->get_scope(), log); vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs); ivl_expr_t delay = ivl_logic_delay(log, 1); if (delay) ass->set_after(translate_time_expr(delay)); arch->add_stmt(ass); } } } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/display.cc0000644000202500001440000000005012204466647017735 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/display.cc0000644000202500001440000001375312204466647017270 0ustar00steveusers00000000000000/* * VHDL implementation of $display. * * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_target.h" #include #include #include #include #include static const char *DISPLAY_LINE = "Verilog_Display_Line"; /* * Write a VHDL expression into the current display line. */ static void display_write(stmt_container *container, vhdl_expr *expr) { vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write"); vhdl_var_ref *ref = new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line()); write->add_expr(ref); vhdl_type_name_t type = expr->get_type()->get_name(); if (type == VHDL_TYPE_SIGNED || type == VHDL_TYPE_UNSIGNED) { vhdl_type integer(VHDL_TYPE_INTEGER); write->add_expr(expr->cast(&integer)); } else if (type != VHDL_TYPE_STRING) { // Need to add a call to Type'Image for types not // supported by std.textio std::string name(expr->get_type()->get_string()); name += "'Image"; vhdl_fcall *cast = new vhdl_fcall(name.c_str(), vhdl_type::string()); cast->add_expr(expr); write->add_expr(cast); } else write->add_expr(expr); container->add_stmt(write); } /* * Write the value of DISPLAY_LINE to the output. */ static void display_line(stmt_container *container) { vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine"); vhdl_var_ref *output_ref = new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE)); write_line->add_expr(output_ref); vhdl_var_ref *ref = new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line()); write_line->add_expr(ref); container->add_stmt(write_line); } /* * Parse an octal escape sequence. */ static char parse_octal(const char *p) { assert(*p && *(p+1) && *(p+2)); assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1))); return (*p - '0') * 64 + (*(p+1) - '0') * 8 + (*(p+2) - '0') * 1; } static void flush_string(std::ostringstream &ss, stmt_container *container) { display_write(container, new vhdl_const_string(ss.str().c_str())); // Clear the stream ss.str(""); } // This should display the hierarchical module name, but we don't support // this in VHDL. So just emit a warning. static void display_m(stmt_container* container) { cerr << "Warning: no VHDL translation for %m format code" << endl; } /* * Generate VHDL for the $display system task. * This is implemented using the functions in std.textio. Each * parameter is written to a line variable in the process and * then the line is written to the special variable `Output' * (which represents the console). Subsequent $displays will * use the same line variable. * * It's possible, although quite unlikely, that there will be * name collision with an existing variable called * `Verilog_Display_Line' -- do something about this? */ int draw_stask_display(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool newline) { if (!proc->get_scope()->have_declared(DISPLAY_LINE)) { vhdl_var_decl *line_var = new vhdl_var_decl(DISPLAY_LINE, vhdl_type::line()); line_var->set_comment("For generating $display output"); proc->get_scope()->add_decl(line_var); } // Write the data into the line int count = ivl_stmt_parm_count(stmt), i = 0; while (i < count) { // $display may have an empty parameter, in which case // the expression will be null // The behaviour here seems to be to output a space ivl_expr_t net = ivl_stmt_parm(stmt, i++); if (net == NULL) { display_write(container, new vhdl_const_string(" ")); continue; } if (ivl_expr_type(net) == IVL_EX_STRING) { ostringstream ss; for (const char *p = ivl_expr_string(net); *p; p++) { if (*p == '\\') { // Octal escape char ch = parse_octal(p+1); if (ch == '\n') { flush_string(ss, container); display_line(container); } else ss << ch; p += 3; } else if (*p == '%' && *(++p) != '%') { flush_string(ss, container); // Skip over width for now while (isdigit(*p)) ++p; switch (*p) { case 'm': display_m(container); break; default: { assert(i < count); ivl_expr_t netp = ivl_stmt_parm(stmt, i++); assert(netp); vhdl_expr *base = translate_expr(netp); if (NULL == base) return 1; display_write(container, base); } } } else ss << *p; } // Call Write on any non-empty string data left in the buffer if (!ss.str().empty()) display_write(container, new vhdl_const_string(ss.str().c_str())); } else { vhdl_expr *base = translate_expr(net); if (NULL == base) return 1; display_write(container, base); } } if (newline) display_line(container); return 0; } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl_config.h.in0000644000202500001440000000005012204466647021021 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl_config.h.in0000644000202500001440000000227012204466647020344 0ustar00steveusers00000000000000/* vhdl_config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/process.cc0000644000202500001440000000005012204466647017746 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/process.cc0000644000202500001440000000750312204466647017275 0ustar00steveusers00000000000000/* * VHDL code generation for processes. * * Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_target.h" #include "vhdl_element.hh" #include "state.hh" #include #include #include /* * Convert a Verilog process to VHDL and add it to the architecture * of the given entity. */ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) { set_active_entity(ent); // Create a new process and store it in the entity's // architecture. This needs to be done first or the // parent link won't be valid (and draw_stmt needs this // to add information to the architecture) vhdl_process *vhdl_proc = new vhdl_process(); ent->get_arch()->add_stmt(vhdl_proc); // If this is an initial process, push signal initialisation // into the declarations vhdl_proc->get_scope()->set_initializing (ivl_process_type(proc) == IVL_PR_INITIAL); ivl_statement_t stmt = ivl_process_stmt(proc); int rc = draw_stmt(vhdl_proc, vhdl_proc->get_container(), stmt); if (rc != 0) return rc; // Initial processes are translated to VHDL processes with // no sensitivity list and and indefinite wait statement at // the end // However, if no statements were added to the container // by draw_stmt, don't bother adding a wait as `emit' // will optimise the process out of the output if (ivl_process_type(proc) == IVL_PR_INITIAL) { // Get rid of any useless `wait for 0 ns's at the end of the process prune_wait_for_0(vhdl_proc->get_container()); // The above pruning might have removed all logic from the process if (!vhdl_proc->get_container()->empty()) { vhdl_wait_stmt *wait = new vhdl_wait_stmt(); vhdl_proc->get_container()->add_stmt(wait); } } // Add a comment indicating where it came from ivl_scope_t scope = ivl_process_scope(proc); const char *type = ivl_process_type(proc) == IVL_PR_INITIAL ? "initial" : "always"; std::ostringstream ss; ss << "Generated from " << type << " process in " << ivl_scope_tname(scope) << " (" << ivl_process_file(proc) << ":" << ivl_process_lineno(proc) << ")"; vhdl_proc->set_comment(ss.str()); set_active_entity(NULL); return 0; } extern "C" int draw_process(ivl_process_t proc, void *cd) { ivl_scope_t scope = ivl_process_scope(proc); if (!is_default_scope_instance(scope)) return 0; // Ignore this process at it's not in a scope that // we're using to generate code debug_msg("Translating process in scope type %s (%s:%d)", ivl_scope_tname(scope), ivl_process_file(proc), ivl_process_lineno(proc)); // Skip over any generate and begin scopes until we find // the module that contains them - this is where we will // generate the process while (ivl_scope_type(scope) == IVL_SCT_GENERATE || ivl_scope_type(scope) == IVL_SCT_BEGIN) scope = ivl_scope_parent(scope); assert(ivl_scope_type(scope) == IVL_SCT_MODULE); vhdl_entity *ent = find_entity(scope); assert(ent != NULL); return generate_vhdl_process(ent, proc); } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/support.cc0000644000202500001440000000005012204466647020004 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/support.cc0000644000202500001440000001371212204466647017332 0ustar00steveusers00000000000000/* * Support functions for VHDL output. * * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_target.h" #include "support.hh" #include "state.hh" #include #include void require_support_function(support_function_t f) { vhdl_scope *scope = get_active_entity()->get_arch()->get_scope(); if (!scope->have_declared(support_function::function_name(f))) scope->add_decl(new support_function(f)); } const char *support_function::function_name(support_function_t type) { switch (type) { case SF_UNSIGNED_TO_BOOLEAN: return "Unsigned_To_Boolean"; case SF_SIGNED_TO_BOOLEAN: return "Signed_To_Boolean"; case SF_BOOLEAN_TO_LOGIC: return "Boolean_To_Logic"; case SF_REDUCE_OR: return "Reduce_OR"; case SF_REDUCE_AND: return "Reduce_AND"; case SF_REDUCE_XOR: return "Reduce_XOR"; case SF_REDUCE_XNOR: return "Reduce_XNOR"; case SF_TERNARY_LOGIC: return "Ternary_Logic"; case SF_TERNARY_UNSIGNED: return "Ternary_Unsigned"; case SF_TERNARY_SIGNED: return "Ternary_Signed"; case SF_LOGIC_TO_INTEGER: return "Logic_To_Integer"; case SF_SIGNED_TO_LOGIC: return "Signed_To_Logic"; case SF_UNSIGNED_TO_LOGIC: return "Unsigned_To_Logic"; default: assert(false); } return "Invalid"; } vhdl_type *support_function::function_type(support_function_t type) { switch (type) { case SF_UNSIGNED_TO_BOOLEAN: case SF_SIGNED_TO_BOOLEAN: return vhdl_type::boolean(); case SF_BOOLEAN_TO_LOGIC: case SF_REDUCE_OR: case SF_REDUCE_AND: case SF_REDUCE_XOR: case SF_REDUCE_XNOR: case SF_TERNARY_LOGIC: case SF_SIGNED_TO_LOGIC: case SF_UNSIGNED_TO_LOGIC: return vhdl_type::std_logic(); case SF_TERNARY_SIGNED: return new vhdl_type(VHDL_TYPE_SIGNED); case SF_TERNARY_UNSIGNED: return new vhdl_type(VHDL_TYPE_UNSIGNED); case SF_LOGIC_TO_INTEGER: return vhdl_type::integer(); } assert(false); return vhdl_type::boolean(); } void support_function::emit_ternary(std::ostream &of, int level) const { of << nl_string(level) << "begin" << nl_string(indent(level)) << "if T then return X; else return Y; end if;"; } void support_function::emit_reduction(std::ostream &of, int level, const char *op, char unit) const { // Emit a VHDL function emulating a Verilog reduction operator // Where op is the corresponding VHDL operator and unit is the // right-unit of the operator of << "(X : std_logic_vector) return std_logic is" << nl_string(indent(level)) << "variable R : std_logic := '" << unit << "';" << nl_string(level) << "begin" << nl_string(indent(level)) << "for I in X'Range loop" << nl_string(indent(indent(level))) << "R := X(I) " << op << " R;" << nl_string(indent(level)) << "end loop;" << nl_string(indent(level)) << "return R;"; } void support_function::emit(std::ostream &of, int level) const { of << nl_string(level) << "function " << function_name(type_); switch (type_) { case SF_UNSIGNED_TO_BOOLEAN: of << "(X : unsigned) return Boolean is" << nl_string(level) << "begin" << nl_string(indent(level)) << "return X /= To_Unsigned(0, X'Length);"; break; case SF_SIGNED_TO_BOOLEAN: of << "(X : signed) return Boolean is" << nl_string(level) << "begin" << nl_string(indent(level)) << "return X /= To_Signed(0, X'Length);"; break; case SF_BOOLEAN_TO_LOGIC: of << "(B : Boolean) return std_logic is" << nl_string(level) << "begin" << nl_string(indent(level)) << "if B then" << nl_string(indent(indent(level))) << "return '1';" << nl_string(indent(level)) << "else" << nl_string(indent(indent(level))) << "return '0';" << nl_string(indent(level)) << "end if;"; break; case SF_UNSIGNED_TO_LOGIC: of << "(X : unsigned) return std_logic is" << nl_string(level) << "begin" << nl_string(indent(level)) << "return X(0);"; break; case SF_SIGNED_TO_LOGIC: of << "(X : signed) return std_logic is" << nl_string(level) << "begin" << nl_string(indent(level)) << "return X(0);"; break; case SF_REDUCE_OR: emit_reduction(of, level, "or", '0'); break; case SF_REDUCE_AND: emit_reduction(of, level, "and", '1'); break; case SF_REDUCE_XOR: emit_reduction(of, level, "xnor", '0'); break; case SF_REDUCE_XNOR: emit_reduction(of, level, "xnor", '0'); break; case SF_TERNARY_LOGIC: of << "(T : Boolean; X, Y : std_logic) return std_logic is"; emit_ternary(of, level); break; case SF_TERNARY_SIGNED: of << "(T : Boolean; X, Y : signed) return signed is"; emit_ternary(of, level); break; case SF_TERNARY_UNSIGNED: of << "(T : Boolean; X, Y : unsigned) return unsigned is"; emit_ternary(of, level); break; case SF_LOGIC_TO_INTEGER: of << "(X : std_logic) return integer is" << nl_string(level) << "begin" << nl_string(indent(level)) << "if X = '1' then return 1; else return 0; end if;"; break; default: assert(false); } of << nl_string(level) << "end function;"; } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/support.hh0000644000202500001440000000005012204466647020016 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/support.hh0000644000202500001440000000342512204466647017344 0ustar00steveusers00000000000000/* * Support functions for VHDL output. * * Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef INC_SUPPORT_HH #define INC_SUPPORT_HH #include "vhdl_syntax.hh" enum support_function_t { SF_UNSIGNED_TO_BOOLEAN = 0, SF_SIGNED_TO_BOOLEAN, SF_BOOLEAN_TO_LOGIC, SF_REDUCE_OR, SF_REDUCE_AND, SF_REDUCE_XOR, SF_REDUCE_XNOR, SF_TERNARY_LOGIC, SF_TERNARY_UNSIGNED, SF_TERNARY_SIGNED, SF_LOGIC_TO_INTEGER, SF_SIGNED_TO_LOGIC, SF_UNSIGNED_TO_LOGIC }; class support_function : public vhdl_function { public: support_function(support_function_t type) : vhdl_function(function_name(type), function_type(type)), type_(type) {} void emit(std::ostream &of, int level) const; static const char *function_name(support_function_t type); static vhdl_type *function_type(support_function_t type); private: void emit_ternary(std::ostream &of, int level) const; void emit_reduction(std::ostream &of, int level, const char *op, char unit) const; support_function_t type_; }; #endif verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhpi0000644000202500001440000000005012204466647016652 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhpi/0000755000202500001440000000000012204466647016251 5ustar00steveusers00000000000000verilog-0.9.7/tgt-vhdl/vhpi/PaxHeaders.14238/finish.c0000644000202500001440000000005012204466647020353 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhpi/finish.c0000644000202500001440000000006712204466647017700 0ustar00steveusers00000000000000#include void finish(void) { exit(0); } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/scope.cc0000644000202500001440000000005012204466647017401 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/scope.cc0000644000202500001440000011156612204466647016735 0ustar00steveusers00000000000000/* * VHDL code generation for scopes. * * Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_target.h" #include "vhdl_element.hh" #include "state.hh" #include #include #include #include /* * This represents the portion of a nexus that is visible within * a VHDL scope. If that nexus portion does not contain a signal, * then `tmpname' gives the name of the temporary that will be * used when this nexus is used in `scope' (e.g. for LPMs that * appear in instantiations). The list `connect' lists all the * signals that should be joined together to re-create the net. */ struct scope_nexus_t { vhdl_scope *scope; ivl_signal_t sig; // A real signal unsigned pin; // The pin this signal is connected to string tmpname; // A new temporary signal list connect; // Other signals to wire together }; /* * This structure is stored in the private part of each nexus. * It stores a scope_nexus_t for each VHDL scope which is * connected to that nexus. It's stored as a list so we can use * contained_within to allow several nested scopes to reference * the same signal. */ struct nexus_private_t { list signals; vhdl_expr *const_driver; }; /* * Returns the scope_nexus_t of this nexus visible within scope. */ static scope_nexus_t *visible_nexus(nexus_private_t *priv, vhdl_scope *scope) { list::iterator it; for (it = priv->signals.begin(); it != priv->signals.end(); ++it) { if (scope->contained_within((*it).scope)) return &*it; } return NULL; } /* * Remember that a signal in `scope' is part of this nexus. The * first signal passed to this function for a scope will be used * as the canonical representation of this nexus when we need to * convert it to a variable reference (e.g. in a LPM input/output). */ static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope, ivl_signal_t sig, unsigned pin) { scope_nexus_t *sn; if ((sn = visible_nexus(priv, scope))) { assert(sn->tmpname == ""); // Remember to connect this signal up later // If one of the signals is a input, make sure the input is not being driven if (ivl_signal_port(sn->sig) == IVL_SIP_INPUT) sn->sig = sig; else sn->connect.push_back(sig); } else { scope_nexus_t new_sn = { scope, sig, pin, "" }; priv->signals.push_back(new_sn); } } /* * Make a temporary the representative of this nexus in scope. */ static void link_scope_to_nexus_tmp(nexus_private_t *priv, vhdl_scope *scope, const string &name) { scope_nexus_t new_sn = { scope, NULL, 0, name }; priv->signals.push_back(new_sn); } /* * Finds the name of the nexus signal within this scope. */ static string visible_nexus_signal_name(nexus_private_t *priv, vhdl_scope *scope, unsigned *pin) { scope_nexus_t *sn = visible_nexus(priv, scope); assert(sn); *pin = sn->pin; return sn->sig ? get_renamed_signal(sn->sig) : sn->tmpname; } /* * Calculate the signal type of a nexus. This is modified from * draw_net_input in tgt-vvp. This also returns the width of * the signal(s) connected to the nexus. */ static ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex, int &width) { ivl_signal_type_t out = IVL_SIT_TRI; width = 0; for (unsigned idx = 0; idx < ivl_nexus_ptrs(nex); idx += 1) { ivl_signal_type_t stype; ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx); ivl_signal_t sig = ivl_nexus_ptr_sig(ptr); if (sig == 0) continue; width = ivl_signal_width(sig); stype = ivl_signal_type(sig); if (stype == IVL_SIT_TRI) continue; if (stype == IVL_SIT_NONE) continue; out = stype; } return out; } /* * Generates VHDL code to fully represent a nexus. */ void draw_nexus(ivl_nexus_t nexus) { nexus_private_t *priv = new nexus_private_t; int nexus_signal_width = -1; priv->const_driver = NULL; int nptrs = ivl_nexus_ptrs(nexus); // Number of drivers for this nexus int ndrivers = 0; // First pass through connect all the signals up for (int i = 0; i < nptrs; i++) { ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); ivl_signal_t sig; if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { vhdl_scope *scope = find_scope_for_signal(sig); if (scope) { unsigned pin = ivl_nexus_ptr_pin(nexus_ptr); link_scope_to_nexus_signal(priv, scope, sig, pin); } nexus_signal_width = ivl_signal_width(sig); } } // Second pass through make sure logic/LPMs have signal // inputs and outputs for (int i = 0; i < nptrs; i++) { ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); ivl_net_logic_t log; ivl_lpm_t lpm; ivl_net_const_t con; if ((log = ivl_nexus_ptr_log(nexus_ptr))) { ivl_scope_t log_scope = ivl_logic_scope(log); if (!is_default_scope_instance(log_scope)) continue; vhdl_entity *ent = find_entity(log_scope); assert(ent); vhdl_scope *vhdl_scope = ent->get_arch()->get_scope(); if (visible_nexus(priv, vhdl_scope)) { // Already seen this signal in vhdl_scope } else { // Create a temporary signal to connect it to the nexus vhdl_type *type = vhdl_type::type_for(ivl_logic_width(log), false); ostringstream ss; ss << "LO" << ivl_logic_basename(log); vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type)); link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str()); } // If this is connected to pin-0 then this nexus is driven // by this logic gate if (ivl_logic_pin(log, 0) == nexus) ndrivers++; } else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { ivl_scope_t lpm_scope = ivl_lpm_scope(lpm); vhdl_entity *ent = find_entity(lpm_scope); assert(ent); vhdl_scope *vhdl_scope = ent->get_arch()->get_scope(); if (visible_nexus(priv, vhdl_scope)) { // Already seen this signal in vhdl_scope } else { // Create a temporary signal to connect the nexus // TODO: we could avoid this for IVL_LPM_PART_PV // If we already know how wide the temporary should be // (i.e. because we've seen a signal it's connected to) // then use that, otherwise use the width of the LPM int lpm_temp_width; if (nexus_signal_width != -1) lpm_temp_width = nexus_signal_width; else lpm_temp_width = ivl_lpm_width(lpm); vhdl_type *type = vhdl_type::type_for(lpm_temp_width, ivl_lpm_signed(lpm) != 0); ostringstream ss; ss << "LPM" << ivl_lpm_basename(lpm); if (!vhdl_scope->have_declared(ss.str())) vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type)); link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str()); } // If this is connected to the LPM output then this nexus // is driven by the LPM if (ivl_lpm_q(lpm, 0) == nexus) ndrivers++; } else if ((con = ivl_nexus_ptr_con(nexus_ptr))) { if (ivl_const_type(con) == IVL_VT_REAL) { error("No VHDL translation for real constant (%g)", ivl_const_real(con)); continue; } if (ivl_const_width(con) == 1) priv->const_driver = new vhdl_const_bit(ivl_const_bits(con)[0]); else priv->const_driver = new vhdl_const_bits(ivl_const_bits(con), ivl_const_width(con), ivl_const_signed(con) != 0); // A constant is a sort of driver ndrivers++; } } // Drive undriven nets with a constant if (ndrivers == 0) { char def = 0; int width; switch (signal_type_of_nexus(nexus, width)) { case IVL_SIT_TRI: def = 'Z'; break; case IVL_SIT_TRI0: def = '0'; break; case IVL_SIT_TRI1: def = '1'; break; case IVL_SIT_TRIAND: error("No VHDL translation for triand nets"); break; case IVL_SIT_TRIOR: error("No VHDL translation for trior nets"); break; default: ; } if (def) { if (width > 1) priv->const_driver = new vhdl_bit_spec_expr(vhdl_type::std_logic(), new vhdl_const_bit(def)); else priv->const_driver = new vhdl_const_bit(def); } } // Save the private data in the nexus ivl_nexus_set_private(nexus, priv); } /* * Ensure that a nexus has been initialised. I.e. all the necessary * statements, declarations, etc. have been generated. */ static void seen_nexus(ivl_nexus_t nexus) { if (ivl_nexus_get_private(nexus) == NULL) draw_nexus(nexus); } /* * Translate a nexus to a variable reference. Given a nexus and a * scope, this function returns a reference to a signal that is * connected to the nexus and within the given scope. This signal * might not exist in the original Verilog source (even as a * compiler-generated temporary). If this nexus hasn't been * encountered before, the necessary code to connect up the nexus * will be generated. */ vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus) { seen_nexus(nexus); nexus_private_t *priv = static_cast(ivl_nexus_get_private(nexus)); unsigned pin; string renamed(visible_nexus_signal_name(priv, scope, &pin)); vhdl_decl *decl = scope->get_decl(renamed); assert(decl); vhdl_type *type = new vhdl_type(*(decl->get_type())); vhdl_var_ref *ref = new vhdl_var_ref(renamed.c_str(), type); if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY) ref->set_slice(new vhdl_const_int(pin), 0); return ref; } // Return a variable reference for a nexus that is guaranteed to // be readable. vhdl_var_ref* readable_ref(vhdl_scope* scope, ivl_nexus_t nex) { vhdl_var_ref* ref = nexus_to_var_ref(scope, nex); vhdl_decl* decl = scope->get_decl(ref->get_name()); decl->ensure_readable(); return ref; } /* * Translate all the primitive logic gates into concurrent * signal assignments. */ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) { debug_msg("Declaring logic in scope type %s", ivl_scope_tname(scope)); int nlogs = ivl_scope_logs(scope); for (int i = 0; i < nlogs; i++) draw_logic(arch, ivl_scope_log(scope, i)); } // Replace consecutive underscores with a single underscore static void replace_consecutive_underscores(string& str) { size_t pos = str.find("__"); while (pos != string::npos) { str.replace(pos, 2, "_"); pos = str.find("__"); } } // Return a valid VHDL name for a Verilog module static string valid_entity_name(const string& module_name) { string name(module_name); replace_consecutive_underscores(name); if (name[0] == '_') name = "Mod" + name; if (*name.rbegin() == '_') name += "Mod"; ostringstream ss; int i = 1; ss << name; while (find_entity(ss.str())) { // Keep adding an extra number until we get a unique name ss.str(""); ss << name << i++; } return ss.str(); } // Make sure a signal name conforms to VHDL naming rules. string make_safe_name(ivl_signal_t sig) { string base(ivl_signal_basename(sig)); if (ivl_signal_local(sig)) base = "Tmp" + base; if (base[0] == '_') base = "Sig" + base; if (*base.rbegin() == '_') base += "Sig"; // Can't have two consecutive underscores replace_consecutive_underscores(base); // A signal name may not be the same as a component name if (find_entity(base) != NULL) base += "_Sig"; // This is the complete list of VHDL reserved words const char *vhdl_reserved[] = { "abs", "access", "after", "alias", "all", "and", "architecture", "array", "assert", "attribute", "begin", "block", "body", "buffer", "bus", "case", "component", "configuration", "constant", "disconnect", "downto", "else", "elsif", "end", "entity", "exit", "file", "for", "function", "generate", "generic", "group", "guarded", "if", "impure", "in", "inertial", "inout", "is", "label", "library", "linkage", "literal", "loop", "map", "mod", "nand", "new", "next", "nor", "not", "null", "of", "on", "open", "or", "others", "out", "package", "port", "postponed", "procedure", "process", "pure", "range", "record", "register", "reject", "rem", "report", "return", "rol", "ror", "select", "severity", "signal", "shared", "sla", "sll", "sra", "srl", "subtype", "then", "to", "transport", "type", "unaffected", "units", "until", "use", "variable", "wait", "when", "while", "with", "xnor", "xor", NULL }; for (const char **p = vhdl_reserved; *p != NULL; p++) { if (strcasecmp(*p, base.c_str()) == 0) { return "Sig_" + base; break; } } return string(base); } // Check if `name' differs from an existing name only in case and // make it unique if it does. static void avoid_name_collision(string& name, vhdl_scope* scope) { if (scope->name_collides(name)) { name += "_"; ostringstream ss; int i = 1; do { // Keep adding an extra number until we get a unique name ss.str(""); ss << name << i++; } while (scope->name_collides(ss.str())); name = ss.str(); } } // Concatenate the expanded genvar values together to make a unique // instance name // This isn't ideal: it would be better to replace the Verilog // generate with an equivalent VHDL generate, but this isn't possible // with the current API static string genvar_unique_suffix(ivl_scope_t scope) { ostringstream suffix; while (scope && ivl_scope_type(scope) == IVL_SCT_GENERATE) { for (unsigned i = 0; i < ivl_scope_params(scope); i++) { ivl_parameter_t param = ivl_scope_param(scope, i); ivl_expr_t e = ivl_parameter_expr(param); if (ivl_expr_type(e) == IVL_EX_NUMBER) { vhdl_expr* value = translate_expr(e); assert(value); value = value->cast(vhdl_type::integer()); suffix << "_" << ivl_parameter_basename(param); value->emit(suffix, 0); delete value; } else { error("Only numeric genvars supported at the moment"); return "_ERROR"; // Never used } } scope = ivl_scope_parent(scope); } return suffix.str(); } // Declare a single signal in a scope static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig, ivl_scope_t scope) { remember_signal(sig, ent->get_arch()->get_scope()); string name(make_safe_name(sig)); name += genvar_unique_suffix(scope); avoid_name_collision(name, ent->get_arch()->get_scope()); rename_signal(sig, name); vhdl_type *sig_type; unsigned dimensions = ivl_signal_dimensions(sig); if (dimensions > 0) { // Arrays are implemented by generating a separate type // declaration for each array, and then declaring a // signal of that type if (dimensions > 1) { error("> 1 dimension arrays not implemented yet"); return; } string type_name = name + "_Type"; vhdl_type *base_type = vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); int lsb = ivl_signal_array_base(sig); int msb = lsb + ivl_signal_array_count(sig) - 1; vhdl_type *array_type = vhdl_type::array_of(base_type, type_name, msb, lsb); vhdl_decl *array_decl = new vhdl_type_decl(type_name.c_str(), array_type); ent->get_arch()->get_scope()->add_decl(array_decl); sig_type = new vhdl_type(*array_type); } else sig_type = vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); ivl_signal_port_t mode = ivl_signal_port(sig); switch (mode) { case IVL_SIP_NONE: { vhdl_decl *decl = new vhdl_signal_decl(name.c_str(), sig_type); ostringstream ss; if (ivl_signal_local(sig)) { ss << "Temporary created at " << ivl_signal_file(sig) << ":" << ivl_signal_lineno(sig); } else { ss << "Declared at " << ivl_signal_file(sig) << ":" << ivl_signal_lineno(sig); } decl->set_comment(ss.str().c_str()); ent->get_arch()->get_scope()->add_decl(decl); } break; case IVL_SIP_INPUT: ent->get_scope()->add_decl (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_IN)); break; case IVL_SIP_OUTPUT: { vhdl_port_decl *decl = new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT); ent->get_scope()->add_decl(decl); } if (ivl_signal_type(sig) == IVL_SIT_REG) { // A registered output // In Verilog the output and reg can have the // same name: this is not valid in VHDL // Instead a new signal foo_Reg is created // which represents the register std::string newname(name); newname += "_Reg"; rename_signal(sig, newname.c_str()); vhdl_type *reg_type = new vhdl_type(*sig_type); ent->get_arch()->get_scope()->add_decl (new vhdl_signal_decl(newname.c_str(), reg_type)); // Create a concurrent assignment statement to // connect the register to the output ent->get_arch()->add_stmt (new vhdl_cassign_stmt (new vhdl_var_ref(name.c_str(), NULL), new vhdl_var_ref(newname.c_str(), NULL))); } break; case IVL_SIP_INOUT: ent->get_scope()->add_decl (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_INOUT)); break; default: assert(false); } } // Declare all signals and ports for a scope. // This is done in two phases: first the ports are added then then // internal signals. Making two passes like this ensures ports get // first pick of names when there is a collision. static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) { debug_msg("Declaring signals in scope type %s", ivl_scope_tname(scope)); int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); if (ivl_signal_port(sig) != IVL_SIP_NONE) declare_one_signal(ent, sig, scope); } for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); if (ivl_signal_port(sig) == IVL_SIP_NONE) declare_one_signal(ent, sig, scope); } } /* * Generate VHDL for LPM instances in a module. */ static void declare_lpm(vhdl_arch *arch, ivl_scope_t scope) { int nlpms = ivl_scope_lpms(scope); for (int i = 0; i < nlpms; i++) { ivl_lpm_t lpm = ivl_scope_lpm(scope, i); if (draw_lpm(arch, lpm) != 0) error("Failed to translate LPM %s", ivl_lpm_name(lpm)); } } /* * Map two signals together in an instantiation. * The signals are joined by a nexus. */ static void map_signal(ivl_signal_t to, vhdl_entity *parent, vhdl_comp_inst *inst) { // TODO: Work for multiple words ivl_nexus_t nexus = ivl_signal_nex(to, 0); seen_nexus(nexus); vhdl_scope *arch_scope = parent->get_arch()->get_scope(); nexus_private_t *priv = static_cast(ivl_nexus_get_private(nexus)); assert(priv); vhdl_expr *map_to = NULL; const string name(make_safe_name(to)); // We can only map ports to signals or constants if (visible_nexus(priv, arch_scope)) { vhdl_var_ref *ref = nexus_to_var_ref(parent->get_arch()->get_scope(), nexus); // If we're mapping an output of this entity to an output of // the child entity, then VHDL will not let us read the value // of the signal (i.e. it must pass straight through). // However, Verilog allows the signal to be read in the parent. // The solution used here is to create an intermediate signal // and connect it to both ports. vhdl_decl* from_decl = parent->get_arch()->get_scope()->get_decl(ref->get_name()); if (!from_decl->is_readable() && !arch_scope->have_declared(name + "_Readable")) { vhdl_decl* tmp_decl = new vhdl_signal_decl(name + "_Readable", ref->get_type()); // Add a comment to explain what this is for tmp_decl->set_comment("Needed to connect outputs"); arch_scope->add_decl(tmp_decl); parent->get_arch()->add_stmt (new vhdl_cassign_stmt(from_decl->make_ref(), tmp_decl->make_ref())); map_to = tmp_decl->make_ref(); } else map_to = ref; } else if (priv->const_driver && ivl_signal_port(to) == IVL_SIP_INPUT) { map_to = priv->const_driver; priv->const_driver = NULL; } else { // This nexus isn't attached to anything in the parent return; } inst->map_port(name, map_to); } /* * Find all the port mappings of a module instantiation. */ static void port_map(ivl_scope_t scope, vhdl_entity *parent, vhdl_comp_inst *inst) { // Find all the port mappings int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); ivl_signal_port_t mode = ivl_signal_port(sig); switch (mode) { case IVL_SIP_NONE: // Internal signals don't appear in the port map break; case IVL_SIP_INPUT: case IVL_SIP_OUTPUT: case IVL_SIP_INOUT: map_signal(sig, parent, inst); break; default: assert(false); } } } /* * Create a VHDL function from a Verilog function definition. */ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) { assert(ivl_scope_type(scope) == IVL_SCT_FUNCTION); debug_msg("Generating function %s (%s)", ivl_scope_tname(scope), ivl_scope_name(scope)); // Find the containing entity vhdl_entity *ent = find_entity(parent); assert(ent); const char *funcname = ivl_scope_tname(scope); assert(!ent->get_arch()->get_scope()->have_declared(funcname)); // The return type is worked out from the output port vhdl_function *func = new vhdl_function(funcname, NULL); // Set the parent scope of this function to be the containing // architecture. This allows us to look up non-local variables // referenced in the body, but if we do the `impure' flag must // be set on the function // (There are actually two VHDL scopes in a function: the local // variables and the formal parameters hence the call to get_parent) func->get_scope()->get_parent()->set_parent(ent->get_arch()->get_scope()); // First we add the input/output parameters in order int nports = ivl_scope_ports(scope); for (int i = 0; i < nports; i++) { ivl_signal_t sig = ivl_scope_port(scope, i); vhdl_type *sigtype = vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); string signame(make_safe_name(sig)); switch (ivl_signal_port(sig)) { case IVL_SIP_INPUT: func->add_param(new vhdl_param_decl(signame.c_str(), sigtype)); break; case IVL_SIP_OUTPUT: // The magic variable _Result holds the return value signame = funcname; signame += "_Result"; func->set_type(new vhdl_type(*sigtype)); func->get_scope()->add_decl (new vhdl_var_decl(signame, sigtype)); break; default: // Only expecting inputs and outputs assert(false); } remember_signal(sig, func->get_scope()); rename_signal(sig, signame); } int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); if (ivl_signal_port(sig) == IVL_SIP_NONE) { vhdl_type *sigtype = vhdl_type::type_for( ivl_signal_width(sig), ivl_signal_signed(sig) != 0); string signame(make_safe_name(sig)); func->get_scope()->add_decl( new vhdl_var_decl(signame, sigtype)); remember_signal(sig, func->get_scope()); rename_signal(sig, signame); } } // Non-blocking assignment not allowed in functions func->get_scope()->set_allow_signal_assignment(false); set_active_entity(ent); { draw_stmt(func, func->get_container(), ivl_scope_def(scope)); } set_active_entity(NULL); // Add a forward declaration too in case it is called by // another function that has already been added ent->get_arch()->get_scope()->add_forward_decl (new vhdl_forward_fdecl(func)); ostringstream ss; ss << "Generated from function " << funcname << " at " << ivl_scope_def_file(scope) << ":" << ivl_scope_def_lineno(scope); func->set_comment(ss.str().c_str()); ent->get_arch()->get_scope()->add_decl(func); return 0; } /* * Create the signals necessary to expand this task later. */ static int draw_task(ivl_scope_t scope, ivl_scope_t parent) { assert(ivl_scope_type(scope) == IVL_SCT_TASK); // Find the containing entity vhdl_entity *ent = find_entity(parent); assert(ent); const char *taskname = ivl_scope_tname(scope); int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); vhdl_type *sigtype = vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); string signame(make_safe_name(sig)); // Check this signal isn't declared in the outer scope if (ent->get_arch()->get_scope()->have_declared(signame)) { signame += "_"; signame += taskname; } vhdl_signal_decl *decl = new vhdl_signal_decl(signame.c_str(), sigtype); ostringstream ss; ss << "Declared at " << ivl_signal_file(sig) << ":" << ivl_signal_lineno(sig) << " (in task " << taskname << ")"; decl->set_comment(ss.str().c_str()); ent->get_arch()->get_scope()->add_decl(decl); remember_signal(sig, ent->get_arch()->get_scope()); rename_signal(sig, signame); } return 0; } /* * Create an empty VHDL entity for a Verilog module. */ static void create_skeleton_entity_for(ivl_scope_t scope, int depth) { assert(ivl_scope_type(scope) == IVL_SCT_MODULE); // The type name will become the entity name const string tname = valid_entity_name(ivl_scope_tname(scope)); // Verilog does not have the entity/architecture distinction // so we always create a pair and associate the architecture // with the entity for convenience (this also means that we // retain a 1-to-1 mapping of scope to VHDL element) vhdl_arch *arch = new vhdl_arch(tname, "FromVerilog"); vhdl_entity *ent = new vhdl_entity(tname, arch, depth); // Calculate the VHDL units to use for time values ent->set_time_units(ivl_scope_time_units(scope), ivl_scope_time_precision(scope)); // Build a comment to add to the entity/architecture ostringstream ss; ss << "Generated from Verilog module " << ivl_scope_tname(scope) << " (" << ivl_scope_def_file(scope) << ":" << ivl_scope_def_lineno(scope) << ")"; arch->set_comment(ss.str()); ent->set_comment(ss.str()); remember_entity(ent, scope); } /* * A first pass through the hierarchy: create VHDL entities for * each unique Verilog module type. */ extern "C" int draw_skeleton_scope(ivl_scope_t scope, void *_unused) { static int depth = 0; if (seen_this_scope_type(scope)) return 0; // Already generated a skeleton for this scope type debug_msg("Initial visit to scope type %s at depth %d", ivl_scope_tname(scope), depth); switch (ivl_scope_type(scope)) { case IVL_SCT_MODULE: create_skeleton_entity_for(scope, depth); break; case IVL_SCT_FORK: error("No translation for fork statements yet"); return 1; default: // The other scope types are expanded later on break; } ++depth; int rc = ivl_scope_children(scope, draw_skeleton_scope, NULL); --depth; return rc; } extern "C" int draw_all_signals(ivl_scope_t scope, void *_parent) { if (!is_default_scope_instance(scope)) return 0; // Not interested in this instance if (ivl_scope_type(scope) == IVL_SCT_MODULE) { vhdl_entity *ent = find_entity(scope); assert(ent); declare_signals(ent, scope); } else if (ivl_scope_type(scope) == IVL_SCT_GENERATE) { // Because generate scopes don't appear in the // output VHDL all their signals are added to the // containing entity (after being uniqued) ivl_scope_t parent = ivl_scope_parent(scope); while (ivl_scope_type(parent) == IVL_SCT_GENERATE) parent = ivl_scope_parent(scope); vhdl_entity* ent = find_entity(parent); assert(ent); declare_signals(ent, scope); } return ivl_scope_children(scope, draw_all_signals, scope); } /* * Draw all tasks and functions in the hierarchy. */ extern "C" int draw_functions(ivl_scope_t scope, void *_parent) { if (!is_default_scope_instance(scope)) return 0; // Not interested in this instance ivl_scope_t parent = static_cast(_parent); if (ivl_scope_type(scope) == IVL_SCT_FUNCTION) { if (draw_function(scope, parent) != 0) return 1; } else if (ivl_scope_type(scope) == IVL_SCT_TASK) { if (draw_task(scope, parent) != 0) return 1; } return ivl_scope_children(scope, draw_functions, scope); } /* * Make concurrent assignments for constants in nets. This works * bottom-up so that the driver is in the lowest instance it can. * This also has the side effect of generating all the necessary * nexus code. */ extern "C" int draw_constant_drivers(ivl_scope_t scope, void *_parent) { if (!is_default_scope_instance(scope)) return 0; // Not interested in this instance ivl_scope_children(scope, draw_constant_drivers, scope); if (ivl_scope_type(scope) == IVL_SCT_MODULE) { vhdl_entity *ent = find_entity(scope); assert(ent); int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); for (unsigned j = ivl_signal_array_base(sig); j < ivl_signal_array_count(sig); j++) { // Make sure the nexus code is generated ivl_nexus_t nex = ivl_signal_nex(sig, j); if (!nex) continue; // skip virtual pins seen_nexus(nex); nexus_private_t *priv = static_cast(ivl_nexus_get_private(nex)); assert(priv); vhdl_scope *arch_scope = ent->get_arch()->get_scope(); if (priv->const_driver && ivl_signal_port(sig) != IVL_SIP_INPUT) { // Don't drive inputs assert(j == 0); // TODO: Make work for more words vhdl_var_ref *ref = nexus_to_var_ref(arch_scope, nex); ent->get_arch()->add_stmt (new vhdl_cassign_stmt(ref, priv->const_driver)); priv->const_driver = NULL; } // Connect up any signals which are wired together in the // same nexus scope_nexus_t *sn = visible_nexus(priv, arch_scope); // Make sure we don't drive inputs if (ivl_signal_port(sn->sig) != IVL_SIP_INPUT) { for (list::const_iterator it = sn->connect.begin(); it != sn->connect.end(); ++it) { vhdl_type* rtype = vhdl_type::type_for(ivl_signal_width(sn->sig), ivl_signal_signed(sn->sig)); vhdl_type* ltype = vhdl_type::type_for(ivl_signal_width(*it), ivl_signal_signed(*it)); vhdl_var_ref *rref = new vhdl_var_ref(get_renamed_signal(sn->sig).c_str(), rtype); vhdl_var_ref *lref = new vhdl_var_ref(get_renamed_signal(*it).c_str(), ltype); // Make sure the LHS and RHS have the same type vhdl_expr* rhs = rref->cast(lref->get_type()); ent->get_arch()->add_stmt(new vhdl_cassign_stmt(lref, rhs)); } } sn->connect.clear(); } } } return 0; } extern "C" int draw_all_logic_and_lpm(ivl_scope_t scope, void *_parent) { if (!is_default_scope_instance(scope)) return 0; // Not interested in this instance if (ivl_scope_type(scope) == IVL_SCT_MODULE) { vhdl_entity *ent = find_entity(scope); assert(ent); set_active_entity(ent); { declare_logic(ent->get_arch(), scope); declare_lpm(ent->get_arch(), scope); } set_active_entity(NULL); } return ivl_scope_children(scope, draw_all_logic_and_lpm, scope); } extern "C" int draw_hierarchy(ivl_scope_t scope, void *_parent) { if (ivl_scope_type(scope) == IVL_SCT_MODULE && _parent) { ivl_scope_t parent = static_cast(_parent); // Skip over any containing generate scopes while (ivl_scope_type(parent) == IVL_SCT_GENERATE) parent = ivl_scope_parent(parent); if (!is_default_scope_instance(parent)) return 0; // Not generating code for the parent instance so // don't generate for the child vhdl_entity *ent = find_entity(scope); assert(ent); vhdl_entity *parent_ent = find_entity(parent); assert(parent_ent); vhdl_arch *parent_arch = parent_ent->get_arch(); assert(parent_arch != NULL); // Create a forward declaration for it vhdl_scope *parent_scope = parent_arch->get_scope(); if (!parent_scope->have_declared(ent->get_name())) { vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); parent_arch->get_scope()->add_decl(comp_decl); } // And an instantiation statement string inst_name(ivl_scope_basename(scope)); inst_name += genvar_unique_suffix(ivl_scope_parent(scope)); if (inst_name == ent->get_name() || parent_scope->have_declared(inst_name)) { // Cannot have instance name the same as type in VHDL inst_name += "_Inst"; } // Need to replace any [ and ] characters that result // from generate statements string::size_type loc = inst_name.find('[', 0); if (loc != string::npos) inst_name.erase(loc, 1); loc = inst_name.find(']', 0); if (loc != string::npos) inst_name.erase(loc, 1); // No leading or trailing underscores if (inst_name[0] == '_') inst_name = "Inst" + inst_name; if (*inst_name.rbegin() == '_') inst_name += "Inst"; // Can't have two consecutive underscores replace_consecutive_underscores(inst_name); // Make sure the name doesn't collide with anything we've // already declared avoid_name_collision(inst_name, parent_arch->get_scope()); vhdl_comp_inst *inst = new vhdl_comp_inst(inst_name.c_str(), ent->get_name().c_str()); port_map(scope, parent_ent, inst); ostringstream ss; ss << "Generated from instantiation at " << ivl_scope_file(scope) << ":" << ivl_scope_lineno(scope); inst->set_comment(ss.str().c_str()); parent_arch->add_stmt(inst); } return ivl_scope_children(scope, draw_hierarchy, scope); } int draw_scope(ivl_scope_t scope, void *_parent) { int rc = draw_skeleton_scope(scope, _parent); if (rc != 0) return rc; rc = draw_all_signals(scope, _parent); if (rc != 0) return rc; rc = draw_all_logic_and_lpm(scope, _parent); if (rc != 0) return rc; rc = draw_hierarchy(scope, _parent); if (rc != 0) return rc; rc = draw_functions(scope, _parent); if (rc != 0) return rc; rc = draw_constant_drivers(scope, _parent); if (rc != 0) return rc; return 0; } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl_type.hh0000644000202500001440000000005012204466647020300 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl_type.hh0000644000202500001440000000560312204466647017626 0ustar00steveusers00000000000000/* * VHDL variable and signal types. * * Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef INC_VHDL_TYPE_HH #define INC_VHDL_TYPE_HH #include "vhdl_element.hh" enum vhdl_type_name_t { VHDL_TYPE_STD_LOGIC, VHDL_TYPE_STD_LOGIC_VECTOR, VHDL_TYPE_STRING, VHDL_TYPE_LINE, VHDL_TYPE_FILE, VHDL_TYPE_INTEGER, VHDL_TYPE_BOOLEAN, VHDL_TYPE_SIGNED, VHDL_TYPE_UNSIGNED, VHDL_TYPE_TIME, VHDL_TYPE_ARRAY }; /* * A type at the moment is just a name. It shouldn't get * too much more complex, as Verilog's type system is much * simpler than VHDL's. */ class vhdl_type : public vhdl_element { public: // Scalar constructor vhdl_type(vhdl_type_name_t name, int msb = 0, int lsb = 0) : name_(name), msb_(msb), lsb_(lsb), base_(NULL) {} // Array constructor vhdl_type(vhdl_type *base, const std::string &array_name, int msb, int lsb) : name_(VHDL_TYPE_ARRAY), msb_(msb), lsb_(lsb), base_(base), array_name_(array_name) {} // Copy constructor vhdl_type(const vhdl_type &other); virtual ~vhdl_type(); void emit(std::ostream &of, int level) const; vhdl_type_name_t get_name() const { return name_; } std::string get_string() const; std::string get_decl_string() const; std::string get_type_decl_string() const; vhdl_type *get_base() const; int get_width() const { return msb_ - lsb_ + 1; } int get_msb() const { return msb_; } int get_lsb() const { return lsb_; } // Common types static vhdl_type *std_logic(); static vhdl_type *string(); static vhdl_type *line(); static vhdl_type *std_logic_vector(int msb, int lsb); static vhdl_type *nunsigned(int width, int lsb=0); static vhdl_type *nsigned(int width, int lsb=0); static vhdl_type *integer(); static vhdl_type *boolean(); static vhdl_type *time(); static vhdl_type *type_for(int width, bool issigned, int lsb=0); static vhdl_type *array_of(vhdl_type *b, std::string &n, int m, int l); protected: vhdl_type_name_t name_; int msb_, lsb_; vhdl_type *base_; // Array base type for VHDL_TYPE_ARRAY std::string array_name_; // Type name for the array `type array_name_ is ...' }; #endif verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/state.hh0000644000202500001440000000005012204466647017422 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/state.hh0000644000202500001440000000366312204466647016754 0ustar00steveusers00000000000000/* * Managing global state for the VHDL code generator. * * Copyright (C) 2009 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef INC_VHDL_STATE_HH #define INC_VHDL_STATE_HH #include "ivl_target.h" #include #include class vhdl_scope; class vhdl_entity; // Mapping of Verilog to VHDL signals bool seen_signal_before(ivl_signal_t sig); void remember_signal(ivl_signal_t sig, vhdl_scope *scope); void rename_signal(ivl_signal_t sig, const std::string &renamed); vhdl_scope *find_scope_for_signal(ivl_signal_t sig); const std::string &get_renamed_signal(ivl_signal_t sig); ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope); // Manage the set of VHDL entities void remember_entity(vhdl_entity *ent, ivl_scope_t scope); vhdl_entity* find_entity(ivl_scope_t scope); vhdl_entity* find_entity(const std::string& name); void emit_all_entities(std::ostream& os, int max_depth); void free_all_vhdl_objects(); // Get and set the active entity vhdl_entity *get_active_entity(); void set_active_entity(vhdl_entity *ent); // Manage mapping of scopes to a single VHDL entity bool is_default_scope_instance(ivl_scope_t s); bool seen_this_scope_type(ivl_scope_t s); #endif // #ifndef INC_VHDL_STATE_HH verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl_element.hh0000644000202500001440000000005012204466647020750 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl_element.hh0000644000202500001440000000501212204466647020270 0ustar00steveusers00000000000000/* * VHDL abstract syntax elements. * * Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef INC_VHDL_ELEMENT_HH #define INC_VHDL_ELEMENT_HH #include #include #include #include #include typedef std::list string_list_t; // Any VHDL syntax element. Each element can also contain a comment. // // Memory management is handled specially for vhdl_element subclasses: // The vast majority of vhdl_elements will be created during code generation // and persist until after they have been printed, at which point *all* // vhdl_element objects should be destroyed. To support this all allocations // of vhdl_element subclasses call a special operator new which records // the pointer allocated so we can ensure that it is disposed of when // the code generator completes -- by free_all_objects. // // The two big advantages of this are that we don't have to worry about // memory leaks of vhdl_element objects, and we can freely share pointers // between different parts of the AST. class vhdl_element { public: virtual ~vhdl_element() {} void* operator new(size_t size) throw (std::bad_alloc); void operator delete(void* ptr); virtual void emit(std::ostream &of, int level=0) const = 0; void print() const; void set_comment(std::string comment); static int free_all_objects(); static size_t total_allocated(); protected: void emit_comment(std::ostream &of, int level, bool end_of_line=false) const; private: std::string comment_; static std::vector allocated_; static size_t total_alloc_; }; typedef std::list element_list_t; int indent(int level); void newline(std::ostream &of, int level); std::string nl_string(int level); void blank_line(std::ostream &of, int level); #endif verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl_target.h0000644000202500001440000000005012204466647020435 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl_target.h0000644000202500001440000000223712204466647017763 0ustar00steveusers00000000000000#ifndef INC_VHDL_TARGET_H #define INC_VHDL_TARGET_H #include "vhdl_config.h" #include "ivl_target.h" #include "support.hh" #include "vhdl_syntax.hh" #include using namespace std; void error(const char *fmt, ...); void debug_msg(const char *fmt, ...); int draw_scope(ivl_scope_t scope, void *_parent); extern "C" int draw_process(ivl_process_t net, void *cd); int draw_stmt(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool is_last = false); int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm); void draw_logic(vhdl_arch *arch, ivl_net_logic_t log); vhdl_expr *translate_expr(ivl_expr_t e); vhdl_expr *translate_time_expr(ivl_expr_t e); ivl_design_t get_vhdl_design(); vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus); vhdl_var_ref* readable_ref(vhdl_scope* scope, ivl_nexus_t nex); string make_safe_name(ivl_signal_t sig); int draw_stask_display(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool newline = true); void prune_wait_for_0(stmt_container *container); void require_support_function(support_function_t f); #endif /* #ifndef INC_VHDL_TARGET_H */ verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl.conf0000644000202500001440000000005012204466647017565 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl.conf0000644000202500001440000000006112204466647017104 0ustar00steveusers00000000000000functor:cprop functor:nodangle flag:DLL=vhdl.tgt verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/vhdl.cc0000644000202500001440000000005012204466647017225 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/vhdl.cc0000644000202500001440000001020512204466647016545 0ustar00steveusers00000000000000/* * VHDL code generator for Icarus Verilog. * * Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "version_base.h" #include "version_tag.h" #include "vhdl_target.h" #include "state.hh" #include #include #include #include #include #include #include static const char*version_string = "Icarus Verilog VHDL Code Generator " VERSION " (" VERSION_TAG ")\n\n" "Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)\n\n" " This program is free software; you can redistribute it and/or modify\n" " it under the terms of the GNU General Public License as published by\n" " the Free Software Foundation; either version 2 of the License, or\n" " (at your option) any later version.\n" "\n" " This program is distributed in the hope that it will be useful,\n" " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" " GNU General Public License for more details.\n" "\n" " You should have received a copy of the GNU General Public License along\n" " with this program; if not, write to the Free Software Foundation, Inc.,\n" " 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n" ; static int g_errors = 0; // Total number of errors encountered static ivl_design_t g_design; /* * Called when an unrecoverable problem is encountered. */ void error(const char *fmt, ...) { std::va_list args; va_start(args, fmt); std::printf("VHDL conversion error: "); // Source/line number? std::vprintf(fmt, args); std::putchar('\n'); va_end(args); g_errors++; } /* * Print a message only if -pdebug was specified. */ void debug_msg(const char *fmt, ...) { std::va_list args; va_start(args, fmt); if (std::strcmp(ivl_design_flag(g_design, "debug"), "")) { std::fputs("[DEBUG] ", stdout); std::vprintf(fmt, args); std::putchar('\n'); } va_end(args); } ivl_design_t get_vhdl_design() { return g_design; } extern "C" int target_design(ivl_design_t des) { ivl_scope_t *roots; unsigned int nroots; ivl_design_roots(des, &roots, &nroots); g_design = des; for (unsigned int i = 0; i < nroots; i++) draw_scope(roots[i], NULL); // Only generate processes if there were no errors generating entities // (otherwise the necessary information won't be present) if (0 == g_errors) ivl_design_process(des, draw_process, NULL); // Write the generated elements to the output file // only if there were no errors generating entities or processes if (0 == g_errors) { const char *ofname = ivl_design_flag(des, "-o"); ofstream outfile(ofname); outfile << "-- This VHDL was converted from Verilog using the" << endl << "-- Icarus Verilog VHDL Code Generator " VERSION " (" VERSION_TAG ")" << endl << endl; // If the user passed -pdepth=N then only emit entities with // depth < N // I.e. -pdepth=1 emits only the top-level entity // If max_depth is zero then all entities will be emitted // (This is handy since it means we can use atoi ;-) int max_depth = std::atoi(ivl_design_flag(des, "depth")); emit_all_entities(outfile, max_depth); } // Clean up free_all_vhdl_objects(); return g_errors; } extern "C" const char* target_query(const char*key) { if (strcmp(key, "version") == 0) return version_string; return 0; } verilog-0.9.7/tgt-vhdl/PaxHeaders.14238/cast.cc0000644000202500001440000000005012204466647017222 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-vhdl/cast.cc0000644000202500001440000002124012204466647016543 0ustar00steveusers00000000000000/* * Generate code to convert between VHDL types. * * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk) * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "vhdl_syntax.hh" #include "vhdl_target.h" #include "support.hh" #include #include vhdl_expr *vhdl_expr::cast(const vhdl_type *to) { //std::cout << "Cast: from=" << type_->get_string() // << " (" << type_->get_width() << ") " // << " to=" << to->get_string() << " (" // << to->get_width() << ")" << std::endl; // If this expression hasn't been given a type then // we can't generate any type conversion code if (NULL == type_) return this; if (to->get_name() == type_->get_name()) { if (to->get_width() == type_->get_width()) return this; // Identical else return resize(to->get_width()); } else { switch (to->get_name()) { case VHDL_TYPE_BOOLEAN: return to_boolean(); case VHDL_TYPE_INTEGER: return to_integer(); case VHDL_TYPE_UNSIGNED: case VHDL_TYPE_SIGNED: case VHDL_TYPE_STD_LOGIC_VECTOR: return to_vector(to->get_name(), to->get_width()); case VHDL_TYPE_STD_LOGIC: return to_std_logic(); default: assert(false); } } assert(false); return NULL; } /* * Generate code to cast an expression to a vector type (std_logic_vector, * signed, unsigned). */ vhdl_expr *vhdl_expr::to_vector(vhdl_type_name_t name, int w) { if (type_->get_name() == VHDL_TYPE_STD_LOGIC) { vhdl_expr *others = w == 1 ? NULL : new vhdl_const_bit('0'); vhdl_bit_spec_expr *bs = new vhdl_bit_spec_expr(new vhdl_type(name, w - 1, 0), others); bs->add_bit(0, this); return bs; } else { // We have to cast the expression before resizing or the // wrong sign bit may be extended (i.e. when casting between // signed/unsigned *and* resizing) vhdl_type *t = new vhdl_type(name, w - 1, 0); vhdl_fcall *conv = new vhdl_fcall(t->get_string().c_str(), t); conv->add_expr(this); if (w != type_->get_width()) return conv->resize(w); else return conv; } } /* * Convert a generic expression to an Integer. */ vhdl_expr *vhdl_expr::to_integer() { vhdl_fcall *conv; if (type_->get_name() == VHDL_TYPE_STD_LOGIC) { require_support_function(SF_LOGIC_TO_INTEGER); conv = new vhdl_fcall(support_function::function_name(SF_LOGIC_TO_INTEGER), vhdl_type::integer()); } else conv = new vhdl_fcall("To_Integer", vhdl_type::integer()); conv->add_expr(this); return conv; } /* * Convert a generic expression to a Boolean. */ vhdl_expr *vhdl_expr::to_boolean() { if (type_->get_name() == VHDL_TYPE_STD_LOGIC) { // '1' is true all else are false vhdl_const_bit *one = new vhdl_const_bit('1'); return new vhdl_binop_expr (this, VHDL_BINOP_EQ, one, vhdl_type::boolean()); } else if (type_->get_name() == VHDL_TYPE_UNSIGNED) { // Need to use a support function for this conversion require_support_function(SF_UNSIGNED_TO_BOOLEAN); vhdl_fcall *conv = new vhdl_fcall(support_function::function_name(SF_UNSIGNED_TO_BOOLEAN), vhdl_type::boolean()); conv->add_expr(this); return conv; } else if (type_->get_name() == VHDL_TYPE_SIGNED) { require_support_function(SF_SIGNED_TO_BOOLEAN); vhdl_fcall *conv = new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_BOOLEAN), vhdl_type::boolean()); conv->add_expr(this); return conv; } assert(false); return NULL; } /* * Generate code to convert and expression to std_logic. */ vhdl_expr *vhdl_expr::to_std_logic() { if (type_->get_name() == VHDL_TYPE_BOOLEAN) { require_support_function(SF_BOOLEAN_TO_LOGIC); vhdl_fcall *ah = new vhdl_fcall(support_function::function_name(SF_BOOLEAN_TO_LOGIC), vhdl_type::std_logic()); ah->add_expr(this); return ah; } else if (type_->get_name() == VHDL_TYPE_SIGNED) { require_support_function(SF_SIGNED_TO_LOGIC); vhdl_fcall *ah = new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_LOGIC), vhdl_type::std_logic()); ah->add_expr(this); return ah; } else if (type_->get_name() == VHDL_TYPE_UNSIGNED) { require_support_function(SF_UNSIGNED_TO_LOGIC); vhdl_fcall *ah = new vhdl_fcall(support_function::function_name(SF_UNSIGNED_TO_LOGIC), vhdl_type::std_logic()); ah->add_expr(this); return ah; } assert(false); return NULL; } /* * Change the width of a signed/unsigned type. */ vhdl_expr *vhdl_expr::resize(int newwidth) { vhdl_type *rtype; assert(type_); if (type_->get_name() == VHDL_TYPE_SIGNED) rtype = vhdl_type::nsigned(newwidth); else if (type_->get_name() == VHDL_TYPE_UNSIGNED) rtype = vhdl_type::nunsigned(newwidth); else if (type_->get_name() == VHDL_TYPE_STD_LOGIC) { // Pad it with zeros vhdl_expr* zeros = new vhdl_const_bits(string(newwidth - 1, '0').c_str(), newwidth - 1, false, true); vhdl_binop_expr* concat = new vhdl_binop_expr(zeros, VHDL_BINOP_CONCAT, this, vhdl_type::nunsigned(newwidth)); return concat; } else return this; // Doesn't make sense to resize non-vector type vhdl_fcall *resizef = new vhdl_fcall("Resize", rtype); resizef->add_expr(this); resizef->add_expr(new vhdl_const_int(newwidth)); return resizef; } vhdl_expr *vhdl_const_int::to_vector(vhdl_type_name_t name, int w) { if (name == VHDL_TYPE_SIGNED || name == VHDL_TYPE_UNSIGNED) { const char *fname = name == VHDL_TYPE_SIGNED ? "To_Signed" : "To_Unsigned"; vhdl_fcall *conv = new vhdl_fcall(fname, new vhdl_type(name, w - 1, 0)); conv->add_expr(this); conv->add_expr(new vhdl_const_int(w)); return conv; } else return vhdl_expr::to_vector(name, w); } int64_t vhdl_const_bits::bits_to_int() const { char msb = value_[value_.size() - 1]; int64_t result = 0, bit; for (int i = sizeof(int64_t)*8 - 1; i >= 0; i--) { if (i > (int)value_.size() - 1) bit = (msb == '1' && signed_) ? 1 : 0; else bit = value_[i] == '1' ? 1 : 0; result = (result << 1) | bit; } return result; } vhdl_expr *vhdl_const_bits::to_std_logic() { // VHDL won't let us cast directly between a vector and // a scalar type // But we don't need to here as we have the bits available // Take the least significant bit char lsb = value_[0]; return new vhdl_const_bit(lsb); } char vhdl_const_bits::sign_bit() const { return signed_ ? value_[value_.length()-1] : '0'; } vhdl_expr *vhdl_const_bits::to_vector(vhdl_type_name_t name, int w) { if (name == VHDL_TYPE_STD_LOGIC_VECTOR) { // Don't need to do anything return this; } else if (name == VHDL_TYPE_SIGNED || name == VHDL_TYPE_UNSIGNED) { // Extend with sign bit value_.resize(w, sign_bit()); return this; } assert(false); return NULL; } vhdl_expr *vhdl_const_bits::to_integer() { return new vhdl_const_int(bits_to_int()); } vhdl_expr *vhdl_const_bits::resize(int w) { // Rather than generating a call to Resize, when can just sign-extend // the bits here. As well as looking better, this avoids any ambiguity // between which of the signed/unsigned versions of Resize to use. value_.resize(w, sign_bit()); return this; } vhdl_expr *vhdl_const_bit::to_integer() { return new vhdl_const_int(bit_ == '1' ? 1 : 0); } vhdl_expr *vhdl_const_bit::to_boolean() { return new vhdl_const_bool(bit_ == '1'); } vhdl_expr *vhdl_const_bit::to_vector(vhdl_type_name_t name, int w) { // Zero-extend this bit to the correct width return (new vhdl_const_bits(&bit_, 1, name == VHDL_TYPE_SIGNED))->resize(w); } verilog-0.9.7/PaxHeaders.14238/pform.cc0000644000202500001440000000005012204466647015662 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/pform.cc0000644000202500001440000017403312204466647015214 0ustar00steveusers00000000000000/* * Copyright (c) 1998-2012 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "compiler.h" # include "pform.h" # include "parse_misc.h" # include "parse_api.h" # include "PEvent.h" # include "PUdp.h" # include "PGenerate.h" # include "PSpec.h" # include "discipline.h" # include # include # include # include # include # include # include # include # include "ivl_assert.h" map pform_modules; map pform_primitives; /* * The lexor accesses the vl_* variables. */ string vl_file = ""; extern int VLparse(); /* This tracks the current module being processed. There can only be exactly one module currently being parsed, since Verilog does not allow nested module definitions. */ static Module*pform_cur_module = 0; bool pform_library_flag = false; /* increment this for generate schemes within a module, and set it to zero when a new module starts. */ static unsigned scope_generate_counter = 1; /* This tracks the current generate scheme being processed. This is always within a module. */ static PGenerate*pform_cur_generate = 0; static NetNet::Type pform_default_nettype = NetNet::WIRE; /* * These variables track the current time scale, as well as where the * timescale was set. This supports warnings about tangled timescales. */ static int pform_time_unit; static int pform_time_prec; static char*pform_timescale_file = 0; static unsigned pform_timescale_line; static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno) { obj->set_lineno(lineno); obj->set_file(filename_strings.make(file)); } /* * The lexical_scope keeps track of the current lexical scope that is * being parsed. The lexical scope may stack, so the current scope may * have a parent, that is restored when the current scope ends. * * Items that have scoped names are put in the lexical_scope object. */ static PScope* lexical_scope = 0; void pform_pop_scope() { if (pform_cur_generate) { assert(pform_cur_generate->lexical_scope); PScope*cur = pform_cur_generate->lexical_scope; pform_cur_generate->lexical_scope = cur->pscope_parent(); } else { assert(lexical_scope); lexical_scope = lexical_scope->pscope_parent(); } } PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) { perm_string task_name = lex_strings.make(name); PTask*task; if (pform_cur_generate) { task = new PTask(task_name, pform_cur_generate->lexical_scope, is_auto); FILE_NAME(task, loc); // Check if the task is already in the dictionary. if (pform_cur_generate->tasks.find(task->pscope_name()) != pform_cur_generate->tasks.end()) { cerr << task->get_fileline() << ": error: duplicate " "definition for task '" << name << "' in '" << pform_cur_module->mod_name() << "' (generate)." << endl; error_count += 1; } pform_cur_generate->tasks[task->pscope_name()] = task; pform_cur_generate->lexical_scope = task; } else { task = new PTask(task_name, lexical_scope, is_auto); FILE_NAME(task, loc); // Check if the task is already in the dictionary. if (pform_cur_module->tasks.find(task->pscope_name()) != pform_cur_module->tasks.end()) { cerr << task->get_fileline() << ": error: duplicate " "definition for task '" << name << "' in '" << pform_cur_module->mod_name() << "'." << endl; error_count += 1; } pform_cur_module->tasks[task->pscope_name()] = task; lexical_scope = task; } return task; } PFunction* pform_push_function_scope(const struct vlltype&loc, char*name, bool is_auto) { perm_string func_name = lex_strings.make(name); PFunction*func; if (pform_cur_generate) { func = new PFunction(func_name, pform_cur_generate->lexical_scope, is_auto); FILE_NAME(func, loc); // Check if the function is already in the dictionary. if (pform_cur_generate->funcs.find(func->pscope_name()) != pform_cur_generate->funcs.end()) { cerr << func->get_fileline() << ": error: duplicate " "definition for function '" << name << "' in '" << pform_cur_module->mod_name() << "' (generate)." << endl; error_count += 1; } pform_cur_generate->funcs[func->pscope_name()] = func; pform_cur_generate->lexical_scope = func; } else { func = new PFunction(func_name, lexical_scope, is_auto); FILE_NAME(func, loc); // Check if the function is already in the dictionary. if (pform_cur_module->funcs.find(func->pscope_name()) != pform_cur_module->funcs.end()) { cerr << func->get_fileline() << ": error: duplicate " "definition for function '" << name << "' in '" << pform_cur_module->mod_name() << "'." << endl; error_count += 1; } pform_cur_module->funcs[func->pscope_name()] = func; lexical_scope = func; } return func; } PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt) { perm_string block_name = lex_strings.make(name); PBlock*block; if (pform_cur_generate) { block = new PBlock(block_name, pform_cur_generate->lexical_scope, bt); pform_cur_generate->lexical_scope = block; } else { block = new PBlock(block_name, lexical_scope, bt); lexical_scope = block; } return block; } void pform_bind_attributes(map&attributes, svector*attr) { if (attr == 0) return; for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { named_pexpr_t*tmp = (*attr)[idx]; attributes[tmp->name] = tmp->parm; } delete attr; } static LexicalScope*pform_get_cur_scope() { if (pform_cur_generate) if (pform_cur_generate->lexical_scope) return pform_cur_generate->lexical_scope; else return pform_cur_generate; else return lexical_scope; } static bool pform_at_module_level() { if (pform_cur_generate) if (pform_cur_generate->lexical_scope) return false; else return true; else if (lexical_scope->pscope_parent()) return false; else return true; } PWire*pform_get_wire_in_scope(perm_string name) { /* Note that if we are processing a generate, then the scope depth will be empty because generate schemes cannot be within sub-scopes. Only directly in modules. */ return pform_get_cur_scope()->wires_find(name); } static void pform_put_wire_in_scope(perm_string name, PWire*net) { pform_get_cur_scope()->wires[name] = net; } static void pform_put_behavior_in_scope(PProcess*pp) { pform_get_cur_scope()->behaviors.push_back(pp); } void pform_put_behavior_in_scope(AProcess*pp) { pform_get_cur_scope()->analog_behaviors.push_back(pp); } void pform_set_default_nettype(NetNet::Type type, const char*file, unsigned lineno) { pform_default_nettype = type; if (pform_cur_module) { cerr << file<<":"<mod_name() << " starts on line " << pform_cur_module->get_fileline() << "." << endl; error_count += 1; } } /* * The lexor calls this function to set the active timescale when it * detects a `timescale directive. The function saves the directive * values (for use by modules) and if warnings are enabled checks to * see if some modules have no timescale. */ void pform_set_timescale(int unit, int prec, const char*file, unsigned lineno) { bool first_flag = true; assert(unit >= prec); pform_time_unit = unit; pform_time_prec = prec; if (pform_timescale_file) { free(pform_timescale_file); first_flag = false; } if (file) pform_timescale_file = strdup(file); else pform_timescale_file = 0; pform_timescale_line = lineno; if (!warn_timescale || !first_flag || !file) return; /* Look to see if we have any modules without a timescale. */ bool have_no_ts = false; map::iterator mod; for (mod = pform_modules.begin(); mod != pform_modules.end(); mod++) { const Module*mp = (*mod).second; if (mp->time_from_timescale || mp->timescale_warn_done) continue; have_no_ts = true; break; } /* If we do then print a message for the new ones. */ if (have_no_ts) { cerr << file << ":" << lineno << ": warning: " << "Some modules have no timescale. This may cause" << endl; cerr << file << ":" << lineno << ": : " << "confusing timing results. Affected modules are:" << endl; for (mod = pform_modules.begin() ; mod != pform_modules.end() ; mod++) { Module*mp = (*mod).second; if (mp->time_from_timescale || mp->timescale_warn_done) continue; mp->timescale_warn_done = true; cerr << file << ":" << lineno << ": : " << " -- module " << (*mod).first << " declared here: " << mp->get_fileline() << endl; } } } verinum* pform_verinum_with_size(verinum*siz, verinum*val, const char*file, unsigned lineno) { assert(siz->is_defined()); unsigned long size = siz->as_ulong(); verinum::V pad; switch (val->get(val->len()-1)) { case verinum::Vz: pad = verinum::Vz; break; case verinum::Vx: pad = verinum::Vx; break; default: pad = verinum::V0; break; } verinum*res = new verinum(pad, size, true); unsigned copy = val->len(); if (res->len() < copy) copy = res->len(); for (unsigned idx = 0 ; idx < copy ; idx += 1) { res->set(idx, val->get(idx)); } res->has_sign(val->has_sign()); bool trunc_flag = false; for (unsigned idx = copy ; idx < val->len() ; idx += 1) { if (val->get(idx) != pad) { trunc_flag = true; break; } } if (trunc_flag) { cerr << file << ":" << lineno << ": warning: Numeric constant " << "truncated to " << copy << " bits." << endl; } delete siz; delete val; return res; } void pform_startmodule(const char*name, const char*file, unsigned lineno, svector*attr) { assert( pform_cur_module == 0 ); perm_string lex_name = lex_strings.make(name); pform_cur_module = new Module(lex_name); pform_cur_module->time_unit = pform_time_unit; pform_cur_module->time_precision = pform_time_prec; /* If we have a timescale file then the time information is from * a timescale directive. */ pform_cur_module->time_from_timescale = pform_timescale_file != 0; pform_cur_module->default_nettype = pform_default_nettype; FILE_NAME(pform_cur_module, file, lineno); pform_cur_module->library_flag = pform_library_flag; ivl_assert(*pform_cur_module, lexical_scope == 0); lexical_scope = pform_cur_module; /* The generate scheme numbering starts with *1*, not zero. That's just the way it is, thanks to the standard. */ scope_generate_counter = 1; if (warn_timescale && pform_timescale_file && (strcmp(pform_timescale_file,file) != 0)) { cerr << pform_cur_module->get_fileline() << ": warning: " << "timescale for " << name << " inherited from another file." << endl; cerr << pform_timescale_file << ":" << pform_timescale_line << ": ...: The inherited timescale is here." << endl; } if (attr) { for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { named_pexpr_t*tmp = (*attr)[idx]; pform_cur_module->attributes[tmp->name] = tmp->parm; } } } /* * This function is called by the parser to make a simple port * reference. This is a name without a .X(...), so the internal name * should be generated to be the same as the X. */ Module::port_t* pform_module_port_reference(perm_string name, const char*file, unsigned lineno) { Module::port_t*ptmp = new Module::port_t; PEIdent*tmp = new PEIdent(name); FILE_NAME(tmp, file, lineno); ptmp->name = name; ptmp->expr.push_back(tmp); return ptmp; } void pform_module_set_ports(vector*ports) { assert(pform_cur_module); /* The parser parses ``module foo()'' as having one unconnected port, but it is really a module with no ports. Fix it up here. */ if (ports && (ports->size() == 1) && ((*ports)[0] == 0)) { delete ports; ports = 0; } if (ports != 0) { pform_cur_module->ports = *ports; delete ports; } } void pform_endmodule(const char*name, bool inside_celldefine, Module::UCDriveType uc_drive_def) { assert(pform_cur_module); perm_string mod_name = pform_cur_module->mod_name(); assert(strcmp(name, mod_name) == 0); pform_cur_module->is_cell = inside_celldefine; pform_cur_module->uc_drive = uc_drive_def; map::const_iterator test = pform_modules.find(mod_name); if (test != pform_modules.end()) { ostringstream msg; msg << "Module " << name << " was already declared here: " << (*test).second->get_fileline() << endl; VLerror(msg.str().c_str()); } else { pform_modules[mod_name] = pform_cur_module; } // The current lexical scope should be this module by now, and // this module should not have a parent lexical scope. ivl_assert(*pform_cur_module, lexical_scope == pform_cur_module); lexical_scope = pform_cur_module->pscope_parent(); ivl_assert(*pform_cur_module, lexical_scope == 0); pform_cur_module = 0; } static void pform_add_genvar(const struct vlltype&li, const perm_string&name, map&genvars) { LineInfo*lni = new LineInfo(); FILE_NAME(lni, li); if (genvars.find(name) != genvars.end()) { cerr << lni->get_fileline() << ": error: genvar '" << name << "' has already been declared." << endl; cerr << genvars[name]->get_fileline() << ": the previous declaration is here." << endl; error_count += 1; delete lni; } else { genvars[name] = lni; } } void pform_genvars(const struct vlltype&li, list*names) { list::const_iterator cur; for (cur = names->begin(); cur != names->end() ; *cur++) { if (pform_cur_generate) pform_add_genvar(li, *cur, pform_cur_generate->genvars); else pform_add_genvar(li, *cur, pform_cur_module->genvars); } delete names; } void pform_start_generate_for(const struct vlltype&li, char*ident1, PExpr*init, PExpr*test, char*ident2, PExpr*next) { PGenerate*gen = new PGenerate(scope_generate_counter++); FILE_NAME(gen, li); gen->parent = pform_cur_generate; pform_cur_generate = gen; pform_cur_generate->scheme_type = PGenerate::GS_LOOP; pform_cur_generate->loop_index = lex_strings.make(ident1); pform_cur_generate->loop_init = init; pform_cur_generate->loop_test = test; pform_cur_generate->loop_step = next; delete[]ident1; delete[]ident2; } void pform_start_generate_if(const struct vlltype&li, PExpr*test) { PGenerate*gen = new PGenerate(scope_generate_counter++); FILE_NAME(gen, li); gen->parent = pform_cur_generate; pform_cur_generate = gen; pform_cur_generate->scheme_type = PGenerate::GS_CONDIT; pform_cur_generate->loop_init = 0; pform_cur_generate->loop_test = test; pform_cur_generate->loop_step = 0; } void pform_start_generate_else(const struct vlltype&li) { assert(pform_cur_generate); assert(pform_cur_generate->scheme_type == PGenerate::GS_CONDIT); PGenerate*cur = pform_cur_generate; pform_endgenerate(); PGenerate*gen = new PGenerate(scope_generate_counter++); FILE_NAME(gen, li); gen->parent = pform_cur_generate; pform_cur_generate = gen; pform_cur_generate->scheme_type = PGenerate::GS_ELSE; pform_cur_generate->loop_init = 0; pform_cur_generate->loop_test = cur->loop_test; pform_cur_generate->loop_step = 0; } /* * The GS_CASE version of the PGenerate contains only case items. The * items in turn contain the generated items themselves. */ void pform_start_generate_case(const struct vlltype&li, PExpr*expr) { PGenerate*gen = new PGenerate(scope_generate_counter++); FILE_NAME(gen, li); gen->parent = pform_cur_generate; pform_cur_generate = gen; pform_cur_generate->scheme_type = PGenerate::GS_CASE; pform_cur_generate->loop_init = 0; pform_cur_generate->loop_test = expr; pform_cur_generate->loop_step = 0; } /* * The named block generate case. */ void pform_start_generate_nblock(const struct vlltype&li, char*name) { PGenerate*gen = new PGenerate(scope_generate_counter++); FILE_NAME(gen, li); gen->parent = pform_cur_generate; pform_cur_generate = gen; pform_cur_generate->scheme_type = PGenerate::GS_NBLOCK; pform_cur_generate->loop_init = 0; pform_cur_generate->loop_test = 0; pform_cur_generate->loop_step = 0; pform_cur_generate->scope_name = lex_strings.make(name); delete[]name; } /* * The generate case item is a special case schema that takes its id * from the case schema that it is a part of. The idea is that the * case schema can only instantiate exactly one item, so the items * need not have a unique number. */ void pform_generate_case_item(const struct vlltype&li, svector*expr_list) { assert(pform_cur_generate); assert(pform_cur_generate->scheme_type == PGenerate::GS_CASE); PGenerate*gen = new PGenerate(pform_cur_generate->id_number); FILE_NAME(gen, li); gen->parent = pform_cur_generate; pform_cur_generate = gen; pform_cur_generate->scheme_type = PGenerate::GS_CASE_ITEM; pform_cur_generate->loop_init = 0; pform_cur_generate->loop_test = 0; pform_cur_generate->loop_step = 0; if (expr_list != 0) { pform_cur_generate->item_test.resize(expr_list->count()); for (unsigned idx = 0 ; idx < expr_list->count() ; idx += 1) pform_cur_generate->item_test[idx] = expr_list[0][idx]; } } void pform_generate_block_name(char*name) { assert(pform_cur_generate != 0); assert(pform_cur_generate->scope_name == 0); pform_cur_generate->scope_name = lex_strings.make(name); delete[]name; } void pform_endgenerate() { assert(pform_cur_generate != 0); assert(pform_cur_module); // If there is no explicit block name then generate a temporary // name. This will be replaced by the correct name later, once // we know all the explicit names in the surrounding scope. If // the naming scheme used here is changed, PGenerate::elaborate // must be changed to match. if (pform_cur_generate->scope_name == 0) { char tmp[16]; snprintf(tmp, sizeof tmp, "$gen%d", pform_cur_generate->id_number); pform_cur_generate->scope_name = lex_strings.make(tmp); } PGenerate*cur = pform_cur_generate; pform_cur_generate = cur->parent; if (pform_cur_generate != 0) { assert(cur->scheme_type == PGenerate::GS_CASE_ITEM || pform_cur_generate->scheme_type != PGenerate::GS_CASE); pform_cur_generate->generate_schemes.push_back(cur); } else { assert(cur->scheme_type != PGenerate::GS_CASE_ITEM); pform_cur_module->generate_schemes.push_back(cur); } } MIN_TYP_MAX min_typ_max_flag = TYP; unsigned min_typ_max_warn = 10; PExpr* pform_select_mtm_expr(PExpr*min, PExpr*typ, PExpr*max) { PExpr*res = 0; switch (min_typ_max_flag) { case MIN: res = min; delete typ; delete max; break; case TYP: res = typ; delete min; delete max; break; case MAX: res = max; delete min; delete typ; break; } if (min_typ_max_warn > 0) { cerr << res->get_fileline() << ": warning: choosing "; switch (min_typ_max_flag) { case MIN: cerr << "min"; break; case TYP: cerr << "typ"; break; case MAX: cerr << "max"; break; } cerr << " expression." << endl; min_typ_max_warn -= 1; } return res; } template <> inline svector::svector(unsigned size) : nitems_(size), items_(new perm_string[size]) { } static void process_udp_table(PUdp*udp, list*table, const char*file, unsigned lineno) { const bool synchronous_flag = udp->sequential; /* Interpret and check the table entry strings, to make sure they correspond to the inputs, output and output type. Make up vectors for the fully interpreted result that can be placed in the PUdp object. The table strings are made up by the parser to be two or three substrings separated by ';', i.e.: 0101:1:1 (synchronous device entry) 0101:0 (combinational device entry) The parser doesn't check that we got the right kind here, so this loop must watch out. */ svector input (table->size()); svector current (table->size()); svector output (table->size()); { unsigned idx = 0; for (list::iterator cur = table->begin() ; cur != table->end() ; cur ++, idx += 1) { string tmp = *cur; /* Pull the input values from the string. */ assert(tmp.find(':') == (udp->ports.count() - 1)); input[idx] = tmp.substr(0, udp->ports.count()-1); tmp = tmp.substr(udp->ports.count()-1); assert(tmp[0] == ':'); /* If this is a synchronous device, get the current output string. */ if (synchronous_flag) { if (tmp.size() != 4) { cerr << file<<":"<tinput = input; udp->tcurrent = current; udp->toutput = output; } void pform_make_udp(perm_string name, list*parms, svector*decl, list*table, Statement*init_expr, const char*file, unsigned lineno) { unsigned local_errors = 0; assert(parms->size() > 0); /* Put the declarations into a map, so that I can check them off with the parameters in the list. If the port is already in the map, merge the port type. I will rebuild a list of parameters for the PUdp object. */ map defs; for (unsigned idx = 0 ; idx < decl->count() ; idx += 1) { perm_string port_name = (*decl)[idx]->basename(); if (PWire*cur = defs[port_name]) { bool rc = true; assert((*decl)[idx]); if ((*decl)[idx]->get_port_type() != NetNet::PIMPLICIT) { rc = cur->set_port_type((*decl)[idx]->get_port_type()); assert(rc); } if ((*decl)[idx]->get_wire_type() != NetNet::IMPLICIT) { rc = cur->set_wire_type((*decl)[idx]->get_wire_type()); assert(rc); } } else { defs[port_name] = (*decl)[idx]; } } /* Put the parameters into a vector of wire descriptions. Look in the map for the definitions of the name. In this loop, the parms list in the list of ports in the port list of the UDP declaration, and the defs map maps that name to a PWire* created by an input or output declaration. */ svector pins (parms->size()); svector pin_names (parms->size()); { list::iterator cur; unsigned idx; for (cur = parms->begin(), idx = 0 ; cur != parms->end() ; idx++, cur++) { pins[idx] = defs[*cur]; pin_names[idx] = *cur; } } /* Check that the output is an output and the inputs are inputs. I can also make sure that only the single output is declared a register, if anything. The possible errors are: -- an input port (not the first) is missing an input declaration. -- An input port is declared output. */ assert(pins.count() > 0); do { if (pins[0] == 0) { cerr << file<<":"<get_port_type() != NetNet::POUTPUT) { cerr << file<<":"<get_port_type() != NetNet::PINPUT) { cerr << file<<":"<get_wire_type() == NetNet::REG) { cerr << file<<":"< 0) { delete parms; delete decl; delete table; delete init_expr; return; } /* Verify the "initial" statement, if present, to be sure that it only assigns to the output and the output is registered. Then save the initial value that I get. */ verinum::V init = verinum::Vx; if (init_expr) { // XXXX assert(pins[0]->get_wire_type() == NetNet::REG); PAssign*pa = dynamic_cast(init_expr); assert(pa); const PEIdent*id = dynamic_cast(pa->lval()); assert(id); // XXXX //assert(id->name() == pins[0]->name()); const PENumber*np = dynamic_cast(pa->rval()); assert(np); init = np->value()[0]; } // Put the primitive into the primitives table if (pform_primitives[name]) { VLerror("UDP primitive already exists."); } else { PUdp*udp = new PUdp(name, parms->size()); // Detect sequential udp. if (pins[0]->get_wire_type() == NetNet::REG) udp->sequential = true; // Make the port list for the UDP for (unsigned idx = 0 ; idx < pins.count() ; idx += 1) udp->ports[idx] = pins[idx]->basename(); process_udp_table(udp, table, file, lineno); udp->initial = init; pform_primitives[name] = udp; } /* Delete the excess tables and lists from the parser. */ delete parms; delete decl; delete table; delete init_expr; } void pform_make_udp(perm_string name, bool synchronous_flag, perm_string out_name, PExpr*init_expr, list*parms, list*table, const char*file, unsigned lineno) { svector pins(parms->size() + 1); /* Make the PWire for the output port. */ pins[0] = new PWire(out_name, synchronous_flag? NetNet::REG : NetNet::WIRE, NetNet::POUTPUT, IVL_VT_LOGIC); FILE_NAME(pins[0], file, lineno); /* Make the PWire objects for the input ports. */ { list::iterator cur; unsigned idx; for (cur = parms->begin(), idx = 1 ; cur != parms->end() ; idx += 1, cur++) { assert(idx < pins.count()); pins[idx] = new PWire(*cur, NetNet::WIRE, NetNet::PINPUT, IVL_VT_LOGIC); FILE_NAME(pins[idx], file, lineno); } assert(idx == pins.count()); } /* Verify the initial expression, if present, to be sure that it only assigns to the output and the output is registered. Then save the initial value that I get. */ verinum::V init = verinum::Vx; if (init_expr) { // XXXX assert(pins[0]->get_wire_type() == NetNet::REG); PAssign*pa = dynamic_cast(init_expr); assert(pa); const PEIdent*id = dynamic_cast(pa->lval()); assert(id); // XXXX //assert(id->name() == pins[0]->name()); const PENumber*np = dynamic_cast(pa->rval()); assert(np); init = np->value()[0]; } // Put the primitive into the primitives table if (pform_primitives[name]) { VLerror("UDP primitive already exists."); } else { PUdp*udp = new PUdp(name, pins.count()); // Detect sequential udp. udp->sequential = synchronous_flag; // Make the port list for the UDP for (unsigned idx = 0 ; idx < pins.count() ; idx += 1) udp->ports[idx] = pins[idx]->basename(); assert(udp); assert(table); process_udp_table(udp, table, file, lineno); udp->initial = init; pform_primitives[name] = udp; } delete parms; delete table; delete init_expr; } /* * This function attaches a range to a given name. The function is * only called by the parser within the scope of the net declaration, * and the name that I receive only has the tail component. */ static void pform_set_net_range(perm_string name, const svector*range, bool signed_flag, ivl_variable_type_t dt, PWSRType rt, svector*attr) { PWire*cur = pform_get_wire_in_scope(name); if (cur == 0) { VLerror("error: name is not a valid net."); return; } if (range == 0) { /* This is the special case that we really mean a scalar. Set a fake range. */ cur->set_range(0, 0, rt, true); } else { assert(range->count() == 2); assert((*range)[0]); assert((*range)[1]); cur->set_range((*range)[0], (*range)[1], rt, false); } cur->set_signed(signed_flag); if (dt != IVL_VT_NO_TYPE) cur->set_data_type(dt); if (attr) { for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { named_pexpr_t*tmp = (*attr)[idx]; cur->attributes[tmp->name] = tmp->parm; } } } void pform_set_net_range(list*names, svector*range, bool signed_flag, ivl_variable_type_t dt, PWSRType rt) { assert((range == 0) || (range->count() == 2)); for (list::iterator cur = names->begin() ; cur != names->end() ; cur ++ ) { perm_string txt = *cur; pform_set_net_range(txt, range, signed_flag, dt, rt, 0); } delete names; if (range) delete range; } /* * This is invoked to make a named event. This is the declaration of * the event, and not necessarily the use of it. */ static void pform_make_event(perm_string name, const char*fn, unsigned ln) { LexicalScope*scope = pform_get_cur_scope(); // Check if the named event is already in the dictionary. if (scope->events.find(name) != scope->events.end()) { LineInfo tloc; FILE_NAME(&tloc, fn, ln); cerr << tloc.get_fileline() << ": error: duplicate definition " "for named event '" << name << "' in '" << pform_cur_module->mod_name() << "'." << endl; error_count += 1; } PEvent*event = new PEvent(name); FILE_NAME(event, fn, ln); scope->events[name] = event; } void pform_make_events(list*names, const char*fn, unsigned ln) { list::iterator cur; for (cur = names->begin() ; cur != names->end() ; cur++) { perm_string txt = *cur; pform_make_event(txt, fn, ln); } delete names; } /* * pform_makegates is called when a list of gates (with the same type) * are ready to be instantiated. The function runs through the list of * gates and calls the pform_makegate function to make the individual gate. */ void pform_makegate(PGBuiltin::Type type, struct str_pair_t str, svector* delay, const lgate&info, svector*attr) { if (info.parms_by_name) { cerr << info.file << ":" << info.lineno << ": Gates do not " "have port names." << endl; error_count += 1; return; } perm_string dev_name = lex_strings.make(info.name); PGBuiltin*cur = new PGBuiltin(type, dev_name, info.parms, delay); if (info.range[0]) cur->set_range(info.range[0], info.range[1]); if (attr) { for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { named_pexpr_t*tmp = (*attr)[idx]; cur->attributes[tmp->name] = tmp->parm; } } cur->strength0(str.str0); cur->strength1(str.str1); FILE_NAME(cur, info.file, info.lineno); if (pform_cur_generate) pform_cur_generate->add_gate(cur); else pform_cur_module->add_gate(cur); } void pform_makegates(PGBuiltin::Type type, struct str_pair_t str, svector*delay, svector*gates, svector*attr) { for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) { pform_makegate(type, str, delay, (*gates)[idx], attr); } if (attr) { for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { named_pexpr_t*cur = (*attr)[idx]; delete cur; } delete attr; } delete gates; } /* * A module is different from a gate in that there are different * constraints, and sometimes different syntax. The X_modgate * functions handle the instantiations of modules (and UDP objects) by * making PGModule objects. * * The first pform_make_modgate handles the case of a module * instantiated with ports passed by position. The "wires" is an * ordered array of port expressions. * * The second pform_make_modgate handles the case of a module * instantiated with ports passed by name. The "bind" argument is the * ports matched with names. */ static void pform_make_modgate(perm_string type, perm_string name, struct parmvalue_t*overrides, svector*wires, PExpr*msb, PExpr*lsb, const char*fn, unsigned ln) { PGModule*cur = new PGModule(type, name, wires); FILE_NAME(cur, fn, ln); cur->set_range(msb,lsb); if (overrides && overrides->by_name) { unsigned cnt = overrides->by_name->count(); named*byname = new named[cnt]; for (unsigned idx = 0 ; idx < cnt ; idx += 1) { named_pexpr_t*curp = (*overrides->by_name)[idx]; byname[idx].name = curp->name; byname[idx].parm = curp->parm; } cur->set_parameters(byname, cnt); } else if (overrides && overrides->by_order) { cur->set_parameters(overrides->by_order); } if (pform_cur_generate) pform_cur_generate->add_gate(cur); else pform_cur_module->add_gate(cur); } static void pform_make_modgate(perm_string type, perm_string name, struct parmvalue_t*overrides, svector*bind, PExpr*msb, PExpr*lsb, const char*fn, unsigned ln) { unsigned npins = bind->count(); named*pins = new named[npins]; for (unsigned idx = 0 ; idx < npins ; idx += 1) { named_pexpr_t*curp = (*bind)[idx]; pins[idx].name = curp->name; pins[idx].parm = curp->parm; } PGModule*cur = new PGModule(type, name, pins, npins); FILE_NAME(cur, fn, ln); cur->set_range(msb,lsb); if (overrides && overrides->by_name) { unsigned cnt = overrides->by_name->count(); named*byname = new named[cnt]; for (unsigned idx = 0 ; idx < cnt ; idx += 1) { named_pexpr_t*curp = (*overrides->by_name)[idx]; byname[idx].name = curp->name; byname[idx].parm = curp->parm; } cur->set_parameters(byname, cnt); } else if (overrides && overrides->by_order) { cur->set_parameters(overrides->by_order); } if (pform_cur_generate) pform_cur_generate->add_gate(cur); else pform_cur_module->add_gate(cur); } void pform_make_modgates(perm_string type, struct parmvalue_t*overrides, svector*gates) { for (unsigned idx = 0 ; idx < gates->count() ; idx += 1) { lgate cur = (*gates)[idx]; perm_string cur_name = lex_strings.make(cur.name); if (cur.parms_by_name) { pform_make_modgate(type, cur_name, overrides, cur.parms_by_name, cur.range[0], cur.range[1], cur.file, cur.lineno); } else if (cur.parms) { /* If there are no parameters, the parser will be tricked into thinking it is one empty parameter. This fixes that. */ if ((cur.parms->count() == 1) && (cur.parms[0][0] == 0)) { delete cur.parms; cur.parms = new svector(0); } pform_make_modgate(type, cur_name, overrides, cur.parms, cur.range[0], cur.range[1], cur.file, cur.lineno); } else { svector*wires = new svector(0); pform_make_modgate(type, cur_name, overrides, wires, cur.range[0], cur.range[1], cur.file, cur.lineno); } } delete gates; } static PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval, svector*del, struct str_pair_t str) { svector*wires = new svector(2); (*wires)[0] = lval; (*wires)[1] = rval; PGAssign*cur; if (del == 0) cur = new PGAssign(wires); else cur = new PGAssign(wires, del); cur->strength0(str.str0); cur->strength1(str.str1); if (pform_cur_generate) pform_cur_generate->add_gate(cur); else pform_cur_module->add_gate(cur); return cur; } void pform_make_pgassign_list(svector*alist, svector*del, struct str_pair_t str, const char* fn, unsigned lineno) { PGAssign*tmp; for (unsigned idx = 0 ; idx < alist->count()/2 ; idx += 1) { tmp = pform_make_pgassign((*alist)[2*idx], (*alist)[2*idx+1], del, str); FILE_NAME(tmp, fn, lineno); } } /* * this function makes the initial assignment to a register as given * in the source. It handles the case where a reg variable is assigned * where it it declared: * * reg foo = ; * * This is equivalent to the combination of statements: * * reg foo; * initial foo = ; * * and that is how it is parsed. This syntax is not part of the * IEEE1364-1995 standard, but is approved by OVI as enhancement * BTF-B14. */ void pform_make_reginit(const struct vlltype&li, perm_string name, PExpr*expr) { if (! pform_at_module_level()) { VLerror(li, "variable declaration assignments are only " "allowed at the module level."); delete expr; return; } PWire*cur = pform_get_wire_in_scope(name); if (cur == 0) { VLerror(li, "internal error: reginit to non-register?"); delete expr; return; } PEIdent*lval = new PEIdent(name); FILE_NAME(lval, li); PAssign*ass = new PAssign(lval, expr, true); FILE_NAME(ass, li); PProcess*top = new PProcess(IVL_PR_INITIAL, ass); FILE_NAME(top, li); pform_put_behavior_in_scope(top); } /* * This function is used by the parser when I have port definition of * the form like this: * * input wire signed [7:0] nm; * * The port_type, type, signed_flag and range are known all at once, * so we can create the PWire object all at once instead of piecemeal * as is done for the old method. */ void pform_module_define_port(const struct vlltype&li, perm_string name, NetNet::PortType port_type, NetNet::Type type, bool signed_flag, svector*range, svector*attr) { PWire*cur = pform_get_wire_in_scope(name); if (cur) { ostringstream msg; msg << name << " definition conflicts with " << "definition at " << cur->get_fileline() << "."; VLerror(msg.str().c_str()); return; } cur = new PWire(name, type, port_type, IVL_VT_LOGIC); FILE_NAME(cur, li); cur->set_signed(signed_flag); if (range == 0) { cur->set_range(0, 0, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH, true); } else { assert(range->count() == 2); assert((*range)[0]); assert((*range)[1]); cur->set_range((*range)[0], (*range)[1], (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH, false); } if (attr) { for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { named_pexpr_t*tmp = (*attr)[idx]; cur->attributes[tmp->name] = tmp->parm; } } pform_put_wire_in_scope(name, cur); } /* * This function makes a single signal (a wire, a reg, etc) as * requested by the parser. The name is unscoped, so I attach the * current scope to it (with the scoped_name function) and I try to * resolve it with an existing PWire in the scope. * * The wire might already exist because of an implicit declaration in * a module port, i.e.: * * module foo (bar... * * reg bar; * * The output (or other port direction indicator) may or may not have * been seen already, so I do not do any checking with it yet. But I * do check to see if the name has already been declared, as this * function is called for every declaration. */ /* * this is the basic form of pform_makewire. This takes a single simple * name, port type, net type, data type, and attributes, and creates * the variable/net. Other forms of pform_makewire ultimately call * this one to create the wire and stash it. */ void pform_makewire(const vlltype&li, perm_string name, NetNet::Type type, NetNet::PortType pt, ivl_variable_type_t dt, svector*attr) { PWire*cur = pform_get_wire_in_scope(name); // If this is not implicit ("implicit" meaning we don't know // what the type is yet) then set the type now. if (cur && type != NetNet::IMPLICIT) { bool rc = cur->set_wire_type(type); if (rc == false) { ostringstream msg; msg << name << " " << type << " definition conflicts with " << cur->get_wire_type() << " definition at " << cur->get_fileline() << "."; VLerror(msg.str().c_str()); } } bool new_wire_flag = false; if (! cur) { new_wire_flag = true; cur = new PWire(name, type, pt, dt); FILE_NAME(cur, li.text, li.first_line); } if (type != NetNet::IMPLICIT) FILE_NAME(cur, li.text, li.first_line); bool flag; switch (dt) { case IVL_VT_REAL: flag = cur->set_data_type(dt); if (flag == false) { cerr << cur->get_fileline() << ": internal error: " << " wire data type handling mismatch. Cannot change " << cur->get_data_type() << " to " << dt << "." << endl; } ivl_assert(*cur, flag); cur->set_range(0, 0, SR_NET, true); cur->set_signed(true); break; default: break; } if (attr) { for (unsigned idx = 0 ; idx < attr->count() ; idx += 1) { named_pexpr_t*tmp = (*attr)[idx]; cur->attributes[tmp->name] = tmp->parm; } } if (new_wire_flag) pform_put_wire_in_scope(name, cur); } /* * This form takes a list of names and some type information, and * generates a bunch of variables/nets. We use the basic * pform_makewire above. */ void pform_makewire(const vlltype&li, svector*range, bool signed_flag, list*names, NetNet::Type type, NetNet::PortType pt, ivl_variable_type_t dt, svector*attr, PWSRType rt) { for (list::iterator cur = names->begin() ; cur != names->end() ; cur ++ ) { perm_string txt = *cur; pform_makewire(li, txt, type, pt, dt, attr); /* This has already been done for real variables. */ if (dt != IVL_VT_REAL) { pform_set_net_range(txt, range, signed_flag, dt, rt, 0); } } delete names; if (range) delete range; if (attr) delete attr; } /* * This form makes nets with delays and continuous assignments. */ void pform_makewire(const vlltype&li, svector*range, bool signed_flag, svector*delay, str_pair_t str, net_decl_assign_t*decls, NetNet::Type type, ivl_variable_type_t dt) { net_decl_assign_t*first = decls->next; decls->next = 0; while (first) { net_decl_assign_t*next = first->next; pform_makewire(li, first->name, type, NetNet::NOT_A_PORT, dt, 0); /* This has already been done for real variables. */ if (dt != IVL_VT_REAL) { pform_set_net_range(first->name, range, signed_flag, dt, SR_NET, 0); } PWire*cur = pform_get_wire_in_scope(first->name); if (cur != 0) { PEIdent*lval = new PEIdent(first->name); FILE_NAME(lval, li.text, li.first_line); PGAssign*ass = pform_make_pgassign(lval, first->expr, delay, str); FILE_NAME(ass, li.text, li.first_line); } delete first; first = next; } } void pform_set_port_type(perm_string name, NetNet::PortType pt, const char*file, unsigned lineno) { PWire*cur = pform_get_wire_in_scope(name); if (cur == 0) { cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE); FILE_NAME(cur, file, lineno); pform_put_wire_in_scope(name, cur); } switch (cur->get_port_type()) { case NetNet::PIMPLICIT: if (! cur->set_port_type(pt)) VLerror("error setting port direction."); break; case NetNet::NOT_A_PORT: cerr << file << ":" << lineno << ": error: " << "port " << name << " is not in the port list." << endl; error_count += 1; break; default: cerr << file << ":" << lineno << ": error: " << "port " << name << " already has a port declaration." << endl; error_count += 1; break; } } /* * This function is called by the parser to create task ports. The * resulting wire (which should be a register) is put into a list to * be packed into the task parameter list. * * It is possible that the wire (er, register) was already created, * but we know that if the name matches it is a part of the current * task, so in that case I just assign direction to it. * * The following example demonstrates some of the issues: * * task foo; * input a; * reg a, b; * input b; * [...] * endtask * * This function is called when the parser matches the "input a" and * the "input b" statements. For ``a'', this function is called before * the wire is declared as a register, so I create the foo.a * wire. For ``b'', I will find that there is already a foo.b and I * just set the port direction. In either case, the ``reg a, b'' * statement is caught by the block_item non-terminal and processed * there. * * Ports are implicitly type reg, because it must be possible for the * port to act as an l-value in a procedural assignment. It is obvious * for output and inout ports that the type is reg, because the task * only contains behavior (no structure) to a procedural assignment is * the *only* way to affect the output. It is less obvious for input * ports, but in practice an input port receives its value as if by a * procedural assignment from the calling behavior. * * This function also handles the input ports of function * definitions. Input ports to function definitions have the same * constraints as those of tasks, so this works fine. Functions have * no output or inout ports. */ svector*pform_make_task_ports(NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, svector*range, list*names, const char* file, unsigned lineno, bool isint) { assert(names); svector*res = new svector(0); for (list::iterator cur = names->begin() ; cur != names->end() ; cur ++ ) { perm_string name = *cur; /* Look for a preexisting wire. If it exists, set the port direction. If not, create it. */ PWire*curw = pform_get_wire_in_scope(name); if (curw) { curw->set_port_type(pt); } else { curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype); FILE_NAME(curw, file, lineno); pform_put_wire_in_scope(name, curw); } curw->set_signed(signed_flag); if (isint) assert(curw->set_wire_type(NetNet::INTEGER)); /* If there is a range involved, it needs to be set. */ if (range) curw->set_range((*range)[0], (*range)[1], SR_PORT, false); svector*tmp = new svector(*res, curw); delete res; res = tmp; } if (range) delete range; delete names; return res; } void pform_set_attrib(perm_string name, perm_string key, char*value) { if (PWire*cur = lexical_scope->wires_find(name)) { cur->attributes[key] = new PEString(value); } else if (PGate*curg = pform_cur_module->get_gate(name)) { curg->attributes[key] = new PEString(value); } else { delete[] value; VLerror("Unable to match name for setting attribute."); } } /* * Set the attribute of a TYPE. This is different from an object in * that this applies to every instantiation of the given type. */ void pform_set_type_attrib(perm_string name, const string&key, char*value) { map::const_iterator udp = pform_primitives.find(name); if (udp == pform_primitives.end()) { VLerror("type name is not (yet) defined."); delete[] value; return; } (*udp).second ->attributes[key] = new PEString(value); } /* * This function attaches a memory index range to an existing * register. (The named wire must be a register. */ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r) { PWire*cur = 0; if (pform_cur_generate) { cur = pform_cur_generate->wires_find(name); } else { cur = lexical_scope->wires_find(name); } if (cur == 0) { VLerror("internal error: name is not a valid memory for index."); return; } cur->set_memory_idx(l, r); } LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag, bool low_open, PExpr*low_expr, bool hig_open, PExpr*hig_expr) { // Detect +-inf and make the the *_open flags false to force // the range interpretation as inf. if (low_expr == 0) low_open = false; if (hig_expr == 0) hig_open = false; LexicalScope::range_t*tmp = new LexicalScope::range_t; tmp->exclude_flag = exclude_flag; tmp->low_open_flag = low_open; tmp->low_expr = low_expr; tmp->high_open_flag = hig_open; tmp->high_expr = hig_expr; tmp->next = 0; return tmp; } void pform_set_parameter(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, bool signed_flag, svector*range, PExpr*expr, LexicalScope::range_t*value_range) { LexicalScope*scope = pform_get_cur_scope(); if (scope == pform_cur_generate) { VLerror("parameter declarations are not permitted in generate blocks"); return; } // Check if the parameter name is already in the dictionary. if (scope->parameters.find(name) != scope->parameters.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: duplicate definition " "for parameter '" << name << "' in '" << pform_cur_module->mod_name() << "'." << endl; error_count += 1; } if (scope->localparams.find(name) != scope->localparams.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: localparam and " "parameter in '" << pform_cur_module->mod_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } assert(expr); Module::param_expr_t&parm = scope->parameters[name]; FILE_NAME(&parm, loc); parm.expr = expr; parm.type = type; if (range) { assert(range->count() == 2); assert((*range)[0]); assert((*range)[1]); parm.msb = (*range)[0]; parm.lsb = (*range)[1]; } else { parm.msb = 0; parm.lsb = 0; } parm.signed_flag = signed_flag; parm.range = value_range; if (scope == pform_cur_module) pform_cur_module->param_names.push_back(name); } void pform_set_localparam(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, bool signed_flag, svector*range, PExpr*expr) { LexicalScope*scope = pform_get_cur_scope(); // Check if the localparam name is already in the dictionary. if (scope->localparams.find(name) != scope->localparams.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: duplicate definition " "for localparam '" << name << "' in '" << pform_cur_module->mod_name() << "'." << endl; error_count += 1; } if (scope->parameters.find(name) != scope->parameters.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: parameter and " "localparam in '" << pform_cur_module->mod_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } assert(expr); Module::param_expr_t&parm = pform_get_cur_scope()->localparams[name]; FILE_NAME(&parm, loc); parm.expr = expr; parm.type = type; if (range) { assert(range->count() == 2); assert((*range)[0]); assert((*range)[1]); parm.msb = (*range)[0]; parm.lsb = (*range)[1]; } else { parm.msb = 0; parm.lsb = 0; } parm.signed_flag = signed_flag; parm.range = 0; } void pform_set_specparam(perm_string name, PExpr*expr) { // Check if the specparam name is already in the dictionary. if (pform_cur_module->specparams.find(name) != pform_cur_module->specparams.end()) { cerr << expr->get_fileline() << ": error: duplicate definition " "for specparam '" << name << "' in '" << pform_cur_module->mod_name() << "'." << endl; error_count += 1; } assert(expr); pform_cur_module->specparams[name] = expr; } void pform_set_defparam(const pform_name_t&name, PExpr*expr) { assert(expr); if (pform_cur_generate) pform_cur_generate->defparms.push_back(make_pair(name,expr)); else pform_cur_module->defparms.push_back(make_pair(name,expr)); } /* * Specify paths. */ extern PSpecPath* pform_make_specify_path(const struct vlltype&li, list*src, char pol, bool full_flag, list*dst) { PSpecPath*path = new PSpecPath(src->size(), dst->size()); FILE_NAME(path, li.text, li.first_line); path->polarity = pol; path->full_flag = full_flag; unsigned idx; list::const_iterator cur; idx = 0; for (idx = 0, cur = src->begin() ; cur != src->end() ; idx++, cur++) { path->src[idx] = *cur; } assert(idx == path->src.size()); delete src; for (idx = 0, cur = dst->begin() ; cur != dst->end() ; idx++, cur++) { path->dst[idx] = *cur; } assert(idx == path->dst.size()); delete dst; return path; } extern PSpecPath*pform_make_specify_edge_path(const struct vlltype&li, int edge_flag, /*posedge==true */ list*src, char pol, bool full_flag, list*dst, PExpr*data_source_expression) { PSpecPath*tmp = pform_make_specify_path(li, src, pol, full_flag, dst); tmp->edge = edge_flag; tmp->data_source_expression = data_source_expression; return tmp; } extern PSpecPath* pform_assign_path_delay(PSpecPath*path, svector*del) { if (path == 0) return 0; assert(path->delays.size() == 0); path->delays.resize(del->count()); for (unsigned idx = 0 ; idx < path->delays.size() ; idx += 1) path->delays[idx] = (*del)[idx]; delete del; return path; } extern void pform_module_specify_path(PSpecPath*obj) { if (obj == 0) return; pform_cur_module->specify_paths.push_back(obj); } void pform_set_port_type(const struct vlltype&li, list*names, svector*range, bool signed_flag, NetNet::PortType pt, svector*attr) { for (list::iterator cur = names->begin() ; cur != names->end() ; cur ++ ) { perm_string txt = *cur; pform_set_port_type(txt, pt, li.text, li.first_line); pform_set_net_range(txt, range, signed_flag, IVL_VT_NO_TYPE, SR_PORT, attr); } delete names; if (range) delete range; if (attr) delete attr; } static void pform_set_reg_integer(perm_string name) { PWire*cur = pform_get_wire_in_scope(name); if (cur == 0) { cur = new PWire(name, NetNet::INTEGER, NetNet::NOT_A_PORT, IVL_VT_LOGIC); cur->set_signed(true); pform_put_wire_in_scope(name, cur); } else { bool rc = cur->set_wire_type(NetNet::INTEGER); assert(rc); cur->set_data_type(IVL_VT_LOGIC); cur->set_signed(true); } assert(cur); cur->set_range(new PENumber(new verinum(integer_width-1, integer_width)), new PENumber(new verinum((uint64_t)0, integer_width)), SR_NET, false); cur->set_signed(true); } void pform_set_reg_integer(list*names) { for (list::iterator cur = names->begin() ; cur != names->end() ; cur ++ ) { perm_string txt = *cur; pform_set_reg_integer(txt); } delete names; } static void pform_set_reg_time(perm_string name) { PWire*cur = pform_get_wire_in_scope(name); if (cur == 0) { cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC); pform_put_wire_in_scope(name, cur); } else { bool rc = cur->set_wire_type(NetNet::REG); assert(rc); rc = cur->set_data_type(IVL_VT_LOGIC); assert(rc); } assert(cur); cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, integer_width)), new PENumber(new verinum((uint64_t)0, integer_width)), SR_NET, false); } void pform_set_reg_time(list*names) { for (list::iterator cur = names->begin() ; cur != names->end() ; cur ++ ) { perm_string txt = *cur; pform_set_reg_time(txt); } delete names; } svector* pform_make_udp_input_ports(list*names) { svector*out = new svector(names->size()); unsigned idx = 0; for (list::iterator cur = names->begin() ; cur != names->end() ; cur ++ ) { perm_string txt = *cur; PWire*pp = new PWire(txt, NetNet::IMPLICIT, NetNet::PINPUT, IVL_VT_LOGIC); (*out)[idx] = pp; idx += 1; } delete names; return out; } PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st, svector*attr) { PProcess*pp = new PProcess(type, st); pform_bind_attributes(pp->attributes, attr); pform_put_behavior_in_scope(pp); return pp; } FILE*vl_input = 0; extern void reset_lexor(); int pform_parse(const char*path, FILE*file) { vl_file = path; if (file == 0) { if (strcmp(path, "-") == 0) vl_input = stdin; else vl_input = fopen(path, "r"); if (vl_input == 0) { cerr << "Unable to open " <get_fileline() << ": error: original module " "(" << pform_cur_module->mod_name() << ") defined here." << endl; } verilog-0.9.7/PaxHeaders.14238/sync.cc0000644000202500001440000000005012204466647015513 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/sync.cc0000644000202500001440000000333412204466647015040 0ustar00steveusers00000000000000/* * Copyright (c) 2002-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "functor.h" # include "netlist.h" # include /* * Most process statements are not roots of synchronous logic. */ bool NetProc::is_synchronous() { return false; } bool NetEvWait::is_synchronous() { for (unsigned idx = 0 ; idx < nevents_ ; idx += 1) { NetEvent*ev = events_[idx]; if (ev->nprobe() == 0) return false; for (unsigned pdx = 0 ; pdx < ev->nprobe() ; pdx += 1) { NetEvProbe*pr = ev->probe(pdx); /* No level sensitive clocks. */ if (pr->edge() == NetEvProbe::ANYEDGE) return false; } } /* So we know that there is a clock source. Check that the input to the storage is asynchronous. */ return true; //statement_->is_asynchronous(); } bool NetProcTop::is_synchronous() { if (type_ == IVL_PR_INITIAL) return false; return statement_->is_synchronous(); } verilog-0.9.7/PaxHeaders.14238/mingw.txt0000644000202500001440000000005012204466647016112 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/mingw.txt0000644000202500001440000002452312204466647015442 0ustar00steveusers00000000000000MINGW PORT OF ICARUS VERILOG Copyright 2006 Stephen Williams Copyright 2010 Martin Whitaker Icarus Verilog source can be compiled with the MinGW C/C++ compilers to get a Windows binary that does not require the POSIX compatibility cruft of the Cygwin.dll library. The resulting program can be run with or without Cygwin, so this is the preferred Windows distribution form. The configure scripts automatically detect that the compilers in use are the MinGW compilers and will configure the Makefiles appropriately. The base MinGW package doesn't contain tools beyond the compiler, but there is the MSYS package that the makers of MinGW publish that has enough extra tools to get most everything else working. There are a few extra packages needed beyond MinGW and MSYS, and the following instructions explain how to get them and install them. * Some Preliminary Comments -- PLEASE READ ME -- The Windows port of Icarus Verilog is the most difficult of all the ports. The Windows system off the shelf is completely stripped, devoid of any support for software development. Everything needed to compile Icarus Verilog must be collected from various sources and stitched together by hand. Normal human beings with a basic understanding of software development can do this, but some patience (and access to the Internet) is required. You may choose to print these instructions. FOR BEST RESULTS, FOLLOW THESE INSTRUCTIONS CAREFULLY. NOTE that if you have Cygwin installed, it is best to not use a Cygwin window to do the build, as the Cygwin tools will intermix with the MinGW tools such that it is hard to be sure you are using the right compiler. Thus, it is recommended that these steps *not* be done in a Cygwin window. Use a MinGW window instead, and be careful that your MSYS/MinGW tools are not masked by paths that point to Cygwin binaries. We have no plans to intentionally support MSVC++ compilation. Don't ask. Incidentally, besides MinGW, none of the packages installed in the following steps are needed after installation of Icarus Verilog is complete. They are only needed to build the compiler. The MinGW package can be used to compile VPI modules if you choose. * Install MinGW and MSYS Base Packages From the MinGW project (http://www.mingw.org), download and run the MinGW graphical installer (mingw-get-inst). Select the following components to be installed: C Compiler C++ Compiler MSYS Basic System MinGW Developer Toolkit NOTE: If the download site is responding slowly, the installer tends to time out. If this happens it will skip the package it is currently trying to download and continue. If this happens, you can install the skipped packages later using the mingw-get command in a MinGW shell. The default installation path is C:\MinGW, but you can change this to anything you like (but make sure there are no spaces in the path names). This path is referred to as in subsequent instructions. The installation will leave a "MinGW Shell" icon in the MinGW sub-menu of your Start menu. This icon brings up a shell window (a command line) that has paths all set up for executing MSYS and MinGW commands. NOTE: If you intend to compile VPI modules for Icarus Verilog, you need MinGW, even if you are using a precompiled binary. VPI modules only require MinGW, and none of the other libraries. * Install Additional MinGW Packages Start a MinGW shell. In the shell window, execute the following commands: mingw-get install libz mingw-get install bzip2 mingw-get install pthreads-w32 mingw-get install msys-man If you also want to build Git (optional): mingw-get install libiconv mingw-get install msys-perl NOTE: Building Git allows you to execute Git commands in a MinGW shell, and allows the Icarus Verilog tools to report more detailed version information when called with the -V option. * Install GnuWin32 Packages The GnuWin32 project is a collection of open source programs and libraries ported to Windows. These also work well with the MinGW compiler, and in fact Icarus Verilog uses a few pieces from this collection. From the GnuWin project (http://gnuwin32.sourceforge.net), download the following packages: gperf-3.0.1-bin readline-5.0.1-bin NOTE: You need the binaries and the developer files, but you do not need the source to these packages. From the downloaded gperf-3.0.1-bin zip archive: extract bin\gperf.exe to \bin From the downloaded readline-5.0.1-bin zip archive: extract bin\* to \bin extract lib\* to \lib extract include\* to \include where is the location you chose to install MinGW. NOTE: readline is only required to enable command line editing when in the vvp interactive mode. * Install Git for Windows (optional) NOTE: You can skip this step if you are building from a snapshot or stable release. From the msysgit project (http://code.google.com/p/msysgit), download and install the Git for Windows binary package. NOTE: When installing, you must select the option of preserving Unix style line endings. The installation will leave a "Git Shell" icon on the desktop and in the Git sub-menu of your Start menu. This icon brings up a shell window (a command line) that has paths all set up for executing Git commands. * Get the Git Source (optional) NOTE: You can skip this step if you don't want to build Git. Start a Git shell. In the Git shell window, change directory to the location where you wish to store the source code and execute the following command: git clone git://repo.or.cz/git/mingw.git git This will create a directory "git" that contains all the source code for Icarus Verilog. The path to the directory containing the source code is referred to as in subsequent instructions. NOTE: Make sure there are no spaces in the path names. Use forward slashes in place of back slashes when using in a MinGW shell. * Build Git (optional) NOTE: You can skip this step if you don't want to build Git. In the MinGW shell window, execute the following commands: cd make NO_OPENSSL=YesPlease NO_TCLTK=YesPlease INSTALL=/bin/install \ prefix=/usr/local install You can now uninstall the Git for Windows binary package if you wish, as Git commands can now be executed in the MinGW shell. * Get the Icarus Verilog Source In the MinGW shell window, change directory to the location where you wish to store the source code. If you are building from a snapshot, execute the following command: gunzip -d verilog-xxxxxxxx.tar.gz | tar xvf - This will create a directory "verilog-xxxxxxxx" that contains all the source code for Icarus Verilog. NOTE: The exact name of the file will vary according to the snapshot. The 'xxxxxxxx' name is only an example. If you are obtaining source from Git, execute the following command: git clone git://icarus.com/~steve-icarus/verilog verilog This will create a directory "verilog" that contains all the source code for Icarus Verilog. NOTE: If you haven't built Git, you will need to execute the above command in a Git shell. The path to the directory containing the source code is referred to as in subsequent instructions. NOTE: Make sure there are no spaces in the path names. Use forward slashes in place of back slashes when using in a MinGW shell. * Preconfigure Icarus Verilog (not normally needed) Under certain cases, you may need to "preconfigure" the Icarus Verilog source tree. You should only need to do this if you are obtaining source from Git, or you are using an existing source tree that you've patched to cause configure.in files to change. NOTE: If you are building from a fresh, bundled source tree that you downloaded from an FTP site, then SKIP THIS STEP. Go on to the "Configure Icarus Verilog" step below. First, remove any autom4te.cache directories that may exist in your source tree. These can make a mess of autoconf runs. Then, in the MinGW shell window, execute the following commands: cd sh autoconf.sh This script will run the "autoconf" command to generate all the necessary "configure" scripts. * Configure and Build Icarus Verilog Now we are all set to configure and compile Icarus Verilog. Choose a destination path where you will want to install the binaries. This choice is not permanent, so don't get too much angst over it. Just choose a name without white space. The destination path is referred to as in subsequent instructions. NOTE: Make sure there are no spaces in the path names. Use forward slashes in place of back slashes when using in a MinGW shell. In the MinGW shell window, execute the following commands: cd ./configure --prefix= make NOTE: If you execute configure without the --prefix option, the default installation path is \msys\1.0\local, which in a MinGW shell is aliased to /usr/local/bin. * Install Icarus Verilog If the compile ran OK, then next you install Icarus Verilog in the directory you have chosen. In the MinGW shell window, execute the following commands: cd make install This is part of what the configure program did for you. The Makefiles know to put the files in the directory. You now need to add \bin and \bin to your Windows "PATH" environment variable. Alternatively, you can copy the DLLs needed by Icarus Verilog from \bin to bin, and just add \bin to your Windows "PATH" environment variable. * Running Icarus Verilog You can run Icarus Verilog either from a Windows command shell window or from a MinGW shell window. NOTE: You will need to start a new shell to pick up any changes you have made to the "PATH" environment variable. Currently, iverilog.exe uses the path to itself to locate the libraries and modules associated with itself. In other words, if you execute the \bin\iverilog.exe program, it will locate its subparts in the directory and subdirectories below that. This means you can move the Icarus Verilog installation by simply moving the root directory and all its contents. The vvp.pdf and iverilog.pdf files document the main commands. View these with Acrobat reader, or any other viewer capable of displaying PDF format files. verilog-0.9.7/PaxHeaders.14238/check.conf0000644000202500001440000000005012204466647016154 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/check.conf0000644000202500001440000000007712204466647015502 0ustar00steveusers00000000000000functor:cprop functor:nodangle -t:dll flag:DLL=tgt-vvp/vvp.tgt verilog-0.9.7/PaxHeaders.14238/net_func.cc0000644000202500001440000000005012204466647016340 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/net_func.cc0000644000202500001440000001053512204466647015666 0ustar00steveusers00000000000000/* * Copyright (c) 2002-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "netlist.h" # include "compiler.h" # include "PExpr.h" # include /* * To make a NetUserFunc device, make as many pins as there are ports * in the function. Get the port count from the function definition, * which accounts for all the inputs, plus one for the phantom output * that is the result. */ NetUserFunc::NetUserFunc(NetScope*s, perm_string n, NetScope*d, NetEvWait*trigger__) : NetNode(s, n, d->func_def()->port_count()+1), def_(d), trigger_(trigger__) { pin(0).set_dir(Link::OUTPUT); for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { pin(idx).set_dir(Link::INPUT); pin(idx).drive0(Link::HIGHZ); pin(idx).drive1(Link::HIGHZ); } } NetUserFunc::~NetUserFunc() { } ivl_variable_type_t NetUserFunc::data_type(unsigned port) const { NetFuncDef*fdef = def_->func_def(); /* Port 0 is the return port. */ if (port == 0) { const NetNet*sig = fdef->return_sig(); assert(sig); return sig->data_type(); } port -= 1; assert(port < fdef->port_count()); const NetNet*port_sig = fdef->port(port); return port_sig->data_type(); } unsigned NetUserFunc::port_width(unsigned port) const { NetFuncDef*fdef = def_->func_def(); /* Port 0 is the return port. */ if (port == 0) { const NetNet*sig = fdef->return_sig(); assert(sig); return sig->vector_width(); } port -= 1; assert(port < fdef->port_count()); const NetNet*port_sig = fdef->port(port); return port_sig->vector_width(); } const NetScope* NetUserFunc::def() const { return def_; } /* * This method of the PECallFunction class checks that the parameters * of the PECallFunction match the function definition. This is used * during elaboration to validate the parameters before using them. */ bool PECallFunction::check_call_matches_definition_(Design*des, NetScope*dscope) const { assert(dscope); /* How many parameters have I got? Normally the size of the list is correct, but there is the special case of a list of 1 nil pointer. This is how the parser tells me of no parameter. In other words, ``func()'' is 1 nil parameter. */ unsigned parms_count = parms_.size(); if ((parms_count == 1) && (parms_[0] == 0)) parms_count = 0; if (dscope->type() != NetScope::FUNC) { cerr << get_fileline() << ": error: Attempt to call scope " << scope_path(dscope) << " as a function." << endl; des->errors += 1; return false; } if (parms_count != dscope->func_def()->port_count()) { cerr << get_fileline() << ": error: Function " << scope_path(dscope) << " expects " << (dscope->func_def()->port_count()) << " arguments, you passed " << parms_count << "." << endl; des->errors += 1; return false; } return true; } NetSysFunc::NetSysFunc(NetScope*s, perm_string n, const struct sfunc_return_type*def, unsigned ports, NetEvWait*trigger__) : NetNode(s, n, ports), def_(def), trigger_(trigger__) { pin(0).set_dir(Link::OUTPUT); // Q for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { pin(idx).set_dir(Link::INPUT); pin(idx).drive0(Link::HIGHZ); pin(idx).drive1(Link::HIGHZ); } } NetSysFunc::~NetSysFunc() { } const char*NetSysFunc::func_name() const { return def_->name; } ivl_variable_type_t NetSysFunc::data_type() const { return def_->type; } unsigned NetSysFunc::vector_width() const { return def_->wid; } verilog-0.9.7/PaxHeaders.14238/PTask.h0000644000202500001440000000005012204466647015423 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/PTask.h0000644000202500001440000000646312204466647014756 0ustar00steveusers00000000000000#ifndef __PTask_H #define __PTask_H /* * Copyright (c) 1999-2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "LineInfo.h" # include "PScope.h" # include "svector.h" # include "StringHeap.h" # include class Design; class NetScope; class PWire; class Statement; class PExpr; enum PTaskFuncEnum { PTF_NONE, PTF_REG, PTF_REG_S, PTF_INTEGER, PTF_REAL, PTF_REALTIME, PTF_TIME }; struct PTaskFuncArg { PTaskFuncEnum type; svector*range; }; /* * The PTask holds the parsed definitions of a task. */ class PTask : public PScope, public LineInfo { public: explicit PTask(perm_string name, PScope*parent, bool is_auto); ~PTask(); void set_ports(svector*p); void set_statement(Statement *s); // Tasks introduce scope, to need to be handled during the // scope elaboration pass. The scope passed is my scope, // created by the containing scope. I fill it in with stuff if // I need to. void elaborate_scope(Design*des, NetScope*scope) const; // Bind the ports to the regs that are the ports. void elaborate_sig(Design*des, NetScope*scope) const; // Elaborate the statement to finish off the task definition. void elaborate(Design*des, NetScope*scope) const; bool is_auto() const { return is_auto_; }; void dump(ostream&, unsigned) const; private: svector*ports_; Statement*statement_; bool is_auto_; private: // Not implemented PTask(const PTask&); PTask& operator=(const PTask&); }; /* * The function is similar to a task (in this context) but there is a * single output port and a set of input ports. The output port is the * function return value. * * The output value is not elaborated until elaborate_sig. */ class PFunction : public PScope, public LineInfo { public: explicit PFunction(perm_string name, PScope*parent, bool is_auto); ~PFunction(); void set_ports(svector*p); void set_statement(Statement *s); void set_return(PTaskFuncArg t); void elaborate_scope(Design*des, NetScope*scope) const; /* elaborate the ports and return value. */ void elaborate_sig(Design *des, NetScope*) const; /* Elaborate the behavioral statement. */ void elaborate(Design *des, NetScope*) const; bool is_auto() const { return is_auto_; }; void dump(ostream&, unsigned) const; private: PTaskFuncArg return_type_; svector *ports_; Statement *statement_; bool is_auto_; }; #endif verilog-0.9.7/PaxHeaders.14238/aclocal.m40000644000202500001440000000005012204466647016070 xustar000000000000000020 atime=1376939566 20 ctime=1376939565 verilog-0.9.7/aclocal.m40000644000202500001440000001553012204466647015416 0ustar00steveusers00000000000000 # AX_ENABLE_SUFFIX # ---------------- # Create the configure option --enable-suffix[=suffix] to generate suffix # strings for the installed commands. This allows for shared installs of # different builds. Remember to change the default suffix string to some # value appropriate for the current version. AC_DEFUN([AX_ENABLE_SUFFIX], [AC_ARG_ENABLE([suffix],[AC_HELP_STRING([--enable-suffix], [Use/set the installation command suffix])], [true],[enable_suffix=no]) if test X$enable_suffix = Xyes; then install_suffix='-0.9' elif test X$enable_suffix = Xno; then install_suffix='' else install_suffix="$enable_suffix" fi AC_SUBST(install_suffix) ])# AX_ENABLE_SUFFIX # _AX_C_UNDERSCORES_MATCH_IFELSE(PATTERN, ACTION-IF-MATCH, ACTION-IF-NOMATCH) # ------------------------------ # Sub-macro for AX_C_UNDERSCORES_LEADING and AX_C_UNDERSCORES_TRAILING. # Unwarranted assumptions: # - the object file produced by AC_COMPILE_IFELSE is called "conftest.$ac_objext" # - the nm(1) utility is available, and its name is "nm". AC_DEFUN([_AX_C_UNDERSCORES_MATCH_IF], [AC_COMPILE_IFELSE([AC_LANG_SOURCE([void underscore(void){}])], [AS_IF([nm conftest.$ac_objext|grep $1 >/dev/null 2>/dev/null],[$2],[$3])], [AC_MSG_ERROR([underscore test crashed])] )]) # AX_C_UNDERSCORES_LEADING # --------------------------------- # Check if symbol names in object files produced by C compiler have # leading underscores. Define NEED_LU if so. AC_DEFUN([AX_C_UNDERSCORES_LEADING], [AC_CACHE_CHECK([for leading underscores], ax_cv_c_underscores_leading, [_AX_C_UNDERSCORES_MATCH_IF([_underscore], [AS_VAR_SET(ax_cv_c_underscores_leading, yes)], [AS_VAR_SET(ax_cv_c_underscores_leading, no)])]) if test $ax_cv_c_underscores_leading = yes -a "$CYGWIN" != "yes" -a "$MINGW32" != "yes"; then AC_DEFINE([NEED_LU], [1], [Symbol names in object files produced by C compiler have leading underscores.]) fi ])# AX_C_UNDERSCORES_LEADING # AX_C_UNDERSCORES_TRAILING # --------------------------------- # Check if symbol names in object files produced by C compiler have # trailing underscores. Define NEED_TU if so. AC_DEFUN([AX_C_UNDERSCORES_TRAILING], [AC_CACHE_CHECK([for trailing underscores], ax_cv_c_underscores_trailing, [_AX_C_UNDERSCORES_MATCH_IF([underscore_], [AS_VAR_SET(ax_cv_c_underscores_trailing, yes)], [AS_VAR_SET(ax_cv_c_underscores_trailing, no)])]) if test $ax_cv_c_underscores_trailing = yes; then AC_DEFINE([NEED_TU], [1], [Symbol names in object files produced by C compiler have trailing underscores.]) fi ])# AX_C_UNDERSCORES_TRAILING # AX_WIN32 # -------- # Combined check for several flavors of Microsoft Windows so # their "issues" can be dealt with AC_DEFUN([AX_WIN32], [AC_MSG_CHECKING([for Microsoft Windows]) AC_REQUIRE([AC_CANONICAL_HOST]) []dnl case $host_os in *cygwin*) MINGW32=no; WIN32=yes;; *mingw*) MINGW32=yes; WIN32=yes;; *) MINGW32=no; WIN32=no;; esac AC_SUBST(MINGW32) AC_SUBST(WIN32) AC_MSG_RESULT($WIN32) if test $WIN32 = yes; then AC_MSG_CHECKING([for MinGW]) AC_MSG_RESULT($MINGW32) fi ])# AX_WIN32 # AX_LD_EXTRALIBS # --------------- # mingw needs to link with libiberty.a, but cygwin alone can't tolerate it AC_DEFUN([AX_LD_EXTRALIBS], [AC_MSG_CHECKING([for extra libs needed]) EXTRALIBS= case "${host}" in *-*-cygwin* ) if test "$MINGW32" = "yes"; then EXTRALIBS="-liberty" fi ;; esac AC_SUBST(EXTRALIBS) AC_MSG_RESULT($EXTRALIBS) ])# AX_LD_EXTRALIBS # AX_LD_SHAREDLIB_OPTS # -------------------- # linker options when building a shared library AC_DEFUN([AX_LD_SHAREDLIB_OPTS], [AC_MSG_CHECKING([for shared library link flag]) shared=-shared case "${host}" in *-*-cygwin*) shared="-shared -Wl,--enable-auto-image-base" ;; *-*-mingw*) shared="-shared -Wl,--enable-auto-image-base" ;; *-*-hpux*) shared="-b" ;; *-*-darwin1.[0123]) shared="-bundle -undefined suppress" ;; *-*-darwin*) shared="-bundle -undefined suppress -flat_namespace" ;; *-*-solaris*) if test ${using_sunpro_c} = 1 then shared="-G" fi ;; esac AC_SUBST(shared) AC_MSG_RESULT($shared) ])# AX_LD_SHAREDLIB_OPTS # AX_C_PICFLAG # ------------ # The -fPIC flag is used to tell the compiler to make position # independent code. It is needed when making shared objects. AC_DEFUN([AX_C_PICFLAG], [AC_MSG_CHECKING([for flag to make position independent code]) PICFLAG=-fPIC case "${host}" in *-*-cygwin*) PICFLAG= ;; *-*-mingw*) PICFLAG= ;; *-*-hpux*) PICFLAG=+z ;; *-*-solaris*) if test ${using_sunpro_c} = 1 then PICFLAG=-G fi ;; esac AC_SUBST(PICFLAG) AC_MSG_RESULT($PICFLAG) ])# AX_C_PICFLAG # AX_LD_RDYNAMIC # -------------- # The -rdynamic flag is used by iverilog when compiling the target, # to know how to export symbols of the main program to loadable modules # that are brought in by -ldl AC_DEFUN([AX_LD_RDYNAMIC], [AC_MSG_CHECKING([for -rdynamic compiler flag]) rdynamic=-rdynamic case "${host}" in *-*-netbsd*) rdynamic="-Wl,--export-dynamic" ;; *-*-openbsd*) rdynamic="-Wl,--export-dynamic" ;; *-*-solaris*) rdynamic="" ;; *-*-cygwin*) rdynamic="" ;; *-*-mingw*) rdynamic="" ;; *-*-hpux*) rdynamic="-E" ;; *-*-darwin*) rdynamic="-Wl,-all_load" strip_dynamic="-SX" ;; esac AC_SUBST(rdynamic) AC_MSG_RESULT($rdynamic) AC_SUBST(strip_dynamic) # since we didn't tell them we're "checking", no good place to tell the answer # AC_MSG_RESULT($strip_dynamic) ])# AX_LD_RDYNAMIC # AX_CPP_PRECOMP # -------------- AC_DEFUN([AX_CPP_PRECOMP], [# Darwin requires -no-cpp-precomp case "${host}" in *-*-darwin*) CPPFLAGS="-no-cpp-precomp $CPPFLAGS" CFLAGS="-no-cpp-precomp $CFLAGS" ;; esac ])# AX_CPP_PRECOMP # AX_C99_STRTOD # ------------- AC_DEFUN([AX_C99_STRTOD], [# On MinGW we need to jump through hoops to get a C99 compliant strtod(). case "${host}" in *-*-mingw*) LDFLAGS+=" -Wl,--undefined=___strtod,--wrap,strtod,--defsym,___wrap_strtod=___strtod" ;; esac ])# AX_C99_STRTOD # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp file name are based on the header name. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [ _config_header=$1 _stamp_name=stamp-`expr //$_config_header : '.*/\([[^./]]*\)\.[[^./]]*$'`-h echo "timestamp for $_config_header" > `AS_DIRNAME(["$_config_header"])`/[]$_stamp_name ]) #_AC_AM_CONFIG_HEADER_HOOK verilog-0.9.7/PaxHeaders.14238/veriuser.h0000644000202500001440000000005012204466647016245 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/veriuser.h0000644000202500001440000002644512204466647015602 0ustar00steveusers00000000000000#ifndef __veriuser_H #define __veriuser_H /* * Copyright (c) 2002-2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * This header file contains the definitions and declarations needed * by an Icarus Verilog user using tf_ routines. * * NOTE 1: Icarus Verilog does not directly support tf_ routines. This * header file defines a tf_ compatibility later. The functions that * are implemented here are actually implemented using VPI routines. * * NOTE 2: The routines and definitions of the tf_ library were * clearly not designed to account for C++, or even ANSI-C. This * header file attempts to fix these problems in a source code * compatible way. In the end, though, it is not completely * possible. Instead, users should not use this or the acc_user.h * header files or functions in new applications, and instead use the * more modern vpi_user.h and VPI functions. * * This API is provided by Icarus Verilog only to support legacy software. */ #ifdef __cplusplus # define EXTERN_C_START extern "C" { # define EXTERN_C_END } #else # define EXTERN_C_START # define EXTERN_C_END #endif #ifndef __GNUC__ # undef __attribute__ # define __attribute__(x) #endif EXTERN_C_START # include "_pli_types.h" /* * defines for tf_message */ #define ERR_MESSAGE 1 #define ERR_WARNING 2 #define ERR_ERROR 3 #define ERR_INTERNAL 4 #define ERR_SYSTEM 5 /* * These are some defines for backwards compatibility. They should not * be used in new code. */ #ifndef TRUE # define TRUE 1 #endif #ifndef FALSE # define FALSE 0 #endif #ifndef __cplusplus # ifndef true # define true 1 # endif # ifndef false # define false 0 # endif # ifndef bool # define bool int # endif #endif /* * structure for veriusertfs array */ typedef struct t_tfcell { short type; /* usertask|userfunction|userrealfunction */ short data; /* data passed to user routine */ int (*checktf)(int user_data, int reason); int (*sizetf)(int user_data, int reason); int (*calltf)(int user_data, int reason); int (*misctf)(int user_data, int reason, int paramvc); char *tfname; /* name of the system task/function */ int forwref; /* usually set to 1 */ char *tfveritool; /* usually ignored */ char *tferrmessage; /* usually ignored */ char reserved[20]; /* reserved */ } s_tfcell, *p_tfcell; /* * Normal PLI1.0 modules export a veriusertfs array that contains all * the function definitions for use by the simulator. The user code is * expected to supply that array. The method of export varies amongst * Verilog simulators, but at least one vendor gets a pointer to the * veriusertfs array by calling a boot function that takes no * arguments and returns a pointer to the table. * * The Icarus Verilog bootstrap process is a little bit different, and * is described in the vpi_user.h header file. However, a fairly * simple adaptation to your application fixes it so that it * automatically boots with Icarus Verilog. * * The trick is to write a vlog_startup_routine that calls the * veriusertfs_register_table function. A simple example: * * static struct s_tfcell my_veriusertfs_table[] = { * [... table entries, null terminated ...] * }; * * // Cadence compatibility * struct s_tfcell* my_bootstrap(void) * { return my_veriusertfs_table; } * * // Icarus Verilog compatibility * static void veriusertfs_register(void) * { * veriusertfs_register_table(my_veriusertfs_table); * } * void (*vlog_startup_routines[])() = { &veriusertfs_register, 0 }; * * The veriusertfs_register function and vlog_startup_routines table * are specific to Icarus Verilog, and arrange for automatic loading * of the PLI1 application. The vvp program will treat this as any * other VPI module. * * By structuring the bootstrap process in this manner, it is * plausible to make source code compatibility with a variety of * Verilog simulators. * * NOTE: The cadpli module of Icarus Verilog also makes it possible to * be *binary* compatible with other simulators. Create the * my_bootstrap function and leave out the vlog_startup_routines, then * use the "-mcadpli" module to load it in compatibility mode. */ extern s_tfcell veriusertfs[]; extern void veriusertfs_register_table(p_tfcell vtable); #define usertask 1 #define userfunction 2 #define userrealfunction 3 /* callback reasons */ #define reason_checktf 1 #define reason_calltf 3 #define reason_paramvc 7 #define reason_synch 8 #define REASON_SYNCH reason_synch #define reason_finish 9 #define reason_reactivate 10 #define REASON_REACTIVATE reason_reactivate #define reason_rosynch 11 #define REASON_ROSYNCH reason_rosynch #define reason_endofcompile 16 /* These are values returned by tf_typep */ #define tf_nullparam 0 #define TF_NULLPARAM tf_nullparam #define tf_string 1 #define TF_STRING tf_string #define tf_readonly 10 #define TF_READONLY tf_readonly #define tf_readwrite 11 #define TF_READWRITE tf_readwrite #define tf_rwbitselect 12 #define TF_RWBITSELECT tf_rwbitselect #define tf_rwpartselect 13 #define TF_RWPARTSELECT tf_rwpartselect #define tf_rwmemselect 14 #define TF_RWMEMSELECT tf_rwmemselect #define tf_readonlyreal 15 #define TF_READONLYREAL tf_readonlyreal #define tf_readwritereal 16 #define TF_READWRITEREAL tf_readwritereal typedef struct t_tfnodeinfo { PLI_INT16 node_type; PLI_INT16 padding; union { struct t_vecval *vecval_p; struct t_strengthval *strengthval_p; PLI_BYTE8 *memoryval_p; double *read_value_p; } node_value; char* node_symbol; PLI_INT32 node_ngroups; PLI_INT32 node_vec_size; PLI_INT32 node_sign; PLI_INT32 node_ms_index; PLI_INT32 node_ls_index; PLI_INT32 node_mem_size; PLI_INT32 node_lhs_element; PLI_INT32 node_rhs_element; PLI_INT32*node_handle; } s_tfnodeinfo, *p_tfnodeinfo; /* values used in the node_type of the tfnodeinfo structure. */ #define tf_null_node 100 #define TF_NULL_NODE tf_null_node #define tf_reg_node 101 #define TF_REG_NODE tf_reg_node #define tf_integer_node 102 #define TF_INTEGER_NODE tf_integer_node #define tf_time_node 103 #define TF_TIME_NODE tf_time_node #define tf_netvector_node 104 #define TF_NETVECTOR_NODE tf_netvector_node #define tf_netscalar_node 105 #define TF_NETSCALAR_NODE tf_netscalar_node #define tf_memory_node 106 #define TF_MEMORY_NODE tf_memory_node #define tf_real_node 107 #define TF_REAL_NODE tf_real_node /* Structure used by the tf_exprinfo function. */ typedef struct t_tfexprinfo { PLI_INT16 expr_type; PLI_INT16 padding; struct t_vecval*expr_value_p; double real_value; char*expr_string; PLI_INT32 expr_ngroups; PLI_INT32 expr_vec_size; PLI_INT32 expr_sign; PLI_INT32 expr_lhs_select; PLI_INT32 expr_rhs_select; } s_tfexprinfo, *p_tfexprinfo; /* Extern functions from the library. */ extern void io_printf (const char *, ...) __attribute__((format (printf,1,2))); extern char* mc_scan_plusargs(char*plusarg); extern int tf_asynchoff(void); extern int tf_asynchon(void); extern int tf_dofinish(void); extern int tf_dostop(void); extern void tf_error(const char*, ...) __attribute__((format (printf,1,2))); extern struct t_tfexprinfo* tf_exprinfo(PLI_INT32 a, struct t_tfexprinfo*ip); extern char* tf_getcstringp(int nparam); extern PLI_BYTE8* tf_getinstance(void); extern int tf_getlongp(int*aof_highvalue, int pnum); extern PLI_INT32 tf_getp(PLI_INT32); extern PLI_INT32 tf_igetp(PLI_INT32, void*); extern double tf_getrealp(PLI_INT32); extern double tf_igetrealp(PLI_INT32, void*); extern char *tf_strgetp(PLI_INT32, PLI_INT32); extern char *tf_istrgetp(PLI_INT32, PLI_INT32, void*); extern char *tf_strgettime(void); extern PLI_INT32 tf_gettime(void); extern PLI_INT32 tf_getlongtime(PLI_INT32*); extern PLI_INT32 tf_igetlongtime(PLI_INT32*, void*); extern void tf_scale_longdelay(void*,PLI_INT32,PLI_INT32,PLI_INT32*,PLI_INT32*); extern void tf_unscale_longdelay(void*,PLI_INT32,PLI_INT32,PLI_INT32*,PLI_INT32*); extern void tf_scale_realdelay(void*,double,double*); extern void tf_unscale_realdelay(void*,double,double*); extern PLI_INT32 tf_gettimeprecision(void); extern PLI_INT32 tf_igettimeprecision(void*); extern PLI_INT32 tf_gettimeunit(void); extern PLI_INT32 tf_igettimeunit(void*); extern PLI_BYTE8* tf_getworkarea(void); extern PLI_INT32 tf_message(PLI_INT32 level, char*facility, char*messno, char*fmt, ...) __attribute__((format (printf,4,5))); extern void tf_multiply_long(PLI_INT32*aof_low1, PLI_INT32*aof_high1, PLI_INT32 aof_low2, PLI_INT32 aof_high2); extern void tf_real_to_long(double real, PLI_INT32*low, PLI_INT32*high); extern void tf_long_to_real(PLI_INT32 low, PLI_INT32 high, double *real); extern PLI_INT32 tf_nump(void); extern PLI_INT32 tf_inump(void*); /* IEEE1364 NOTE: tf_putlongp is listed as returning in in the header file shown in the standard, but as returning void in the detailed description of the function. So I call it void. */ extern void tf_putlongp(int pnum, int lowvalue, int highvalue); extern PLI_INT32 tf_putp(PLI_INT32, PLI_INT32); extern PLI_INT32 tf_iputp(PLI_INT32, PLI_INT32, void*); extern PLI_INT32 tf_putrealp(PLI_INT32, double); extern PLI_INT32 tf_iputrealp(PLI_INT32, double, void*); /* Activate the misctf function after a delay. The units are of the current scope. The tf_isetdelay variant specifies a particular system task instance to use as the context for the units. tf_getinstance gets that value. */ extern int tf_setdelay(PLI_INT32 delay); extern int tf_isetdelay(PLI_INT32 delay, void* sys); /* IEEE1364 NOTE: tf_setworkarea is listed as taking a PLI_BYTE8*, but that is silly, it really takes any kind of pointer. Taking void* is compatible with those who pass a PLI_BYTE8*. */ extern PLI_INT32 tf_setworkarea(void*workarea); /* Return the complete, hierarchical name of the current scope. The current scope is the scope containing the currently running system task call. */ extern char* tf_spname(void); extern char* tf_mipname(void); extern char* tf_imipname(void*); extern PLI_INT32 tf_synchronize(void); extern PLI_INT32 tf_isynchronize(void* sys); extern PLI_INT32 tf_rosynchronize(void); extern PLI_INT32 tf_irosynchronize(void* sys); extern PLI_INT32 tf_setrealdelay(double realdelay); extern PLI_INT32 tf_isetrealdelay(double realdelay, void*inst); extern PLI_INT32 tf_typep(PLI_INT32 narg); extern void tf_warning(const char*, ...) __attribute__((format (printf,1,2))); EXTERN_C_END #endif verilog-0.9.7/PaxHeaders.14238/symbol_search.cc0000644000202500001440000000005012204466647017371 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/symbol_search.cc0000644000202500001440000000532312204466647016716 0ustar00steveusers00000000000000/* * Copyright (c) 2003-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "netlist.h" # include "netmisc.h" # include /* * Search for the hierarchical name. */ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope, pform_name_t path, NetNet*&net, const NetExpr*&par, NetEvent*&eve, const NetExpr*&ex1, const NetExpr*&ex2) { assert(scope); bool hier_path = false; /* Get the tail name of the object we are looking for. */ perm_string key = peek_tail_name(path); path.pop_back(); /* Initialize output argument to cleared. */ net = 0; par = 0; eve = 0; /* If the path has a scope part, then search for the specified scope that we are supposed to search. */ if (! path.empty()) { list path_list = eval_scope_path(des, scope, path); assert(path_list.size() <= path.size()); // If eval_scope_path returns a short list, then some // part of the scope was not found. Abort. if (path_list.size() < path.size()) return 0; scope = des->find_scope(scope, path_list); if (scope && scope->is_auto() && li) { cerr << li->get_fileline() << ": error: Hierarchical " "reference to automatically allocated item " "`" << key << "' in path `" << path << "'" << endl; des->errors += 1; } hier_path = true; } while (scope) { if ( (net = scope->find_signal(key)) ) return scope; if ( (eve = scope->find_event(key)) ) return scope; if ( (par = scope->get_parameter(key, ex1, ex2)) ) return scope; /* We can't look up if we are at the enclosing module scope * or if a hierarchical path was given. */ if ((scope->type() == NetScope::MODULE) || hier_path) scope = 0; else scope = scope->parent(); } return 0; } verilog-0.9.7/PaxHeaders.14238/netlist.h0000644000202500001440000000005012204466647016063 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/netlist.h0000644000202500001440000035247312204466647015423 0ustar00steveusers00000000000000#ifndef __netlist_H #define __netlist_H /* * Copyright (c) 1998-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * The netlist types, as described in this header file, are intended * to be the output from elaboration of the source design. The design * can be passed around in this form to the various stages and design * processors. */ # include # include # include # include # include # include # include "ivl_target.h" # include "ivl_target_priv.h" # include "pform_types.h" # include "config.h" # include "verinum.h" # include "verireal.h" # include "StringHeap.h" # include "HName.h" # include "LineInfo.h" # include "svector.h" # include "Attrib.h" #ifdef HAVE_IOSFWD # include #else class ostream; #endif class Design; class Link; class Nexus; class NetEvent; class NetNet; class NetNode; class NetObj; class NetPins; class NetProc; class NetProcTop; class NetRelease; class NetScope; class NetEvProbe; class NetExpr; class NetEAccess; class NetESignal; class NetFuncDef; class NetRamDq; class NetTaskDef; class NetEvTrig; class NetEvWait; struct target; struct functor_t; ostream& operator << (ostream&o, ivl_variable_type_t val); extern void join_island(NetPins*obj); class Link { friend void connect(Link&, Link&); friend void connect(Nexus*, Link&); friend class NetPins; friend class Nexus; public: enum DIR { PASSIVE, INPUT, OUTPUT }; enum strength_t { HIGHZ, WEAK, PULL, STRONG, SUPPLY }; private: // Only NetPins can create/delete Link objects Link(); ~Link(); public: // Manipulate the link direction. void set_dir(DIR d); DIR get_dir() const; // Set the delay for all the drivers to this nexus. void drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay); // A link has a drive strength for 0 and 1 values. The drive0 // strength is for when the link has the value 0, and drive1 // strength is for when the link has a value 1. void drive0(strength_t); void drive1(strength_t); // This sets the drives for all drivers of this link, and not // just the current link. void drivers_drive(strength_t d0, strength_t d1); strength_t drive0() const; strength_t drive1() const; // A link has an initial value that is used by the nexus to // figure out its initial value. Normally, only the object // that contains the link sets the initial value, and only the // attached Nexus gets it. The default link value is Vx. void set_init(verinum::V val); verinum::V get_init() const; void cur_link(NetPins*&net, unsigned &pin); void cur_link(const NetPins*&net, unsigned &pin) const; // Get a pointer to the nexus that represents all the links // connected to me. Nexus* nexus(); const Nexus* nexus()const; // Return a pointer to the next link in the nexus. Link* next_nlink(); const Link* next_nlink() const; // Remove this link from the set of connected pins. The // destructor will automatically do this if needed. void unlink(); // Return true if this link is connected to anything else. bool is_linked() const; // Return true if these pins are connected. bool is_linked(const Link&that) const; // Return true if this is the same pin of the same object of // that link. bool is_equal(const Link&that) const; // Return information about the object that this link is // a part of. const NetPins*get_obj() const; NetPins*get_obj(); unsigned get_pin() const; private: // The NetNode manages these. They point back to the // NetNode so that following the links can get me here. union { NetPins *node_; unsigned pin_; }; bool pin_zero_ : 1; DIR dir_ : 2; strength_t drive0_ : 3; strength_t drive1_ : 3; verinum::V init_ : 2; private: // The Nexus uses these to maintain a single linked list of // Link objects. If this link is not connected to anything, // then these pointers are nil. Link *next_; Nexus*nexus_; private: // not implemented Link(const Link&); Link& operator= (const Link&); }; class NetPins : public LineInfo { public: explicit NetPins(unsigned npins); virtual ~NetPins(); unsigned pin_count() const { return npins_; } Link&pin(unsigned idx); const Link&pin(unsigned idx) const; void dump_node_pins(ostream&, unsigned, const char**pin_names =0) const; void set_default_dir(Link::DIR d); void set_default_init(verinum::V val); bool is_linked(); bool pins_are_virtual(void) const; void devirtualize_pins(void); private: Link*pins_; const unsigned npins_; Link::DIR default_dir_; verinum::V default_init_; }; /* ========= * A NetObj is anything that has any kind of behavior in the * netlist. Nodes can be gates, registers, etc. and are linked * together to form a design web. * * The web of nodes that makes up a circuit is held together by the * Link class. There is a link for each pin. All mutually connected * pins form a ring of links. * * A link can be INPUT, OUTPUT or PASSIVE. An input never drives the * signal, and PASSIVE never receives the value of the signal. Wires * are PASSIVE, for example. * * A NetObj also has delays specified as rise_time, fall_time and * decay_time. The rise and fall time are the times to transition to 1 * or 0 values. The decay_time is the time needed to decay to a 'bz * value, or to decay of the net is a trireg. The exact and precise * interpretation of the rise/fall/decay times is typically left to * the target to properly interpret. */ class NetObj : public NetPins, public Attrib { public: public: // The name of the object must be a permallocated string. A // lex_strings string, for example. explicit NetObj(NetScope*s, perm_string n, unsigned npins); virtual ~NetObj(); NetScope* scope(); const NetScope* scope() const; perm_string name() const { return name_; } const NetExpr* rise_time() const { return delay1_; } const NetExpr* fall_time() const { return delay2_; } const NetExpr* decay_time() const { return delay3_; } void rise_time(const NetExpr* d) { delay1_ = d; } void fall_time(const NetExpr* d) { delay2_ = d; } void decay_time(const NetExpr* d) { delay3_ = d; } void dump_obj_attr(ostream&, unsigned) const; private: NetScope*scope_; perm_string name_; const NetExpr* delay1_; const NetExpr* delay2_; const NetExpr* delay3_; }; /* * Objects that can be island branches are derived from this. (It is * possible for an object to be a NetObj and an IslandBranch.) This is * used to collect island information about the node. */ class IslandBranch { public: IslandBranch(ivl_discipline_t dis =0) : island_(0), discipline_(dis) { } ivl_island_t get_island() const { return island_; } friend void join_island(NetPins*); private: ivl_island_t island_; ivl_discipline_t discipline_; }; /* * A NetBranch is a construct of Verilog-A that is a branch between * two nodes. The branch has exactly 2 pins and a discipline. * * pin(0) is the source of flow through a branch and the plus side of * potential. Pin(1) is the sink of flow and the minus (or ground) of * potential. */ class NetBranch : public NetPins, public IslandBranch { public: explicit NetBranch(ivl_discipline_t dis); explicit NetBranch(ivl_discipline_t dis, perm_string name); ~NetBranch(); // If the branch is named, this returns the name. perm_string name() const { return name_; } ivl_branch_s* target_obj() const { return &target_obj_; } void dump(ostream&, unsigned) const; private: perm_string name_; mutable ivl_branch_s target_obj_; // The design class uses this member to list the branches. friend class Design; NetBranch*next_; }; /* * The Nexus represents a collection of links that are joined * together. Each link has its own properties, this class holds the * properties of the group. * * The links in a nexus are grouped into a singly linked list, with * the nexus pointing to the first Link. Each link in turn points to * the next link in the nexus, with the last link pointing to 0. * * The t_cookie() is a void* that targets can use to store information * in a Nexus. ivl guarantees that the t_cookie will be 0 when the * target is invoked. */ class Nexus { friend void connect(Link&, Link&); friend void connect(Nexus*, Link&); friend class Link; public: explicit Nexus(); ~Nexus(); const char* name() const; verinum::V get_init() const; void drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay); void drivers_drive(Link::strength_t d0, Link::strength_t d1); Link*first_nlink(); const Link* first_nlink()const; /* Get the width of the Nexus, or 0 if there are no vectors (in the form of NetNet objects) linked. */ unsigned vector_width() const; NetNet* pick_any_net(); /* This method returns true if there are any assignments that use this nexus as an l-value. This can be true if the nexus is a variable, but also if this is a net with a force. */ bool assign_lval() const; /* This method returns true if there are any drivers (including variables) attached to this nexus. */ bool drivers_present() const; /* This method returns true if all the possible drivers of this nexus are constant. It will also return true if there are no drivers at all. */ bool drivers_constant() const; /* Given the nexus has constant drivers, this method returns the value that has been driven. */ verinum::V driven_value() const; ivl_nexus_t t_cookie() const; ivl_nexus_t t_cookie(ivl_nexus_t) const; private: Link*list_; void unlink(Link*); void relink(Link*); mutable char* name_; /* Cache the calculated name for the Nexus. */ mutable ivl_nexus_t t_cookie_; enum VALUE { NO_GUESS, V0, V1, Vx, Vz, VAR }; mutable VALUE driven_; private: // not implemented Nexus(const Nexus&); Nexus& operator= (const Nexus&); }; class NexusSet { public: ~NexusSet(); NexusSet(); unsigned count() const; // Add the nexus to the set, if it is not already present. void add(Nexus*that); void add(const NexusSet&that); // Remove the nexus from the set, if it is present. void rem(Nexus*that); void rem(const NexusSet&that); Nexus* operator[] (unsigned idx) const; // Return true if this set contains every nexus in that set. bool contains(const NexusSet&that) const; // Return true if this set contains any nexus in that set. bool intersect(const NexusSet&that) const; private: Nexus**items_; unsigned nitems_; unsigned bsearch_(Nexus*that) const; private: // not implemented NexusSet(const NexusSet&); NexusSet& operator= (const NexusSet&); }; /* * A NetBus is a transparent device that is merely a bunch of pins * used to tie some pins to. It is a convenient way to collect a * bundle of pins and pass that bundle around. */ class NetBus : public NetObj { public: NetBus(NetScope*scope, unsigned pin_count); ~NetBus(); private: // not implemented NetBus(const NetBus&); NetBus& operator= (const NetBus&); }; /* * A NetNode is a device of some sort, where each pin has a different * meaning. (i.e., pin(0) is the output to an and gate.) NetNode * objects are listed in the nodes_ of the Design object. */ class NetNode : public NetObj { public: // The name parameter must be a permallocated string. explicit NetNode(NetScope*s, perm_string n, unsigned npins); virtual ~NetNode(); virtual bool emit_node(struct target_t*) const; virtual void dump_node(ostream&, unsigned) const; // This is used to scan a modifiable netlist, one node at a time. virtual void functor_node(Design*, functor_t*); private: friend class Design; NetNode*node_next_, *node_prev_; Design*design_; }; /* * A NetDelaySrc is an input-only device that calculates a path delay * based on the time that the inputs change. This class is used by the * NetNet class, and NetDelaySrc objects cannot exist outside of its * association with NetNet objects. */ class NetDelaySrc : public NetObj { public: explicit NetDelaySrc(NetScope*s, perm_string n, unsigned nsrc, bool condit_src, bool conditional); ~NetDelaySrc(); // These functions set the delays from the values in the // source. These set_delays functions implement the various // rules wrt collections of transitions. // One transition specified. void set_delays(uint64_t del); // Two transitions: rise and fall void set_delays(uint64_t rise, uint64_t fall); // Three transitions void set_delays(uint64_t rise, uint64_t fall, uint64_t tz); void set_delays(uint64_t t01, uint64_t t10, uint64_t t0z, uint64_t tz1, uint64_t t1z, uint64_t tz0); void set_delays(uint64_t t01, uint64_t t10, uint64_t t0z, uint64_t tz1, uint64_t t1z, uint64_t tz0, uint64_t t0x, uint64_t tx1, uint64_t t1x, uint64_t tx0, uint64_t txz, uint64_t tzx); uint64_t get_delay(unsigned pe) const; void set_posedge(); void set_negedge(); bool is_posedge() const; bool is_negedge() const; unsigned src_count() const; Link&src_pin(unsigned); const Link&src_pin(unsigned) const; bool is_condit() const; bool has_condit() const; Link&condit_pin(); const Link&condit_pin() const; void dump(ostream&, unsigned ind) const; private: uint64_t transition_delays_[12]; bool condit_flag_; bool conditional_; bool posedge_; bool negedge_; private: // Not implemented NetDelaySrc(const NetDelaySrc&); NetDelaySrc& operator= (const NetDelaySrc&); }; /* * NetNet is a special kind of NetObj that doesn't really do anything, * but carries the properties of the wire/reg/trireg, including its * name. Scalars and vectors are all the same thing here, a NetNet * with a single pin. The difference between a scalar and vector is * the width of the atomic vector datum it carries. * * NetNet objects can also appear as side effects of synthesis or * other abstractions. * * Note that INTEGER types are an alias for a ``reg signed [31:0]''. * * NetNet objects have a name and exist within a scope, so the * constructor takes a pointer to the containing scope. The object * automatically adds itself to the scope. * * NetNet objects are located by searching NetScope objects. * * The pin of a NetNet object are PASSIVE: they do not drive * anything and they are not a data sink, per se. The pins follow the * values on the nexus. */ class NetNet : public NetObj { public: enum Type { NONE, IMPLICIT, IMPLICIT_REG, INTEGER, WIRE, TRI, TRI1, SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG, UWIRE }; enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT }; // The width in this case is a shorthand for ms=width-1 and // ls=0. Only one pin is created, the width is of the vector // that passed through. explicit NetNet(NetScope*s, perm_string n, Type t, unsigned width =1); // This form supports an array of vectors. The [ms:ls] define // the base vector, and the [s0:e0] define the array // dimensions. If s0==e0, then this is not an array after // all. explicit NetNet(NetScope*s, perm_string n, Type t, long ms, long ls); explicit NetNet(NetScope*s, perm_string n, Type t, long ms, long ls, long s0, long e0); virtual ~NetNet(); Type type() const; void type(Type t); PortType port_type() const; void port_type(PortType t); ivl_variable_type_t data_type() const; void data_type(ivl_variable_type_t t); /* If a NetNet is signed, then its value is to be treated as signed. Otherwise, it is unsigned. */ bool get_signed() const; void set_signed(bool); /* Used to maintain original type of net since integers are implemented as 'reg signed [31:0]' in Icarus */ bool get_isint() const; void set_isint(bool); bool get_scalar() const; void set_scalar(bool); /* Attach a discipline to the net. */ ivl_discipline_t get_discipline() const; void set_discipline(ivl_discipline_t dis); /* These methods return the msb and lsb indices for the most significant and least significant bits. These are signed longs, and may be different from pin numbers. For example, reg [1:8] has 8 bits, msb==1 and lsb==8. */ long msb() const; long lsb() const; unsigned long vector_width() const; /* This method converts a signed index (the type that might be found in the Verilog source) to a pin number. It accounts for variation in the definition of the reg/wire/whatever. */ long sb_to_idx(long sb) const; /* This method checks that the signed index is valid for this signal. If it is, the above sb_to_idx can be used to get the pin# from the index. */ bool sb_is_valid(long sb) const; /* This method returns 0 for scalars and vectors, and greater for arrays. The value is the number of array indices. (Currently only one array index is supported.) */ unsigned array_dimensions() const; long array_first() const; bool array_addr_swapped() const; // This is the number of array elements. unsigned array_count() const; // This method returns a 0 based address of an array entry as // indexed by idx. The Verilog source may give index ranges // that are not zero based. bool array_index_is_valid(long idx) const; unsigned array_index_to_address(long idx) const; bool local_flag() const { return local_flag_; } void local_flag(bool f) { local_flag_ = f; } /* NetESignal objects may reference this object. Keep a reference count so that I keep track of them. */ void incr_eref(); void decr_eref(); unsigned peek_eref() const; /* Assignment statements count their lrefs here. */ void incr_lref(); void decr_lref(); unsigned peek_lref() const; unsigned get_refs() const; /* Manage path delays */ void add_delay_path(class NetDelaySrc*path); unsigned delay_paths(void) const; const class NetDelaySrc*delay_path(unsigned idx) const; virtual void dump_net(ostream&, unsigned) const; void initialize_value_and_dir(verinum::V init_value, Link::DIR dir); private: Type type_; PortType port_type_; ivl_variable_type_t data_type_; bool signed_; bool isint_; // original type of integer bool is_scalar_; ivl_discipline_t discipline_; long msb_, lsb_; const unsigned dimensions_; long s0_, e0_; bool local_flag_; unsigned eref_count_; unsigned lref_count_; vector delay_paths_; }; /* * This object type is used to contain a logical scope within a * design. The scope doesn't represent any executable hardware, but is * just a handle that netlist processors can use to grab at the design. */ class NetScope : public Attrib { public: enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK }; /* Create a new scope, and attach it to the given parent. The name is expected to have been permallocated. */ NetScope(NetScope*up, const hname_t&name, TYPE t); ~NetScope(); /* Rename the scope using the name generated by inserting as many pad characters as required between prefix and suffix to make the name unique in the parent scope. Return false if a unique name couldn't be generated. */ bool auto_name(const char* prefix, char pad, const char* suffix); /* Parameters exist within a scope, and these methods allow one to manipulate the set. In these cases, the name is the *simple* name of the parameter, the hierarchy is implicit in the scope. The return value from set_parameter is the previous expression, if there was one. */ struct range_t; NetExpr* set_parameter(perm_string name, NetExpr*val, ivl_variable_type_t type, NetExpr*msb, NetExpr*lsb, bool signed_flag, NetScope::range_t*range_list, const LineInfo&file_line); NetExpr* set_localparam(perm_string name, NetExpr*val, const LineInfo&file_line); const NetExpr*get_parameter(const char* name, const NetExpr*&msb, const NetExpr*&lsb) const; /* These are used by defparam elaboration to replace the expression with a new expression, without affecting the range or signed_flag. Return false if the name does not exist. */ bool replace_parameter(perm_string name, NetExpr*val); /* These methods set or access events that live in this scope. */ void add_event(NetEvent*); void rem_event(NetEvent*); NetEvent*find_event(perm_string name); /* These methods add or find a genvar that lives in this scope. */ void add_genvar(perm_string name, LineInfo *li); LineInfo* find_genvar(perm_string name); /* These methods manage signals. The add_ and rem_signal methods are used by the NetNet objects to make themselves available to the scope, and the find_signal method can be used to locate signals within a scope. */ void add_signal(NetNet*); void rem_signal(NetNet*); NetNet* find_signal(perm_string name); /* The parent and child() methods allow users of NetScope objects to locate nearby scopes. */ NetScope* parent(); NetScope* child(const hname_t&name); const NetScope* parent() const; const NetScope* child(const hname_t&name) const; TYPE type() const; void print_type(ostream&) const; void set_task_def(NetTaskDef*); void set_func_def(NetFuncDef*); void set_module_name(perm_string); NetTaskDef* task_def(); NetFuncDef* func_def(); void set_line(perm_string file, perm_string def_file, unsigned lineno, unsigned def_lineno); void set_line(perm_string file, unsigned lineno); void set_line(const LineInfo *info); perm_string get_file() const { return file_; }; perm_string get_def_file() const { return def_file_; }; unsigned get_lineno() const { return lineno_; }; unsigned get_def_lineno() const { return def_lineno_; }; bool in_func(); /* Is the task or function automatic. */ void is_auto(bool is_auto__) { is_auto_ = is_auto__; }; bool is_auto() const { return is_auto_; }; /* Is the module a cell (is in a `celldefine) */ void is_cell(bool is_cell__) { is_cell_ = is_cell__; }; bool is_cell() const { return is_cell_; }; const NetTaskDef* task_def() const; const NetFuncDef* func_def() const; /* If the scope represents a module instance, the module_name is the name of the module itself. */ perm_string module_name() const; /* Scopes have their own time units and time precision. The unit and precision are given as power of 10, i.e., -3 is units of milliseconds. If a NetScope is created with a parent scope, the new scope will initially inherit the unit and precision of the parent scope. */ void time_unit(int); void time_precision(int); void time_from_timescale(bool); int time_unit() const; int time_precision() const; bool time_from_timescale() const; void default_nettype(NetNet::Type); NetNet::Type default_nettype() const; /* The fullname of the scope is the hierarchical name component (which includes the name and array index) whereas the basename is just my name. */ perm_string basename() const; const hname_t& fullname() const { return name_; } void run_defparams(class Design*); void run_defparams_later(class Design*); void evaluate_parameters(class Design*); // Look for defparams that never matched, and print warnings. void residual_defparams(class Design*); /* This method generates a non-hierarchical name that is guaranteed to be unique within this scope. */ perm_string local_symbol(); void dump(ostream&) const; void emit_scope(struct target_t*tgt) const; bool emit_defs(struct target_t*tgt) const; /* This method runs the functor on me. Recurse through the children of this node as well. */ void run_functor(Design*des, functor_t*fun); /* This member is used during elaboration to pass defparam assignments from the scope pass to the parameter evaluation step. After that, it is not used. */ list > defparams; list,NetExpr*> > defparams_later; public: struct range_t { bool exclude_flag; // Lower bound bool low_open_flag; NetExpr*low_expr; // Upper bound bool high_open_flag; NetExpr*high_expr; // Link to the next range specification struct range_t*next; }; /* After everything is all set up, the code generators like access to these things to make up the parameter lists. */ struct param_expr_t : public LineInfo { param_expr_t() : type(IVL_VT_NO_TYPE), signed_flag(false), msb(0), lsb(0), range(0), expr(0) { } // Type information ivl_variable_type_t type; bool signed_flag; NetExpr*msb; NetExpr*lsb; // range constraints struct range_t*range; // Expression value NetExpr*expr; }; mapparameters; maplocalparams; typedef map::iterator param_ref_t; param_ref_t find_parameter(perm_string name); struct spec_val_t { ivl_variable_type_t type; union { double real_val; // type == IVL_VT_REAL long integer; // type == IVL_VT_BOOL }; }; mapspecparams; /* Module instance arrays are collected here for access during the multiple elaboration passes. */ typedef vector scope_vec_t; mapinstance_arrays; /* Loop generate uses this as scratch space during elaboration. Expression evaluation can use this to match names. */ perm_string genvar_tmp; long genvar_tmp_val; private: void evaluate_parameter_logic_(Design*des, param_ref_t cur); void evaluate_parameter_real_(Design*des, param_ref_t cur); private: TYPE type_; hname_t name_; perm_string file_; perm_string def_file_; unsigned lineno_; unsigned def_lineno_; signed char time_unit_, time_prec_; bool time_from_timescale_; NetNet::Type default_nettype_; NetEvent *events_; map genvars_; typedef std::map::const_iterator signals_map_iter_t; std::map signals_map_; perm_string module_name_; union { NetTaskDef*task_; NetFuncDef*func_; }; NetScope*up_; NetScope*sib_; NetScope*sub_; unsigned lcounter_; bool is_auto_, is_cell_; }; /* * This class implements the LPM_ABS component. The node has a single * input, a signed expression, that it converts to the absolute * value. The gate is simple: pin(0) is the output and pin(1) is the input. */ class NetAbs : public NetNode { public: NetAbs(NetScope*s, perm_string n, unsigned width); ~NetAbs(); unsigned width() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*des, functor_t*fun); private: unsigned width_; }; /* * This class implements the LPM_ADD_SUB component as described in the * EDIF LPM Version 2 1 0 standard. It is used as a structural * implementation of the + and - operators. */ class NetAddSub : public NetNode { public: NetAddSub(NetScope*s, perm_string n, unsigned width); ~NetAddSub(); // Get the width of the device (that is, the width of the // operands and results). unsigned width() const; Link& pin_Cout(); Link& pin_DataA(); Link& pin_DataB(); Link& pin_Result(); const Link& pin_Cout() const; const Link& pin_DataA() const; const Link& pin_DataB() const; const Link& pin_Result() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*des, functor_t*fun); private: unsigned width_; }; /* * The NetArrayDq node represents an array dereference. The NetNet * that this object refers to is an array, and the Address pin selects * which word of the array to place on the Result. */ class NetArrayDq : public NetNode { public: NetArrayDq(NetScope*s, perm_string name, NetNet*mem, unsigned awid); ~NetArrayDq(); unsigned width() const; unsigned awidth() const; unsigned size() const; const NetNet*mem() const; Link& pin_Address(); Link& pin_Result(); const Link& pin_Address() const; const Link& pin_Result() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; private: NetNet*mem_; unsigned awidth_; }; /* * Convert an IVL_VT_REAL input to a logical value with the * given width. The input is pin(1) and the output is pin(0). */ class NetCastInt : public NetNode { public: NetCastInt(NetScope*s, perm_string n, unsigned width); unsigned width() const { return width_; } virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; private: unsigned width_; }; /* * Convert an input to IVL_VT_REAL. The input is pin(1), which can be * any vector type (VT_BOOL or VT_LOGIC) and the output is pin(0), * which is IVL_VT_REAL. The conversion interprets the input as an * unsigned value unless the signed_flag is true. */ class NetCastReal : public NetNode { public: NetCastReal(NetScope*s, perm_string n, bool signed_flag); bool signed_flag() const { return signed_flag_; } virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; private: bool signed_flag_; }; /* * This type represents the LPM_CLSHIFT device. */ class NetCLShift : public NetNode { public: NetCLShift(NetScope*s, perm_string n, unsigned width, unsigned width_dist, bool right_flag, bool signed_flag); ~NetCLShift(); unsigned width() const; unsigned width_dist() const; bool right_flag() const; bool signed_flag() const; Link& pin_Data(); Link& pin_Result(); Link& pin_Distance(); const Link& pin_Data() const; const Link& pin_Result() const; const Link& pin_Distance() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; private: unsigned width_; unsigned width_dist_; bool right_flag_; bool signed_flag_; }; /* * This class supports the LPM_COMPARE device. * * The width of the device is the width of the inputs. If one of the * inputs is narrower then the other, it is up to the generator to * make sure all the data pins are properly driven. * * The signed() property is true if the comparison is to be done to * signed arguments. The result is always UNsigned. * * NOTE: This is not the same as the device used to support case * compare. Case comparisons handle Vx and Vz values, whereas this * device need not. */ class NetCompare : public NetNode { public: NetCompare(NetScope*scope, perm_string n, unsigned width); ~NetCompare(); unsigned width() const; bool get_signed() const; void set_signed(bool); Link& pin_AGB(); Link& pin_AGEB(); Link& pin_AEB(); Link& pin_ANEB(); Link& pin_ALB(); Link& pin_ALEB(); Link& pin_DataA(); Link& pin_DataB(); const Link& pin_AGB() const; const Link& pin_AGEB() const; const Link& pin_AEB() const; const Link& pin_ANEB() const; const Link& pin_ALB() const; const Link& pin_ALEB() const; const Link& pin_DataA() const; const Link& pin_DataB() const; virtual void functor_node(Design*, functor_t*); virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; private: unsigned width_; bool signed_flag_; }; /* * This node is a means to connect net inputs together to form a wider * vector. The output (pin 0) is a concatenation of the input vectors, * with pin-1 at the LSB, pin-2 next, and so on. This node is most * like the NetLogic node, as it has one output at pin 0 and the * remaining pins are the input that are combined to make the * output. It is separated out because it it generally a special case * for the code generators. * * When constructing the node, the width is the vector_width of the * output, and the cnt is the number of pins. (the number of input * vectors.) */ class NetConcat : public NetNode { public: NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt); ~NetConcat(); unsigned width() const; void dump_node(ostream&, unsigned ind) const; bool emit_node(struct target_t*) const; private: unsigned width_; }; /* * This class represents a theoretical (though not necessarily * practical) integer divider gate. This is not to represent any real * hardware, but to support the / operator in Verilog, when it shows * up in structural contexts. * * The operands of the operation are the DataA and DataB inputs, * and the Result output reflects the value DataA/DataB. */ class NetDivide : public NetNode { public: NetDivide(NetScope*scope, perm_string n, unsigned width, unsigned wa, unsigned wb); ~NetDivide(); unsigned width_r() const; unsigned width_a() const; unsigned width_b() const; void set_signed(bool); bool get_signed() const; Link& pin_DataA(); Link& pin_DataB(); Link& pin_Result(); const Link& pin_DataA() const; const Link& pin_DataB() const; const Link& pin_Result() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*des, functor_t*fun); private: unsigned width_r_; unsigned width_a_; unsigned width_b_; bool signed_flag_; }; /* * This class represents a theoretical (though not necessarily * practical) integer modulo gate. This is not to represent any real * hardware, but to support the % operator in Verilog, when it shows * up in structural contexts. * * The operands of the operation are the DataA and DataB inputs, * and the Result output reflects the value DataA%DataB. */ class NetModulo : public NetNode { public: NetModulo(NetScope*s, perm_string n, unsigned width, unsigned wa, unsigned wb); ~NetModulo(); unsigned width_r() const; unsigned width_a() const; unsigned width_b() const; void set_signed(bool); bool get_signed() const; Link& pin_DataA(); Link& pin_DataB(); Link& pin_Result(); const Link& pin_DataA() const; const Link& pin_DataB() const; const Link& pin_Result() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*des, functor_t*fun); private: unsigned width_r_; unsigned width_a_; unsigned width_b_; bool signed_flag_; }; /* * This class represents an LPM_FF device. There is no literal gate * type in Verilog that maps, but gates of this type can be inferred. */ class NetFF : public NetNode { public: NetFF(NetScope*s, perm_string n, unsigned vector_width); ~NetFF(); unsigned width() const; Link& pin_Clock(); Link& pin_Enable(); Link& pin_Aset(); Link& pin_Aclr(); Link& pin_Sset(); Link& pin_Sclr(); Link& pin_Data(); Link& pin_Q(); const Link& pin_Clock() const; const Link& pin_Enable() const; const Link& pin_Aset() const; const Link& pin_Aclr() const; const Link& pin_Sset() const; const Link& pin_Sclr() const; const Link& pin_Data() const; const Link& pin_Q() const; void aset_value(const verinum&val); const verinum& aset_value() const; void sset_value(const verinum&val); const verinum& sset_value() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*des, functor_t*fun); private: unsigned width_; verinum aset_value_; verinum sset_value_; }; /* * This class implements a basic LPM_MULT combinational multiplier. It * is used as a structural representation of the * operator. The * device has inputs A and B and output Result all with independent * widths. * * NOTE: Check this width thing. I think that the independence of the * widths is not necessary or even useful. */ class NetMult : public NetNode { public: NetMult(NetScope*sc, perm_string n, unsigned width, unsigned wa, unsigned wb); ~NetMult(); bool get_signed() const; void set_signed(bool); // Get the width of the device bussed inputs. There are these // parameterized widths: unsigned width_r() const; // Result unsigned width_a() const; // DataA unsigned width_b() const; // DataB Link& pin_DataA(); Link& pin_DataB(); Link& pin_Result(); const Link& pin_DataA() const; const Link& pin_DataB() const; const Link& pin_Result() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*des, functor_t*fun); private: bool signed_; unsigned width_r_; unsigned width_a_; unsigned width_b_; }; /* * This class represents an LPM_MUX device. This device has some * number of Result points (the width of the device) and some number * of input choices. There is also a selector of some width. The * parameters are: * * width -- Width of the result and each possible Data input * size -- Number of Data input (each of width) * selw -- Width in bits of the select input * * All the data inputs must have the same type, and are the type of * the result. The actual type does not matter, as the mux does not * process data, just selects alternatives. * * The select input must be an integral type of some sort. Not real. */ class NetMux : public NetNode { public: NetMux(NetScope*scope, perm_string n, unsigned width, unsigned size, unsigned selw); ~NetMux(); unsigned width() const; unsigned size() const; unsigned sel_width() const; Link& pin_Result(); Link& pin_Data(unsigned si); Link& pin_Sel(); const Link& pin_Result() const; const Link& pin_Data(unsigned) const; const Link& pin_Sel() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*des, functor_t*fun); private: unsigned width_; unsigned size_; unsigned swidth_; }; /* * This class implements a basic LPM_POW combinational power. It * is used as a structural representation of the ** operator. The * device has inputs A and B and output Result all with independent * widths. * * NOTE: Check this width thing. I think that the independence of the * widths is not necessary or even useful. */ class NetPow : public NetNode { public: NetPow(NetScope*sc, perm_string n, unsigned width, unsigned wa, unsigned wb); ~NetPow(); bool get_signed() const; void set_signed(bool); // Get the width of the device bussed inputs. There are these // parameterized widths: unsigned width_r() const; // Result unsigned width_a() const; // DataA unsigned width_b() const; // DataB Link& pin_DataA(); Link& pin_DataB(); Link& pin_Result(); const Link& pin_DataA() const; const Link& pin_DataB() const; const Link& pin_Result() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*des, functor_t*fun); private: bool signed_; unsigned width_r_; unsigned width_a_; unsigned width_b_; }; /* * The NetReplicate node takes a vector input and makes it into a larger * vector by repeating the input vector some number of times. The * repeat count is a fixed value. This is just like the repeat * concatenation of Verilog: {{}}. * * When constructing this node, the wid is the vector width of the * output, and the rpt is the repeat count. The wid must be an even * multiple of the cnt, and wid/cnt is the expected input width. * * The device has exactly 2 pins: pin(0) is the output and pin(1) the * input. */ class NetReplicate : public NetNode { public: NetReplicate(NetScope*scope, perm_string n, unsigned wid, unsigned rpt); ~NetReplicate(); unsigned width() const; unsigned repeat() const; void dump_node(ostream&, unsigned ind) const; bool emit_node(struct target_t*) const; private: unsigned width_; unsigned repeat_; }; /* * This node represents the call of a user defined function in a * structural context. The pin count is the same as the port count, * with pin0 the return value. */ class NetUserFunc : public NetNode { public: NetUserFunc(NetScope*s, perm_string n, NetScope*def, NetEvWait*trigger__); ~NetUserFunc(); ivl_variable_type_t data_type(unsigned port) const; unsigned port_width(unsigned port) const; const NetScope* def() const; const NetEvWait* trigger() const { return trigger_; } virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; private: NetScope*def_; NetEvWait*trigger_; }; /* * The number of ports includes the return value, so will always be at * least 1. */ class NetSysFunc : public NetNode { public: NetSysFunc(NetScope*s, perm_string n, const struct sfunc_return_type*def, unsigned ports, NetEvWait*trigger__); ~NetSysFunc(); ivl_variable_type_t data_type() const; unsigned vector_width() const; const char* func_name() const; const NetEvWait* trigger() const { return trigger_; } virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; private: const struct sfunc_return_type*def_; NetEvWait*trigger_; }; class NetTran : public NetNode, public IslandBranch { public: // Tran devices other than TRAN_VP NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type); // Create a TRAN_VP NetTran(NetScope*scope, perm_string n, unsigned wid, unsigned part, unsigned off); ~NetTran(); ivl_switch_type_t type() const { return type_; } // These are only used for IVL_SW_TRAN_PV unsigned vector_width() const; unsigned part_width() const; unsigned part_offset() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; private: ivl_switch_type_t type_; unsigned wid_; unsigned part_; unsigned off_; }; /* ========= * There are cases where expressions need to be represented. The * NetExpr class is the root of a hierarchy that serves that purpose. * * The expr_width() is the width of the expression, that accounts * for the widths of the sub-expressions I might have. It is up to the * derived classes to properly set the expr width, if need be. The * set_width() method is used to compel an expression to have a * certain width, and is used particularly when the expression is an * rvalue in an assignment statement. */ class NetExpr : public LineInfo { public: explicit NetExpr(unsigned w =0); virtual ~NetExpr() =0; virtual void expr_scan(struct expr_scan_t*) const =0; virtual void dump(ostream&) const; // Expressions have type. virtual ivl_variable_type_t expr_type() const; // How wide am I? unsigned expr_width() const { return width_; } // Coerce the expression to have a specific width. If the // coercion works, then return true. Otherwise, return false. // A coercion will work or not depending on the implementation // in the derived class. Normally, the width will be set if // the expression is: // - already the requested size, OR // - otherwise unsized. // Normally, the resize will not allow a width size that loses // data. For example, it will not reduce a constant expression // to the point where significant bits are lost. But if the // last_chance flag is true, then the method assumes that high // bits will be lost anyhow, so try harder. Loss will be // allowed, but it still won't resize fixed size expressions // such as vector signals. This flag is meant to be used by // elaboration of procedural assignment to set the expression // width to the l-value width, if possible. virtual bool set_width(unsigned wid, bool last_chance =false); // This method returns true if the expression is // signed. Unsigned expressions return false. bool has_sign() const; virtual void cast_signed(bool flag); // This returns true if the expression has a definite // width. This is generally true, but in some cases the // expression is amorphous and desires a width from its // environment. For example, 'd5 has indefinite width, but // 5'd5 has a definite width. // This method is only really used within concatenation // expressions to check validity. virtual bool has_width() const; // Expressions in parameter declarations may have encountered // arguments that are themselves untyped parameters. These // cannot be fully resolved for type when elaborated (they are // elaborated before all parameter overrides are complete) so // this virtual method needs to be called right before // evaluating the expression. This wraps up the evaluation of // the type. virtual void resolve_pexpr_type(); // This method evaluates the expression and returns an // equivalent expression that is reduced as far as compile // time knows how. Essentially, this is designed to fold // constants. // // The prune_to_width is the maximum width that the result // should be. If it is 0 or -1, then do not prune the // result. If it is -1, go through special efforts to preserve // values that may expand. A width of 0 corresponds to a // self-determined context, and a width of -1 corresponds to // an infinitely wide context. virtual NetExpr*eval_tree(int prune_to_width = -1); // Make a duplicate of myself, and subexpressions if I have // any. This is a deep copy operation. virtual NetExpr*dup_expr() const =0; // Get the Nexus that are the input to this // expression. Normally this descends down to the reference to // a signal that reads from its input. virtual NexusSet* nex_input(bool rem_out = true) =0; // Return a version of myself that is structural. This is used // for converting expressions to gates. The arguments are: // // des, scope: The context where this work is done // // root: The root expression of which this expression is a part. // // rise/fall/decay: Attach these delays to the driver for the // expression output. // // drive0/drive1: Attach these strengths tp the driver for // the expression output. virtual NetNet*synthesize(Design*des, NetScope*scope, NetExpr*root); protected: void expr_width(unsigned w); void cast_signed_base_(bool flag) {signed_flag_ = flag; } private: unsigned width_; bool signed_flag_; private: // not implemented NetExpr(const NetExpr&); NetExpr& operator=(const NetExpr&); }; /* * The expression constant is slightly special, and is sometimes * returned from other classes that can be evaluated at compile * time. This class represents constant values in expressions. */ class NetEConst : public NetExpr { public: explicit NetEConst(const verinum&val); ~NetEConst(); const verinum&value() const; virtual bool set_width(unsigned w, bool last_chance =false); virtual void cast_signed(bool sign_flag); virtual bool has_width() const; virtual ivl_variable_type_t expr_type() const; virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; virtual NetEConst* dup_expr() const; virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*); virtual NexusSet* nex_input(bool rem_out = true); private: verinum value_; }; class NetEConstParam : public NetEConst { public: explicit NetEConstParam(NetScope*scope, perm_string name, const verinum&val); ~NetEConstParam(); perm_string name() const; const NetScope*scope() const; virtual bool set_width(unsigned w, bool last_chance =false); virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; virtual NetEConstParam* dup_expr() const; private: NetScope*scope_; perm_string name_; }; /* * This class represents a constant real value. */ class NetECReal : public NetExpr { public: explicit NetECReal(const verireal&val); ~NetECReal(); const verireal&value() const; // Reals can be used in vector expressions. Conversions will // be done at the right time. virtual bool set_width(unsigned w, bool last_chance); // This type has no self-determined width. This is false. virtual bool has_width() const; // The type of this expression is ET_REAL ivl_variable_type_t expr_type() const; virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; virtual NetECReal* dup_expr() const; virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*); virtual NexusSet* nex_input(bool rem_out = true); private: verireal value_; }; class NetECRealParam : public NetECReal { public: explicit NetECRealParam(NetScope*scope, perm_string name, const verireal&val); ~NetECRealParam(); perm_string name() const; const NetScope*scope() const; virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; virtual NetECRealParam* dup_expr() const; private: NetScope*scope_; perm_string name_; }; /* * The NetPartSelect device represents a netlist part select of a * signal vector. Pin 0 is a vector that is a part select of pin 1, * which connected to the NetNet of the signal being selected from. * * The part to be selected is the canonical (0-based) offset and the * specified number of bits (wid). * * If the offset is non-constant, then pin(2) is the input vector for * the selector. If this pin is present, then use the non-constant * selector as the input. * * The NetPartSelect can be output from the signal (i.e. reading a * part) or input into the signal. The DIR method gives the type of * the node. * * VP (Vector-to-Part) * Output pin 0 is the part select, and input pin 1 is connected to * the NetNet object. * * PV (Part-to-Vector) * Output pin 1 is connected to the NetNet, and input pin 0 is the * part select. In this case, the node is driving the NetNet. * * Note that whatever the direction that data is intended to flow, * pin-0 is the part select and pin-1 is connected to the NetNet. */ class NetPartSelect : public NetNode { public: // enum for the device direction enum dir_t { VP, PV}; explicit NetPartSelect(NetNet*sig, unsigned off, unsigned wid, dir_t dir); explicit NetPartSelect(NetNet*sig, NetNet*sel, unsigned wid, bool signed_flag__ = false); ~NetPartSelect(); unsigned base() const; unsigned width() const; dir_t dir() const; /* Is the select signal signed? */ bool signed_flag() const { return signed_flag_; } virtual void dump_node(ostream&, unsigned ind) const; bool emit_node(struct target_t*tgt) const; private: unsigned off_; unsigned wid_; dir_t dir_; bool signed_flag_; }; /* * The NetBUFZ is a magic device that represents the continuous * assign, with the output being the target register and the input * the logic that feeds it. The netlist preserves the directional * nature of that assignment with the BUFZ. The target may elide it if * that makes sense for the technology. */ class NetBUFZ : public NetNode { public: explicit NetBUFZ(NetScope*s, perm_string n, unsigned wid); ~NetBUFZ(); unsigned width() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; private: unsigned width_; }; /* * This node is used to represent case equality in combinational * logic. Although this is not normally synthesizable, it makes sense * to support an abstract gate that can compare x and z. This node * always generates a single bit result, no matter the width of the * input. The elaboration, btw, needs to make sure the input widths * match. * * This pins are assigned as: * * 0 -- Output (always returns 0 or 1) * 1 -- Input * 2 -- Input */ class NetCaseCmp : public NetNode { public: explicit NetCaseCmp(NetScope*s, perm_string n, unsigned wid, bool eeq); ~NetCaseCmp(); unsigned width() const; // true if this is ===, false if this is !== bool eeq() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; private: unsigned width_; bool eeq_; }; /* NOTE: This class should be replaced with the NetLiteral class * below, that is more general in that it supports different types of * values. * * This class represents instances of the LPM_CONSTANT device. The * node has only outputs and a constant value. The width is available * by getting the pin_count(), and the value bits are available one at * a time. There is no meaning to the aggregation of bits to form a * wide NetConst object, although some targets may have an easier time * detecting interesting constructs if they are combined. */ class NetConst : public NetNode { public: explicit NetConst(NetScope*s, perm_string n, verinum::V v); explicit NetConst(NetScope*s, perm_string n, const verinum&val); ~NetConst(); verinum::V value(unsigned idx) const; unsigned width() const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*, functor_t*); virtual void dump_node(ostream&, unsigned ind) const; private: unsigned width_; verinum::V*value_; }; /* * This class represents instances of the LPM_CONSTANT device. The * node has only outputs and a constant value. The width is available * by getting the pin_count(), and the value bits are available one at * a time. There is no meaning to the aggregation of bits to form a * wide NetConst object, although some targets may have an easier time * detecting interesting constructs if they are combined. */ class NetLiteral : public NetNode { public: // A read-valued literal. explicit NetLiteral(NetScope*s, perm_string n, const verireal&val); ~NetLiteral(); ivl_variable_type_t data_type() const; const verireal& value_real() const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*, functor_t*); virtual void dump_node(ostream&, unsigned ind) const; private: verireal real_; }; /* * This class represents all manner of logic gates. Pin 0 is OUTPUT and * all the remaining pins are INPUT. The BUFIF[01] gates have the * more specific pinout as follows: * * bufif * 0 -- output * 1 -- input data * 2 -- enable * * The pullup and pulldown gates have no inputs at all, and pin0 is * the output 1 or 0, depending on the gate type. It is the strength * of that value that is important. * * All these devices process vectors bitwise, so each bit can be * logically separated. The exception is the CONCAT gate, which is * really an abstract gate that takes the inputs and turns it into a * vector of bits. */ class NetLogic : public NetNode { public: enum TYPE { AND, BUF, BUFIF0, BUFIF1, CMOS, NAND, NMOS, NOR, NOT, NOTIF0, NOTIF1, OR, PULLDOWN, PULLUP, RCMOS, RNMOS, RPMOS, PMOS, XNOR, XOR }; explicit NetLogic(NetScope*s, perm_string n, unsigned pins, TYPE t, unsigned wid); TYPE type() const; unsigned width() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*, functor_t*); private: TYPE type_; unsigned width_; }; /* * This class represents a structural sign extension. The pin-0 is a * vector of the input pin-1 sign-extended. The input is taken to be * signed. This generally matches a hardware implementation of * replicating the top bit enough times to create the desired output * width. */ class NetSignExtend : public NetNode { public: explicit NetSignExtend(NetScope*s, perm_string n, unsigned wid); ~NetSignExtend(); unsigned width() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*, functor_t*); private: unsigned width_; }; /* * This class represents *reduction* logic operators. Certain boolean * logic operators have reduction forms which take in a vector and * return a single bit that is calculated by applying the logic * operation through the width of the input vector. These correspond * to reduction unary operators in Verilog. */ class NetUReduce : public NetNode { public: enum TYPE {NONE, AND, OR, XOR, NAND, NOR, XNOR}; NetUReduce(NetScope*s, perm_string n, TYPE t, unsigned wid); TYPE type() const; unsigned width() const; virtual void dump_node(ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*, functor_t*); private: TYPE type_; unsigned width_; }; /* * The UDP is a User Defined Primitive from the Verilog source. Do not * expand it out any further than this in the netlist, as this can be * used to represent target device primitives. * * The UDP can be combinational or sequential. The sequential UDP * includes the current output in the truth table, and supports edges, * whereas the combinational does not and is entirely level sensitive. * In any case, pin 0 is an output, and all the remaining pins are * inputs. * * Set_table takes as input a string with one letter per pin. The * parser translates the written sequences to one of these. The * valid characters are: * * 0, 1, x -- The levels * r -- (01) * R -- (x1) * f -- (10) * F -- (x0) * P -- (0x) * N -- (1x) * * It also takes one of the following glob letters to represent more * than one item. * * p -- 01, 0x or x1 // check this with the lexer * n -- 10, 1x or x0 // check this with the lexer * ? -- 0, 1, or x * * -- any edge * + -- 01 or x1 * _ -- 10 or x0 (Note that this is not the output '-'.) * % -- 0x or 1x * * SEQUENTIAL * These objects have a single bit of memory. The logic table includes * an entry for the current value, and allows edges on the inputs. In * canonical form, only the entries that generate 0, 1 or - (no change) * are listed. * * COMBINATIONAL * The logic table is a map between the input levels and the * output. Each input pin can have the value 0, 1 or x and the output * can have the values 0 or 1. If the input matches nothing, the * output is x. In canonical form, only the entries that generate 0 or * 1 are listed. * */ #include "PUdp.h" class NetUDP : public NetNode { public: explicit NetUDP(NetScope*s, perm_string n, unsigned pins, PUdp*u); virtual bool emit_node(struct target_t*) const; virtual void dump_node(ostream&, unsigned ind) const; /* Use these methods to scan the truth table of the device. "first" returns the first item in the table, and "next" returns the next item in the table. The method will return false when the scan is done. */ bool first(string&inp, char&out) const; bool next(string&inp, char&out) const; unsigned rows() const { return udp->tinput.count(); } unsigned nin() const { return pin_count()-1; } bool is_sequential() const { return udp->sequential; } perm_string udp_name() const { return udp->name_; } char get_initial() const; private: mutable unsigned table_idx; PUdp *udp; }; enum DelayType { NO_DELAY, ZERO_DELAY, POSSIBLE_DELAY, DEFINITE_DELAY }; /* ========= * A process is a behavioral-model description. A process is a * statement that may be compound. The various statement types may * refer to places in a netlist (by pointing to nodes) but is not * linked into the netlist. However, elaborating a process may cause * special nodes to be created to handle things like events. */ class NetProc : public virtual LineInfo { public: explicit NetProc(); virtual ~NetProc(); // Find the nexa that are input by the statement. This is used // for example by @* to find the inputs to the process for the // sensitivity list. virtual NexusSet* nex_input(bool rem_out = true); // Find the nexa that are set by the statement. Add the output // values to the set passed as a parameter. virtual void nex_output(NexusSet&); // This method is called to emit the statement to the // target. The target returns true if OK, false for errors. virtual bool emit_proc(struct target_t*) const; // This method is called by functors that want to scan a // process in search of matchable patterns. virtual int match_proc(struct proc_match_t*); // Return true if this represents the root of a combinational // process. Most process types are not. virtual bool is_asynchronous(); // Return true if this represents the root of a synchronous // process. Most process types are not. virtual bool is_synchronous(); // Synthesize as asynchronous logic, and return true. virtual bool synth_async(Design*des, NetScope*scope, const NetBus&nex_map, NetBus&nex_out); virtual bool synth_sync(Design*des, NetScope*scope, NetFF*ff, const NetBus&nex_map, NetBus&nex_out, const svector&events); virtual void dump(ostream&, unsigned ind) const; // Recursively checks to see if there is delay in this element. virtual DelayType delay_type() const; private: friend class NetBlock; NetProc*next_; private: // not implemented NetProc(const NetProc&); NetProc& operator= (const NetProc&); }; class NetAlloc : public NetProc { public: NetAlloc(NetScope*); ~NetAlloc(); const string name() const; const NetScope* scope() const; virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; private: NetScope*scope_; }; /* * Procedural assignment is broken into a suite of classes. These * classes represent the various aspects of the assignment statement * in behavioral code. (The continuous assignment is *not* * represented here.) * * The NetAssignBase carries the common aspects of an assignment, * including the r-value. This class has no cares of blocking vs * non-blocking, however it carries nearly all the other properties * of the assignment statement. It is abstract because it does not * differentiate the virtual behaviors. * * The NetAssign and NetAssignNB classes are the concrete classes that * give the assignment its final, precise meaning. These classes fill * in the NetProc behaviors. * * The l-value of the assignment is a collection of NetAssign_ * objects that are connected to the structural netlist where the * assignment has its effect. The NetAssign_ class is not to be * derived from. * * The collection is arranged from lsb up to msb, and represents the * concatenation of l-values. The elaborator may collapse some * concatenations into a single NetAssign_. The "more" member of the * NetAssign_ object points to the next most significant bits of l-value. * * NOTE: The elaborator will make an effort to match the width of the * r-value to the width of the l-value, but targets and functions * should know that this is not a guarantee. */ class NetAssign_ { public: NetAssign_(NetNet*sig); ~NetAssign_(); // If this expression exists, then it is used to select a word // from an array/memory. NetExpr*word(); const NetExpr*word() const; // Get the base index of the part select, or 0 if there is no // part select. const NetExpr* get_base() const; void set_word(NetExpr*); void set_part(NetExpr* loff, unsigned wid); // Get the width of the r-value that this node expects. This // method accounts for the presence of the mux, so it is not // necessarily the same as the pin_count(). unsigned lwidth() const; ivl_variable_type_t expr_type() const; // Get the name of the underlying object. perm_string name() const; NetNet* sig() const; // Mark that the synthesizer has worked with this l-value, so // when it is released, the l-value signal should be turned // into a wire. void turn_sig_to_wire_on_release(); // It is possible that l-values can have *inputs*, as well as // being outputs. For example foo[idx] = ... is the l-value // (NetAssign_ object) with a foo l-value and the input // expression idx. NexusSet* nex_input(bool rem_out = true); // This pointer is for keeping simple lists. NetAssign_* more; void dump_lval(ostream&o) const; private: NetNet *sig_; // Memory word index NetExpr*word_; bool turn_sig_to_wire_on_release_; // indexed part select base NetExpr*base_; unsigned lwid_; }; class NetAssignBase : public NetProc { public: NetAssignBase(NetAssign_*lv, NetExpr*rv); virtual ~NetAssignBase() =0; // This is the (procedural) value that is to be assigned when // the assignment is executed. NetExpr*rval(); const NetExpr*rval() const; void set_rval(NetExpr*); NetAssign_* l_val(unsigned); const NetAssign_* l_val(unsigned) const; unsigned l_val_count() const; void set_delay(NetExpr*); const NetExpr* get_delay() const; virtual NexusSet* nex_input(bool rem_out = true); virtual void nex_output(NexusSet&o); // This returns the total width of the accumulated l-value. It // accounts for any grouping of NetAssign_ objects that might happen. unsigned lwidth() const; bool synth_async(Design*des, NetScope*scope, const NetBus&nex_map, NetBus&nex_out); // This dumps all the lval structures. void dump_lval(ostream&) const; virtual void dump(ostream&, unsigned ind) const; private: NetAssign_*lval_; NetExpr *rval_; NetExpr *delay_; }; class NetAssign : public NetAssignBase { public: explicit NetAssign(NetAssign_*lv, NetExpr*rv); ~NetAssign(); bool is_asynchronous(); virtual bool emit_proc(struct target_t*) const; virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; private: }; class NetAssignNB : public NetAssignBase { public: explicit NetAssignNB(NetAssign_*lv, NetExpr*rv, NetEvWait*ev, NetExpr*cnt); ~NetAssignNB(); virtual bool emit_proc(struct target_t*) const; virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; unsigned nevents() const; const NetEvent*event(unsigned) const; const NetExpr* get_count() const; private: NetEvWait*event_; NetExpr*count_; }; /* * A block is stuff like begin-end blocks, that contain an ordered * list of NetProc statements. * * NOTE: The emit method calls the target->proc_block function but * does not recurse. It is up to the target-supplied proc_block * function to call emit_recurse. */ class NetBlock : public NetProc { public: enum Type { SEQU, PARA }; NetBlock(Type t, NetScope*subscope); ~NetBlock(); Type type() const { return type_; } NetScope* subscope() const { return subscope_; } void append(NetProc*); const NetProc*proc_first() const; const NetProc*proc_next(const NetProc*cur) const; // synthesize as asynchronous logic, and return true. bool synth_async(Design*des, NetScope*scope, const NetBus&nex_map, NetBus&nex_out); bool synth_sync(Design*des, NetScope*scope, NetFF*ff, const NetBus&nex_map, NetBus&nex_out, const svector&events); // This version of emit_recurse scans all the statements of // the begin-end block sequentially. It is typically of use // for sequential blocks. void emit_recurse(struct target_t*) const; virtual NexusSet* nex_input(bool rem_out = true); virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; private: const Type type_; NetScope*subscope_; NetProc*last_; }; /* * A CASE statement in the Verilog source leads, eventually, to one of * these. This is different from a simple conditional because of the * way the comparisons are performed. Also, it is likely that the * target may be able to optimize differently. * * Case can be one of three types: * EQ -- All bits must exactly match * EQZ -- z bits are don't care * EQX -- x and z bits are don't care. */ class NetCase : public NetProc { public: enum TYPE { EQ, EQX, EQZ }; NetCase(TYPE c, NetExpr*ex, unsigned cnt); ~NetCase(); void set_case(unsigned idx, NetExpr*ex, NetProc*st); TYPE type() const; const NetExpr*expr() const { return expr_; } unsigned nitems() const { return nitems_; } const NetExpr*expr(unsigned idx) const { return items_[idx].guard;} const NetProc*stat(unsigned idx) const { return items_[idx].statement; } virtual NexusSet* nex_input(bool rem_out = true); virtual void nex_output(NexusSet&out); bool synth_async(Design*des, NetScope*scope, const NetBus&nex_map, NetBus&nex_out); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; private: TYPE type_; struct Item { NetExpr*guard; NetProc*statement; }; NetExpr* expr_; unsigned nitems_; Item*items_; }; /* * The cassign statement causes the r-val net to be forced onto the * l-val reg when it is executed. The code generator is expected to * know what that means. */ class NetCAssign : public NetAssignBase { public: explicit NetCAssign(NetAssign_*lv, NetExpr*rv); ~NetCAssign(); virtual NexusSet* nex_input(bool rem_out = true); virtual void dump(ostream&, unsigned ind) const; virtual bool emit_proc(struct target_t*) const; private: // not implemented NetCAssign(const NetCAssign&); NetCAssign& operator= (const NetCAssign&); }; /* * A condit represents a conditional. It has an expression to test, * and a pair of statements to select from. If the original statement * has empty clauses, then the NetProc for it will be a null pointer. */ class NetCondit : public NetProc { public: explicit NetCondit(NetExpr*ex, NetProc*i, NetProc*e); ~NetCondit(); const NetExpr*expr() const; NetExpr*expr(); NetProc* if_clause(); NetProc* else_clause(); // Replace the condition expression. void set_expr(NetExpr*ex); bool emit_recurse_if(struct target_t*) const; bool emit_recurse_else(struct target_t*) const; virtual NexusSet* nex_input(bool rem_out = true); virtual void nex_output(NexusSet&o); bool is_asynchronous(); bool synth_async(Design*des, NetScope*scope, const NetBus&nex_map, NetBus&nex_out); bool synth_sync(Design*des, NetScope*scope, NetFF*ff, const NetBus&nex_map, NetBus&nex_out, const svector&events); virtual bool emit_proc(struct target_t*) const; virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; private: NetExpr* expr_; NetProc*if_; NetProc*else_; }; /* * This represents the analog contribution statement. The l-val is a * branch expression, and the r-value is an arbitrary expression that * may include branches and real values. */ class NetContribution : public NetProc { public: explicit NetContribution(NetEAccess*lval, NetExpr*rval); ~NetContribution(); const NetEAccess* lval() const; const NetExpr* rval() const; virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; private: NetEAccess*lval_; NetExpr*rval_; }; /* * The procedural deassign statement (the opposite of assign) releases * any assign expressions attached to the bits of the reg. The * lval is the expression of the "deassign ;" statement with the * expr elaborated to a net. */ class NetDeassign : public NetAssignBase { public: explicit NetDeassign(NetAssign_*l); ~NetDeassign(); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; private: // not implemented NetDeassign(const NetDeassign&); NetDeassign& operator= (const NetDeassign&); }; /* * This node represents the behavioral disable statement. The Verilog * source that produces it looks like: * * disable ; * * Where the scope is a named block or a task. It cannot be a module * instance scope because module instances cannot be disabled. */ class NetDisable : public NetProc { public: explicit NetDisable(NetScope*tgt); ~NetDisable(); const NetScope*target() const; virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; private: NetScope*target_; private: // not implemented NetDisable(const NetDisable&); NetDisable& operator= (const NetDisable&); }; /* * A NetEvent is an object that represents an event object, that is * objects declared like so in Verilog: * * event foo; * * Once an object of this type exists, behavioral code can wait on the * event or trigger the event. Event waits refer to this object, as do * the event trigger statements. The NetEvent class may have a name and * a scope. The name is a simple name (no hierarchy) and the scope is * the NetScope that contains the object. The scope member is written * by the NetScope object when the NetEvent is stored. * * The NetEvWait class represents a thread wait for an event. When * this statement is executed, it starts waiting on the * event. Conceptually, it puts itself on the event list for the * referenced event. When the event is triggered, the wait ends its * block and starts the associated statement. * * The NetEvTrig class represents trigger statements. Executing this * statement causes the referenced event to be triggered, which in * turn awakens the waiting threads. Each NetEvTrig 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 * NetEvent. Each NetEvProbe references exactly one event object, and * the NetEvent objects have a list of NetEvProbe objects that * reference it. */ class NetEvent : public LineInfo { friend class NetScope; friend class NetEvProbe; friend class NetEvTrig; friend class NetEvWait; friend class NetEEvent; public: // The name of the event is the basename, and should not // include the scope. Also, the name passed here should be // perm-allocated. explicit NetEvent (perm_string n); ~NetEvent(); perm_string name() const; // Get information about probes connected to me. unsigned nprobe() const; NetEvProbe* probe(unsigned); const NetEvProbe* probe(unsigned) const; // Return the number of NetEvWait nodes that reference me. unsigned nwait() const; unsigned ntrig() const; unsigned nexpr() const; NetScope* scope(); const NetScope* scope() const; void nex_output(NexusSet&); // Locate the first event that matches my behavior and // monitors the same signals. void find_similar_event(list&); // This method replaces pointers to me with pointers to // that. It is typically used to replace similar events // located by the find_similar_event method. void replace_event(NetEvent*that); private: // This returns a nexus set if it represents possibly // asynchronous inputs, otherwise 0. NexusSet*nex_async_(); private: perm_string name_; // The NetScope class uses these to list the events. NetScope*scope_; NetEvent*snext_; // Use these methods to list the probes attached to me. NetEvProbe*probes_; // Use these methods to list the triggers attached to me. NetEvTrig* trig_; // Use This member to count references by NetEvWait objects. unsigned waitref_; struct wcell_ { NetEvWait*obj; struct wcell_*next; }; struct wcell_ *wlist_; // expression references, ala. task/funcs unsigned exprref_; private: // not implemented NetEvent(const NetEvent&); NetEvent& operator= (const NetEvent&); }; class NetEvTrig : public NetProc { friend class NetEvent; public: explicit NetEvTrig(NetEvent*tgt); ~NetEvTrig(); const NetEvent*event() const; virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; private: NetEvent*event_; // This is used to place me in the NetEvents lists of triggers. NetEvTrig*enext_; }; class NetEvWait : public NetProc { public: explicit NetEvWait(NetProc*st); ~NetEvWait(); void add_event(NetEvent*tgt); void replace_event(NetEvent*orig, NetEvent*repl); unsigned nevents() const; const NetEvent*event(unsigned) const; NetEvent*event(unsigned); NetProc*statement(); virtual bool emit_proc(struct target_t*) const; bool emit_recurse(struct target_t*) const; virtual int match_proc(struct proc_match_t*); // It is possible that this is the root of a combinational // process. This method checks. virtual bool is_asynchronous(); // It is possible that this is the root of a synchronous // process? This method checks. virtual bool is_synchronous(); virtual void nex_output(NexusSet&out); virtual bool synth_async(Design*des, NetScope*scope, const NetBus&nex_map, NetBus&nex_out); virtual bool synth_sync(Design*des, NetScope*scope, NetFF*ff, const NetBus&nex_map, NetBus&nex_out, const svector&events); virtual void dump(ostream&, unsigned ind) const; // This will ignore any statement. virtual void dump_inline(ostream&) const; virtual DelayType delay_type() const; private: NetProc*statement_; unsigned nevents_; NetEvent**events_; }; ostream& operator << (ostream&out, const NetEvWait&obj); class NetEvProbe : public NetNode { friend class NetEvent; public: enum edge_t { ANYEDGE, POSEDGE, NEGEDGE }; explicit NetEvProbe(NetScope*s, perm_string n, NetEvent*tgt, edge_t t, unsigned p); ~NetEvProbe(); edge_t edge() const; NetEvent* event(); const NetEvent* event() const; void find_similar_probes(list&); virtual bool emit_node(struct target_t*) const; virtual void dump_node(ostream&, unsigned ind) const; private: NetEvent*event_; edge_t edge_; // The NetEvent class uses this to list me. NetEvProbe*enext_; }; /* * The force statement causes the r-val net to be forced onto the * l-val net when it is executed. The code generator is expected to * know what that means. */ class NetForce : public NetAssignBase { public: explicit NetForce(NetAssign_*l, NetExpr*r); ~NetForce(); virtual NexusSet* nex_input(bool rem_out = true); virtual void dump(ostream&, unsigned ind) const; virtual bool emit_proc(struct target_t*) const; }; /* * A forever statement is executed over and over again forever. Or * until its block is disabled. */ class NetForever : public NetProc { public: explicit NetForever(NetProc*s); ~NetForever(); void emit_recurse(struct target_t*) const; virtual NexusSet* nex_input(bool rem_out = true); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; private: NetProc*statement_; }; class NetFree : public NetProc { public: NetFree(NetScope*); ~NetFree(); const string name() const; const NetScope* scope() const; virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; private: NetScope*scope_; }; /* * A function definition is elaborated just like a task, though by now * it is certain that the first parameter (a phantom parameter) is the * output and all the remaining parameters are the inputs. This makes * for easy code generation in targets that support behavioral * descriptions. * * The NetNet array that is passed in as a parameter is the set of * signals that make up its parameter list. These are all internal to * the scope of the function. */ class NetFuncDef { public: NetFuncDef(NetScope*, NetNet*result, const svector&po); ~NetFuncDef(); void set_proc(NetProc*st); //const string name() const; const NetProc*proc() const; const NetScope*scope() const; NetScope*scope(); unsigned port_count() const; const NetNet*port(unsigned idx) const; const NetNet*return_sig() const; void dump(ostream&, unsigned ind) const; private: NetScope*scope_; NetProc*statement_; NetNet*result_sig_; svectorports_; }; /* * This class represents delay statements of the form: * * # * * Where the statement may be null. The delay is evaluated at * elaboration time to make a constant unsigned long that is the delay * in simulation ticks. * * If the delay expression is non-constant, construct the NetPDelay * object with a NetExpr* instead of the d value, and use the expr() * method to get the expression. If expr() returns 0, use the delay() * method to get the constant delay. */ class NetPDelay : public NetProc { public: NetPDelay(uint64_t d, NetProc*st); NetPDelay(NetExpr* d, NetProc*st); ~NetPDelay(); uint64_t delay() const; const NetExpr*expr() const; virtual NexusSet* nex_input(bool rem_out = true); virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; bool emit_proc_recurse(struct target_t*) const; private: uint64_t delay_; NetExpr*expr_; NetProc*statement_; }; /* * A repeat statement is executed some fixed number of times. */ class NetRepeat : public NetProc { public: explicit NetRepeat(NetExpr*e, NetProc*s); ~NetRepeat(); const NetExpr*expr() const; void emit_recurse(struct target_t*) const; virtual NexusSet* nex_input(bool rem_out = true); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; private: NetExpr*expr_; NetProc*statement_; }; /* * The procedural release statement (the opposite of force) releases * any force expressions attached to the bits of the wire or reg. The * lval is the expression of the "release ;" statement with the * expr elaborated to a net. */ class NetRelease : public NetAssignBase { public: explicit NetRelease(NetAssign_*l); ~NetRelease(); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; private: }; /* * The NetSTask class is a call to a system task. These kinds of tasks * are generally handled very simply in the target. They certainly are * handled differently from user defined tasks because ivl knows all * about the user defined tasks. */ class NetSTask : public NetProc { public: NetSTask(const char*na, const svector&); ~NetSTask(); const char* name() const; unsigned nparms() const; const NetExpr* parm(unsigned idx) const; virtual NexusSet* nex_input(bool rem_out = true); virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; private: const char* name_; svectorparms_; }; /* * This class represents an elaborated class definition. NetUTask * classes may refer to objects of this type to get the meaning of the * defined task. * * The task also introduces a scope, and the parameters are actually * reg objects in the new scope. The task is called by the calling * thread assigning (blocking assignment) to the in and inout * parameters, then invoking the thread, and finally assigning out the * output and inout variables. The variables accessible as ports are * also elaborated and accessible as ordinary reg objects. */ class NetTaskDef { public: NetTaskDef(NetScope*n, const svector&po); ~NetTaskDef(); void set_proc(NetProc*p); //const string& name() const; const NetScope* scope() const; const NetProc*proc() const; unsigned port_count() const; NetNet*port(unsigned idx); void dump(ostream&, unsigned) const; DelayType delay_type() const; private: NetScope*scope_; NetProc*proc_; svectorports_; private: // not implemented NetTaskDef(const NetTaskDef&); NetTaskDef& operator= (const NetTaskDef&); }; /* * This node represents a function call in an expression. The object * contains a pointer to the function definition, which is used to * locate the value register and input expressions. */ class NetEUFunc : public NetExpr { public: NetEUFunc(NetScope*, NetScope*, NetESignal*, svector&); ~NetEUFunc(); const NetESignal*result_sig() const; unsigned parm_count() const; const NetExpr* parm(unsigned idx) const; const NetScope* func() const; virtual bool set_width(unsigned, bool last_chance); virtual ivl_variable_type_t expr_type() const; virtual void dump(ostream&) const; virtual void expr_scan(struct expr_scan_t*) const; virtual NetEUFunc*dup_expr() const; virtual NexusSet* nex_input(bool rem_out = true); virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root); private: NetScope*scope_; NetScope*func_; NetESignal*result_sig_; svector parms_; private: // not implemented NetEUFunc(const NetEUFunc&); NetEUFunc& operator= (const NetEUFunc&); }; /* * A call to a nature access function for a branch. */ class NetEAccess : public NetExpr { public: explicit NetEAccess(NetBranch*br, ivl_nature_t nat); ~NetEAccess(); ivl_nature_t get_nature() const { return nature_; } NetBranch* get_branch() const { return branch_; } virtual ivl_variable_type_t expr_type() const; virtual void dump(ostream&) const; virtual void expr_scan(struct expr_scan_t*) const; virtual NetEAccess*dup_expr() const; virtual NexusSet* nex_input(bool rem_out = true); private: NetBranch*branch_; ivl_nature_t nature_; }; /* * A call to a user defined task is elaborated into this object. This * contains a pointer to the elaborated task definition, but is a * NetProc object so that it can be linked into statements. */ class NetUTask : public NetProc { public: NetUTask(NetScope*); ~NetUTask(); const string name() const; const NetScope* task() const; virtual NexusSet* nex_input(bool rem_out = true); virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; private: NetScope*task_; }; /* * The while statement is a condition that is tested in the front of * each iteration, and a statement (a NetProc) that is executed as * long as the condition is true. */ class NetWhile : public NetProc { public: NetWhile(NetExpr*c, NetProc*p) : cond_(c), proc_(p) { } const NetExpr*expr() const { return cond_; } void emit_proc_recurse(struct target_t*) const; virtual NexusSet* nex_input(bool rem_out = true); virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; private: NetExpr* cond_; NetProc*proc_; }; /* * The is the top of any process. It carries the type (initial or * always) and a pointer to the statement, probably a block, that * makes up the process. */ class NetProcTop : public LineInfo, public Attrib { public: NetProcTop(NetScope*s, ivl_process_type_t t, class NetProc*st); ~NetProcTop(); ivl_process_type_t type() const { return type_; } NetProc*statement(); const NetProc*statement() const; NetScope*scope(); const NetScope*scope() const; /* Return true if this process represents combinational logic. */ bool is_asynchronous(); /* Create asynchronous logic from this thread and return true, or return false if that cannot be done. */ bool synth_async(Design*des); /* Return true if this process represents synchronous logic. */ bool is_synchronous(); /* Create synchronous logic from this thread and return true, or return false if that cannot be done. */ bool synth_sync(Design*des); void dump(ostream&, unsigned ind) const; bool emit(struct target_t*tgt) const; private: const ivl_process_type_t type_; NetProc*const statement_; NetScope*scope_; friend class Design; NetProcTop*next_; }; class NetAnalogTop : public LineInfo, public Attrib { public: NetAnalogTop(NetScope*scope, ivl_process_type_t t, NetProc*st); ~NetAnalogTop(); ivl_process_type_t type() const { return type_; } NetProc*statement(); const NetProc*statement() const; NetScope*scope(); const NetScope*scope() const; void dump(ostream&, unsigned ind) const; bool emit(struct target_t*tgt) const; private: const ivl_process_type_t type_; NetProc* statement_; NetScope*scope_; friend class Design; NetAnalogTop*next_; }; /* * This class represents a binary operator, with the left and right * operands and a single character for the operator. The operator * values are: * * ^ -- Bit-wise exclusive OR * + -- Arithmetic add * - -- Arithmetic minus * * -- Arithmetic multiply * / -- Arithmetic divide * % -- Arithmetic modulus * p -- Arithmetic power (**) * & -- Bit-wise AND * | -- Bit-wise OR * < -- Less than * > -- Greater than * e -- Logical equality (==) * E -- Case equality (===) * L -- Less or equal * G -- Greater or equal * n -- Logical inequality (!=) * N -- Case inequality (!==) * a -- Logical AND (&&) * A -- Bitwise NAND (~&) * o -- Logical OR (||) * O -- Bit-wise NOR (~|) * l -- Left shift (<<) * r -- Right shift (>>) * R -- signed right shift (>>>) * X -- Bitwise exclusive NOR (~^) * m -- min(a,b) * M -- max(a,b) */ class NetEBinary : public NetExpr { public: NetEBinary(char op, NetExpr*l, NetExpr*r); ~NetEBinary(); const NetExpr*left() const { return left_; } const NetExpr*right() const { return right_; } char op() const { return op_; } virtual bool set_width(unsigned w, bool last_chance =false); // A binary expression node only has a definite // self-determinable width if the operands both have definite // widths. virtual bool has_width() const; virtual void resolve_pexpr_type(); virtual NetEBinary* dup_expr() const; virtual NexusSet* nex_input(bool rem_out = true); virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; protected: char op_; NetExpr* left_; NetExpr* right_; bool get_real_arguments_(verireal&lv, verireal&rv); }; /* * The addition operators have slightly more complex width * calculations because there is the optional carry bit that can be * used. The operators covered by this class are: * + -- Arithmetic add * - -- Arithmetic minus */ class NetEBAdd : public NetEBinary { public: NetEBAdd(char op, NetExpr*l, NetExpr*r, bool lossless_flag =false); ~NetEBAdd(); virtual ivl_variable_type_t expr_type() const; virtual bool set_width(unsigned w, bool last_chance); virtual void cast_signed(bool sign_flag); virtual NetEBAdd* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: NetECReal* eval_tree_real_(); }; /* * This class represents the integer division operators. * / -- Divide * % -- Modulus */ class NetEBDiv : public NetEBinary { public: NetEBDiv(char op, NetExpr*l, NetExpr*r); ~NetEBDiv(); virtual ivl_variable_type_t expr_type() const; virtual bool set_width(unsigned w, bool last_chance); virtual void cast_signed(bool sign_flag); virtual NetEBDiv* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: NetExpr* eval_tree_real_(); }; /* * The bitwise binary operators are represented by this class. This is * a specialization of the binary operator, so is derived from * NetEBinary. The particular constraints on these operators are that * operand and result widths match exactly, and each bit slice of the * operation can be represented by a simple gate. The operators * covered by this class are: * * ^ -- Bit-wise exclusive OR * & -- Bit-wise AND * | -- Bit-wise OR * O -- Bit-wise NOR * X -- Bit-wise XNOR (~^) */ class NetEBBits : public NetEBinary { public: NetEBBits(char op, NetExpr*l, NetExpr*r); ~NetEBBits(); virtual bool set_width(unsigned w, bool last_chance); virtual NetEBBits* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); }; /* * The binary comparison operators are handled by this class. This * this case the bit width of the expression is 1 bit, and the * operands take their natural widths. The supported operators are: * * < -- Less than * > -- Greater than * e -- Logical equality (==) * E -- Case equality (===) * L -- Less or equal (<=) * G -- Greater or equal (>=) * n -- Logical inequality (!=) * N -- Case inequality (!==) */ class NetEBComp : public NetEBinary { public: NetEBComp(char op, NetExpr*l, NetExpr*r); ~NetEBComp(); virtual bool set_width(unsigned w, bool last_chance =false); /* A compare expression has a definite width. */ virtual bool has_width() const; virtual ivl_variable_type_t expr_type() const; virtual NetEBComp* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: NetEConst* must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag); NetEConst*eval_eqeq_(bool ne_flag); NetEConst*eval_eqeq_real_(NetExpr*le, NetExpr*ri, bool ne_flag); NetEConst*eval_less_(); NetEConst*eval_leeq_(); NetEConst*eval_leeq_real_(NetExpr*le, NetExpr*ri, bool eq_flag); NetEConst*eval_gt_(); NetEConst*eval_gteq_(); NetEConst*eval_eqeqeq_(bool ne_flag); }; /* * The binary logical operators are those that return boolean * results. The supported operators are: * * a -- Logical AND (&&) * o -- Logical OR (||) */ class NetEBLogic : public NetEBinary { public: NetEBLogic(char op, NetExpr*l, NetExpr*r); ~NetEBLogic(); virtual bool set_width(unsigned w, bool last_chance =false); virtual NetEBLogic* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: NetEConst* eval_tree_real_(); }; /* * Support the binary min(l,r) and max(l,r) operators. The opcodes * supported are: * * m -- min * M -- max */ class NetEBMinMax : public NetEBinary { public: NetEBMinMax(char op, NetExpr*l, NetExpr*r); ~NetEBMinMax(); virtual ivl_variable_type_t expr_type() const; private: }; /* * Support the binary multiplication (*) operator. */ class NetEBMult : public NetEBinary { public: NetEBMult(char op, NetExpr*l, NetExpr*r); ~NetEBMult(); virtual ivl_variable_type_t expr_type() const; virtual bool set_width(unsigned w, bool last_chance); virtual void cast_signed(bool sign_flag); virtual NetEBMult* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: NetExpr* eval_tree_real_(); }; /* * Support the binary power (**) operator. */ class NetEBPow : public NetEBinary { public: NetEBPow(char op, NetExpr*l, NetExpr*r); ~NetEBPow(); virtual ivl_variable_type_t expr_type() const; virtual bool set_width(unsigned w, bool last_chance); virtual NetEBPow* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: NetExpr* eval_tree_real_(); }; /* * The binary logical operators are those that return boolean * results. The supported operators are: * * l -- left shift (<<) * r -- right shift (>>) * R -- right shift arithmetic (>>>) */ class NetEBShift : public NetEBinary { public: NetEBShift(char op, NetExpr*l, NetExpr*r); ~NetEBShift(); virtual bool set_width(unsigned w, bool last_chance); // A shift expression only needs the left expression to have a // definite width to give the expression a definite width. virtual bool has_width() const; virtual NetEBShift* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); private: }; /* * This expression node supports the concat expression. This is an * operator that just glues the results of many expressions into a * single value. * * Note that the class stores the parameter expressions in source code * order. That is, the parm(0) is placed in the most significant * position of the result. */ class NetEConcat : public NetExpr { public: NetEConcat(unsigned cnt, NetExpr* repeat =0); ~NetEConcat(); // Manipulate the parameters. void set(unsigned idx, NetExpr*e); unsigned repeat(); unsigned repeat() const; unsigned nparms() const { return parms_.count() ; } NetExpr* parm(unsigned idx) const { return parms_[idx]; } virtual NexusSet* nex_input(bool rem_out = true); virtual bool has_width() const; virtual bool set_width(unsigned w, bool last_chance =false); virtual NetEConcat* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root); virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; private: svectorparms_; NetExpr* repeat_; unsigned repeat_value_; bool repeat_calculated_; }; /* * This class is a placeholder for a parameter expression. When * parameters are first created, an instance of this object is used to * hold the place where the parameter expression goes. Then, when the * parameters are resolved, these objects are removed. * * If the parameter object is created with a path and name, then the * object represents a reference to a parameter that is known to exist. */ class NetEParam : public NetExpr { public: NetEParam(); NetEParam(class Design*des, NetScope*scope, perm_string name); ~NetEParam(); virtual NexusSet* nex_input(bool rem_out = true); virtual void resolve_pexpr_type(); virtual bool set_width(unsigned w, bool last_chance); virtual bool has_width() const; virtual void expr_scan(struct expr_scan_t*) const; virtual ivl_variable_type_t expr_type() const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetEParam* dup_expr() const; void solving(bool arg); bool solving() const; virtual void dump(ostream&) const; private: Design*des_; NetScope*scope_; typedef map::iterator ref_t; ref_t reference_; bool solving_; NetEParam(class Design*des, NetScope*scope, ref_t ref); }; /* * This expression node supports bit/part selects from general * expressions. The sub-expression is self-sized, and has bits * selected from it. The base is the expression that identifies the * lsb of the expression, and the wid is the width of the part select, * or 1 for a bit select. No matter what the subexpression is, the * base is translated in canonical bits. It is up to the elaborator * to figure this out and adjust the expression if the subexpression * has a non-canonical base or direction. * * If the base expression is null, then this expression node can be * used to express width expansion, signed or unsigned depending on * the has_sign() flag. */ class NetESelect : public NetExpr { public: NetESelect(NetExpr*exp, NetExpr*base, unsigned wid); ~NetESelect(); const NetExpr*sub_expr() const; const NetExpr*select() const; virtual NexusSet* nex_input(bool rem_out = true); virtual bool set_width(unsigned w, bool last_chance =false); virtual bool has_width() const; virtual void expr_scan(struct expr_scan_t*) const; virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetESelect* dup_expr() const; virtual NetNet*synthesize(Design*des, NetScope*scope, NetExpr*root); virtual void dump(ostream&) const; private: NetExpr*expr_; NetExpr*base_; }; /* * This node is for representation of named events. */ class NetEEvent : public NetExpr { public: NetEEvent(NetEvent*); ~NetEEvent(); const NetEvent* event() const; virtual void expr_scan(struct expr_scan_t*) const; virtual NetEEvent* dup_expr() const; virtual NexusSet* nex_input(bool rem_out = true); virtual void dump(ostream&os) const; private: NetEvent*event_; }; /* * This class is a special (and magical) expression node type that * represents scope names. These can only be found as parameters to * NetSTask objects. */ class NetEScope : public NetExpr { public: NetEScope(NetScope*); ~NetEScope(); const NetScope* scope() const; virtual void expr_scan(struct expr_scan_t*) const; virtual NetEScope* dup_expr() const; virtual NexusSet* nex_input(bool rem_out = true); virtual void dump(ostream&os) const; private: NetScope*scope_; }; /* * This node represents a system function call in an expression. The * object contains the name of the system function, which the backend * uses to do VPI matching. */ class NetESFunc : public NetExpr { public: NetESFunc(const char*name, ivl_variable_type_t t, unsigned width, unsigned nprms); ~NetESFunc(); const char* name() const; unsigned nparms() const; void parm(unsigned idx, NetExpr*expr); NetExpr* parm(unsigned idx); const NetExpr* parm(unsigned idx) const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual ivl_variable_type_t expr_type() const; virtual NexusSet* nex_input(bool rem_out = true); virtual bool set_width(unsigned, bool last_chance); virtual void dump(ostream&) const; virtual void expr_scan(struct expr_scan_t*) const; virtual NetESFunc*dup_expr() const; virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root); private: const char* name_; ivl_variable_type_t type_; unsigned nparms_; NetExpr**parms_; private: // not implemented NetESFunc(const NetESFunc&); NetESFunc& operator= (const NetESFunc&); }; /* * This class represents the ternary (?:) operator. It has 3 * expressions, one of which is a condition used to select which of * the other two expressions is the result. */ class NetETernary : public NetExpr { public: NetETernary(NetExpr*c, NetExpr*t, NetExpr*f); ~NetETernary(); virtual bool set_width(unsigned w, bool last_chance); const NetExpr*cond_expr() const; const NetExpr*true_expr() const; const NetExpr*false_expr() const; virtual NetETernary* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual ivl_variable_type_t expr_type() const; virtual NexusSet* nex_input(bool rem_out = true); virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root); public: static bool test_operand_compat(ivl_variable_type_t tru, ivl_variable_type_t fal); private: NetExpr*cond_; NetExpr*true_val_; NetExpr*false_val_; }; /* * This class represents a unary operator, with the single operand * and a single character for the operator. The operator values are: * * ~ -- Bit-wise negation * ! -- Logical negation * & -- Reduction AND * | -- Reduction OR * ^ -- Reduction XOR * + -- * - -- * A -- Reduction NAND (~&) * N -- Reduction NOR (~|) * X -- Reduction NXOR (~^ or ^~) * m -- abs(x) (i.e. "magnitude") */ class NetEUnary : public NetExpr { public: NetEUnary(char op, NetExpr*ex); ~NetEUnary(); char op() const { return op_; } const NetExpr* expr() const { return expr_; } virtual bool set_width(unsigned w, bool last_chance); virtual NetEUnary* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual ivl_variable_type_t expr_type() const; virtual NexusSet* nex_input(bool rem_out = true); virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; protected: char op_; NetExpr* expr_; private: virtual NetExpr* eval_tree_real_(); }; class NetEUBits : public NetEUnary { public: NetEUBits(char op, NetExpr*ex); ~NetEUBits(); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetEUBits* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual ivl_variable_type_t expr_type() const; }; class NetEUReduce : public NetEUnary { public: NetEUReduce(char op, NetExpr*ex); ~NetEUReduce(); virtual bool set_width(unsigned w, bool last_chance); virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual NetEUReduce* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); virtual ivl_variable_type_t expr_type() const; private: virtual NetEConst* eval_tree_real_(); }; /* * When a signal shows up in an expression, this type represents * it. From this the expression can get any kind of access to the * structural signal, including arrays. * * The NetESignal may refer to an array, if the word_index is * included. This expression calculates the index of the word in the * array. It may only be nil if the expression refers to the whole * array, and that is legal only in limited situation. */ class NetESignal : public NetExpr { public: NetESignal(NetNet*n); NetESignal(NetNet*n, NetExpr*word_index); ~NetESignal(); perm_string name() const; virtual bool set_width(unsigned, bool last_chance); virtual NetESignal* dup_expr() const; NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root); NexusSet* nex_input(bool rem_out = true); // This is the expression for selecting an array word, if this // signal refers to an array. const NetExpr* word_index() const; // This is the width of the vector that this signal refers to. unsigned vector_width() const; // Point back to the signal that this expression node references. const NetNet* sig() const; NetNet* sig(); // Declared vector dimensions for the signal. long msi() const; long lsi() const; virtual ivl_variable_type_t expr_type() const; virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; private: NetNet*net_; // Expression to select a word from the net. NetExpr*word_; }; /* * The Design object keeps a list of work items for processing * elaboration. This is the type of those work items. */ struct elaborator_work_item_t { explicit elaborator_work_item_t(Design*d) : des(d) { } virtual ~elaborator_work_item_t() { } virtual void elaborate_runrun() =0; protected: Design*des; }; /* * This class contains an entire design. It includes processes and a * netlist, and can be passed around from function to function. */ class Design { public: Design(); ~Design(); /* The flags are a generic way of accepting command line parameters/flags and passing them to the processing steps that deal with the design. The compilation driver sets the entire flags map after elaboration is done. Subsequent steps can then use the get_flag() function to get the value of an interesting key. */ void set_flags(const map&f) { flags_ = f; } const char* get_flag(const string&key) const; NetScope* make_root_scope(perm_string name); NetScope* find_root_scope(); list find_root_scopes(); const list find_root_scopes() const; /* Attempt to set the precision to the specified value. If the precision is already more precise, the keep the precise setting. This is intended to hold the simulation precision for use throughout the entire design. */ void set_precision(int val); int get_precision() const; /* This function takes a delay value and a scope, and returns the delay value scaled to the precision of the design. */ uint64_t scale_to_precision(uint64_t, const NetScope*)const; /* Look up a scope. If no starting scope is passed, then the path is taken as an absolute scope name. Otherwise, the scope is located starting at the passed scope and working up if needed. */ NetScope* find_scope(const std::list&path) const; NetScope* find_scope(NetScope*, const std::list&path, NetScope::TYPE type = NetScope::MODULE) const; /* These members help manage elaboration of scopes. When we get to a point in scope elaboration where we want to put off a scope elaboration, an object of scope_elaboration_t is pushed onto the scope_elaborations list. The scope elaborator will go through this list elaborating scopes until the list is empty. */ listelaboration_work_list; void run_elaboration_work(void); set defparams_later; // PARAMETERS void run_defparams(); void evaluate_parameters(); // Look for defparams that never matched, and print warnings. void residual_defparams(); /* This method locates a signal, starting at a given scope. The name parameter may be partially hierarchical, so this method, unlike the NetScope::find_signal method, handles global name binding. */ NetNet*find_signal(NetScope*scope, pform_name_t path); // Functions NetFuncDef* find_function(NetScope*scope, const pform_name_t&key); // Tasks NetScope* find_task(NetScope*scope, const pform_name_t&name); // NODES void add_node(NetNode*); void del_node(NetNode*); // BRANCHES void add_branch(NetBranch*); // PROCESSES void add_process(NetProcTop*); void add_process(NetAnalogTop*); void delete_process(NetProcTop*); bool check_always_delay() const; NetNet* find_discipline_reference(ivl_discipline_t dis, NetScope*scope); // Iterate over the design... void dump(ostream&) const; void functor(struct functor_t*); void join_islands(void); int emit(struct target_t*) const; // This is incremented by elaboration when an error is // detected. It prevents code being emitted. unsigned errors; private: // Keep a tree of scopes. The NetScope class handles the wide // tree and per-hop searches for me. listroot_scopes_; // List the nodes in the design. NetNode*nodes_; // These are in support of the node functor iterator. NetNode*nodes_functor_cur_; NetNode*nodes_functor_nxt_; // List the branches in the design. NetBranch*branches_; // List the processes in the design. NetProcTop*procs_; NetProcTop*procs_idx_; // List the ANALOG processes in the design. NetAnalogTop*aprocs_; // Map of discipline take to NetNet for the reference node. mapdiscipline_references_; // Map the design arguments to values. map flags_; int des_precision_; private: // not implemented Design(const Design&); Design& operator= (const Design&); }; /* ======= */ inline bool operator == (const Link&l, const Link&r) { return l.is_equal(r); } inline bool operator != (const Link&l, const Link&r) { return ! l.is_equal(r); } /* Connect the pins of two nodes together. Either may already be connected to other things, connect is transitive. */ extern void connect(Link&, Link&); /* Return true if l and r are connected. */ inline bool connected(const Link&l, const Link&r) { return l.is_linked(r); } /* Return the number of links in the ring that are of the specified type. */ extern unsigned count_inputs(const Link&pin); extern unsigned count_outputs(const Link&pin); extern unsigned count_signals(const Link&pin); /* Find the next link that is an output into the nexus. */ extern Link* find_next_output(Link*lnk); /* Find the signal connected to the given node pin. There should always be exactly one signal. The bidx parameter gets filled with the signal index of the Net, in case it is a vector. */ const NetNet* find_link_signal(const NetObj*net, unsigned pin, unsigned&bidx); inline ostream& operator << (ostream&o, const NetExpr&exp) { exp.dump(o); return o; } extern ostream& operator << (ostream&, NetNet::Type); /* * Manipulator to dump a scope complete path to the output. The * manipulator is "scope_path" and works like this: * * out << .... << scope_path(sc) << ... ; */ struct __ScopePathManip { const NetScope*scope; }; inline __ScopePathManip scope_path(const NetScope*scope) { __ScopePathManip tmp; tmp.scope = scope; return tmp; } extern ostream& operator << (ostream&o, __ScopePathManip); #endif verilog-0.9.7/PaxHeaders.14238/eval.cc0000644000202500001440000000005012204466647015466 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/eval.cc0000644000202500001440000001503212204466647015011 0ustar00steveusers00000000000000/* * Copyright (c) 1998-1999 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include # include # include "PExpr.h" # include "netlist.h" # include "netmisc.h" # include "compiler.h" verinum* PExpr::eval_const(Design*, NetScope*) const { return 0; } verinum* PEBinary::eval_const(Design*des, NetScope*scope) const { verinum*l = left_->eval_const(des, scope); if (l == 0) return 0; verinum*r = right_->eval_const(des, scope); if (r == 0) { delete l; return 0; } verinum*res; switch (op_) { case '+': { if (l->is_defined() && r->is_defined()) { res = new verinum(*l + *r); } else { res = new verinum(verinum::Vx, l->len()); } break; } case '-': { if (l->is_defined() && r->is_defined()) { res = new verinum(*l - *r); } else { res = new verinum(verinum::Vx, l->len()); } break; } case '*': { if (l->is_defined() && r->is_defined()) { res = new verinum(*l * *r); } else { res = new verinum(verinum::Vx, l->len()); } break; } case '/': { if (l->is_defined() && r->is_defined()) { long lv = l->as_long(); long rv = r->as_long(); res = new verinum(lv / rv, l->len()); } else { res = new verinum(verinum::Vx, l->len()); } break; } case '%': { if (l->is_defined() && r->is_defined()) { long lv = l->as_long(); long rv = r->as_long(); res = new verinum(lv % rv, l->len()); } else { res = new verinum(verinum::Vx, l->len()); } break; } case '>': { if (l->is_defined() && r->is_defined()) { long lv = l->as_long(); long rv = r->as_long(); res = new verinum(lv > rv, l->len()); } else { res = new verinum(verinum::Vx, l->len()); } break; } case '<': { if (l->is_defined() && r->is_defined()) { long lv = l->as_long(); long rv = r->as_long(); res = new verinum(lv < rv, l->len()); } else { res = new verinum(verinum::Vx, l->len()); } break; } case 'l': { // left shift (<<) assert(r->is_defined()); unsigned long rv = r->as_ulong(); res = new verinum(verinum::V0, l->len()); if (rv < res->len()) { unsigned cnt = res->len() - rv; for (unsigned idx = 0 ; idx < cnt ; idx += 1) res->set(idx+rv, l->get(idx)); } break; } case 'r': { // right shift (>>) assert(r->is_defined()); unsigned long rv = r->as_ulong(); res = new verinum(verinum::V0, l->len()); if (rv < res->len()) { unsigned cnt = res->len() - rv; for (unsigned idx = 0 ; idx < cnt ; idx += 1) res->set(idx, l->get(idx+rv)); } break; } default: delete l; delete r; return 0; } delete l; delete r; return res; } verinum* PEConcat::eval_const(Design*des, NetScope*scope) const { verinum*accum = parms_[0]->eval_const(des, scope); if (accum == 0) return 0; for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) { verinum*tmp = parms_[idx]->eval_const(des, scope); if (tmp == 0) { delete accum; return 0; } assert(tmp); *accum = concat(*accum, *tmp); delete tmp; } return accum; } /* * Evaluate an identifier as a constant expression. This is only * possible if the identifier is that of a parameter. */ verinum* PEIdent::eval_const(Design*des, NetScope*scope) const { assert(scope); NetNet*net; NetEvent*eve; const NetExpr*expr; const name_component_t&name_tail = path_.back(); // Handle the special case that this ident is a genvar // variable name. In that case, the genvar meaning preempts // everything and we just return that value immediately. if (scope->genvar_tmp && strcmp(name_tail.name,scope->genvar_tmp) == 0) { return new verinum(scope->genvar_tmp_val); } symbol_search(this, des, scope, path_, net, expr, eve); if (expr == 0) return 0; const NetEConst*eval = dynamic_cast(expr); if (eval == 0) { cerr << get_fileline() << ": internal error: Unable to evaluate " << "constant expression (parameter=" << path_ << "): " << *expr << endl; return 0; } assert(eval); if (!name_tail.index.empty()) return 0; return new verinum(eval->value()); } verinum* PEFNumber::eval_const(Design*, NetScope*) const { long val = value_->as_long(); return new verinum(val); } verinum* PENumber::eval_const(Design*, NetScope*) const { return new verinum(value()); } verinum* PEString::eval_const(Design*, NetScope*) const { return new verinum(string(text_)); } verinum* PETernary::eval_const(Design*des, NetScope*scope) const { verinum*test = expr_->eval_const(des, scope); if (test == 0) return 0; verinum::V bit = test->get(0); delete test; switch (bit) { case verinum::V0: return fal_->eval_const(des, scope); case verinum::V1: return tru_->eval_const(des, scope); default: return 0; // XXXX It is possible to handle this case if both fal_ // and tru_ are constant. Someday... } } verinum* PEUnary::eval_const(Design*des, NetScope*scope) const { verinum*val = expr_->eval_const(des, scope); if (val == 0) return 0; switch (op_) { case '+': return val; case '-': { /* We need to expand the value a bit if we are taking the 2's complement so that we are guaranteed to not overflow. */ verinum tmp ((uint64_t)0, val->len()+1); for (unsigned idx = 0 ; idx < val->len() ; idx += 1) tmp.set(idx, val->get(idx)); *val = v_not(tmp) + verinum(verinum::V1, 1); val->has_sign(true); return val; } } delete val; return 0; } verilog-0.9.7/PaxHeaders.14238/net_tran.cc0000644000202500001440000000005012204466647016351 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/net_tran.cc0000644000202500001440000001131612204466647015675 0ustar00steveusers00000000000000/* * Copyright (c) 2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include # include # include # include "compiler.h" # include "netlist.h" # include "netmisc.h" # include "ivl_target_priv.h" # include "ivl_assert.h" static bool has_enable(ivl_switch_type_t tt) { switch (tt) { case IVL_SW_TRANIF0: case IVL_SW_TRANIF1: case IVL_SW_RTRANIF0: case IVL_SW_RTRANIF1: return true; default: return false; } } NetTran::NetTran(NetScope*scope__, perm_string n, ivl_switch_type_t tt) : NetNode(scope__, n, has_enable(tt)? 3 : 2), type_(tt) { pin(0).set_dir(Link::PASSIVE); pin(1).set_dir(Link::PASSIVE); if (pin_count() == 3) { pin(2).set_dir(Link::INPUT); // Enable } } NetTran::NetTran(NetScope*scope__, perm_string n, unsigned wid, unsigned part, unsigned off) : NetNode(scope__, n, 2), type_(IVL_SW_TRAN_VP), wid_(wid), part_(part), off_(off) { pin(0).set_dir(Link::PASSIVE); pin(1).set_dir(Link::PASSIVE); } NetTran::~NetTran() { } unsigned NetTran::vector_width() const { return wid_; } unsigned NetTran::part_width() const { return part_; } unsigned NetTran::part_offset() const { return off_; } void join_island(NetPins*obj) { IslandBranch*branch = dynamic_cast (obj); // If this is not even a branch, then stop now. if (branch == 0) return; // If this is a branch, but already given to an island, then // stop. if (branch->island_) return; list uncommitted_neighbors; // Look for neighboring objects that might already be in // islands. If we find something, then join that island. for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) { Nexus*nex = obj->pin(idx).nexus(); for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) { unsigned pin; NetPins*tmp_pins; cur->cur_link(tmp_pins, pin); NetObj*tmp = dynamic_cast (tmp_pins); if (tmp == 0) continue; // Skip self. if (tmp == obj) continue; // If tmp is not a branch, then skip it. IslandBranch*tmp_branch = dynamic_cast (tmp); if (tmp_branch == 0) continue; // If tmp is an uncommitted branch, then save // it. When I finally choose an island for self, // these branches will be scanned so that they join // this island as well. if (tmp_branch->island_ == 0) { uncommitted_neighbors.push_back(tmp); continue; } ivl_assert(*obj, branch->island_==0 || branch->island_==tmp_branch->island_); // We found an existing island to join. Join it // now. Keep scanning in order to find more neighbors. if (branch->island_ == 0) { if (debug_elaborate) cerr << obj->get_fileline() << ": debug: " << "Join branch to existing island." << endl; branch->island_ = tmp_branch->island_; ivl_assert(*obj, branch->island_->discipline == tmp_branch->island_->discipline); } else if (branch->island_ != tmp_branch->island_) { cerr << obj->get_fileline() << ": internal error: " << "Oops, Found 2 neighboring islands." << endl; ivl_assert(*obj, 0); } } } // If after all that we did not find an island to join, then // start the island not and join it. if (branch->island_ == 0) { branch->island_ = new ivl_island_s; branch->island_->discipline = branch->discipline_; if (debug_elaborate) cerr << obj->get_fileline() << ": debug: " << "Create new island for this branch" << endl; } // Now scan all the uncommitted neighbors I found. Calling // join_island() on them will cause them to notice me in the // process, and thus they will join my island. This process // will recurse until all the connected branches join this island. for (list::iterator cur = uncommitted_neighbors.begin() ; cur != uncommitted_neighbors.end() ; cur ++ ) { join_island(*cur); } } verilog-0.9.7/PaxHeaders.14238/elab_sig_analog.cc0000644000202500001440000000005012204466647017625 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/elab_sig_analog.cc0000644000202500001440000000165212204466647017153 0ustar00steveusers00000000000000/* * Copyright (c) 2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "AStatement.h" # include # include verilog-0.9.7/PaxHeaders.14238/mkinstalldirs0000644000202500001440000000005012204466647017033 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/mkinstalldirs0000755000202500001440000000664712204466647016375 0ustar00steveusers00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy scriptversion=2006-05-11.19 # Original author: Noah Friedman # Created: 1993-05-16 # Public domain. # # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' IFS=" "" $nl" errstatus=0 dirmode= usage="\ Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... Create each directory DIR (with mode MODE, if specified), including all leading file name components. Report bugs to ." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help echo "$usage" exit $? ;; -m) # -m PERM arg shift test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } dirmode=$1 shift ;; --version) echo "$0 $scriptversion" exit $? ;; --) # stop option processing shift break ;; -*) # unknown option echo "$usage" 1>&2 exit 1 ;; *) # first non-opt arg break ;; esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac # Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and # mkdir -p a/c at the same time, both will detect that a is missing, # one will create a, then the other will try to create a and die with # a "File exists" error. This is a problem when calling mkinstalldirs # from a parallel make. We use --version in the probe to restrict # ourselves to GNU mkdir, which is thread-safe. case $dirmode in '') if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. test -d ./-p && rmdir ./-p test -d ./--version && rmdir ./--version fi ;; *) if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" else # Clean up after NextStep and OpenStep mkdir. for d in ./-m ./-p ./--version "./$dirmode"; do test -d $d && rmdir $d done fi ;; esac for file do case $file in /*) pathcomp=/ ;; *) pathcomp= ;; esac oIFS=$IFS IFS=/ set fnord $file shift IFS=$oIFS for d do test "x$d" = x && continue pathcomp=$pathcomp$d case $pathcomp in -*) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr else if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" lasterr= chmod "$dirmode" "$pathcomp" || lasterr=$? if test ! -z "$lasterr"; then errstatus=$lasterr fi fi fi fi pathcomp=$pathcomp/ done done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: verilog-0.9.7/PaxHeaders.14238/acc_user.h0000644000202500001440000000005012204466647016165 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/acc_user.h0000644000202500001440000001663712204466647015524 0ustar00steveusers00000000000000#ifndef __acc_user_H #define __acc_user_H /* * Copyright (c) 2002 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * This header file contains the definitions and declarations needed * by an Icarus Verilog user using acc_ routines. * * NOTE: Icarus Verilog does not support acc_ routines. This is just a * stub. The functions that are implemented here are actually * implemented using VPI routines. */ #ifdef __cplusplus # define EXTERN_C_START extern "C" { # define EXTERN_C_END } #else # define EXTERN_C_START # define EXTERN_C_END # define bool int #endif EXTERN_C_START # include "_pli_types.h" /* * This is a declaration of the "handle" type that is compatible with * the vpiHandle from vpi_user.h. The libveriuser library implements * the acc handle type as a vpiHandle, to prevent useless indirection. */ typedef struct __vpiHandle *handle; /* OBJECT TYPES */ #define accModule 20 #define accScope 21 #define accNet 25 #define accReg 30 #define accIntegerParam 200 #define accRealParam 202 #define accStringParam 204 #define accParameter 220 #define accTopModule 224 #define accModuleInstance 226 #define accWire 260 #define accNamedEvent 280 #define accIntegerVar 281 #define accRealVar 282 #define accTimeVar 283 #define accIntVar accIntegerVar #define accScalar 300 #define accVector 302 #define accUnknown 412 #define accConstant 600 /* type VALUES FOR t_setval_delay STRUCTURE */ #define accNoDelay 0 #define accInertialDelay 1 #define accTransportDelay 2 #define accPureTransportDelay 3 #define accForceFlag 4 #define accReleaseFlag 5 /* type VALUES FOR t_setval_value STRUCTURE */ #define accBinStrVal 1 #define accOctStrVal 2 #define accDecStrVal 3 #define accHexStrVal 4 #define accScalarVal 5 #define accIntVal 6 #define accRealVal 7 #define accStringVal 8 #define accVectorVal 9 /* Scalar values */ #define acc0 0 #define acc1 1 #define accX 2 #define accZ 3 /* type VALUES FOR t_acc_time STRUCTURE */ #define accTime 1 #define accSimTime 2 #define accRealTime 3 /* reason codes */ #define logic_value_change 1 #define strength_value_change 2 #define real_value_change 3 #define vector_value_change 4 #define event_value_change 5 #define integer_value_change 6 #define time_value_change 7 #define sregister_value_change 8 #define vregister_value_change 9 #define realtime_value_change 10 /* VCL strength values */ #define vclSupply 7 #define vclStrong 6 #define vclPull 5 #define vclLarge 4 #define vclWeak 3 #define vclMedium 2 #define vclSmall 1 #define vclHighZ 0 /* Constants used by acc_vcl_add */ #define vcl_verilog_logic 2 #define VCL_VERILOG_LOGIC vcl_verilog_logic #define vcl_verilog_strength 3 #define VCL_VERILOG_STRENGTH vcl_verilog_strength typedef struct t_acc_time { int type; int low, high; double real; } s_acc_time, *p_acc_time; typedef struct t_setval_delay { s_acc_time time; int model; } s_setval_delay, *p_setval_delay; typedef struct t_acc_vecval { int aval; int bval; } s_acc_vecval, *p_acc_vecval; typedef struct t_setval_value { int format; union { char*str; int scalar; int integer; double real; p_acc_vecval vector; } value; } s_setval_value, *p_setval_value, s_acc_value, *p_acc_value; typedef struct t_strengths { PLI_UBYTE8 logic_value; PLI_UBYTE8 strength1; PLI_UBYTE8 strength2; } s_strengths, *p_strengths; typedef struct t_vc_record { PLI_INT32 vc_reason; PLI_INT32 vc_hightime; PLI_INT32 vc_lowtime; void* user_data; union { PLI_UBYTE8 logic_value; double real_value; handle vector_handle; s_strengths strengths_s; } out_value; } s_vc_record, *p_vc_record; typedef struct t_location { PLI_INT32 line_no; const char*filename; } s_location, *p_location; extern int acc_error_flag; extern int acc_initialize(void); extern void acc_close(void); /* * This is the acc_configure command, and the config_param * codes that are accepted. */ extern int acc_configure(PLI_INT32 config_param, const char*value); #define accEnableArgs 6 #define accDevelopmentVersion 11 extern int acc_fetch_argc(void); extern char**acc_fetch_argv(void); extern PLI_INT32 acc_fetch_direction(handle obj); /* XXXX FIXME: Values returned by acc_fetch_direction */ # define accInout 2 extern char* acc_fetch_fullname(handle obj); extern int acc_fetch_location(p_location loc, handle obj); extern char* acc_fetch_name(handle obj); extern char* acc_fetch_defname(handle obj); extern double acc_fetch_paramval(handle obj); extern double acc_fetch_tfarg(PLI_INT32); extern double acc_fetch_itfarg(PLI_INT32, handle); extern PLI_INT32 acc_fetch_tfarg_int(PLI_INT32); extern PLI_INT32 acc_fetch_itfarg_int(PLI_INT32, handle); extern char* acc_fetch_tfarg_str(PLI_INT32); extern char* acc_fetch_itfarg_str(PLI_INT32, handle); typedef struct t_timescale_info { PLI_INT16 unit; PLI_INT16 precision; } s_timescale_info, *p_timescale_info; extern void acc_fetch_timescale_info(handle obj, p_timescale_info info); extern PLI_INT32 acc_fetch_size(handle obj); extern PLI_INT32 acc_fetch_type(handle obj); extern PLI_INT32 acc_fetch_fulltype(handle obj); extern PLI_INT32 acc_fetch_range(handle object, int *msb, int *lsb); extern char* acc_fetch_type_str(PLI_INT32 type); extern char* acc_fetch_value(handle obj, const char*fmt, s_acc_value*value); extern handle acc_handle_by_name(const char*name, handle scope); extern handle acc_handle_hiconn(handle port_ref_handle); extern handle acc_handle_object(const char*name); extern handle acc_handle_parent(handle obj); extern handle acc_handle_scope(handle obj); extern handle acc_handle_simulated_net(handle net); extern handle acc_handle_tfarg(int n); extern handle acc_handle_tfinst(void); extern PLI_INT32 acc_compare_handles(handle, handle); extern handle acc_next(PLI_INT32 *, handle, handle); extern handle acc_next_bit(handle ref, handle bit); extern handle acc_next_port(handle ref, handle bit); extern handle acc_next_scope(handle, handle); extern handle acc_next_topmod(handle prev_topmod); extern int acc_object_in_typelist(handle object, PLI_INT32*typelist); extern int acc_object_of_type(handle object, PLI_INT32 type); extern char*acc_product_version(void); extern char*acc_set_scope(handle ref, ...); extern int acc_set_value(handle obj, p_setval_value value, p_setval_delay delay); extern void acc_vcl_add(handle obj, PLI_INT32(*consumer)(p_vc_record), void*data, PLI_INT32 vcl_flag); extern void acc_vcl_delete(handle obj, PLI_INT32(*consumer)(p_vc_record), void*data, PLI_INT32 vcl_flag); extern char* acc_version(void); EXTERN_C_END #endif verilog-0.9.7/PaxHeaders.14238/PGenerate.cc0000644000202500001440000000005012204466647016411 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/PGenerate.cc0000644000202500001440000000576412204466647015747 0ustar00steveusers00000000000000/* * Copyright (c) 2006,2009 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "PGenerate.h" # include "PWire.h" # include "ivl_assert.h" PGenerate::PGenerate(unsigned id) : id_number(id) { direct_nested_ = false; parent = 0; lexical_scope = 0; } PGenerate::~PGenerate() { } void PGenerate::add_gate(PGate*gate) { gates.push_back(gate); } void PGenerate::probe_for_direct_nesting_(void) { direct_nested_ = false; ivl_assert(*this, scheme_type==GS_CASE_ITEM || scheme_type==GS_CONDIT || scheme_type==GS_ELSE); // If this scheme has received an explicit name, then it // cannot be direct nested. if (scope_name[0] != '$') return; if (tasks.size() > 0) return; if (funcs.size() > 0) return; if (gates.size() > 0) return; if (parameters.size() > 0) return; if (localparams.size() > 0) return; if (events.size() > 0) return; if (wires.size() > 0) return; if (genvars.size() > 0) return; if (behaviors.size() > 0) return; if (analog_behaviors.size() > 0) return; if (generate_schemes.size() == 0) return; switch (generate_schemes.size()) { case 1: { PGenerate*child = generate_schemes.front(); if (child->scheme_type == GS_CONDIT) direct_nested_ = true; if (child->scheme_type == GS_CASE) direct_nested_ = true; break; } case 2: { PGenerate*child1 = generate_schemes.front(); PGenerate*child2 = generate_schemes.back(); if (child1->scheme_type==GS_CONDIT && child2->scheme_type==GS_ELSE) direct_nested_ = true; if (child2->scheme_type==GS_CONDIT && child1->scheme_type==GS_ELSE) direct_nested_ = true; break; } } } ostream& operator << (ostream&out, PGenerate::scheme_t type) { switch (type) { case PGenerate::GS_NONE: out << "GS_NONE"; break; case PGenerate::GS_LOOP: out << "GS_LOOP"; break; case PGenerate::GS_CONDIT: out << "GS_CONDIT"; break; case PGenerate::GS_ELSE: out << "GS_ELSE"; break; case PGenerate::GS_CASE: out << "GS_CASE"; break; case PGenerate::GS_CASE_ITEM: out << "GS_CASE_ITEM"; break; case PGenerate::GS_NBLOCK: out << "GS_NBLOCK"; break; } return out; } verilog-0.9.7/PaxHeaders.14238/PWire.cc0000644000202500001440000000005012204466647015565 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/PWire.cc0000644000202500001440000001153712204466647015116 0ustar00steveusers00000000000000/* * Copyright (c) 1999-2011 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "PWire.h" # include "PExpr.h" # include PWire::PWire(perm_string n, NetNet::Type t, NetNet::PortType pt, ivl_variable_type_t dt) : name_(n), type_(t), port_type_(pt), data_type_(dt), signed_(false), isint_(false), port_msb_(0), port_lsb_(0), port_set_(false), net_msb_(0), net_lsb_(0), net_set_(false), is_scalar_(false), error_cnt_(0), lidx_(0), ridx_(0), discipline_(0) { if (t == NetNet::INTEGER) { type_ = NetNet::REG; signed_ = true; isint_ = true; } } NetNet::Type PWire::get_wire_type() const { return type_; } perm_string PWire::basename() const { return name_; } bool PWire::set_wire_type(NetNet::Type t) { assert(t != NetNet::IMPLICIT); switch (type_) { case NetNet::IMPLICIT: type_ = t; return true; case NetNet::IMPLICIT_REG: if (t == NetNet::REG) { type_ = t; return true; } if (t == NetNet::INTEGER) { type_ = NetNet::REG; isint_ = true; return true; } return false; case NetNet::REG: if (t == NetNet::INTEGER) { isint_ = true; return true; } if (t == NetNet::REG) return true; return false; default: if (type_ != t) return false; else return true; } } NetNet::PortType PWire::get_port_type() const { return port_type_; } bool PWire::set_port_type(NetNet::PortType pt) { assert(pt != NetNet::NOT_A_PORT); assert(pt != NetNet::PIMPLICIT); switch (port_type_) { case NetNet::PIMPLICIT: port_type_ = pt; return true; case NetNet::NOT_A_PORT: return false; default: if (port_type_ != pt) return false; else return true; } } bool PWire::set_data_type(ivl_variable_type_t dt) { if (data_type_ != IVL_VT_NO_TYPE) { if (data_type_ != dt) return false; else return true; } assert(data_type_ == IVL_VT_NO_TYPE); data_type_ = dt; return true; } ivl_variable_type_t PWire::get_data_type() const { return data_type_; } void PWire::set_signed(bool flag) { signed_ = flag; } bool PWire::get_signed() const { return signed_; } bool PWire::get_isint() const { return isint_; } bool PWire::get_scalar() const { return is_scalar_; } void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) { switch (type) { case SR_PORT: if (port_set_) { cerr << get_fileline() << ": error: Port ``" << name_ << "'' has already been declared a port." << endl; error_cnt_ += 1; } else { port_msb_ = m; port_lsb_ = l; port_set_ = true; is_scalar_ = is_scalar; } return; case SR_NET: if (net_set_) { cerr << get_fileline() << ": error: Net ``" << name_ << "'' has already been declared." << endl; error_cnt_ += 1; } else { net_msb_ = m; net_lsb_ = l; net_set_ = true; is_scalar_ = is_scalar; } return; case SR_BOTH: if (port_set_ || net_set_) { if (port_set_) { cerr << get_fileline() << ": error: Port ``" << name_ << "'' has already been declared a port." << endl; error_cnt_ += 1; } if (net_set_) { cerr << get_fileline() << ": error: Net ``" << name_ << "'' has already been declared." << endl; error_cnt_ += 1; } } else { port_msb_ = m; port_lsb_ = l; port_set_ = true; net_msb_ = m; net_lsb_ = l; net_set_ = true; is_scalar_ = is_scalar; } return; } } void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx) { if (lidx_ != 0 || ridx_ != 0) { cerr << get_fileline() << ": error: Array ``" << name_ << "'' has already been declared." << endl; error_cnt_ += 1; } else { lidx_ = ldx; ridx_ = rdx; } } void PWire::set_discipline(ivl_discipline_t d) { assert(discipline_ == 0); discipline_ = d; } ivl_discipline_t PWire::get_discipline(void) const { return discipline_; } verilog-0.9.7/PaxHeaders.14238/discipline.h0000644000202500001440000000005012204466647016524 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/discipline.h0000644000202500001440000000476712204466647016064 0ustar00steveusers00000000000000#ifndef __discipline_H #define __discipline_H /* * Copyright (c) 2008-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * The discipline types include the discipline, nature and other * related types for managing declared and used disciplines in a * Verilog-AMS program. */ # include "StringHeap.h" # include # include # include "ivl_target.h" # include "LineInfo.h" extern std::ostream& operator << (std::ostream&, ivl_dis_domain_t); class ivl_nature_s : public LineInfo { public: explicit ivl_nature_s(perm_string name, perm_string access); ~ivl_nature_s(); perm_string name() const { return name_; } // Identifier for the access function for this nature perm_string access() const { return access_; } private: perm_string name_; perm_string access_; }; class ivl_discipline_s : public LineInfo { public: explicit ivl_discipline_s (perm_string name, ivl_dis_domain_t dom, ivl_nature_t pot, ivl_nature_t flow); ~ivl_discipline_s(); perm_string name() const { return name_; } ivl_dis_domain_t domain() const { return domain_; } ivl_nature_t potential() const { return potential_; } ivl_nature_t flow() const { return flow_; } private: perm_string name_; ivl_dis_domain_t domain_; ivl_nature_t potential_; ivl_nature_t flow_; private: // not implemented ivl_discipline_s(const ivl_discipline_s&); ivl_discipline_s& operator = (const ivl_discipline_s&); }; extern map natures; extern map disciplines; // Map access function name to the nature that it accesses. extern map access_function_nature; #endif verilog-0.9.7/PaxHeaders.14238/t-dll.txt0000644000202500001440000000005012204466647016005 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/t-dll.txt0000644000202500001440000000406612204466647015335 0ustar00steveusers00000000000000 LOADABLE TARGETS Icarus Verilog supports dynamically loading code generator modules to perform the back-end processing of the completed design. The user specifies on the command line the module to load. The compiler loads the module (once the design is compiled and elaborated) and calls it to finally handle the design. Loadable target modules implement a set of functions that the core compiler calls to pass the design to it, and the module in turn uses a collection of functions in the core (the API) to access details of the design. LOADING TARGET MODULES The target module loader is invoked with the ivl flag "-tdll". That is, the DLL loader is a linked in target type. The name of the target module to load is then specified with the DLL flag, i.e. "-fDLL=". COMPILING TARGET MODULES LOADABLE TARGET MODULE API The target module API is defined in the ivl_target.h header file. This declares all the type and functions that a loadable module needs to access the design. ABOUT SPECIFIC EXPRESSION TYPES In this section find notes about the various kinds of expression nodes. The notes here are in addition to the more generation documentation in the ivl_target.h header file. * IVL_EX_CONCAT The concatenation operator forms an expression node that holds the repeat count and all the parameter expressions. The repeat count is an integer that is calculated by the core compiler so it fully evaluated, and *not* an expression. The parameter expressions are retrieved by the ivl_expr_parm method, with the index increasing as parameters go from left to right, from most significant to least significant. (Note that this is different from the order of bits within an expression node.) * IVL_EX_NUMBER This is a constant number. The width is fully known, and the bit values are all represented by the ASCII characters 0, 1, x or z. The ivl_expr_bits method returns a pointer to the least significant bit, and the remaining bits are ordered from least significant to most significant. For example, 5'b1zzx0 is the 5 character string "0xzz1". verilog-0.9.7/PaxHeaders.14238/libveriuser0000644000202500001440000000005012204466647016506 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/0000755000202500001440000000000012204466647016105 5ustar00steveusers00000000000000verilog-0.9.7/libveriuser/PaxHeaders.14238/a_next_port.c0000644000202500001440000000005012204466647021251 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_next_port.c0000644000202500001440000000274612204466647020604 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_next_port.c,v 1.1 2003/10/10 02:57:46 steve Exp $" #endif # include # include # include # include # include "priv.h" handle acc_next_port(handle ref, handle bit) { if (pli_trace) { fprintf(pli_trace, "acc_next_port: enter.\n"); fflush(pli_trace); } fprintf(stderr, "acc_next_port: XXXX not implemented. XXXX\n"); if (pli_trace) { fprintf(pli_trace, "acc_next_port: return.\n"); fflush(pli_trace); } return 0; } /* * $Log: a_next_port.c,v $ * Revision 1.1 2003/10/10 02:57:46 steve * Some PLI1 stubs. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_handle_object.c0000644000202500001440000000005012204466647022010 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_handle_object.c0000644000202500001440000000357312204466647021342 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_handle_object.c,v 1.2 2003/12/17 15:45:07 steve Exp $" #endif #include #include #include "priv.h" static vpiHandle search_scope = 0; handle acc_handle_object(const char*name) { vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle scope = search_scope? search_scope : vpi_handle(vpiScope, sys); vpiHandle res = vpi_handle_by_name(name, scope); if (pli_trace) { fprintf(pli_trace, "acc_handle_object(%s ) --> .\n", name, acc_fetch_fullname(scope)); } return res; } char* acc_set_scope(handle ref, ...) { char*name; search_scope = ref; name = acc_fetch_fullname(search_scope); if (pli_trace) { fprintf(pli_trace, "acc_set_scope()\n", name); } return acc_fetch_fullname(ref); } /* * $Log: a_handle_object.c,v $ * Revision 1.2 2003/12/17 15:45:07 steve * Add acc_set_scope function. * * Revision 1.1 2003/03/13 04:35:09 steve * Add a bunch of new acc_ and tf_ functions. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_close.c0000644000202500001440000000005012204466647020334 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_close.c0000644000202500001440000000317712204466647017666 0ustar00steveusers00000000000000/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_close.c,v 1.4 2003/06/17 16:55:07 steve Exp $" #endif # include # include "priv.h" void acc_close(void) { if (pli_trace) { fprintf(pli_trace, "acc_close()\n"); } } /* * $Log: a_close.c,v $ * Revision 1.4 2003/06/17 16:55:07 steve * 1) setlinebuf() for vpi_trace * 2) Addes error checks for trace file opens * 3) removes now extraneous flushes * 4) fixes acc_next() bug * * Revision 1.3 2003/05/18 00:16:35 steve * Add PLI_TRACE tracing of PLI1 modules. * * Add tf_isetdelay and friends, and add * callback return values for acc_vcl support. * * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/05/23 03:46:42 steve * Add the acc_user.h header file. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/mc_scan_plusargs.c0000644000202500001440000000005012204466647022252 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/mc_scan_plusargs.c0000644000202500001440000000405112204466647021574 0ustar00steveusers00000000000000/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: mc_scan_plusargs.c,v 1.3 2002/08/12 01:35:02 steve Exp $" #endif # include # include # include /* * mc_scan_plusargs implemented using VPI interface */ char *mc_scan_plusargs(char *plusarg) { int argc, diff; char **argv, *a, *p; s_vpi_vlog_info vpi_vlog_info; /* get command line */ if (! vpi_get_vlog_info(&vpi_vlog_info)) return (char *)0; /* for each argument */ argv = vpi_vlog_info.argv; for (argc = 0; argc < vpi_vlog_info.argc; argc++, argv++) { a = *argv; p = plusarg; /* only plusargs */ if (*a != '+') continue; a += 1; /* impossible matches */ if (strlen(a) < strlen(p)) continue; diff = 0; while (*p) { if (*a != *p) { diff = 1; break; } a++; p++; } if (!diff) return a; } /* didn't find it yet */ return (char *)0; } /* * $Log: mc_scan_plusargs.c,v $ * Revision 1.3 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.2 2002/05/24 21:46:21 steve * Only match plusargs. * * Revision 1.1 2002/05/24 20:29:07 steve * Implement mc_scan_plusargs. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_handle_hiconn.c0000644000202500001440000000005012204466647022020 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_handle_hiconn.c0000644000202500001440000000276412204466647021353 0ustar00steveusers00000000000000/* * Copyright (c) 2003 Stephen Williams (steve@picturel.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_handle_hiconn.c,v 1.1 2003/10/10 02:57:45 steve Exp $" #endif # include # include # include # include # include "priv.h" handle acc_handle_hiconn(handle obj) { if (pli_trace) { fprintf(pli_trace, "acc_handle_hiconn: enter.\n"); fflush(pli_trace); } fprintf(stderr, "acc_handle_hiconn: XXXX not implemented. XXXX\n"); if (pli_trace) { fprintf(pli_trace, "acc_handle_hiconn: return.\n"); fflush(pli_trace); } return 0; } /* * $Log: a_handle_hiconn.c,v $ * Revision 1.1 2003/10/10 02:57:45 steve * Some PLI1 stubs. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_argc.c0000644000202500001440000000005012204466647021314 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_argc.c0000644000202500001440000000273012204466647020640 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_fetch_argc.c,v 1.2 2002/08/12 01:35:02 steve Exp $" #endif # include # include /* * acc_fetch_argc implemented using VPI interface */ int acc_fetch_argc(void) { s_vpi_vlog_info vpi_vlog_info; /* get command line info */ if (! vpi_get_vlog_info(&vpi_vlog_info)) return 0; /* return argc */ return vpi_vlog_info.argc; } /* * $Log: a_fetch_argc.c,v $ * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/06/11 15:19:12 steve * Add acc_fetch_argc/argv/version (mruff) * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_value.c0000644000202500001440000000005012204466647021514 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_value.c0000644000202500001440000000624212204466647021042 0ustar00steveusers00000000000000/* * Copyright (c) 2003-2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include # include # include "priv.h" # include # include static char* fetch_struct_value(handle obj, s_acc_value*value) { struct t_vpi_value val; switch (value->format) { case accScalarVal: val.format = vpiScalarVal; vpi_get_value(obj, &val); switch (val.value.scalar) { case vpi0: value->value.scalar = acc0; break; case vpi1: value->value.scalar = acc1; break; case vpiX: value->value.scalar = accX; break; case vpiZ: value->value.scalar = accZ; break; default: assert(0); } if (pli_trace) { fprintf(pli_trace, "acc_fetch_value(<%s>, " "accScalarVal) --> %d\n", vpi_get_str(vpiFullName,obj), value->value.scalar); } break; case accIntVal: val.format = vpiIntVal; vpi_get_value(obj, &val); value->value.integer = val.value.integer; if (pli_trace) { fprintf(pli_trace, "acc_fetch_value(<%s>, " "accIntVal) --> %d\n", vpi_get_str(vpiFullName,obj), value->value.integer); } break; case accRealVal: val.format = vpiRealVal; vpi_get_value(obj, &val); value->value.real = val.value.real; if (pli_trace) { fprintf(pli_trace, "acc_fetch_value(<%s>, " "accRealVal) --> %g\n", vpi_get_str(vpiFullName,obj), value->value.real); } break; default: vpi_printf("XXXX acc_fetch_value(..., \"%%%%\", <%d>);\n", value->format); value->value.str = ""; break; } return 0; } static char* fetch_strength_value(handle obj) { struct t_vpi_value val; char str[4]; val.format = vpiStrengthVal; vpi_get_value(obj, &val); /* Should this iterate over the bits? It now matches the old code. */ vpip_format_strength(str, &val, 0); if (pli_trace) { fprintf(pli_trace, "acc_fetch_value(<%s>, \"%%v\") --> %s\n", vpi_get_str(vpiFullName,obj), str); } return __acc_newstring(str); } char* acc_fetch_value(handle obj, const char*fmt, s_acc_value*value) { if (strcmp(fmt, "%%") == 0) return fetch_struct_value(obj, value); if (strcmp(fmt, "%v") == 0) return fetch_strength_value(obj); vpi_printf("XXXX acc_fetch_value(..., \"%s\", ...)\n", fmt); return ""; } verilog-0.9.7/libveriuser/PaxHeaders.14238/exprinfo.c0000644000202500001440000000005012204466647020561 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/exprinfo.c0000644000202500001440000000276312204466647020113 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: exprinfo.c,v 1.1 2003/10/10 02:57:46 steve Exp $" #endif # include # include # include # include # include "priv.h" struct t_tfexprinfo* tf_exprinfo(PLI_INT32 a, struct t_tfexprinfo*ip) { if (pli_trace) { fprintf(pli_trace, "tf_exprinfo: enter.\n"); fflush(pli_trace); } fprintf(stderr, "tf_exprinfo: XXXX not implemented. XXXX\n"); if (pli_trace) { fprintf(pli_trace, "tf_exprinfo: return.\n"); fflush(pli_trace); } return 0; } /* * $Log: exprinfo.c,v $ * Revision 1.1 2003/10/10 02:57:46 steve * Some PLI1 stubs. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/priv.c0000644000202500001440000000005012204466647017707 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/priv.c0000644000202500001440000000407312204466647017235 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: priv.c,v 1.3 2003/05/18 00:16:35 steve Exp $" #endif # include "priv.h" # include # include FILE* pli_trace = 0; static char string_buffer[8192]; static unsigned string_fill = 0; static void buffer_reset(void) { string_fill = 0; } char* __acc_newstring(const char*txt) { char*res; unsigned len; if (txt == 0) return 0; len = strlen(txt); assert(len < sizeof string_buffer); if ((string_fill + len + 1) >= sizeof string_buffer) buffer_reset(); res = string_buffer + string_fill; strcpy(string_buffer + string_fill, txt); string_fill += len + 1; return res; } /* * $Log: priv.c,v $ * Revision 1.3 2003/05/18 00:16:35 steve * Add PLI_TRACE tracing of PLI1 modules. * * Add tf_isetdelay and friends, and add * callback return values for acc_vcl support. * * Revision 1.2 2003/03/13 05:07:46 steve * Declaration warnings. * * Revision 1.1 2003/02/17 06:39:47 steve * Add at least minimal implementations for several * acc_ functions. Add support for standard ACC * string handling. * * Add the _pli_types.h header file to carry the * IEEE1364-2001 standard PLI type declarations. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/priv.h0000644000202500001440000000005012204466647017714 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/priv.h0000644000202500001440000000225512204466647017242 0ustar00steveusers00000000000000#ifndef __priv_H #define __priv_H /* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include /* * This function implements the acc_ string buffer, by adding the * input string to the buffer, and returning a pointer to the first * character of the new string. */ extern char* __acc_newstring(const char*txt); /* * Trace file for logging ACC and TF calls. */ FILE* pli_trace; #endif verilog-0.9.7/libveriuser/PaxHeaders.14238/math.c0000644000202500001440000000005012204466647017660 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/math.c0000644000202500001440000000444112204466647017205 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: math.c,v 1.3 2003/06/13 19:23:42 steve Exp $" #endif # include # include # include # include "config.h" # include "vpi_user.h" # include "veriuser.h" void tf_multiply_long(PLI_INT32*aof_low1, PLI_INT32*aof_high1, PLI_INT32 aof_low2, PLI_INT32 aof_high2) { ivl_u64_t a, b; a = *aof_high1; a = (a << 32) | *aof_low1; b = aof_high2; b = (b << 32) | aof_low2; a *= b; *aof_high1 = (a >> 32) & 0xffffffff; *aof_low1 = a & 0xffffffff; } void tf_real_to_long(double real, PLI_INT32*low, PLI_INT32*high) { ivl_u64_t rtn = (ivl_u64_t)real; *high = (rtn >> 32) & 0xffffffff; *low = rtn & 0xffffffff; } void tf_long_to_real(PLI_INT32 low, PLI_INT32 high, double *real) { ivl_u64_t a; a = high; a = (a << 32) | low; *real = (double)a; } /* * $Log: math.c,v $ * Revision 1.3 2003/06/13 19:23:42 steve * Add a bunch more PLI1 routines. * * Revision 1.2 2003/06/04 01:56:20 steve * 1) Adds configure logic to clean up compiler warnings * 2) adds acc_compare_handle, acc_fetch_range, acc_next_scope and * tf_isetrealdelay, acc_handle_scope * 3) makes acc_next reentrant * 4) adds basic vpiWire type support * 5) fills in some acc_object_of_type() and acc_fetch_{full}type() * 6) add vpiLeftRange/RigthRange to signals * * Revision 1.1 2003/04/23 15:01:29 steve * Add tf_synchronize and tf_multiply_long. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/getcstringp.c0000644000202500001440000000005012204466647021260 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/getcstringp.c0000644000202500001440000000267312204466647020612 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: getcstringp.c,v 1.3 2003/03/13 04:35:09 steve Exp $" #endif #include #include /* * tf_getinstance implemented using equivalent acc_ routing */ char *tf_getcstringp(int n) { char*res = acc_fetch_tfarg_str(n); return res; } /* * $Log: getcstringp.c,v $ * Revision 1.3 2003/03/13 04:35:09 steve * Add a bunch of new acc_ and tf_ functions. * * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/06/07 02:58:59 steve * Add a bunch of acc/tf functions. (mruff) * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/typep.c0000644000202500001440000000005012204466647020070 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/typep.c0000644000202500001440000000370712204466647017421 0ustar00steveusers00000000000000/* * Copyright (c) 2002 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: typep.c,v 1.2 2003/03/13 05:07:46 steve Exp $" #endif #include #include #include PLI_INT32 tf_typep(PLI_INT32 narg) { vpiHandle sys_h, argv, arg_h = 0; int rtn; assert(narg > 0); /* get task/func handle */ sys_h = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, sys_h); /* find nth arg */ while (narg > 0) { /* Watch that the argument is not out of range. */ if (!(arg_h = vpi_scan(argv))) return TF_NULLPARAM; narg -= 1; } switch (vpi_get(vpiType, arg_h)) { case vpiConstant: switch (vpi_get(vpiConstType, arg_h)) { case vpiStringConst: rtn = TF_STRING; break; case vpiRealConst: rtn = TF_READONLYREAL; break; default: rtn = TF_READONLY; break; } break; case vpiIntegerVar: case vpiReg: case vpiMemoryWord: rtn = TF_READWRITE; break; case vpiRealVar: rtn = TF_READWRITEREAL; break; default: rtn = TF_READONLY; break; } vpi_free_object(argv); return rtn; } verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_time.c0000644000202500001440000000005012204466647021336 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_time.c0000644000202500001440000000243412204466647020663 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_fetch_time.c,v 1.1 2003/03/13 04:35:09 steve Exp $" #endif #include #include #include "priv.h" void acc_fetch_timescale_info(handle obj, p_timescale_info info) { info->precision = vpi_get(vpiTimePrecision, 0); info->unit = vpi_get(vpiTimeUnit, obj); } /* * $Log: a_fetch_time.c,v $ * Revision 1.1 2003/03/13 04:35:09 steve * Add a bunch of new acc_ and tf_ functions. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/getp.c0000644000202500001440000000005012204466647017666 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/getp.c0000644000202500001440000001062712204466647017216 0ustar00steveusers00000000000000/* * Copyright (c) 2002-2009 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include # include # include # include # include "priv.h" /* * tf_getp and friends, implemented using VPI interface */ PLI_INT32 tf_igetp(PLI_INT32 n, void *obj) { vpiHandle sys_h, sys_i, arg_h = 0; s_vpi_value value; int rtn = 0; assert(n > 0); /* get task/func handle */ sys_h = (vpiHandle)obj; sys_i = vpi_iterate(vpiArgument, sys_h); /* find nth arg */ while (n > 0) { if (!(arg_h = vpi_scan(sys_i))) { goto out; } n--; } /* If it is a constant string, return a pointer to it else int value */ if (vpi_get(vpiType, arg_h) == vpiConstant && vpi_get(vpiConstType, arg_h) == vpiStringConst) { value.format = vpiStringVal; vpi_get_value(arg_h, &value); /* The following may generate a compilation warning, but this * functionality is required by some versions of the standard. */ rtn = (int) value.value.str; /* Oh my */ } else { value.format = vpiIntVal; vpi_get_value(arg_h, &value); rtn = value.value.integer; } vpi_free_object(sys_i); out: if (pli_trace) { fprintf(pli_trace, "tf_igetp(n=%d, obj=%p) --> %d\n", (int)n, obj, rtn); } return rtn; } PLI_INT32 tf_getp(PLI_INT32 n) { int rtn = tf_igetp(n, vpi_handle(vpiSysTfCall, 0)); return rtn; } double tf_igetrealp(PLI_INT32 n, void *obj) { vpiHandle sys_h, sys_i, arg_h = 0; s_vpi_value value; double rtn = 0.0; assert(n > 0); /* get task/func handle */ sys_h = (vpiHandle)obj; sys_i = vpi_iterate(vpiArgument, sys_h); /* find nth arg */ while (n > 0) { if (!(arg_h = vpi_scan(sys_i))) { goto out; } n--; } if (vpi_get(vpiType, arg_h) == vpiConstant && vpi_get(vpiConstType, arg_h) == vpiStringConst) { rtn = 0.0; } else { value.format = vpiRealVal; vpi_get_value(arg_h, &value); rtn = value.value.real; } vpi_free_object(sys_i); out: if (pli_trace) { fprintf(pli_trace, "tf_igetrealp(n=%d, obj=%p) --> %f\n", (int)n, obj, rtn); } return rtn; } double tf_getrealp(PLI_INT32 n) { double rtn = tf_igetrealp(n, vpi_handle(vpiSysTfCall, 0)); return rtn; } char *tf_istrgetp(PLI_INT32 n, PLI_INT32 fmt, void *obj) { vpiHandle sys_h, sys_i, arg_h = 0; s_vpi_value value; char *rtn = 0; assert(n > 0); /* get task/func handle */ sys_h = (vpiHandle)obj; sys_i = vpi_iterate(vpiArgument, sys_h); /* find nth arg */ while (n > 0) { if (!(arg_h = vpi_scan(sys_i))) { goto out; } n--; } if (vpi_get(vpiType, arg_h) == vpiConstant && vpi_get(vpiConstType, arg_h) == vpiStringConst) { value.format = vpiStringVal; vpi_get_value(arg_h, &value); rtn = value.value.str; } else { value.format = -1; switch (tolower(fmt)) { case 'b': value.format = vpiBinStrVal; break; case 'o': value.format = vpiOctStrVal; break; case 'd': value.format = vpiDecStrVal; break; case 'h': value.format = vpiHexStrVal; break; } if (value.format > 0) { vpi_get_value(arg_h, &value); rtn = value.value.str; } } vpi_free_object(sys_i); out: if (pli_trace) { fprintf(pli_trace, "tf_istrgetp(n=%d, fmt=%c, obj=%p) --> \"%s\"\n", (int)n, (int)fmt, obj, rtn); } return rtn; } char *tf_strgetp(PLI_INT32 n, PLI_INT32 fmt) { char *rtn = tf_istrgetp(n, fmt, vpi_handle(vpiSysTfCall, 0)); return rtn; } verilog-0.9.7/libveriuser/PaxHeaders.14238/nodeinfo.c0000644000202500001440000000005012204466647020530 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/nodeinfo.c0000644000202500001440000000276212204466647020061 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: nodeinfo.c,v 1.1 2003/10/10 02:57:46 steve Exp $" #endif # include # include # include # include # include "priv.h" struct t_tfnoeinfo* tf_nodeinfo(PLI_INT32 a, struct t_tfnodeinfo*ip) { if (pli_trace) { fprintf(pli_trace, "tf_nodeinfo: enter.\n"); fflush(pli_trace); } fprintf(stderr, "tf_nodeinfo: XXXX not implemented. XXXX\n"); if (pli_trace) { fprintf(pli_trace, "tf_nodeinfo: return.\n"); fflush(pli_trace); } return 0; } /* * $Log: nodeinfo.c,v $ * Revision 1.1 2003/10/10 02:57:46 steve * Some PLI1 stubs. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/nump.c0000644000202500001440000000005012204466647017706 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/nump.c0000644000202500001440000000321712204466647017233 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: nump.c,v 1.3 2003/05/28 03:38:05 steve Exp $" #endif #include #include /* * tf_nump implemented using VPI interface */ int tf_inump(void *obj) { vpiHandle sys_h, sys_i; int cnt; sys_h = (vpiHandle)obj; sys_i = vpi_iterate(vpiArgument, sys_h); /* count number of args */ for (cnt = 0; sys_i && vpi_scan(sys_i); cnt++); return cnt; } int tf_nump(void) { vpiHandle sys_h = vpi_handle(vpiSysTfCall, 0 /* NULL */); return tf_inump(sys_h); } /* * $Log: nump.c,v $ * Revision 1.3 2003/05/28 03:38:05 steve * Implement tf_inump * * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/05/30 02:12:17 steve * Add tf_nump from mruff. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/getsimtime.c0000644000202500001440000000005012204466647021076 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/getsimtime.c0000644000202500001440000001276612204466647020434 0ustar00steveusers00000000000000/* * Copyright (c) 2002-2011 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include "config.h" #include "priv.h" #include /* * some TF time routines implemented using VPI interface */ // On some platforms (e.g. MinGW), pow() may not always generate an // exact integer result when supplied with integer operands. Converting // the result to an integer before we use it seems to be enough to work // round this issue. static ivl_u64_t pow10u(PLI_INT32 val) { return (ivl_u64_t)pow(10, val); } static ivl_u64_t scale(int high, int low, void*obj) { vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0)); ivl_u64_t scaled; scaled = high; scaled = (scaled << 32) | low; scaled /= pow10u(vpi_get(vpiTimeUnit,obj ? (vpiHandle)obj : hand) - vpi_get(vpiTimePrecision,0)); return scaled; } PLI_INT32 tf_gettime(void) { s_vpi_time timerec; timerec.type = vpiSimTime; vpi_get_time (0, &timerec); return scale(timerec.high, timerec.low, 0) & 0xffffffff; } char *tf_strgettime(void) { static char buf[32]; s_vpi_time timerec; timerec.type = vpiSimTime; vpi_get_time (0, &timerec); if (timerec.high) snprintf(buf, sizeof(buf)-1, "%u%08u", (unsigned int)timerec.high, (unsigned int)timerec.low); else snprintf(buf, sizeof(buf)-1, "%u", (unsigned int)timerec.low); return buf; } PLI_INT32 tf_igetlongtime(PLI_INT32 *high, void*obj) { s_vpi_time timerec; ivl_u64_t scaled; timerec.type = vpiSimTime; vpi_get_time ((vpiHandle)obj, &timerec); scaled = scale(timerec.high, timerec.low, obj); *high = (scaled >> 32) & 0xffffffff; return scaled & 0xffffffff; } PLI_INT32 tf_getlongtime(PLI_INT32 *high) { return tf_igetlongtime(high, 0); } /* * This function is not defined in the IEE standard, but is provided for * compatibility with other simulators. On platforms that support this, * make it a weak symbol just in case the user has defined their own * function for this. */ #if !defined(__CYGWIN__) && !defined(__MINGW32__) PLI_INT32 tf_getlongsimtime(PLI_INT32 *high) __attribute__ ((weak)); #endif PLI_INT32 tf_getlongsimtime(PLI_INT32 *high) { s_vpi_time timerec; timerec.type = vpiSimTime; vpi_get_time (0, &timerec); *high = timerec.high; return timerec.low; } void tf_scale_longdelay(void*obj, PLI_INT32 low, PLI_INT32 high, PLI_INT32 *alow, PLI_INT32 *ahigh) { ivl_u64_t scaled = scale(high, low, obj); *ahigh = (scaled >> 32) & 0xffffffff; *alow = scaled & 0xffffffff; } void tf_unscale_longdelay(void*obj, PLI_INT32 low, PLI_INT32 high, PLI_INT32 *alow, PLI_INT32 *ahigh) { ivl_u64_t unscaled; vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0)); unscaled = high; unscaled = (unscaled << 32) | low; unscaled *= pow(10, vpi_get(vpiTimeUnit, hand) - vpi_get(vpiTimePrecision, 0)); *ahigh = (unscaled >> 32) & 0xffffffff; *alow = unscaled & 0xffffffff; } void tf_scale_realdelay(void*obj, double real, double *areal) { vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0)); *areal = real / pow(10, vpi_get(vpiTimeUnit, hand) - vpi_get(vpiTimePrecision, 0)); } void tf_unscale_realdelay(void*obj, double real, double *areal) { vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0)); *areal = real * pow(10, vpi_get(vpiTimeUnit, hand) - vpi_get(vpiTimePrecision, 0)); } PLI_INT32 tf_gettimeprecision(void) { PLI_INT32 rc; vpiHandle hand; vpiHandle sys = vpi_handle(vpiSysTfCall,0); assert(sys); hand = vpi_handle(vpiScope, sys); rc = vpi_get(vpiTimePrecision, hand); if (pli_trace) fprintf(pli_trace, "tf_gettimeprecision(<%s>) --> %d\n", vpi_get_str(vpiName, sys), (int)rc); return rc; } PLI_INT32 tf_igettimeprecision(void*obj) { PLI_INT32 rc; if (obj == 0) { /* If the obj pointer is null, then get the simulation time precision. */ rc = vpi_get(vpiTimePrecision, 0); } else { vpiHandle scope = vpi_handle(vpiScope, (vpiHandle)obj); assert(scope); rc = vpi_get(vpiTimePrecision, scope); } if (pli_trace) fprintf(pli_trace, "tf_igettimeprecision(<%s>) --> %d\n", obj? vpi_get_str(vpiName, obj) : ".", (int)rc); return rc; } PLI_INT32 tf_gettimeunit() { vpiHandle hand = vpi_handle(vpiScope, vpi_handle(vpiSysTfCall,0)); return vpi_get(vpiTimeUnit, hand); } PLI_INT32 tf_igettimeunit(void*obj) { return vpi_get(!obj ? vpiTimePrecision : vpiTimeUnit, (vpiHandle)obj); } verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_tfarg.c0000644000202500001440000000005012204466647021503 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_tfarg.c0000644000202500001440000000630512204466647021031 0ustar00steveusers00000000000000/* * Copyright (c) 2002-2009 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include "priv.h" /* * acc_fetch_tfarg and friends implemented using VPI interface */ double acc_fetch_itfarg(PLI_INT32 n, handle obj) { vpiHandle iter, hand = 0; s_vpi_value value; int idx = n; double rtn; iter = vpi_iterate(vpiArgument, obj); /* scan to nth argument */ while (idx > 0 && (hand = vpi_scan(iter))) idx--; if (hand) { value.format=vpiRealVal; vpi_get_value(hand, &value); rtn = value.value.real; vpi_free_object(iter); } else { rtn = 0.0; } if (pli_trace) { fprintf(pli_trace, "%s: acc_fetch_itfarg(%d, %p) --> %f\n", vpi_get_str(vpiName, obj), (int)n, obj, rtn); } return rtn; } double acc_fetch_tfarg(PLI_INT32 n) { return acc_fetch_itfarg_int(n, vpi_handle(vpiSysTfCall,0)); } PLI_INT32 acc_fetch_itfarg_int(PLI_INT32 n, handle obj) { vpiHandle iter, hand = 0; s_vpi_value value; int idx = n; int rtn; iter = vpi_iterate(vpiArgument, obj); /* scan to nth argument */ while (idx > 0 && (hand = vpi_scan(iter))) idx--; if (hand) { value.format=vpiIntVal; vpi_get_value(hand, &value); rtn = value.value.integer; vpi_free_object(iter); } else { rtn = 0; } if (pli_trace) { fprintf(pli_trace, "%s: acc_fetch_itfarg_int(%d, %p) --> %d\n", vpi_get_str(vpiName, obj), (int)n, obj, rtn); } return rtn; } PLI_INT32 acc_fetch_tfarg_int(PLI_INT32 n) { return acc_fetch_itfarg_int(n, vpi_handle(vpiSysTfCall,0)); } char *acc_fetch_itfarg_str(PLI_INT32 n, handle obj) { vpiHandle iter, hand = 0; s_vpi_value value; int idx = n; char *rtn; iter = vpi_iterate(vpiArgument, obj); /* scan to nth argument */ while (idx > 0 && (hand = vpi_scan(iter))) idx -= 1; if (hand) { value.format=vpiStringVal; vpi_get_value(hand, &value); rtn = __acc_newstring(value.value.str); vpi_free_object(iter); } else { rtn = (char *) 0; } if (pli_trace) { fprintf(pli_trace, "%s: acc_fetch_itfarg_str(%d, %p) --> \"%s\"\n", vpi_get_str(vpiName, obj), (int)n, obj, rtn? rtn : ""); } return rtn; } char *acc_fetch_tfarg_str(PLI_INT32 n) { return acc_fetch_itfarg_str(n, vpi_handle(vpiSysTfCall,0)); } verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_fullname.c0000644000202500001440000000005012204466647022203 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_fullname.c0000644000202500001440000000403512204466647021527 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_fetch_fullname.c,v 1.5 2003/05/29 02:21:45 steve Exp $" #endif #include #include #include "priv.h" /* * acc_fetch_fullname implemented using VPI interface */ char *acc_fetch_fullname(handle object) { return __acc_newstring(vpi_get_str(vpiFullName, object)); } char* acc_fetch_name(handle object) { return __acc_newstring(vpi_get_str(vpiName, object)); } char* acc_fetch_defname(handle object) { return __acc_newstring(vpi_get_str(vpiDefName, object)); } /* * $Log: a_fetch_fullname.c,v $ * Revision 1.5 2003/05/29 02:21:45 steve * Implement acc_fetch_defname and its infrastructure in vvp. * * Revision 1.4 2003/03/13 05:07:46 steve * Declaration warnings. * * Revision 1.3 2003/02/17 06:39:47 steve * Add at least minimal implementations for several * acc_ functions. Add support for standard ACC * string handling. * * Add the _pli_types.h header file to carry the * IEEE1364-2001 standard PLI type declarations. * * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/06/07 02:58:58 steve * Add a bunch of acc/tf functions. (mruff) * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/veriusertfs.c0000644000202500001440000000005012204466647021310 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/veriusertfs.c0000644000202500001440000002527612204466647020646 0ustar00steveusers00000000000000/* * Copyright (c) 2002-2011 Michael Ruff (mruff at chiaro.com) * Michael Runyan (mrunyan at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * Contains the routines required to implement veriusertfs routines * via VPI. This is extremely ugly, so don't look after eating dinner. */ # include # include # include # include # include "config.h" # include "priv.h" # include "vpi_user.h" # include "veriuser.h" /* * local structure used to hold the persistent veriusertfs data * and anything else we decide to put in here, like workarea data. */ typedef struct t_pli_data { p_tfcell tf; /* pointer to veriusertfs cell */ int paramvc; /* parameter number for misctf */ } s_pli_data, *p_pli_data; static PLI_INT32 compiletf(char *); static PLI_INT32 calltf(char *); static PLI_INT32 callback(p_cb_data); /* * Keep a pointer to the user data so that it can be freed when the * simulation is finished. */ static p_pli_data* udata_store = 0; static unsigned udata_count = 0; static PLI_INT32 sys_end_of_simulation(p_cb_data cb_data) { unsigned idx; for (idx = 0; idx < udata_count; idx += 1) { free(udata_store[idx]); } free(udata_store); udata_store = 0; udata_count = 0; return 0; } /* * Register veriusertfs routines/wrappers. Iterate over the tfcell * array, registering each function. */ void veriusertfs_register_table(p_tfcell vtable) { static int need_EOS_cb = 1; const char*path; p_tfcell tf; s_vpi_systf_data tf_data; p_pli_data data; static char trace_buf[1024]; if (!pli_trace && (path = getenv("PLI_TRACE"))) { if (strcmp(path,"-") == 0) pli_trace = stdout; else { pli_trace = fopen(path, "w"); if (!pli_trace) { perror(path); exit(1); } } setvbuf(pli_trace, trace_buf, _IOLBF, sizeof(trace_buf)); } for (tf = vtable; tf; tf++) { /* last element */ if (tf->type == 0) break; /* force forwref true */ if (!tf->forwref) { vpi_printf("veriusertfs: %s, forcing forwref = true\n", tf->tfname); } /* squirrel away veriusertfs in persistent user_data */ data = calloc(1, sizeof(s_pli_data)); assert(data != NULL); udata_count += 1; udata_store = (p_pli_data*)realloc(udata_store, udata_count*sizeof(p_pli_data*)); udata_store[udata_count-1] = data; if (need_EOS_cb) { s_cb_data cb_data; cb_data.reason = cbEndOfSimulation; cb_data.time = 0; cb_data.cb_rtn = sys_end_of_simulation; cb_data.user_data = "system"; vpi_register_cb(&cb_data); need_EOS_cb = 0; } data->tf = tf; /* Build a VPI system task/function structure, and point it to the pli_data that represents this function. Supply wrapper functions for the system task actions. */ memset(&tf_data, 0, sizeof(s_vpi_systf_data)); switch (tf->type) { case usertask: tf_data.type = vpiSysTask; break; case userfunction: tf_data.sysfunctype = vpiIntFunc; tf_data.type = vpiSysFunc; break; case userrealfunction: tf_data.sysfunctype = vpiRealFunc; tf_data.type = vpiSysFunc; break; default: vpi_printf("veriusertfs: %s, unsupported type %d\n", tf->tfname, tf->type); continue; } tf_data.tfname = tf->tfname; tf_data.compiletf = compiletf; tf_data.calltf = calltf; tf_data.sizetf = (PLI_INT32 (*)(PLI_BYTE8 *))tf->sizetf; tf_data.user_data = (char *)data; if (pli_trace) { fprintf(pli_trace, "Registering system %s:\n", tf->type == usertask ? "task" : "function"); fprintf(pli_trace, " tfname : %s\n", tf->tfname); if (tf->data) fprintf(pli_trace, " data : %d\n", tf->data); if (tf->checktf) fprintf(pli_trace, " checktf: %p\n", tf->checktf); if (tf->sizetf) fprintf(pli_trace, " sizetf : %p\n", tf->sizetf); if (tf->calltf) fprintf(pli_trace, " calltf : %p\n", tf->calltf); if (tf->misctf) fprintf(pli_trace, " misctf : %p\n", tf->misctf); } /* register */ vpi_register_systf(&tf_data); } return; } /* * This function calls the veriusertfs checktf and sets up all the * callbacks misctf requires. */ static PLI_INT32 compiletf(char *data) { p_pli_data pli; p_tfcell tf; s_cb_data cb_data; vpiHandle call_h, arg_i, arg_h; p_pli_data dp; int paramvc = 1; int rtn = 0; /* cast back from opaque */ pli = (p_pli_data)data; tf = pli->tf; /* get call handle */ call_h = vpi_handle(vpiSysTfCall, NULL); /* Attach the pli_data structure to the vpi handle of the system task. This is how I manage the map from vpiHandle to PLI1 pli data. We do it here (instead of during register) because this is the first that I have both the vpiHandle and the pli_data. */ vpi_put_userdata(call_h, pli); /* default cb_data */ memset(&cb_data, 0, sizeof(s_cb_data)); cb_data.cb_rtn = callback; cb_data.user_data = data; /* register EOS misctf callback */ cb_data.reason = cbEndOfSimulation; cb_data.obj = call_h; vpi_register_cb(&cb_data); /* If there is a misctf function, then create a value change callback for all the arguments. In the tf_* API, misctf functions get value change callbacks, controlled by the tf_asyncon and tf_asyncoff functions. */ if (tf->misctf && ((arg_i = vpi_iterate(vpiArgument, call_h)) != NULL)) { cb_data.reason = cbValueChange; while ((arg_h = vpi_scan(arg_i)) != NULL) { /* replicate user_data for each instance */ dp = calloc(1, sizeof(s_pli_data)); assert(dp != NULL); memcpy(dp, cb_data.user_data, sizeof(s_pli_data)); dp->paramvc = paramvc++; cb_data.user_data = (char *)dp; cb_data.obj = arg_h; vpi_register_cb(&cb_data); } } /* * Since we are in compiletf, checktf and misctf need to * be executed. Check runs first to match other simulators. */ if (tf->checktf) { if (pli_trace) { fprintf(pli_trace, "Call %s->checktf(reason_checktf)\n", tf->tfname); } rtn = tf->checktf(tf->data, reason_checktf); } if (tf->misctf) { if (pli_trace) { fprintf(pli_trace, "Call %s->misctf" "(user_data=%d, reason=%d, paramvc=%d)\n", tf->tfname, tf->data, reason_endofcompile, 0); } tf->misctf(tf->data, reason_endofcompile, 0); } return rtn; } /* * This function is the wrapper for the veriusertfs calltf routine. */ static PLI_INT32 calltf(char *data) { int rc = 0; p_pli_data pli; p_tfcell tf; /* cast back from opaque */ pli = (p_pli_data)data; tf = pli->tf; /* execute calltf */ if (tf->calltf) { if (pli_trace) { fprintf(pli_trace, "Call %s->calltf(%d, %d)\n", tf->tfname, tf->data, reason_calltf); } rc = tf->calltf(tf->data, reason_calltf); } return rc; } /* * This function is the wrapper for all the misctf callbacks */ extern int async_misctf_enable; static PLI_INT32 callback(p_cb_data data) { p_pli_data pli; p_tfcell tf; int reason; int paramvc = 0; PLI_INT32 rc; /* not enabled */ if (data->reason == cbValueChange && !async_misctf_enable) return 0; /* cast back from opaque */ pli = (p_pli_data)data->user_data; tf = pli->tf; switch (data->reason) { case cbValueChange: reason = reason_paramvc; paramvc = pli->paramvc; break; case cbEndOfSimulation: reason = reason_finish; break; case cbReadWriteSynch: reason = reason_synch; break; case cbReadOnlySynch: reason = reason_rosynch; break; case cbAfterDelay: reason = reason_reactivate; break; default: reason = -1; assert(0); } if (pli_trace) { fprintf(pli_trace, "Call %s->misctf" "(user_data=%d, reason=%d, paramvc=%d)\n", tf->tfname, tf->data, reason, paramvc); } /* execute misctf */ rc = (tf->misctf) ? tf->misctf(tf->data, reason, paramvc) : 0; return rc; } PLI_INT32 tf_isynchronize(void*obj) { vpiHandle sys = (vpiHandle)obj; p_pli_data pli = vpi_get_userdata(sys); s_cb_data cb; s_vpi_time ti; ti.type = vpiSuppressTime; cb.reason = cbReadWriteSynch; cb.cb_rtn = callback; cb.obj = sys; cb.time = &ti; cb.user_data = (char *)pli; vpi_register_cb(&cb); if (pli_trace) fprintf(pli_trace, "tf_isynchronize(%p) --> %d\n", obj, 0); return 0; } PLI_INT32 tf_synchronize(void) { return tf_isynchronize(tf_getinstance()); } PLI_INT32 tf_irosynchronize(void*obj) { vpiHandle sys = (vpiHandle)obj; p_pli_data pli = vpi_get_userdata(sys); s_cb_data cb; s_vpi_time ti = {vpiSuppressTime, 0, 0}; cb.reason = cbReadOnlySynch; cb.cb_rtn = callback; cb.obj = sys; cb.time = &ti; cb.user_data = (char *)pli; vpi_register_cb(&cb); if (pli_trace) fprintf(pli_trace, "tf_irosynchronize(%p) --> %d\n", obj, 0); return 0; } PLI_INT32 tf_rosynchronize(void) { return tf_irosynchronize(tf_getinstance()); } PLI_INT32 tf_isetrealdelay(double dly, void*obj) { vpiHandle sys = (vpiHandle)obj; p_pli_data pli = vpi_get_userdata(sys); s_cb_data cb; s_vpi_time ti = {vpiSimTime}; /* Scale delay to SimTime */ ivl_u64_t delay = ((dly / pow(10, tf_gettimeunit() - tf_gettimeprecision())) + 0.5); ti.high = delay >> 32 & 0xffffffff; ti.low = delay & 0xffffffff; cb.reason = cbAfterDelay; cb.cb_rtn = callback; cb.obj = sys; cb.time = &ti; cb.user_data = (char *)pli; vpi_register_cb(&cb); if (pli_trace) fprintf(pli_trace, "tf_isetrealdelay(%f, %p) --> %d\n", dly, obj, 0); return 0; } PLI_INT32 tf_setrealdelay(double dly) { return tf_isetrealdelay(dly, tf_getinstance()); } verilog-0.9.7/libveriuser/PaxHeaders.14238/spname.c0000644000202500001440000000005012204466647020212 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/spname.c0000644000202500001440000000425212204466647017537 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: spname.c,v 1.4 2003/06/17 16:55:08 steve Exp $" #endif #include #include #include #include "priv.h" char* tf_spname(void) { char*rtn; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle scope = vpi_handle(vpiScope, sys); rtn = __acc_newstring(vpi_get_str(vpiFullName, scope)); if (pli_trace) { fprintf(pli_trace, "%s: tf_spname() --> %s\n", vpi_get_str(vpiName,sys), rtn); } return rtn; } char *tf_imipname(void *obj) { return vpi_get_str(vpiFullName, vpi_handle(vpiScope, (vpiHandle)obj)); } char *tf_mipname(void) { return tf_imipname(vpi_handle(vpiSysTfCall,0)); } /* * $Log: spname.c,v $ * Revision 1.4 2003/06/17 16:55:08 steve * 1) setlinebuf() for vpi_trace * 2) Addes error checks for trace file opens * 3) removes now extraneous flushes * 4) fixes acc_next() bug * * Revision 1.3 2003/05/29 03:46:21 steve * Add tf_getp/putp support for integers * and real valued arguments. * * Add tf_mipname function. * * Revision 1.2 2003/05/18 00:16:35 steve * Add PLI_TRACE tracing of PLI1 modules. * * Add tf_isetdelay and friends, and add * callback return values for acc_vcl support. * * Revision 1.1 2003/03/13 04:35:09 steve * Add a bunch of new acc_ and tf_ functions. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_set_value.c0000644000202500001440000000005012204466647021216 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_set_value.c0000644000202500001440000000647712204466647020556 0ustar00steveusers00000000000000/* * Copyright (c) 2002-2009 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include /* * acc_set_value implemented using VPI interface */ int acc_set_value(handle object, p_setval_value value, p_setval_delay delay) { s_vpi_time when, *whenp; s_vpi_value val; int flags; assert(delay); assert(value); assert(object); /* map setval_delay.model to flags */ switch (delay->model) { case accNoDelay: flags = vpiNoDelay; break; case accInertialDelay: flags = vpiInertialDelay; break; case accTransportDelay: flags = vpiTransportDelay; break; case accPureTransportDelay: flags = vpiPureTransportDelay; break; case accForceFlag: flags = vpiForceFlag; break; case accReleaseFlag: flags = vpiReleaseFlag; break; default: flags = -1; assert(0); break; } /* map acc_time to vpi_time */ if (delay->model != accNoDelay) { switch (delay->time.type) { case accSimTime: when.type = vpiSimTime; break; case accRealTime: when.type = vpiScaledRealTime; break; default: assert(0); break; } when.high = delay->time.high; when.low = delay->time.low; when.real = delay->time.real; whenp = &when; } else whenp = 0; /* map setval_value to vpi_value and flags */ switch (value->format) { case accBinStrVal: val.format = vpiBinStrVal; val.value.str = value->value.str; break; case accOctStrVal: val.format = vpiOctStrVal; val.value.str = value->value.str; break; case accDecStrVal: val.format = vpiDecStrVal; val.value.str = value->value.str; break; case accHexStrVal: val.format = vpiHexStrVal; val.value.str = value->value.str; break; case accScalarVal: val.format = vpiScalarVal; val.value.scalar = value->value.scalar; break; case accIntVal: val.format = vpiIntVal; val.value.integer = value->value.integer; break; case accRealVal: val.format = vpiRealVal; val.value.real = value->value.real; break; case accStringVal: val.format = vpiStringVal; val.value.str = value->value.str; break; case accVectorVal: val.format = vpiVectorVal; val.value.vector = (p_vpi_vecval)value->value.vector; break; default: vpi_printf("XXXX acc_set_value(value->format=%d)\n", value->format); assert(0); break; } /* put value */ vpi_put_value(object, &val, whenp, flags); return 1; } verilog-0.9.7/libveriuser/PaxHeaders.14238/a_configure.c0000644000202500001440000000005012204466647021210 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_configure.c0000644000202500001440000000416512204466647020540 0ustar00steveusers00000000000000/* * Copyright (c) 2003-2009 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include "priv.h" #include int acc_configure(PLI_INT32 config_param, const char*value) { int rc; switch (config_param) { case accDevelopmentVersion: vpi_printf("Request PLI Development Version %s\n", value); rc = 1; if (pli_trace) { fprintf(pli_trace, "acc_configure(accDevelopmentVersion, %s)\n", value); } break; case accEnableArgs: if (pli_trace) { fprintf(pli_trace, "acc_configure(accEnableArgs, %s)\n", value); } rc = 1; if (strcmp(value,"acc_set_scope") == 0) { vpi_printf("XXXX acc_configure argument: Sorry: " "(accEnableArgs, %s\n", value); rc = 0; } else if (strcmp(value,"no_acc_set_scope") == 0) { vpi_printf("XXXX acc_configure argument: Sorry: " "(accEnableArgs, %s\n", value); rc = 0; } else { vpi_printf("XXXX acc_configure argument error. " "(accEnableArgs, %s(invalid)\n", value); rc = 0; } break; default: if (pli_trace) { fprintf(pli_trace, "acc_configure(config=%d, %s)\n", (int)config_param, value); } vpi_printf("XXXX acc_configure(%d, %s)\n", (int)config_param, value); rc = 0; break; } return rc; } verilog-0.9.7/libveriuser/PaxHeaders.14238/a_initialize.c0000644000202500001440000000005012204466647021370 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_initialize.c0000644000202500001440000000236312204466647020716 0ustar00steveusers00000000000000/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_initialize.c,v 1.2 2002/08/12 01:35:02 steve Exp $" #endif # include int acc_error_flag; int acc_initialize() { acc_error_flag = 0; return 1; } /* * $Log: a_initialize.c,v $ * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/05/23 03:46:42 steve * Add the acc_user.h header file. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/getlongp.c0000644000202500001440000000005012204466647020546 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/getlongp.c0000644000202500001440000000451712204466647020077 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: getlongp.c,v 1.3 2003/03/15 05:42:39 steve Exp $" #endif #include #include #include #include #include /* * tf_getlongp implemented using VPI interface */ int tf_getlongp(int *highvalue, int n) { vpiHandle sys_h, sys_i, arg_h = 0; s_vpi_value value; int len, rtn; char *str, **end = 0; assert(highvalue); assert(n > 0); /* get task/func handle */ sys_h = vpi_handle(vpiSysTfCall, 0); sys_i = vpi_iterate(vpiArgument, sys_h); /* find nth arg */ while (n > 0) { if (!(arg_h = vpi_scan(sys_i))) assert(0); n--; } /* get the value */ value.format = vpiHexStrVal; vpi_get_value(arg_h, &value); /* convert string to int(s) */ len = strlen(value.value.str); if (len > 8) { /* low word */ str = value.value.str + (len - 8); rtn = (int) strtoul(str, end, 16); /* high word */ *str = '\0'; *highvalue = (int) strtoul(value.value.str, end, 16); } else { *highvalue = 0; rtn = (int) strtoul(value.value.str, end, 16); } vpi_free_object(sys_i); return rtn; } /* * $Log: getlongp.c,v $ * Revision 1.3 2003/03/15 05:42:39 steve * free argument iterators. * * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/06/07 02:58:59 steve * Add a bunch of acc/tf functions. (mruff) * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/delay.c0000644000202500001440000000005012204466647020025 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/delay.c0000644000202500001440000000522312204466647017351 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: delay.c,v 1.3 2003/06/17 16:55:07 steve Exp $" #endif #include #include #include "priv.h" #include static PLI_INT32 delay_callback(struct t_cb_data*cb) { vpi_printf("XXXX delay_callback called.\n"); return 0; } int tf_isetdelay(PLI_INT32 delay, void*ss) { vpiHandle sys = (vpiHandle)ss; int unit = vpi_get(vpiTimeUnit, sys); int prec = vpi_get(vpiTimePrecision, 0); struct t_cb_data cb; struct t_vpi_time ct; if (pli_trace) { fprintf(pli_trace, "%s: tf_isetdelay(%d, ...)" " ;\n", vpi_get_str(vpiName, sys), (int)delay, unit, prec); } /* Convert the delay from the UNITS of the specified task/function to the precision of the simulation. */ assert(unit >= prec); while (unit > prec) { PLI_INT32 tmp = delay * 10; assert(tmp > delay); delay = tmp; unit -= 1; } /* Create a VPI callback to schedule the delay. */ ct.type = vpiSimTime; ct.high = 0; ct.low = delay; cb.reason = cbAfterDelay; cb.cb_rtn = delay_callback; cb.obj = 0; cb.time = &ct; cb.value = 0; cb.user_data = 0; vpi_register_cb(&cb); return 0; } int tf_setdelay(PLI_INT32 delay) { return tf_isetdelay(delay, tf_getinstance()); } /* * $Log: delay.c,v $ * Revision 1.3 2003/06/17 16:55:07 steve * 1) setlinebuf() for vpi_trace * 2) Addes error checks for trace file opens * 3) removes now extraneous flushes * 4) fixes acc_next() bug * * Revision 1.2 2003/05/28 02:42:43 steve * compiler warnings. * * Revision 1.1 2003/05/18 00:16:35 steve * Add PLI_TRACE tracing of PLI1 modules. * * Add tf_isetdelay and friends, and add * callback return values for acc_vcl support. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_range.c0000644000202500001440000000005012204466647021474 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_range.c0000644000202500001440000000333012204466647021015 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2003 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_fetch_range.c,v 1.2 2004/02/18 02:51:59 steve Exp $" #endif #include #include /* * acc_fetch_range implemented using VPI interface */ PLI_INT32 acc_fetch_range(handle object, int *msb, int *lsb) { *msb = vpi_get(vpiLeftRange, object); *lsb = vpi_get(vpiRightRange, object); return 0; } /* * $Log: a_fetch_range.c,v $ * Revision 1.2 2004/02/18 02:51:59 steve * Fix type mismatches of various VPI functions. * * Revision 1.1 2003/06/04 01:56:20 steve * 1) Adds configure logic to clean up compiler warnings * 2) adds acc_compare_handle, acc_fetch_range, acc_next_scope and * tf_isetrealdelay, acc_handle_scope * 3) makes acc_next reentrant * 4) adds basic vpiWire type support * 5) fills in some acc_object_of_type() and acc_fetch_{full}type() * 6) add vpiLeftRange/RigthRange to signals * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/Makefile.in0000644000202500001440000000005012204466647020630 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/Makefile.in0000644000202500001440000000573012204466647020157 0ustar00steveusers00000000000000# # This source code is free software; you can redistribute it # and/or modify it in source code form under the terms of the GNU # Library General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # SHELL = /bin/sh suffix = @install_suffix@ prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ VPATH = $(srcdir) bindir = @bindir@ libdir = @libdir@ includedir = $(prefix)/include CC = @CC@ RANLIB = @RANLIB@ AR = @AR@ LD = @LD@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ CPPFLAGS = -I. -I.. -I$(srcdir) -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ A = a_close.o a_compare_handles.o a_configure.o a_fetch_argc.o \ a_fetch_argv.o a_fetch_dir.o a_fetch_fullname.o a_fetch_location.o \ a_fetch_param.o a_fetch_range.o a_fetch_tfarg.o a_fetch_time.o \ a_fetch_type.o a_fetch_type_str.o a_fetch_value.o a_handle_by_name.o \ a_handle_hiconn.o a_handle_object.o a_handle_parent.o \ a_handle_simulated_net.o a_handle_tfarg.o a_initialize.o \ a_next.o a_next_bit.o a_next_port.o a_next_topmod.o \ a_object_of_type.o a_product_version.o \ a_set_value.o a_vcl.o a_version.o O = asynch.o delay.o exprinfo.o finish.o getcstringp.o getinstance.o \ getlongp.o getp.o getsimtime.o io_print.o math.o mc_scan_plusargs.o \ nodeinfo.o nump.o putlongp.o putp.o spname.o typep.o workarea.o \ veriusertfs.o priv.o $A all: dep libveriuser.a $(ALL32) check: all Makefile: $(srcdir)/Makefile.in cd ..; ./config.status --file=libveriuser/$@ stamp-config-h: $(srcdir)/config.h.in ../config.status @rm -f $@ cd ..; ./config.status --header=libveriuser/config.h config.h: stamp-config-h libveriuser.o: $O $(LD) -r -o $@ $O libveriuser.a: libveriuser.o rm -f $@ $(AR) cvq $@ libveriuser.o $(RANLIB) $@ dep: mkdir dep %.o: %.c config.h $(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep clean: rm -rf *.o dep libveriuser.a libveriuser.o distclean: clean rm -f Makefile config.log rm -f config.h stamp-config-h install:: all installdirs $(libdir)/libveriuser$(suffix).a $(INSTALL32) $(libdir)/libveriuser$(suffix).a: ./libveriuser.a $(INSTALL_DATA) ./libveriuser.a "$(DESTDIR)$(libdir)/libveriuser$(suffix).a" installdirs: $(srcdir)/../mkinstalldirs $(srcdir)/../mkinstalldirs "$(DESTDIR)$(libdir)" uninstall:: rm -f "$(DESTDIR)$(libdir)/libveriuser$(suffix).a" -include $(patsubst %.o, dep/%.d, $O) verilog-0.9.7/libveriuser/PaxHeaders.14238/putlongp.c0000644000202500001440000000005012204466647020577 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/putlongp.c0000644000202500001440000000427712204466647020133 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: putlongp.c,v 1.4 2004/09/10 23:13:05 steve Exp $" #endif #include #include #include #include /* * tf_putlongp implemented using VPI interface */ void tf_putlongp(int n, int lowvalue, int highvalue) { vpiHandle sys_h, sys_i, arg_h = 0; s_vpi_value val; int type; char str[20]; assert(n >= 0); /* get task/func handle */ sys_h = vpi_handle(vpiSysTfCall, 0); sys_i = vpi_iterate(vpiArgument, sys_h); type = vpi_get(vpiType, sys_h); /* verify function */ assert(!(n == 0 && type != vpiSysFuncCall)); /* find nth arg */ while (n > 0) { if (!(arg_h = vpi_scan(sys_i))) assert(0); n--; } if (!arg_h) arg_h = sys_h; /* fill in vpi_value */ sprintf(str, "%x%08x", highvalue, lowvalue); val.format = vpiHexStrVal; val.value.str = str; vpi_put_value(arg_h, &val, 0, vpiNoDelay); vpi_free_object(sys_i); } /* * $Log: putlongp.c,v $ * Revision 1.4 2004/09/10 23:13:05 steve * Compile cleanup of C code. * * Revision 1.3 2003/03/15 05:42:39 steve * free argument iterators. * * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/06/07 16:21:13 steve * Add tf_putlongp and tf_putp. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_version.c0000644000202500001440000000005012204466647020714 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_version.c0000644000202500001440000000251112204466647020235 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_version.c,v 1.2 2002/08/12 01:35:02 steve Exp $" #endif # include # include char *acc_version(void) { s_vpi_vlog_info info; if (! vpi_get_vlog_info(&info)) return (char *)0; return info.version; } /* * $Log: a_version.c,v $ * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/06/11 15:19:12 steve * Add acc_fetch_argc/argv/version (mruff) * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/finish.c0000644000202500001440000000005012204466647020207 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/finish.c0000644000202500001440000000257612204466647017543 0ustar00steveusers00000000000000/* * Copyright (c) 2002 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: finish.c,v 1.2 2002/08/12 01:35:02 steve Exp $" #endif # include # include /* * Implement tf_dofinish and tf_dostop using vpi functions. */ int tf_dofinish(void) { vpi_control(vpiFinish, 0); return 0; } int tf_dostop(void) { vpi_control(vpiStop, 0); return 0; } /* * $Log: finish.c,v $ * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/05/19 05:21:00 steve * Start the libveriuser library. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_compare_handles.c0000644000202500001440000000005012204466647022353 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_compare_handles.c0000644000202500001440000000325412204466647021701 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2003 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_compare_handles.c,v 1.3 2004/02/18 02:51:59 steve Exp $" #endif # include # include PLI_INT32 acc_compare_handles(handle handle1, handle handle2) { return handle1 == handle2; } /* * $Log: a_compare_handles.c,v $ * Revision 1.3 2004/02/18 02:51:59 steve * Fix type mismatches of various VPI functions. * * Revision 1.2 2003/08/26 16:26:02 steve * ifdef idents correctly. * * Revision 1.1 2003/06/04 01:56:20 steve * 1) Adds configure logic to clean up compiler warnings * 2) adds acc_compare_handle, acc_fetch_range, acc_next_scope and * tf_isetrealdelay, acc_handle_scope * 3) makes acc_next reentrant * 4) adds basic vpiWire type support * 5) fills in some acc_object_of_type() and acc_fetch_{full}type() * 6) add vpiLeftRange/RigthRange to signals * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/workarea.c0000644000202500001440000000005012204466647020542 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/workarea.c0000644000202500001440000000351312204466647020066 0ustar00steveusers00000000000000/* * Copyright (c) 2002-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include # include # include /* * Keep a list of sys handle to work area bindings. */ struct workarea_cell { vpiHandle sys; void* area; struct workarea_cell*next; }; static struct workarea_cell*area_list = 0; PLI_INT32 tf_setworkarea(void*workarea) { vpiHandle sys; struct workarea_cell*cur; sys = vpi_handle(vpiSysTfCall, 0); cur = area_list; while (cur) { if (cur->sys == sys) { cur->area = workarea; return 0; } cur = cur->next; } cur = calloc(1, sizeof (struct workarea_cell)); cur->next = area_list; cur->sys = sys; cur->area = workarea; area_list = cur; return 0; } PLI_BYTE8* tf_getworkarea(void) { struct workarea_cell*cur; vpiHandle sys; sys = vpi_handle(vpiSysTfCall, 0); cur = area_list; while (cur) { if (cur->sys == sys) { return cur->area; } cur = cur->next; } return 0; } verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_location.c0000644000202500001440000000005012204466647022210 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_location.c0000644000202500001440000000263512204466647021540 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_fetch_location.c,v 1.1 2003/02/17 06:39:47 steve Exp $" #endif #include #include int acc_fetch_location(p_location loc, handle obj) { loc->line_no = 0; loc->filename = ""; return 1; } /* * $Log: a_fetch_location.c,v $ * Revision 1.1 2003/02/17 06:39:47 steve * Add at least minimal implementations for several * acc_ functions. Add support for standard ACC * string handling. * * Add the _pli_types.h header file to carry the * IEEE1364-2001 standard PLI type declarations. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_handle_by_name.c0000644000202500001440000000005012204466647022154 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_handle_by_name.c0000644000202500001440000000366712204466647021512 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2003 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_handle_by_name.c,v 1.2 2003/06/17 16:55:07 steve Exp $" #endif # include # include # include "priv.h" # include # include /* * acc_handle_by_name implemented using VPI interface */ handle acc_handle_by_name(const char*obj_name, handle scope) { vpiHandle sys_h; vpiHandle res; /* if no scope provided, use tasks scope */ if (!scope) { sys_h = vpi_handle(vpiSysTfCall, 0 /* NULL */); scope = vpi_handle(vpiScope, sys_h); } res = vpi_handle_by_name(obj_name, scope); if (pli_trace) { fprintf(pli_trace, "acc_handle_by_name(\"%s\", scope=%s) " " --> %p\n", obj_name, vpi_get_str(vpiFullName, scope), res); } return res; } /* * $Log: a_handle_by_name.c,v $ * Revision 1.2 2003/06/17 16:55:07 steve * 1) setlinebuf() for vpi_trace * 2) Addes error checks for trace file opens * 3) removes now extraneous flushes * 4) fixes acc_next() bug * * Revision 1.1 2003/05/24 03:02:04 steve * Add implementation of acc_handle_by_name. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/putp.c0000644000202500001440000000005012204466647017717 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/putp.c0000644000202500001440000000704512204466647017247 0ustar00steveusers00000000000000/* * Copyright (c) 2002-2009 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include # include # include # include "priv.h" /* * tf_putp and friends implemented using VPI interface */ PLI_INT32 tf_iputp(PLI_INT32 n, PLI_INT32 value, void *obj) { vpiHandle sys_h, sys_i, arg_h = 0; s_vpi_value val; int rtn = 0, type; assert(n >= 0); /* get task/func handle */ sys_h = (vpiHandle)obj; type = vpi_get(vpiType, sys_h); /* Special case, we are putting the return value. */ if ((type == vpiSysFuncCall) && (n == 0)) { val.format = vpiIntVal; val.value.integer = value; vpi_put_value(sys_h, &val, 0, vpiNoDelay); if (pli_trace) { fprintf(pli_trace, "tf_iputp(, value=%d, func=%s) " "--> %d\n", (int)value, vpi_get_str(vpiName, obj), 0); } return 0; } if ((n == 0) && (type != vpiSysFuncCall)) { if (pli_trace) { fprintf(pli_trace, "tf_iputp(, value=%d, func=%s) " "--> %d\n", (int)value, vpi_get_str(vpiName, obj), 1); } return 1; } sys_i = vpi_iterate(vpiArgument, sys_h); /* find nth arg */ while (n > 0) { if (!(arg_h = vpi_scan(sys_i))) { rtn = 1; goto out; } n--; } /* fill in vpi_value */ val.format = vpiIntVal; val.value.integer = value; vpi_put_value(arg_h, &val, 0, vpiNoDelay); if (arg_h) vpi_free_object(sys_i); out: if (pli_trace) { fprintf(pli_trace, "tf_iputp(n=%d, value=%d, obj=%p) --> %d\n", (int)n, (int)value, obj, rtn); } return rtn; } PLI_INT32 tf_putp(PLI_INT32 n, PLI_INT32 value) { int rtn = tf_iputp(n, value, vpi_handle(vpiSysTfCall, 0)); return rtn; } PLI_INT32 tf_iputrealp(PLI_INT32 n, double value, void *obj) { vpiHandle sys_h, sys_i, arg_h = 0; s_vpi_value val; int rtn = 0, type; assert(n >= 0); /* get task/func handle */ sys_h = (vpiHandle)obj; sys_i = vpi_iterate(vpiArgument, sys_h); type = vpi_get(vpiType, sys_h); /* verify function */ if (n == 0 && type != vpiSysFuncCall) { rtn = 1; goto free; } /* find nth arg */ while (n > 0) { if (!(arg_h = vpi_scan(sys_i))) { rtn = 1; goto out; } n--; } if (!arg_h) arg_h = sys_h; /* fill in vpi_value */ val.format = vpiRealVal; val.value.real = value; vpi_put_value(arg_h, &val, 0, vpiNoDelay); free: vpi_free_object(sys_i); out: if (pli_trace) { fprintf(pli_trace, "tf_iputrealp(n=%d, value=%f, obj=%p) --> %d\n", (int)n, value, obj, rtn); } return rtn; } PLI_INT32 tf_putrealp(PLI_INT32 n, double value) { int rtn = tf_iputrealp(n, value, vpi_handle(vpiSysTfCall, 0)); return rtn; } verilog-0.9.7/libveriuser/PaxHeaders.14238/a_product_version.c0000644000202500001440000000005012204466647022454 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_product_version.c0000644000202500001440000000253012204466647021776 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_product_version.c,v 1.2 2002/08/12 01:35:02 steve Exp $" #endif # include # include char *acc_product_version(void) { s_vpi_vlog_info info; if (! vpi_get_vlog_info(&info)) return (char *)0; return info.version; } /* * $Log: a_product_version.c,v $ * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/05/30 02:06:05 steve * Implement acc_product_version. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_argv.c0000644000202500001440000000005012204466647021337 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_argv.c0000644000202500001440000000274412204466647020670 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_fetch_argv.c,v 1.2 2002/08/12 01:35:02 steve Exp $" #endif # include # include /* * acc_fetch_argv implemented using VPI interface */ char **acc_fetch_argv(void) { s_vpi_vlog_info vpi_vlog_info; /* get command line info */ if (! vpi_get_vlog_info(&vpi_vlog_info)) return (char **)0; /* return argc */ return vpi_vlog_info.argv; } /* * $Log: a_fetch_argv.c,v $ * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/06/11 15:19:12 steve * Add acc_fetch_argc/argv/version (mruff) * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_next_bit.c0000644000202500001440000000005012204466647021043 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_next_bit.c0000644000202500001440000000274212204466647020372 0ustar00steveusers00000000000000/* * Copyright (c) 2003 Stephen Williams (steve@picturel.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_next_bit.c,v 1.1 2003/10/10 02:57:46 steve Exp $" #endif # include # include # include # include # include "priv.h" handle acc_next_bit(handle ref, handle bit) { if (pli_trace) { fprintf(pli_trace, "acc_next_bit: enter.\n"); fflush(pli_trace); } fprintf(stderr, "acc_next_bit: XXXX not implemented. XXXX\n"); if (pli_trace) { fprintf(pli_trace, "acc_next_bit: return.\n"); fflush(pli_trace); } return 0; } /* * $Log: a_next_bit.c,v $ * Revision 1.1 2003/10/10 02:57:46 steve * Some PLI1 stubs. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_handle_simulated_net.c0000644000202500001440000000005012204466647023377 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_handle_simulated_net.c0000644000202500001440000000254012204466647022722 0ustar00steveusers00000000000000/* * Copyright (c) 2003 Stephen Williams (steve@picturel.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_handle_simulated_net.c,v 1.1 2003/10/10 02:57:46 steve Exp $" #endif # include # include # include # include # include "priv.h" handle acc_handle_simulated_net(handle obj) { if (pli_trace) { fprintf(pli_trace, "acc_handle_simulated_set: returns argument\n"); fflush(pli_trace); } return obj; } /* * $Log: a_handle_simulated_net.c,v $ * Revision 1.1 2003/10/10 02:57:46 steve * Some PLI1 stubs. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_handle_parent.c0000644000202500001440000000005012204466647022033 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_handle_parent.c0000644000202500001440000000345612204466647021365 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_handle_parent.c,v 1.2 2003/06/04 01:56:20 steve Exp $" #endif #include #include #include "priv.h" handle acc_handle_parent(handle obj) { vpiHandle scope = vpi_handle(vpiScope, obj); while (scope && (vpi_get(vpiType, scope) != vpiModule)) scope = vpi_handle(vpiScope, scope); return scope; } handle acc_handle_scope(handle obj) { return vpi_handle(vpiScope, obj); } /* * $Log: a_handle_parent.c,v $ * Revision 1.2 2003/06/04 01:56:20 steve * 1) Adds configure logic to clean up compiler warnings * 2) adds acc_compare_handle, acc_fetch_range, acc_next_scope and * tf_isetrealdelay, acc_handle_scope * 3) makes acc_next reentrant * 4) adds basic vpiWire type support * 5) fills in some acc_object_of_type() and acc_fetch_{full}type() * 6) add vpiLeftRange/RigthRange to signals * * Revision 1.1 2003/03/13 04:35:09 steve * Add a bunch of new acc_ and tf_ functions. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_type_str.c0000644000202500001440000000005012204466647022251 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_type_str.c0000644000202500001440000000241712204466647021577 0ustar00steveusers00000000000000/* * Copyright (c) 2003-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include char* acc_fetch_type_str(PLI_INT32 type) { switch (type) { case accNet: return "accNet"; case accReg: return "accReg"; case accParameter: return "accParameter"; case accConstant: return "accConstant"; } vpi_printf("acc_fetch_type_str: type %d is what accType?\n", (int)type); return "acc_fetch_type_str(unknown)"; } verilog-0.9.7/libveriuser/PaxHeaders.14238/a_handle_tfarg.c0000644000202500001440000000005012204466647021645 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_handle_tfarg.c0000644000202500001440000000443112204466647021171 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_handle_tfarg.c,v 1.6 2004/10/04 01:10:56 steve Exp $" #endif #include #include /* * acc_handle_tfarg implemented using VPI interface */ handle acc_handle_tfarg(int n) { vpiHandle sys_h, sys_i, rtn_h = 0; if (n > 0) { sys_h = vpi_handle(vpiSysTfCall, 0 /* NULL */); sys_i = vpi_iterate(vpiArgument, sys_h); /* find nth arg */ while (n > 0) { rtn_h = vpi_scan(sys_i); if (rtn_h == 0) break; n--; } if (rtn_h) vpi_free_object(sys_i); } else { rtn_h = (vpiHandle) 0; } return rtn_h; } handle acc_handle_tfinst(void) { return vpi_handle(vpiSysTfCall, 0); } /* * $Log: a_handle_tfarg.c,v $ * Revision 1.6 2004/10/04 01:10:56 steve * Clean up spurious trailing white space. * * Revision 1.5 2003/03/18 01:21:49 steve * Fix warning about uninitialized variable. * * Revision 1.4 2003/03/14 04:58:50 steve * Free the iterator when Im done. * * Revision 1.3 2003/02/17 06:39:47 steve * Add at least minimal implementations for several * acc_ functions. Add support for standard ACC * string handling. * * Add the _pli_types.h header file to carry the * IEEE1364-2001 standard PLI type declarations. * * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/06/02 19:03:58 steve * Add acc_handle_tfarg and acc_next_topmode * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_next_topmod.c0000644000202500001440000000005012204466647021567 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_next_topmod.c0000644000202500001440000000322112204466647021107 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_next_topmod.c,v 1.2 2002/08/12 01:35:02 steve Exp $" #endif #include #include #include #undef NULL #define NULL 0 /* * acc_next_topmod implemented using VPI interface */ handle acc_next_topmod(handle prev_topmod) { static vpiHandle last = NULL; static vpiHandle mod_i = NULL; if (!prev_topmod) { /* start over */ mod_i = vpi_iterate(vpiModule, NULL); } else { /* subsequent time through */ assert(prev_topmod == last); } last = vpi_scan(mod_i); return last; } /* * $Log: a_next_topmod.c,v $ * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/06/02 19:03:58 steve * Add acc_handle_tfarg and acc_next_topmode * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_param.c0000644000202500001440000000005012204466647021500 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_param.c0000644000202500001440000000270212204466647021023 0ustar00steveusers00000000000000/* * Copyright (c) 2003-2009 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include "priv.h" double acc_fetch_paramval(handle object) { s_vpi_value val; val.format = vpiObjTypeVal; vpi_get_value(object, &val); switch (val.format) { case vpiStringVal: if (pli_trace) { fprintf(pli_trace, "acc_fetch_paramval(%s) --> \"%s\"\n", vpi_get_str(vpiName, object), val.value.str); } return (double) (long)val.value.str; default: vpi_printf("XXXX: parameter %s has type %d\n", vpi_get_str(vpiName, object), (int)val.format); assert(0); return 0.0; } } verilog-0.9.7/libveriuser/PaxHeaders.14238/getinstance.c0000644000202500001440000000005012204466647021233 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/getinstance.c0000644000202500001440000000325612204466647020563 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: getinstance.c,v 1.5 2005/09/20 18:34:01 steve Exp $" #endif #include #include /* * tf_getinstance implemented using VPI interface */ PLI_BYTE8* tf_getinstance(void) { return (PLI_BYTE8 *)vpi_handle(vpiSysTfCall, 0 /* NULL */); } /* * $Log: getinstance.c,v $ * Revision 1.5 2005/09/20 18:34:01 steve * Clean up compiler warnings. * * Revision 1.4 2003/05/18 00:16:35 steve * Add PLI_TRACE tracing of PLI1 modules. * * Add tf_isetdelay and friends, and add * callback return values for acc_vcl support. * * Revision 1.3 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.2 2002/06/03 21:52:59 steve * Fix return type of tf_getinstance. * * Revision 1.1 2002/06/02 18:54:59 steve * Add tf_getinstance function. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_dir.c0000644000202500001440000000005012204466647021156 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_dir.c0000644000202500001440000000277612204466647020514 0ustar00steveusers00000000000000/* * Copyright (c) 2003 Stephen Williams (steve@picturel.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: a_fetch_dir.c,v 1.1 2003/10/10 02:57:45 steve Exp $" #endif # include # include # include # include # include "priv.h" PLI_INT32 acc_fetch_direction(handle obj) { if (pli_trace) { fprintf(pli_trace, "acc_fetch_direction: enter.\n"); fflush(pli_trace); } fprintf(stderr, "acc_fetch_direction: XXXX not implemented. XXXX\n"); if (pli_trace) { fprintf(pli_trace, "acc_fetch_direction: return.\n"); fflush(pli_trace); } return accInout; } /* * $Log: a_fetch_dir.c,v $ * Revision 1.1 2003/10/10 02:57:45 steve * Some PLI1 stubs. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/config.h.in0000644000202500001440000000005012204466647020606 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/config.h.in0000644000202500001440000000237412204466647020136 0ustar00steveusers00000000000000#ifndef __config_H #define __config_H /* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # define SIZEOF_UNSIGNED_LONG_LONG 0 # define SIZEOF_UNSIGNED_LONG 0 # define SIZEOF_UNSIGNED 0 #if SIZEOF_UNSIGNED >= 8 typedef unsigned ivl_u64_t; #else # if SIZEOF_UNSIGNED_LONG >= 8 typedef unsigned long ivl_u64_t; # else # if SIZEOF_UNSIGNED_LONG_LONG > SIZEOF_UNSIGNED_LONG typedef unsigned long long ivl_u64_t; # else typedef unsigned long ivl_u64_t; # endif # endif #endif #endif verilog-0.9.7/libveriuser/PaxHeaders.14238/asynch.c0000644000202500001440000000005012204466647020214 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/asynch.c0000644000202500001440000000275412204466647017546 0ustar00steveusers00000000000000/* vi:sw=6 * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: asynch.c,v 1.3 2003/04/23 15:01:29 steve Exp $" #endif # include /* Enables async misctf callbacks */ int async_misctf_enable = 0; /* * Implement misctf async enable */ int tf_asynchon(void) { async_misctf_enable = 1; return 0; } int tf_asynchoff(void) { async_misctf_enable = 0; return 0; } /* * $Log: asynch.c,v $ * Revision 1.3 2003/04/23 15:01:29 steve * Add tf_synchronize and tf_multiply_long. * * Revision 1.2 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.1 2002/06/04 01:40:03 steve * Add asynchon and asynchoff * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/io_print.c0000644000202500001440000000005012204466647020552 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/io_print.c0000644000202500001440000000430212204466647020073 0ustar00steveusers00000000000000/* * Copyright (c) 2002 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: io_print.c,v 1.4 2002/12/19 21:37:04 steve Exp $" #endif # include # include /* * io_printf implemented using VPI interface */ void io_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vpi_vprintf(fmt, ap); va_end(ap); } void tf_warning(const char *fmt, ...) { va_list ap; vpi_printf("warning! "); va_start(ap, fmt); vpi_vprintf(fmt, ap); va_end(ap); } void tf_error(const char *fmt, ...) { va_list ap; vpi_printf("error! "); va_start(ap, fmt); vpi_vprintf(fmt, ap); va_end(ap); } PLI_INT32 tf_message(PLI_INT32 level, char*facility, char*messno, char*fmt, ...) { va_list ap; vpi_printf("%s[%s] ", facility, messno); va_start(ap, fmt); vpi_vprintf(fmt, ap); va_end(ap); vpi_printf("\n"); return 0; } /* * $Log: io_print.c,v $ * Revision 1.4 2002/12/19 21:37:04 steve * Add tf_message, tf_get/setworkarea, and * ty_typep functions, along with defines * related to these functions. * * Revision 1.3 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.2 2002/05/30 02:10:08 steve * Add tf_error and tf_warning from mruff * * Revision 1.1 2002/05/23 03:35:42 steve * Add the io_printf function to libveriuser. * */ verilog-0.9.7/libveriuser/PaxHeaders.14238/a_vcl.c0000644000202500001440000000005012204466647020013 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_vcl.c0000644000202500001440000001301612204466647017336 0ustar00steveusers00000000000000/* * Copyright (c) 2003-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include "priv.h" #include /* * This is the structure of a record that I use locally to hold the * information about a VCL. This record includes a pointer to the vpi * callback that is actually watching the value, and that callback has * a pointer to this record in its user_data so that I can get to it * when the value changes. * * Keep all these records in a vcl_list so that I can get access to * them for the vcl_delete. */ struct vcl_record { /* Object who's value I'm watching. */ vpiHandle obj; /* User's callback routine. */ PLI_INT32(*consumer)(p_vc_record); void*user_data; PLI_INT32 vcl_flag; vpiHandle callback; struct vcl_record*next; }; static struct vcl_record*vcl_list = 0; static int vpi_strength_to_vcl(int vs) { switch (vs) { case vpiSupplyDrive: return vclSupply; case vpiStrongDrive: return vclStrong; case vpiPullDrive: return vclPull; case vpiLargeCharge: return vclLarge; case vpiWeakDrive: return vclWeak; case vpiMediumCharge: return vclMedium; case vpiSmallCharge: return vclSmall; case vpiHiZ: return vclHighZ; default: return -1; } } /* * This is a VPI callback that notices the value change. This function * further dispatches the information about the callback to the * consumer function. */ static PLI_INT32 vcl_value_callback(struct t_cb_data*cb) { s_vpi_time sim_time; s_vpi_value obj_value; struct t_vc_record vcr; struct vcl_record*cur = (struct vcl_record*)cb->user_data; sim_time.type = vpiSimTime; vpi_get_time(cur->obj, &sim_time); switch (cur->vcl_flag) { case VCL_VERILOG_LOGIC: vpi_printf("XXXX vcl_value_callback(%s=%d);\n", vpi_get_str(vpiName, cur->obj), -1); vcr.vc_reason = logic_value_change; break; case VCL_VERILOG_STRENGTH: vcr.vc_reason = strength_value_change; obj_value.format = vpiStrengthVal; vpi_get_value(cur->obj, &obj_value); assert(obj_value.format == vpiStrengthVal); switch (obj_value.value.strength[0].logic) { case vpi0: vcr.out_value.strengths_s.logic_value = acc0; vcr.out_value.strengths_s.strength1 = vpi_strength_to_vcl(obj_value.value.strength[0].s0); vcr.out_value.strengths_s.strength2 = vpi_strength_to_vcl(obj_value.value.strength[0].s0); break; case vpi1: vcr.out_value.strengths_s.logic_value = acc1; vcr.out_value.strengths_s.strength1 = vpi_strength_to_vcl(obj_value.value.strength[0].s1); vcr.out_value.strengths_s.strength2 = vpi_strength_to_vcl(obj_value.value.strength[0].s1); break; case vpiX: vcr.out_value.strengths_s.logic_value = accX; vcr.out_value.strengths_s.strength1 = vpi_strength_to_vcl(obj_value.value.strength[0].s1); vcr.out_value.strengths_s.strength2 = vpi_strength_to_vcl(obj_value.value.strength[0].s0); break; case vpiZ: vcr.out_value.strengths_s.logic_value = accZ; vcr.out_value.strengths_s.strength1 = vclHighZ; vcr.out_value.strengths_s.strength2 = vclHighZ; break; default: assert(0); } if (pli_trace) { fprintf(pli_trace, "Call vcl_value_callback(%s=%d )\n", vpi_get_str(vpiFullName, cur->obj), vcr.out_value.strengths_s.logic_value, vcr.out_value.strengths_s.strength1, vcr.out_value.strengths_s.strength2); } break; default: assert(0); } vcr.vc_hightime = sim_time.high; vcr.vc_lowtime = sim_time.low; vcr.user_data = cur->user_data; (cur->consumer) (&vcr); return 0; } void acc_vcl_add(handle obj, PLI_INT32(*consumer)(p_vc_record), void*data, PLI_INT32 vcl_flag) { struct vcl_record*cur; struct t_cb_data cb; switch (vpi_get(vpiType, obj)) { case vpiNet: cur = malloc(sizeof (struct vcl_record)); cur->obj = obj; cur->consumer = consumer; cur->user_data = data; cur->vcl_flag = vcl_flag; cur->next = vcl_list; vcl_list = cur; cb.reason = cbValueChange; cb.cb_rtn = vcl_value_callback; cb.obj = obj; cb.time = 0; cb.value = 0; cb.user_data = (void*)cur; cur->callback = vpi_register_cb(&cb); if (pli_trace) { fprintf(pli_trace, "acc_vcl_add(<%s>, ..., %p, %d)\n", vpi_get_str(vpiFullName, obj), data, (int)vcl_flag); } break; default: vpi_printf("XXXX acc_vcl_add(, ..., %d);\n", (int)vpi_get(vpiType, obj), (int)vcl_flag); break; } } void acc_vcl_delete(handle obj, PLI_INT32(*consumer)(p_vc_record), void*data, PLI_INT32 vcl_flag) { vpi_printf("XXXX acc_vcl_delete(...)\n"); } verilog-0.9.7/libveriuser/PaxHeaders.14238/a_object_of_type.c0000644000202500001440000000005012204466647022222 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_object_of_type.c0000644000202500001440000000532712204466647021553 0ustar00steveusers00000000000000/* * Copyright (c) 2002-2009 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include "priv.h" /* * acc_object_of_type implemented using VPI interface */ int acc_object_of_type(handle object, PLI_INT32 type) { int vtype; int rtn = 0; /* false */ if (pli_trace) { fprintf(pli_trace, "acc_object_of_type(%p \"%s\", %d)", object, vpi_get_str(vpiName, object), (int)type); fflush(pli_trace); } /* get VPI type of object */ vtype = vpi_get(vpiType, object); switch (type) { case accModule: rtn = vtype == vpiModule; break; case accScope: if (vtype == vpiModule || vtype == vpiNamedBegin || vtype == vpiNamedFork || vtype == vpiTask || vtype == vpiFunction) rtn = 1; break; case accNet: rtn = vtype == vpiNet; break; case accReg: rtn = vtype == vpiReg; break; case accRealParam: if (vtype == vpiNamedEvent && vpi_get(vpiConstType, object) == vpiRealConst) rtn = 1; break; case accParameter: rtn = vtype == vpiParameter; break; case accNamedEvent: rtn = vtype == vpiNamedEvent; break; case accIntegerVar: rtn = vtype == vpiIntegerVar; break; case accRealVar: rtn = vtype == vpiRealVar; break; case accTimeVar: rtn = vtype == vpiTimeVar; break; case accScalar: if (vtype == vpiReg || vtype == vpiNet) rtn = vpi_get(vpiSize, object) == 1; break; case accVector: if (vtype == vpiReg || vtype == vpiNet) rtn = vpi_get(vpiSize, object) > 1; break; default: vpi_printf("acc_object_of_type: Unknown type %d\n", (int)type); rtn = 0; } if (pli_trace) fprintf(pli_trace, " --> %d\n", rtn); return rtn; } int acc_object_in_typelist(handle object, PLI_INT32*typelist) { while (typelist[0] != 0) { int rtn = acc_object_of_type(object, typelist[0]); if (rtn) return rtn; typelist += 1; } return 0; } verilog-0.9.7/libveriuser/PaxHeaders.14238/a_fetch_type.c0000644000202500001440000000005012204466647021361 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_fetch_type.c0000644000202500001440000000544112204466647020707 0ustar00steveusers00000000000000/* * Copyright (c) 2003-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include # include # include PLI_INT32 acc_fetch_size(handle obj) { return vpi_get(vpiSize, obj); } PLI_INT32 acc_fetch_type(handle obj) { switch (vpi_get(vpiType, obj)) { case vpiConstant: /*XXXX SWIFT PLI tasks seem to assume that string constants show up an accParameter, instead of accConstant. */ if (vpi_get(vpiConstType, obj) == vpiStringConst) return accParameter; else return accConstant; case vpiNamedEvent: return accNamedEvent; case vpiNet: return accNet; case vpiParameter: return accParameter; case vpiReg: return accReg; case vpiIntegerVar: return accIntegerVar; case vpiModule: return accModule; } vpi_printf("acc_fetch_type: vpiType %d is what accType?\n", (int)vpi_get(vpiType, obj)); return accUnknown; } PLI_INT32 acc_fetch_fulltype(handle obj) { int type = vpi_get(vpiType, obj); switch (type) { case vpiNet: { type = vpi_get(vpiNetType, obj); switch(type) { case vpiWire: return accWire; default: vpi_printf("acc_fetch_fulltype: vpiNetType %d unknown?\n", type); return accUnknown; } } case vpiConstant: /* see acc_fetch_type */ if (vpi_get(vpiConstType, obj) == vpiStringConst) return accStringParam; else return accConstant; case vpiIntegerVar: return accIntegerVar; case vpiModule: if (!vpi_handle(vpiScope, obj)) return accTopModule; else return accModuleInstance; /* FIXME accCellInstance */ case vpiNamedEvent: return accNamedEvent; case vpiParameter: switch(vpi_get(vpiConstType, obj)) { case vpiRealConst: return accRealParam; case vpiStringConst: return accStringParam; default: return accIntegerParam; } case vpiReg: return accReg; default: vpi_printf("acc_fetch_fulltype: vpiType %d unknown?\n", type); return accUnknown; } } verilog-0.9.7/libveriuser/PaxHeaders.14238/a_next.c0000644000202500001440000000005012204466647020205 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/libveriuser/a_next.c0000644000202500001440000000477712204466647017546 0ustar00steveusers00000000000000/* * Copyright (c) 2003-2009 Michael Ruff (mruff at chiaro.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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include "priv.h" /* * acc_next and friends implemented using VPI */ handle acc_next(PLI_INT32 *type, handle scope, handle prev) { vpiHandle iter, hand = 0; /* trace */ if (pli_trace) { PLI_INT32 *ip; fprintf(pli_trace, "acc_next(%p <", type); for (ip = type; *ip; ip++) { fprintf(pli_trace, "%s%d", ip != type ? "," : "", (int)*ip); } fprintf(pli_trace, ">, %p", scope); if (scope) fprintf(pli_trace, " \"%s\"", vpi_get_str(vpiName, scope)); fprintf(pli_trace, ", %p", prev); if (prev) fprintf(pli_trace, " \"%s\"", vpi_get_str(vpiName, prev)); else fprintf(pli_trace, ")"); fflush(pli_trace); } /* * The acc_next_* functions need to be reentrant, so we need to * rescan all the items up to the previous one, then return * the next one. */ iter = vpi_iterate(vpiScope, scope); /* ICARUS extension */ if (prev) { while ((hand = vpi_scan(iter))) { if (hand == prev) break; } } /* scan for next */ if (!prev || hand) { while ((hand = vpi_scan(iter))) { if (acc_object_in_typelist(hand, type)) break; } } /* don't leak iterators */ if (hand) vpi_free_object(iter); /* trace */ if (pli_trace) { fprintf(pli_trace, " --> %p", hand); if (hand) fprintf(pli_trace, " \"%s\"\n", vpi_get_str(vpiName, hand)); else fprintf(pli_trace, "\n"); } return hand; } handle acc_next_scope(handle scope, handle prev) { PLI_INT32 type[2] = {accScope, 0}; return acc_next(type, scope, prev); } verilog-0.9.7/PaxHeaders.14238/dosify.c0000644000202500001440000000005012204466647015671 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/dosify.c0000644000202500001440000000361012204466647015213 0ustar00steveusers00000000000000/* * Copyright (c) 2001-2009 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * This is a simple program to make a dosified copy of the * original. That is, it converts unix style line ends to DOS * style. This is useful for installing text files. * * The exact substitution is to replace \n with \r\n. If the line * already ends with \r\n then it is not changed to \r\r\n. */ # include int main(int argc, char*argv[]) { FILE*ifile; FILE*ofile; int ch, pr; if (argc != 3) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } ifile = fopen(argv[1], "rb"); if (ifile == 0) { fprintf(stderr, "Unable to open %s for input.\n", argv[1]); return 2; } ofile = fopen(argv[2], "wb"); if (ofile == 0) { fprintf(stderr, "Unable to open %s for output.\n", argv[2]); fclose(ifile); return 2; } pr = 0; while ((ch = fgetc(ifile)) != EOF) { if ((ch == '\n') && (pr != '\r')) fputc('\r', ofile); fputc(ch, ofile); pr = ch; } fclose(ifile); fclose(ofile); return 0; } verilog-0.9.7/PaxHeaders.14238/t-dll-expr.cc0000644000202500001440000000005012204466647016527 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/t-dll-expr.cc0000644000202500001440000003414312204466647016056 0ustar00steveusers00000000000000/* * Copyright (c) 2000-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include # include # include "t-dll.h" # include "netlist.h" # include # include /* * This is a little convenience function for converting a NetExpr * expression type to the expression type used by ivl_expr_t objects. */ static ivl_variable_type_t get_expr_type(const NetExpr*net) { return net->expr_type(); } /* * These methods implement the expression scan that generates the * ivl_expr_t representing the expression. Each method leaves the * expr_ member filled with the ivl_expr_t that represents it. Each * method expects that the expr_ member empty (0) when it starts. */ /* * This function takes an expression in the expr_ member that is * already built up, and adds a subtraction of the given constant. */ void dll_target::sub_off_from_expr_(long off) { assert(expr_ != 0); char*bits; ivl_expr_t tmpc = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmpc->type_ = IVL_EX_NUMBER; tmpc->value_ = IVL_VT_VECTOR; tmpc->width_ = expr_->width_; tmpc->signed_ = expr_->signed_; tmpc->u_.number_.bits_ = bits = (char*)malloc(tmpc->width_); for (unsigned idx = 0 ; idx < tmpc->width_ ; idx += 1) { bits[idx] = (off & 1)? '1' : '0'; off >>= 1; } /* Now make the subtractor (x-4 in the above example) that has as input A the index expression and input B the constant to subtract. */ ivl_expr_t tmps = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmps->type_ = IVL_EX_BINARY; tmps->value_ = IVL_VT_VECTOR; tmps->width_ = tmpc->width_; tmps->signed_ = tmpc->signed_; tmps->u_.binary_.op_ = '-'; tmps->u_.binary_.lef_ = expr_; tmps->u_.binary_.rig_ = tmpc; /* Replace (x) with (x-off) */ expr_ = tmps; } void dll_target::mul_expr_by_const_(long val) { assert(expr_ != 0); char*bits; ivl_expr_t tmpc = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmpc->type_ = IVL_EX_NUMBER; tmpc->value_ = IVL_VT_VECTOR; tmpc->width_ = expr_->width_; tmpc->signed_ = expr_->signed_; tmpc->u_.number_.bits_ = bits = (char*)malloc(tmpc->width_); for (unsigned idx = 0 ; idx < tmpc->width_ ; idx += 1) { bits[idx] = (val & 1)? '1' : '0'; val >>= 1; } /* Now make the subtractor (x-4 in the above example) that has as input A the index expression and input B the constant to subtract. */ ivl_expr_t tmps = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmps->type_ = IVL_EX_BINARY; tmps->value_ = IVL_VT_VECTOR; tmps->width_ = tmpc->width_; tmps->signed_ = tmpc->signed_; tmps->u_.binary_.op_ = '*'; tmps->u_.binary_.lef_ = expr_; tmps->u_.binary_.rig_ = tmpc; /* Replace (x) with (x*valf) */ expr_ = tmps; } ivl_expr_t dll_target::expr_from_value_(const verinum&val) { ivl_expr_t expr = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr); unsigned idx; char*bits; expr->type_ = IVL_EX_NUMBER; expr->value_= IVL_VT_VECTOR; expr->width_= val.len(); expr->signed_ = val.has_sign()? 1 : 0; expr->u_.number_.bits_ = bits = (char*)malloc(expr->width_ + 1); for (idx = 0 ; idx < expr->width_ ; idx += 1) switch (val.get(idx)) { case verinum::V0: bits[idx] = '0'; break; case verinum::V1: bits[idx] = '1'; break; case verinum::Vx: bits[idx] = 'x'; break; case verinum::Vz: bits[idx] = 'z'; break; default: assert(0); } bits[expr->width_] = 0; return expr; } void dll_target::expr_access_func(const NetEAccess*net) { assert(expr_ == 0); // Make a stub Branch Access Function expression node. expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); expr_->type_ = IVL_EX_BACCESS; expr_->value_ = IVL_VT_REAL; expr_->file = net->get_file(); expr_->lineno = net->get_lineno(); expr_->width_ = 1; expr_->signed_= 1; expr_->u_.branch_.branch = net->get_branch()->target_obj(); expr_->u_.branch_.nature = net->get_nature(); } void dll_target::expr_binary(const NetEBinary*net) { assert(expr_ == 0); net->left()->expr_scan(this); ivl_expr_t left = expr_; expr_ = 0; net->right()->expr_scan(this); ivl_expr_t rght = expr_; expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); expr_->type_ = IVL_EX_BINARY; expr_->value_= get_expr_type(net); expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->u_.binary_.op_ = net->op(); expr_->u_.binary_.lef_ = left; expr_->u_.binary_.rig_ = rght; } void dll_target::expr_concat(const NetEConcat*net) { assert(expr_ == 0); ivl_expr_t cur = new struct ivl_expr_s; assert(cur); cur->type_ = IVL_EX_CONCAT; cur->value_ = IVL_VT_VECTOR; cur->width_ = net->expr_width(); cur->signed_ = net->has_sign() ? 1 : 0; cur->u_.concat_.rept = net->repeat(); cur->u_.concat_.parms = net->nparms(); cur->u_.concat_.parm = new ivl_expr_t [net->nparms()]; for (unsigned idx = 0 ; idx < net->nparms() ; idx += 1) { expr_ = 0; net->parm(idx)->expr_scan(this); assert(expr_); cur->u_.concat_.parm[idx] = expr_; } expr_ = cur; } void dll_target::expr_const(const NetEConst*net) { assert(expr_ == 0); expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); expr_->value_= net->expr_type(); FILE_NAME(expr_, net); if (net->value().is_string()) { expr_->type_ = IVL_EX_STRING; expr_->width_= net->expr_width(); expr_->u_.string_.value_ =strdup(net->value().as_string().c_str()); } else { verinum val = net->value(); unsigned idx; char*bits; expr_->type_ = IVL_EX_NUMBER; expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->u_.number_.bits_ = bits = (char*)malloc(expr_->width_); for (idx = 0 ; idx < expr_->width_ ; idx += 1) switch (val.get(idx)) { case verinum::V0: bits[idx] = '0'; break; case verinum::V1: bits[idx] = '1'; break; case verinum::Vx: bits[idx] = 'x'; break; case verinum::Vz: bits[idx] = 'z'; break; default: assert(0); } } } void dll_target::expr_param(const NetEConstParam*net) { ivl_scope_t scop = find_scope(des_, net->scope()); ivl_parameter_t par = scope_find_param(scop, net->name()); if (par == 0) { cerr << net->get_fileline() << ": internal error: " << "Parameter " << net->name() << " missing from " << ivl_scope_name(scop) << endl; } assert(par); assert(par->value); expr_ = par->value; } void dll_target::expr_rparam(const NetECRealParam*net) { ivl_scope_t scop = find_scope(des_, net->scope()); ivl_parameter_t par = scope_find_param(scop, net->name()); if (par == 0) { cerr << net->get_fileline() << ": internal error: " << "Parameter " << net->name() << " missing from " << ivl_scope_name(scop) << endl; } assert(par); assert(par->value); expr_ = par->value; } void dll_target::expr_creal(const NetECReal*net) { assert(expr_ == 0); expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); expr_->width_ = net->expr_width(); expr_->signed_ = 1; expr_->type_ = IVL_EX_REALNUM; FILE_NAME(expr_, net); expr_->value_= IVL_VT_REAL; expr_->u_.real_.value = net->value().as_double(); } void dll_target::expr_event(const NetEEvent*net) { assert(expr_ == 0); expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); expr_->type_ = IVL_EX_EVENT; FILE_NAME(expr_, net); expr_->value_= IVL_VT_VOID; /* Locate the event by name. Save the ivl_event_t in the expression 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) { expr_->u_.event_.event = ev_scope->event_[idx]; break; } } } void dll_target::expr_scope(const NetEScope*net) { assert(expr_ == 0); expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); expr_->type_ = IVL_EX_SCOPE; expr_->value_= IVL_VT_VOID; expr_->u_.scope_.scope = lookup_scope_(net->scope()); } void dll_target::expr_select(const NetESelect*net) { assert(expr_ == 0); net->sub_expr()->expr_scan(this); ivl_expr_t left = expr_; expr_ = 0; if (net->select()) net->select()->expr_scan(this); ivl_expr_t rght = expr_; expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); FILE_NAME(expr_, net); expr_->type_ = IVL_EX_SELECT; expr_->value_= IVL_VT_VECTOR; expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->u_.binary_.lef_ = left; expr_->u_.binary_.rig_ = rght; } void dll_target::expr_sfunc(const NetESFunc*net) { assert(expr_ == 0); ivl_expr_t expr = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr); expr->type_ = IVL_EX_SFUNC; FILE_NAME(expr, net); expr->value_= net->expr_type(); expr->width_= net->expr_width(); expr->signed_ = net->has_sign()? 1 : 0; /* system function names are lex_strings strings. */ expr->u_.sfunc_.name_ = net->name(); unsigned cnt = net->nparms(); expr->u_.sfunc_.parms = cnt; expr->u_.sfunc_.parm = new ivl_expr_t[cnt]; /* make up the parameter expressions. */ for (unsigned idx = 0 ; idx < cnt ; idx += 1) { net->parm(idx)->expr_scan(this); assert(expr_); expr->u_.sfunc_.parm[idx] = expr_; expr_ = 0; } expr_ = expr; } void dll_target::expr_ternary(const NetETernary*net) { assert(expr_ == 0); ivl_expr_t expr = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr); expr->type_ = IVL_EX_TERNARY; FILE_NAME(expr, net); expr->value_= net->expr_type(); expr->width_ = net->expr_width(); expr->signed_ = net->has_sign()? 1 : 0; net->cond_expr()->expr_scan(this); assert(expr_); expr->u_.ternary_.cond = expr_; expr_ = 0; net->true_expr()->expr_scan(this); assert(expr_); expr->u_.ternary_.true_e = expr_; expr_ = 0; net->false_expr()->expr_scan(this); assert(expr_); expr->u_.ternary_.false_e = expr_; expr_ = expr; } void dll_target::expr_signal(const NetESignal*net) { ivl_signal_t sig = find_signal(des_, net->sig()); assert(expr_ == 0); /* If there is a word expression, generate it. */ ivl_expr_t word_expr = 0; if (const NetExpr*word = net->word_index()) { word->expr_scan(this); assert(expr_); word_expr = expr_; expr_ = 0; } expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); expr_->type_ = IVL_EX_SIGNAL; expr_->value_= net->expr_type(); expr_->file = net->get_file(); expr_->lineno= net->get_lineno(); expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->u_.signal_.word = word_expr; expr_->u_.signal_.sig = sig; /* Make account for the special case that this is a reference to an array as a whole. We detect this case by noting that this is an array (more than 0 array dimensions) and that there is no word select expression. For this case, we have an IVL_EX_ARRAY expression instead of a SIGNAL expression. */ if (sig->array_dimensions_ > 0 && word_expr == 0) { expr_->type_ = IVL_EX_ARRAY; expr_->width_ = 0; // Doesn't make much sense for arrays. } } void dll_target::expr_ufunc(const NetEUFunc*net) { assert(expr_ == 0); ivl_expr_t expr = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr); expr->type_ = IVL_EX_UFUNC; FILE_NAME(expr, net); expr->value_= net->expr_type(); expr->width_= net->expr_width(); expr->signed_ = net->has_sign()? 1 : 0; expr->u_.ufunc_.def = lookup_scope_(net->func()); assert(expr->u_.ufunc_.def->type_ == IVL_SCT_FUNCTION); unsigned cnt = net->parm_count(); expr->u_.ufunc_.parms = cnt; expr->u_.ufunc_.parm = new ivl_expr_t[cnt]; /* make up the parameter expressions. */ for (unsigned idx = 0 ; idx < cnt ; idx += 1) { net->parm(idx)->expr_scan(this); assert(expr_); expr->u_.ufunc_.parm[idx] = expr_; expr_ = 0; } expr_ = expr; } void dll_target::expr_unary(const NetEUnary*net) { assert(expr_ == 0); net->expr()->expr_scan(this); assert(expr_); ivl_expr_t sub = expr_; expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); expr_->type_ = IVL_EX_UNARY; expr_->value_= net->expr_type(); expr_->width_ = net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->u_.unary_.op_ = net->op(); expr_->u_.unary_.sub_ = sub; } verilog-0.9.7/PaxHeaders.14238/eval_tree.cc0000644000202500001440000000005012204466647016505 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/eval_tree.cc0000644000202500001440000015065612204466647016044 0ustar00steveusers00000000000000/* * Copyright (c) 1999-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "compiler.h" # include # include # include # include # include "netlist.h" # include "ivl_assert.h" # include "netmisc.h" NetExpr* NetExpr::eval_tree(int prune_to_width) { return 0; } static bool get_real_arg_(NetExpr*expr, verireal&val) { switch (expr->expr_type()) { case IVL_VT_REAL: { NetECReal*c = dynamic_cast (expr); if (c == 0) return false; val = c->value(); break; } case IVL_VT_BOOL: case IVL_VT_LOGIC: { NetEConst*c = dynamic_cast(expr); if (c == 0) return false; verinum tmp = c->value(); val = verireal(tmp.as_double()); break; } default: assert(0); } return true; } bool NetEBinary::get_real_arguments_(verireal&lval, verireal&rval) { if (!get_real_arg_(left_, lval)) return false; if (!get_real_arg_(right_, rval)) return false; return true; } NetExpr* NetEBAdd::eval_tree(int prune_to_width) { eval_expr(left_, prune_to_width); eval_expr(right_, prune_to_width); if (left_->expr_type() == IVL_VT_REAL || right_->expr_type()==IVL_VT_REAL) return eval_tree_real_(); NetEConst*lc = dynamic_cast(left_); NetEConst*rc = dynamic_cast(right_); /* If both operands are constant, then replace the entire expression with a constant value. */ if (lc != 0 && rc != 0) { verinum lval = lc->value(); verinum rval = rc->value(); verinum val; switch (op_) { case '+': val = lval + rval; break; case '-': val = lval - rval; break; default: return 0; } if (debug_eval_tree) { cerr << get_fileline() << ": debug: Evaluate expr=" << *this << " --- prune=" << prune_to_width << " has_width=" << (has_width()? "true" : "false") << endl; } /* Result might have known width. */ if (has_width()) { unsigned lwid = lc->expr_width(); unsigned rwid = rc->expr_width(); unsigned wid = (rwid > lwid) ? rwid : lwid; if (prune_to_width < 0) wid += 1; verinum val2=verinum(val,wid); val=val2; } else { /* No fixed width, so trim the bits losslessly. */ verinum val2 = trim_vnum(val); val = val2; } return new NetEConst(val); } /* Try to combine a right constant value with the right constant value of a sub-expression add. For example, the expression (a + 2) - 1 can be rewritten as a + 1. */ NetEBAdd*se = dynamic_cast(left_); lc = se? dynamic_cast(se->right_) : 0; if (lc != 0 && rc != 0) { ivl_assert(*this, se != 0); if (debug_eval_tree) { cerr << get_fileline() << ": debug: " << "Partially evaluate " << *this << " using (a+2)-1 --> (a+1) transform." << endl; } verinum lval = lc->value(); verinum rval = rc->value(); if (lval.len() < expr_width()) lval = pad_to_width(lval, expr_width()); if (rval.len() < expr_width()) rval = pad_to_width(rval, expr_width()); if (se->expr_width() > this->expr_width()) { cerr << get_fileline() << ": internal error: " << "expr_width()=" << expr_width() << ", sub expr_width()=" << se->expr_width() << ", sub expression=" << *se << endl; } ivl_assert(*this, se->expr_width() <= this->expr_width()); verinum val; if (op_ == se->op_) { /* (a + lval) + rval --> a + (rval+lval) */ /* (a - lval) - rval --> a - (rval+lval) */ val = rval + lval; } else { /* (a - lval) + rval --> a + (rval-lval) */ /* (a + lval) - rval --> a - (rval-lval) */ val = rval - lval; } // Since we padded the operands above to be the minimum // width, the val should also be at least expr_width(). ivl_assert(*this, val.len() >= expr_width()); if (val.len() > expr_width()) { verinum tmp (val, expr_width()); tmp.has_sign(val.has_sign()); val = tmp; } NetEConst*tmp = new NetEConst(val); left_ = se->left_->dup_expr(); delete se; tmp->set_line(*right_); delete right_; right_ = tmp; /* We've changed the subexpression, but the result is still not constant, so return nil here anyhow. */ return 0; } /* Nothing more to be done, the value is not constant. */ return 0; } NetECReal* NetEBAdd::eval_tree_real_() { verireal lval; verireal rval; bool flag = get_real_arguments_(lval, rval); if (!flag) return 0; verireal res_val; switch (op()) { case '+': res_val = lval + rval; break; case '-': res_val = lval - rval; break; default: ivl_assert(*this, 0); } NetECReal*res = new NetECReal( res_val ); res->set_line(*this); return res; } NetEConst* NetEBBits::eval_tree(int prune_to_width) { eval_expr(left_); eval_expr(right_); NetEConst*lc = dynamic_cast(left_); NetEConst*rc = dynamic_cast(right_); if (lc == 0 || rc == 0) return 0; /* Notice the special case where one of the operands is 0 and this is a bitwise &. If this happens, then the result is known to be 0. */ if ((op() == '&') && (lc->value() == verinum(0))) { verinum res (verinum::V0, expr_width()); return new NetEConst(res); } if ((op() == '&') && (rc->value() == verinum(0))) { verinum res (verinum::V0, expr_width()); return new NetEConst(res); } verinum lval = lc->value(); verinum rval = rc->value(); unsigned lwid = lc->expr_width(); if (lwid == 0) lwid = lval.len(); unsigned rwid = rc->expr_width(); if (rwid == 0) rwid = rval.len(); unsigned wid = expr_width(); if (wid == 0) wid = (rwid > lwid)? rwid : lwid; verinum res (verinum::V0, wid); if (lwid > wid) lwid = wid; if (rwid > wid) rwid = wid; // Sub-expressions of bitwise operators need to be the same // width. Pad them out if necessary. if (lwid < wid) { lval = pad_to_width(lval, wid); lwid = wid; } if (rwid < wid) { rval = pad_to_width(rval, wid); rwid = wid; } switch (op()) { case '|': { unsigned cnt = lwid; if (cnt > wid) cnt = wid; if (cnt > rwid) cnt = rwid; for (unsigned idx = 0 ; idx < cnt ; idx += 1) res.set(idx, lval.get(idx) | rval.get(idx)); if (lwid < rwid) for (unsigned idx = lwid ; idx < rwid ; idx += 1) res.set(idx, rval.get(idx)); if (rwid < lwid) for (unsigned idx = rwid ; idx < lwid ; idx += 1) res.set(idx, lval.get(idx)); break; } case '&': { unsigned cnt = lwid; if (cnt > wid) cnt = wid; if (cnt > rwid) cnt = rwid; for (unsigned idx = 0 ; idx < cnt ; idx += 1) res.set(idx, lval.get(idx) & rval.get(idx)); break; } case '^': { unsigned cnt = lwid; if (cnt > wid) cnt = wid; if (cnt > rwid) cnt = rwid; for (unsigned idx = 0 ; idx < cnt ; idx += 1) res.set(idx, lval.get(idx) ^ rval.get(idx)); if (lwid < rwid) for (unsigned idx = lwid ; idx < rwid ; idx += 1) res.set(idx, rval.get(idx)); if (rwid < lwid) for (unsigned idx = rwid ; idx < lwid ; idx += 1) res.set(idx, lval.get(idx)); break; } default: return 0; } return new NetEConst(res); } NetEConst* NetEBComp::eval_less_() { if (right_->expr_type() == IVL_VT_REAL) return eval_leeq_real_(left_, right_, false); if (left_->expr_type() == IVL_VT_REAL) return eval_leeq_real_(left_, right_, false); NetEConst*r = dynamic_cast(right_); if (r == 0) return 0; verinum rv = r->value(); if (! rv.is_defined()) { verinum result(verinum::Vx, 1); return new NetEConst(result); } if (NetEConst*tmp = must_be_leeq_(left_, rv, false)) { return tmp; } /* Now go on to the normal test of the values. */ NetEConst*l = dynamic_cast(left_); if (l == 0) return 0; verinum lv = l->value(); if (! lv.is_defined()) { verinum result(verinum::Vx, 1); return new NetEConst(result); } if (lv < rv) { verinum result(verinum::V1, 1); return new NetEConst(result); } else { verinum result(verinum::V0, 1); return new NetEConst(result); } } NetEConst* NetEBComp::eval_leeq_real_(NetExpr*le, NetExpr*ri, bool eq_flag) { NetEConst*vtmp; NetECReal*rtmp; double lv, rv; switch (le->expr_type()) { case IVL_VT_REAL: rtmp = dynamic_cast (le); if (rtmp == 0) return 0; lv = rtmp->value().as_double(); break; case IVL_VT_LOGIC: case IVL_VT_BOOL: vtmp = dynamic_cast (le); if (vtmp == 0) return 0; lv = vtmp->value().as_double(); break; default: lv = 0.0; cerr << get_fileline() << ": internal error: " << "Unexpected expression type? " << le->expr_type() << endl; assert(0); } switch (ri->expr_type()) { case IVL_VT_REAL: rtmp = dynamic_cast (ri); if (rtmp == 0) return 0; rv = rtmp->value().as_double(); break; case IVL_VT_LOGIC: case IVL_VT_BOOL: vtmp = dynamic_cast (ri); if (vtmp == 0) return 0; rv = vtmp->value().as_double(); break; default: rv = 0.0; cerr << get_fileline() << ": internal error: " << "Unexpected expression type? " << ri->expr_type() << endl; assert(0); } bool test = false; if (lv < rv) test = true; if (test == false && eq_flag && lv == rv) test = true; verinum result(test? verinum::V1 : verinum::V0, 1); vtmp = new NetEConst(result); vtmp->set_line(*this); return vtmp; } NetEConst* NetEBComp::must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag) { assert(le->expr_width() > 0); verinum lv (verinum::V1, le->expr_width()); if (le->has_sign() && rv.has_sign()) { // If the expression is signed, then the largest // possible value for the left_ needs to have a 0 in the // sign position. lv.set(lv.len()-1, verinum::V0); lv.has_sign(true); } if (lv < rv || (eq_flag && (lv == rv))) { verinum result(verinum::V1, 1); return new NetEConst(result); } return 0; } NetEConst* NetEBComp::eval_leeq_() { if (right_->expr_type() == IVL_VT_REAL) return eval_leeq_real_(left_, right_, true); if (left_->expr_type() == IVL_VT_REAL) return eval_leeq_real_(left_, right_, true); NetEConst*r = dynamic_cast(right_); if (r == 0) return 0; verinum rv = r->value(); if (! rv.is_defined()) { verinum result(verinum::Vx, 1); return new NetEConst(result); } if (left_->expr_width() == 0) { cerr << get_fileline() << ": internal error: Something wrong " << "with the left side width of <= ?" << endl; cerr << get_fileline() << ": : " << *this << endl; } if (NetEConst*tmp = must_be_leeq_(left_, rv, true)) { return tmp; } /* Now go on to the normal test of the values. */ NetEConst*l = dynamic_cast(left_); if (l == 0) return 0; verinum lv = l->value(); if (! lv.is_defined()) { verinum result(verinum::Vx, 1); return new NetEConst(result); } if (lv <= rv) { verinum result(verinum::V1, 1); return new NetEConst(result); } else { verinum result(verinum::V0, 1); return new NetEConst(result); } } NetEConst* NetEBComp::eval_gt_() { if (right_->expr_type() == IVL_VT_REAL) return eval_leeq_real_(right_, left_, false); if (left_->expr_type() == IVL_VT_REAL) return eval_leeq_real_(right_, left_, false); NetEConst*l = dynamic_cast(left_); if (l == 0) return 0; verinum lv = l->value(); if (! lv.is_defined()) { verinum result(verinum::Vx, 1); return new NetEConst(result); } if (NetEConst*tmp = must_be_leeq_(right_, lv, false)) { return tmp; } /* Now go on to the normal test of the values. */ NetEConst*r = dynamic_cast(right_); if (r == 0) return 0; verinum rv = r->value(); if (! rv.is_defined()) { verinum result(verinum::Vx, 1); return new NetEConst(result); } if (lv > rv) { verinum result(verinum::V1, 1); return new NetEConst(result); } else { verinum result(verinum::V0, 1); return new NetEConst(result); } } NetEConst* NetEBComp::eval_gteq_() { if (right_->expr_type() == IVL_VT_REAL) return eval_leeq_real_(right_, left_, true); if (left_->expr_type() == IVL_VT_REAL) return eval_leeq_real_(right_, left_, true); NetEConst*l = dynamic_cast(left_); if (l == 0) return 0; verinum lv = l->value(); if (! lv.is_defined()) { verinum result(verinum::Vx, 1); return new NetEConst(result); } if (NetEConst*tmp = must_be_leeq_(right_, lv, true)) { return tmp; } /* Now go on to the normal test of the values. */ NetEConst*r = dynamic_cast(right_); if (r == 0) return 0; verinum rv = r->value(); if (! rv.is_defined()) { verinum result(verinum::Vx, 1); return new NetEConst(result); } if (lv >= rv) { verinum result(verinum::V1, 1); return new NetEConst(result); } else { verinum result(verinum::V0, 1); return new NetEConst(result); } } /* * Evaluate == or !=. The equality operator checks all the * bits and returns true(false) if there are any bits in the vector * that are defined (0 or 1) and different. If all the defined bits * are equal, but there are are x/z bits, then the situation is * ambiguous so the result is x. */ NetEConst* NetEBComp::eval_eqeq_real_(NetExpr*le, NetExpr*ri, bool ne_flag) { NetEConst*vtmp; NetECReal*rtmp; double lv, rv; switch (le->expr_type()) { case IVL_VT_REAL: rtmp = dynamic_cast (le); if (rtmp == 0) return 0; lv = rtmp->value().as_double(); break; case IVL_VT_LOGIC: case IVL_VT_BOOL: vtmp = dynamic_cast (le); if (vtmp == 0) return 0; lv = vtmp->value().as_double(); break; default: lv = 0.0; cerr << get_fileline() << ": internal error: " << "Unexpected expression type? " << le->expr_type() << endl; assert(0); } switch (ri->expr_type()) { case IVL_VT_REAL: rtmp = dynamic_cast (ri); if (rtmp == 0) return 0; rv = rtmp->value().as_double(); break; case IVL_VT_LOGIC: case IVL_VT_BOOL: vtmp = dynamic_cast (ri); if (vtmp == 0) return 0; rv = vtmp->value().as_double(); break; default: rv = 0.0; cerr << get_fileline() << ": internal error: " << "Unexpected expression type? " << ri->expr_type() << endl; assert(0); } verinum result(((lv == rv) ^ ne_flag) ? verinum::V1 : verinum::V0, 1); vtmp = new NetEConst(result); vtmp->set_line(*this); return vtmp; } NetEConst* NetEBComp::eval_eqeq_(bool ne_flag) { if (right_->expr_type() == IVL_VT_REAL) return eval_eqeq_real_(right_, left_, ne_flag); if (left_->expr_type() == IVL_VT_REAL) return eval_eqeq_real_(right_, left_, ne_flag); NetEConst*l = dynamic_cast(left_); if (l == 0) return 0; NetEConst*r = dynamic_cast(right_); if (r == 0) return 0; const verinum&lv = l->value(); const verinum&rv = r->value(); const verinum::V eq_res = ne_flag? verinum::V0 : verinum::V1; const verinum::V ne_res = ne_flag? verinum::V1 : verinum::V0; verinum::V res = eq_res; unsigned top = lv.len(); if (rv.len() < top) top = rv.len(); for (unsigned idx = 0 ; idx < top ; idx += 1) { bool x_bit_present = false; switch (lv.get(idx)) { case verinum::Vx: case verinum::Vz: res = verinum::Vx; x_bit_present = true; break; default: break; } switch (rv.get(idx)) { case verinum::Vx: case verinum::Vz: res = verinum::Vx; x_bit_present = true; break; default: break; } if (x_bit_present) continue; if (rv.get(idx) != lv.get(idx)) { res = ne_res; break; } } if (res != verinum::Vx) { verinum::V lpad = verinum::V0; verinum::V rpad = verinum::V0; if (lv.has_sign() && lv.get(lv.len()-1) == verinum::V1) lpad = verinum::V1; if (rv.has_sign() && rv.get(rv.len()-1) == verinum::V1) rpad = verinum::V1; for (unsigned idx = top ; idx < lv.len() ; idx += 1) switch (lv.get(idx)) { case verinum::Vx: case verinum::Vz: res = verinum::Vx; break; case verinum::V0: if (res != verinum::Vx && rpad != verinum::V0) res = ne_res; break; case verinum::V1: if (res != verinum::Vx && rpad != verinum::V1) res = ne_res; break; default: break; } for (unsigned idx = top ; idx < rv.len() ; idx += 1) switch (rv.get(idx)) { case verinum::Vx: case verinum::Vz: res = verinum::Vx; break; case verinum::V0: if (res != verinum::Vx && lpad != verinum::V0) res = ne_res; break; case verinum::V1: if (res != verinum::Vx && lpad != verinum::V1) res = ne_res; break; default: break; } } return new NetEConst(verinum(res)); } NetEConst* NetEBComp::eval_eqeqeq_(bool ne_flag) { NetEConst*lc = dynamic_cast(left_); NetEConst*rc = dynamic_cast(right_); if (lc == 0 || rc == 0) return 0; const verinum&lv = lc->value(); const verinum&rv = rc->value(); verinum::V res = verinum::V1; // Find the smallest argument length. unsigned cnt = lv.len(); if (cnt > rv.len()) cnt = rv.len(); // Check the common bits. for (unsigned idx = 0 ; idx < cnt ; idx += 1) if (lv.get(idx) != rv.get(idx)) { res = verinum::V0; break; } bool is_signed = lv.has_sign() && rv.has_sign(); // If the left value is longer check it against the pad bit. if (res == verinum::V1) { verinum::V pad = verinum::V0; if (is_signed) pad = rv.get(rv.len()-1); for (unsigned idx = cnt ; idx < lv.len() ; idx += 1) if (lv.get(idx) != pad) { res = verinum::V0; break; } } // If the right value is longer check it against the pad bit. if (res == verinum::V1) { verinum::V pad = verinum::V0; if (is_signed) pad = lv.get(lv.len()-1); for (unsigned idx = cnt ; idx < rv.len() ; idx += 1) if (rv.get(idx) != pad) { res = verinum::V0; break; } } if (ne_flag) { if (res == verinum::V0) res = verinum::V1; else res = verinum::V0; } NetEConst*result = new NetEConst(verinum(res, 1)); ivl_assert(*this, result); result->set_line(*this); return result; } NetEConst* NetEBComp::eval_tree(int prune_to_width) { eval_expr(left_); eval_expr(right_); switch (op_) { case 'E': // Case equality (===) return eval_eqeqeq_(false); case 'e': // Equality (==) return eval_eqeq_(false); case 'G': // >= return eval_gteq_(); case 'L': // <= return eval_leeq_(); case 'N': // Case inequality (!==) return eval_eqeqeq_(true); case 'n': // not-equal (!=) return eval_eqeq_(true); case '<': // Less than return eval_less_(); case '>': // Greater than return eval_gt_(); default: return 0; } } NetExpr* NetEBDiv::eval_tree_real_() { verireal lval; verireal rval; bool flag = get_real_arguments_(lval, rval); if (! flag) return 0; NetECReal*res = 0; switch (op_) { case '/': res = new NetECReal(lval / rval); break; case '%': // Since this could/may be called early we don't want to // leak functionality. if (!gn_icarus_misc_flag) return 0; res = new NetECReal(lval % rval); break; } ivl_assert(*this, res); res->set_line(*this); return res; } /* * The NetEBDiv operator includes the / and % operators. First evaluate * the sub-expressions, then perform the required operation. */ NetExpr* NetEBDiv::eval_tree(int prune_to_width) { eval_expr(left_); eval_expr(right_); if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); assert(expr_type() == IVL_VT_LOGIC); NetEConst*lc = dynamic_cast(left_); NetEConst*rc = dynamic_cast(right_); if (lc == 0 || rc == 0) return 0; // Make sure the expression is evaluated at the // expression width. verinum lval = pad_to_width(lc->value(), expr_width()); verinum rval = pad_to_width(rc->value(), expr_width()); NetExpr*tmp = 0; switch (op_) { case '/': tmp = new NetEConst(lval / rval); break; case '%': tmp = new NetEConst(lval % rval); break; } ivl_assert(*this, tmp); tmp->set_line(*this); return tmp; } NetEConst* NetEBLogic::eval_tree_real_() { verireal lval; verireal rval; bool flag = get_real_arguments_(lval, rval); if (! flag) return 0; verinum::V res; switch (op_) { case 'a': { // Logical AND (&&) if ((lval.as_double() != 0.0) && (rval.as_double() != 0.0)) res = verinum::V1; else res = verinum::V0; break; } case 'o': { // Logical OR (||) if ((lval.as_double() != 0.0) || (rval.as_double() != 0.0)) res = verinum::V1; else res = verinum::V0; break; } default: return 0; } NetEConst*tmp = new NetEConst(verinum(res, 1)); ivl_assert(*this, tmp); tmp->set_line(*this); if (debug_eval_tree) cerr << get_fileline() << ": debug: Evaluated (real): " << *this << " --> " << *tmp << endl; return tmp; } NetEConst* NetEBLogic::eval_tree(int prune_to_width) { eval_expr(left_); eval_expr(right_); if (left_->expr_type() == IVL_VT_REAL || right_->expr_type() == IVL_VT_REAL) return eval_tree_real_(); assert(expr_type() == IVL_VT_LOGIC); NetEConst*lc = dynamic_cast(left_); NetEConst*rc = dynamic_cast(right_); if (lc == 0 || rc == 0) return 0; verinum::V lv = verinum::V0; verinum::V rv = verinum::V0; verinum v = lc->value(); for (unsigned idx = 0 ; idx < v.len() ; idx += 1) if (v.get(idx) == verinum::V1) { lv = verinum::V1; break; } if (lv == verinum::V0 && ! v.is_defined()) lv = verinum::Vx; v = rc->value(); for (unsigned idx = 0 ; idx < v.len() ; idx += 1) if (v.get(idx) == verinum::V1) { rv = verinum::V1; break; } if (rv == verinum::V0 && ! v.is_defined()) rv = verinum::Vx; verinum::V res; switch (op_) { case 'a': // Logical AND (&&) if ((lv == verinum::V0) || (rv == verinum::V0)) res = verinum::V0; else if ((lv == verinum::V1) && (rv == verinum::V1)) res = verinum::V1; else res = verinum::Vx; break; case 'o': // Logical OR (||) if ((lv == verinum::V1) || (rv == verinum::V1)) res = verinum::V1; else if ((lv == verinum::V0) && (rv == verinum::V0)) res = verinum::V0; else res = verinum::Vx; break; default: return 0; } NetEConst*tmp = new NetEConst(verinum(res, 1)); ivl_assert(*this, tmp); tmp->set_line(*this); if (debug_eval_tree) cerr << get_fileline() << ": debug: Evaluated: " << *this << " --> " << *tmp << endl; return tmp; } NetExpr* NetEBMult::eval_tree_real_() { verireal lval; verireal rval; bool flag = get_real_arguments_(lval, rval); if (! flag) return 0; NetECReal*res = new NetECReal(lval * rval); res->set_line(*this); return res; } NetExpr* NetEBMult::eval_tree(int prune_to_width) { eval_expr(left_); eval_expr(right_); if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); assert(expr_type() == IVL_VT_LOGIC); NetEConst*lc = dynamic_cast(left_); NetEConst*rc = dynamic_cast(right_); if (lc == 0 || rc == 0) return 0; verinum lval = lc->value(); verinum rval = rc->value(); NetEConst*tmp = new NetEConst(lval * rval); if (debug_eval_tree) cerr << get_fileline() << ": debug: Evaluate " << lval << " * " << rval << " --> " << *tmp << endl; return tmp; } NetExpr* NetEBPow::eval_tree_real_() { verireal lval; verireal rval; bool flag = get_real_arguments_(lval, rval); if (! flag) return 0; NetECReal*res = new NetECReal( pow(lval,rval) ); res->set_line(*this); if (debug_eval_tree) cerr << get_fileline() << ": debug: Evaluate (real) " << lval << " ** " << rval << " --> " << *res << endl; return res; } NetExpr* NetEBPow::eval_tree(int prune_to_width) { eval_expr(left_); eval_expr(right_); if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); assert(expr_type() == IVL_VT_LOGIC); NetEConst*lc = dynamic_cast(left_); NetEConst*rc = dynamic_cast(right_); if (lc == 0 || rc == 0) return 0; verinum lval = lc->value(); verinum rval = rc->value(); NetEConst*res = new NetEConst( pow(lval,rval) ); res->set_line(*this); if (debug_eval_tree) cerr << get_fileline() << ": debug: Evaluate " << lval << " ** " << rval << " --> " << *res << endl; return res; } /* * Evaluate the shift operator if possible. For this to work, both * operands must be constant. */ NetEConst* NetEBShift::eval_tree(int prune_to_width) { eval_expr(left_); eval_expr(right_); NetEConst*le = dynamic_cast(left_); NetEConst*re = dynamic_cast(right_); if (le == 0 || re == 0) return 0; NetEConst*res; verinum rv = re->value(); verinum lv = le->value(); /* Make an early estimate of the expression width. */ unsigned wid = expr_width(); if (rv.is_defined()) { unsigned shift = rv.as_ulong(); if (debug_eval_tree) { cerr << get_fileline() << ": debug: " << "Evaluate " << lv << "<<" << op() << ">> " << rv << ", wid=" << wid << ", shift=" << shift << ", lv.has_len()=" << lv.has_len() << endl; } if ((wid == 0) || ! lv.has_len()) { /* If the caller doesn't care what the width is, then calculate a width from the trimmed left expression, plus the shift. This avoids data loss. */ lv = trim_vnum(lv); wid = lv.len(); if (op() == 'l') wid = lv.len() + shift; } if (prune_to_width > 0 && wid > (unsigned)prune_to_width) wid = prune_to_width; assert(wid); verinum::V pad = verinum::V0; if (op() == 'R' && has_sign()) { pad = lv[lv.len()-1]; } verinum nv (pad, wid, lv.has_len()); if (op() == 'r' || op() == 'R') { unsigned cnt = wid; if (cnt > nv.len()) cnt = nv.len(); if (shift >= lv.len()) cnt = 0; else if (cnt > (lv.len()-shift)) cnt = (lv.len()-shift); for (unsigned idx = 0 ; idx < cnt ; idx += 1) nv.set(idx, lv[idx+shift]); } else { unsigned cnt = wid; if (cnt > lv.len()) cnt = lv.len(); if (shift >= nv.len()) cnt = 0; else if (cnt > (nv.len()-shift)) cnt = nv.len() - shift; for (unsigned idx = 0 ; idx < cnt ; idx += 1) nv.set(idx+shift, lv[idx]); } res = new NetEConst(nv); } else { if (wid == 0) wid = left_->expr_width(); verinum nv (verinum::Vx, wid); res = new NetEConst(nv); } return res; } NetEConst* NetEConcat::eval_tree(int prune_to_width) { unsigned repeat_val = repeat(); unsigned local_errors = 0; if (debug_eval_tree) { cerr << get_fileline() << ": debug: Evaluate expr=" << *this << ", prune_to_width=" << prune_to_width << endl; } unsigned gap = 0; for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { // Parameter not here? This is an error, but presumably // already caught and we are here just to catch more. if (parms_[idx] == 0) continue; // If this parameter is already a constant, all is well // so go on. if (dynamic_cast(parms_[idx])) { gap += parms_[idx]->expr_width(); continue; } // Finally, try to evaluate the parameter expression // that is here. If I succeed, reset the parameter to // the evaluated value. assert(parms_[idx]); NetExpr*expr = parms_[idx]->eval_tree(0); if (expr) { expr->set_line(*parms_[idx]); delete parms_[idx]; parms_[idx] = expr; if (! expr->has_width()) { cerr << get_fileline() << ": error: concatenation " << "operand has indefinite width: " << *parms_[idx] << endl; local_errors += 1; } else if (expr->expr_width() == 0) { cerr << expr->get_fileline() << ": internal error: " << "Operand of concatenation has no width: " << *expr << endl; local_errors += 1; } gap += expr->expr_width(); } } if (local_errors > 0) return 0; // At this point, the "gap" is the width of a single repeat of // the concatenation. The total width of the result is the gap // times the repeat count. verinum val (verinum::Vx, repeat_val * gap); // build up the result from least significant to most. unsigned cur = 0; bool is_string_flag = true; for (unsigned idx = parms_.count() ; idx > 0 ; idx -= 1) { NetEConst*expr = dynamic_cast(parms_[idx-1]); if (expr == 0) return 0; verinum tmp = expr->value(); for (unsigned bit = 0; bit < tmp.len(); bit += 1, cur += 1) for (unsigned rep = 0 ; rep < repeat_val ; rep += 1) val.set(rep*gap+cur, tmp[bit]); is_string_flag = is_string_flag && tmp.is_string(); } /* If all the values were strings, then re-stringify this constant. This might be useful information in the code generator or other optimizer steps. */ if (is_string_flag) { val = verinum(val.as_string()); } // Normally, concatenations are unsigned. However, the // $signed() function works by marking the expression as // signed, so we really have to check. val.has_sign( this->has_sign() ); NetEConst*res = new NetEConst(val); res->set_width(val.len()); return res; } NetExpr* NetEParam::eval_tree(int prune_to_width) { if (des_ == 0) { assert(scope_ == 0); return 0; } if (debug_eval_tree) { cerr << get_fileline() << ": debug: evaluating expression: " << *this << endl; } if (solving()) { cerr << get_fileline() << ": warning: Recursive parameter " "reference found involving " << *this << "." << endl; return 0; } assert(scope_); perm_string name = (*reference_).first; const NetExpr*expr = (*reference_).second.expr; // Since constant user functions are not supported we can get // parameters/localparams that are not defined. For now generate // an appropriate error message. if (expr == NULL) { cerr << get_fileline() << ": internal error: parameter/localparam " << *this << " cannot be evaluated." << endl; return 0; } // If the parameter that I refer to is already evaluated, then // return the constant value. if (const NetEConst*tmp = dynamic_cast(expr)) { verinum val = tmp->value(); NetEConstParam*ptmp = new NetEConstParam(scope_, name, val); ptmp->set_line(*this); return ptmp; } if (const NetECReal*tmp = dynamic_cast(expr)) { verireal val = tmp->value(); NetECRealParam*ptmp = new NetECRealParam(scope_, name, val); ptmp->set_line(*this); return ptmp; } // Try to evaluate the expression. If I cannot, then the // expression is not a constant expression and I fail here. solving(true); NetExpr*nexpr = expr->dup_expr(); assert(nexpr); NetExpr*res = nexpr->eval_tree(); solving(false); if (res == 0) { cerr << get_fileline() << ": internal error: Unable to evaluate "; if (expr_type() == IVL_VT_REAL) cerr << "real "; cerr << "parameter " << name << " expression: " << *nexpr << endl; delete nexpr; return 0; } // The result can be saved as the value of the parameter for // future reference, and return a copy to the caller. bool flag = scope_->replace_parameter(name, res); if (!flag) { cerr << get_fileline() << ": internal error: Could not " << "replace parameter expression for " << name << endl; return 0; } /* Return as a result a NetEConstParam or NetECRealParam object, depending on the type of the expression. */ switch (res->expr_type()) { case IVL_VT_BOOL: case IVL_VT_LOGIC: { NetEConst*tmp = dynamic_cast(res); if (tmp == 0) { cerr << get_fileline() << ": internal error: parameter " << name << " evaluates to incomprehensible " << *res << "." << endl; return 0; } assert(tmp); verinum val = tmp->value(); NetEConstParam*ptmp = new NetEConstParam(scope_, name, val); return ptmp; } case IVL_VT_REAL: { NetECReal*tmp = dynamic_cast(res); if (tmp == 0) { cerr << get_fileline() << ": internal error: parameter " << name << " evaluates to incomprehensible " << *res << "." << endl; return 0; } assert(tmp); verireal val = tmp->value(); NetECRealParam*ptmp = new NetECRealParam(scope_, name, val); return ptmp; } default: assert(0); return 0; } } NetEConst* NetESelect::eval_tree(int prune_to_width) { eval_expr(expr_); NetEConst*expr = dynamic_cast(expr_); long bval = 0; if (base_) { eval_expr(base_); NetEConst*base = dynamic_cast(base_); if (base == 0) return 0; bval = base->value().as_long(); } if (expr == 0) return 0; verinum eval = expr->value(); verinum oval (verinum::V0, expr_width(), true); verinum::V pad_bit = verinum::Vx; if (base_ == 0) { /* If the base is NULL (different from 0) the this select is here for sign extension. So calculate a proper pad bit. Extend x or z or 0, and sign extend 1 if this is signed. */ unsigned top = expr->expr_width()-1; pad_bit = eval.get(top); if (pad_bit==verinum::V1 && !has_sign()) pad_bit = verinum::V0; } for (unsigned long idx = 0 ; idx < expr_width() ; idx += 1) { if ((bval >= 0) && ((unsigned long) bval < eval.len())) oval.set(idx, eval.get(bval)); else oval.set(idx, pad_bit); bval += 1; } oval.has_sign(has_sign()); NetEConst*res = new NetEConst(oval); return res; } static void print_ternary_cond(NetExpr*expr) { if (NetEConst*c = dynamic_cast(expr)) { cerr << c->value() << endl; return; } if (NetECReal*c = dynamic_cast(expr)) { cerr << c->value() << endl; return; } assert(0); } /* * A ternary expression evaluation is controlled by the condition * expression. If the condition evaluates to true or false, then * return the evaluated true or false expression. If the condition * evaluates to x or z, then merge the constant bits of the true and * false expressions. */ NetExpr* NetETernary::eval_tree(int prune_to_width) { eval_expr(cond_); switch (const_logical(cond_)) { case C_0: eval_expr(false_val_); if (debug_eval_tree) { cerr << get_fileline() << ": debug: Evaluate ternary with " << "constant condition value: "; print_ternary_cond(cond_); cerr << get_fileline() << ": : Selecting false case: " << *false_val_ << endl; } if (expr_type() == IVL_VT_REAL && false_val_->expr_type() != IVL_VT_REAL) { verireal f; if (get_real_arg_(false_val_, f)) { NetECReal*rc = new NetECReal(f); rc->set_line(*this); return rc; } } return false_val_->dup_expr(); case C_1: eval_expr(true_val_); if (debug_eval_tree) { cerr << get_fileline() << ": debug: Evaluate ternary with " << "constant condition value: "; print_ternary_cond(cond_); cerr << get_fileline() << ": : Selecting true case: " << *true_val_ << endl; } if (expr_type() == IVL_VT_REAL && true_val_->expr_type() != IVL_VT_REAL) { verireal t; if (get_real_arg_(true_val_, t)) { NetECReal*rc = new NetECReal(t); rc->set_line(*this); return rc; } } return true_val_->dup_expr(); case C_X: break; default: return 0; } /* Here we have a more complex case. We need to evaluate both expressions down to constants then compare the values to build up a constant result. */ eval_expr(true_val_); eval_expr(false_val_); NetEConst*t = dynamic_cast(true_val_); NetEConst*f = dynamic_cast(false_val_); if (t == 0 || f == 0) { verireal tv, fv; if (!get_real_arg_(true_val_, tv)) return 0; if (!get_real_arg_(false_val_, fv)) return 0; verireal val = verireal(0.0); if (tv.as_double() == fv.as_double()) val = tv; if (debug_eval_tree) { cerr << get_fileline() << ": debug: Evaluate ternary with " << "constant condition value: "; print_ternary_cond(cond_); cerr << get_fileline() << ": : Blending real cases " << "true=" << tv.as_double() << ", false=" << fv.as_double() << ", to get " << val << endl; } NetECReal*rc = new NetECReal(val); rc->set_line(*this); return rc; } unsigned tsize = t->expr_width(); unsigned fsize = f->expr_width(); /* Size of the result is the size of the widest operand. */ unsigned rsize = tsize > fsize? tsize : fsize; verinum val (verinum::V0, rsize); for (unsigned idx = 0 ; idx < rsize ; idx += 1) { verinum::V tv = idx < tsize? t->value().get(idx) : verinum::V0; verinum::V fv = idx < fsize? f->value().get(idx) : verinum::V0; if (tv == fv) val.set(idx, tv); else val.set(idx, verinum::Vx); } if (debug_eval_tree) { cerr << get_fileline() << ": debug: Evaluate ternary with " << "constant condition value: "; print_ternary_cond(cond_); cerr << get_fileline() << ": : Blending cases to get " << val << endl; } NetEConst*rc = new NetEConst(val); rc->set_line(*this); return rc; } NetExpr* NetEUnary::eval_tree_real_() { NetECReal*val= dynamic_cast (expr_), *res; if (val == 0) return 0; switch (op_) { case '+': res = new NetECReal(val->value()); res->set_line(*this); return res; case '-': res = new NetECReal(-(val->value())); res->set_line(*this); return res; default: return 0; } } NetExpr* NetEUnary::eval_tree(int prune_to_width) { eval_expr(expr_); if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); NetEConst*rval = dynamic_cast(expr_); if (rval == 0) return 0; verinum val = rval->value(); switch (op_) { case '+': /* Unary + is a no-op. */ return new NetEConst(val); case '-': { if (val.is_defined()) { verinum tmp (verinum::V0, val.len()); tmp.has_sign(val.has_sign()); val = tmp - val; } else { for (unsigned idx = 0 ; idx < val.len() ; idx += 1) val.set(idx, verinum::Vx); } return new NetEConst(val); } case '~': { /* Bitwise not is even simpler then logical not. Just invert all the bits of the operand and make the new value with the same dimensions. */ for (unsigned idx = 0 ; idx < val.len() ; idx += 1) switch (val.get(idx)) { case verinum::V0: val.set(idx, verinum::V1); break; case verinum::V1: val.set(idx, verinum::V0); break; default: val.set(idx, verinum::Vx); } return new NetEConst(val); } case '!': assert(0); default: return 0; } } NetExpr* NetEUBits::eval_tree(int prune_to_width) { return NetEUnary::eval_tree(prune_to_width); } NetEConst* NetEUReduce::eval_tree_real_() { ivl_assert(*this, op_ == '!'); NetECReal*val= dynamic_cast (expr_); if (val == 0) return 0; verinum::V res = val->value().as_double() == 0.0 ? verinum::V1 : verinum::V0; return new NetEConst(verinum(res, 1)); } NetEConst* NetEUReduce::eval_tree(int prune_to_width) { eval_expr(expr_); if (expr_type() == IVL_VT_REAL) return eval_tree_real_(); NetEConst*rval = dynamic_cast(expr_); if (rval == 0) return 0; verinum val = rval->value(); verinum::V res; bool invert = false; switch (op_) { case '!': { /* Evaluate the unary logical not by first scanning the operand value for V1 and Vx bits. If we find any V1 bits we know that the value is TRUE, so the result of ! is V0. If there are no V1 bits but there are some Vx/Vz bits, the result is unknown. Otherwise, the result is V1. */ unsigned v1 = 0, vx = 0; for (unsigned idx = 0 ; idx < val.len() ; idx += 1) { switch (val.get(idx)) { case verinum::V0: break; case verinum::V1: v1 += 1; break; default: vx += 1; break; } } res = v1? verinum::V0 : (vx? verinum::Vx : verinum::V1); break; } case 'A': invert = true; case '&': { res = verinum::V1; for (unsigned idx = 0 ; idx < val.len() ; idx += 1) res = res & val.get(idx); break; } case 'N': invert = true; case '|': { res = verinum::V0; for (unsigned idx = 0 ; idx < val.len() ; idx += 1) res = res | val.get(idx); break; } case 'X': invert = true; case '^': { /* Reduction XOR. */ unsigned ones = 0, unknown = 0; for (unsigned idx = 0 ; idx < val.len() ; idx += 1) switch (val.get(idx)) { case verinum::V0: break; case verinum::V1: ones += 1; break; default: unknown += 1; break; } if (unknown) res = verinum::Vx; else if (ones%2) res = verinum::V1; else res = verinum::V0; break; } default: return 0; } if (invert) res = ~res; return new NetEConst(verinum(res, 1)); } NetExpr* evaluate_clog2(NetExpr*&arg_) { eval_expr(arg_); NetEConst*tmpi = dynamic_cast(arg_); NetECReal*tmpr = dynamic_cast(arg_); if (tmpi || tmpr) { verinum arg; if (tmpi) { arg = tmpi->value(); } else { arg = verinum(tmpr->value().as_double(), true); } /* If we have an x in the verinum we return 'bx. */ if (!arg.is_defined()) { verinum tmp (verinum::Vx, integer_width); tmp.has_sign(true); NetEConst*rtn = new NetEConst(tmp); return rtn; } bool is_neg = false; uint64_t res = 0; if (arg.is_negative()) { is_neg = true; // If the length is not defined, then work with // the trimmed version of the number. if (! arg.has_len()) arg = trim_vnum(arg); } arg.has_sign(false); // $unsigned() if (!arg.is_zero()) { arg = arg - verinum((uint64_t)1, 1); while (!arg.is_zero()) { res += 1; arg = arg >> 1; } } if (is_neg && res < integer_width) res = integer_width; verinum tmp (res, integer_width); tmp.has_sign(true); NetEConst*rtn = new NetEConst(tmp); return rtn; } return 0; } NetExpr* evaluate_math_one_arg(NetExpr*&arg_, const char*name) { eval_expr(arg_); NetEConst*tmpi = dynamic_cast(arg_); NetECReal*tmpr = dynamic_cast(arg_); if (tmpi || tmpr) { double arg; if (tmpi) { arg = tmpi->value().as_double(); } else { arg = tmpr->value().as_double(); } if (strcmp(name, "$ln") == 0) { return new NetECReal(verireal(log(arg))); } else if (strcmp(name, "$log10") == 0) { return new NetECReal(verireal(log10(arg))); } else if (strcmp(name, "$exp") == 0) { return new NetECReal(verireal(exp(arg))); } else if (strcmp(name, "$sqrt") == 0) { return new NetECReal(verireal(sqrt(arg))); } else if (strcmp(name, "$floor") == 0) { return new NetECReal(verireal(floor(arg))); } else if (strcmp(name, "$ceil") == 0) { return new NetECReal(verireal(ceil(arg))); } else if (strcmp(name, "$sin") == 0) { return new NetECReal(verireal(sin(arg))); } else if (strcmp(name, "$cos") == 0) { return new NetECReal(verireal(cos(arg))); } else if (strcmp(name, "$tan") == 0) { return new NetECReal(verireal(tan(arg))); } else if (strcmp(name, "$asin") == 0) { return new NetECReal(verireal(asin(arg))); } else if (strcmp(name, "$acos") == 0) { return new NetECReal(verireal(acos(arg))); } else if (strcmp(name, "$atan") == 0) { return new NetECReal(verireal(atan(arg))); } else if (strcmp(name, "$sinh") == 0) { return new NetECReal(verireal(sinh(arg))); } else if (strcmp(name, "$cosh") == 0) { return new NetECReal(verireal(cosh(arg))); } else if (strcmp(name, "$tanh") == 0) { return new NetECReal(verireal(tanh(arg))); } else if (strcmp(name, "$asinh") == 0) { return new NetECReal(verireal(asinh(arg))); } else if (strcmp(name, "$acosh") == 0) { return new NetECReal(verireal(acosh(arg))); } else if (strcmp(name, "$atanh") == 0) { return new NetECReal(verireal(atanh(arg))); } } return 0; } NetExpr* evaluate_math_two_args(NetExpr*&arg0_, NetExpr*&arg1_, const char*name) { eval_expr(arg0_); eval_expr(arg1_); NetEConst*tmpi0 = dynamic_cast(arg0_); NetECReal*tmpr0 = dynamic_cast(arg0_); NetEConst*tmpi1 = dynamic_cast(arg1_); NetECReal*tmpr1 = dynamic_cast(arg1_); if ((tmpi0 || tmpr0) && (tmpi1 || tmpr1)) { double arg0, arg1; if (tmpi0) { arg0 = tmpi0->value().as_double(); } else { arg0 = tmpr0->value().as_double(); } if (tmpi1) { arg1 = tmpi1->value().as_double(); } else { arg1 = tmpr1->value().as_double(); } if (strcmp(name, "$pow") == 0) { return new NetECReal(verireal(pow(arg0, arg1))); } else if (strcmp(name, "$atan2") == 0) { return new NetECReal(verireal(atan2(arg0, arg1))); } else if (strcmp(name, "$hypot") == 0) { return new NetECReal(verireal(hypot(arg0, arg1))); } } return 0; } NetExpr* evaluate_abs(NetExpr*&arg_) { eval_expr(arg_); NetEConst*tmpi = dynamic_cast(arg_); if (tmpi) { verinum arg = tmpi->value(); if (arg.is_negative()) { arg = v_not(arg) + verinum(1); } return new NetEConst(arg); } NetECReal*tmpr = dynamic_cast(arg_); if (tmpr) { double arg = tmpr->value().as_double(); return new NetECReal(verireal(fabs(arg))); } return 0; } NetExpr* evaluate_min_max(NetExpr*&arg0_, NetExpr*&arg1_, const char*name) { eval_expr(arg0_); eval_expr(arg1_); NetEConst*tmpi0 = dynamic_cast(arg0_); NetECReal*tmpr0 = dynamic_cast(arg0_); NetEConst*tmpi1 = dynamic_cast(arg1_); NetECReal*tmpr1 = dynamic_cast(arg1_); if (tmpi0 && tmpi1) { verinum arg0 = tmpi0->value(); verinum arg1 = tmpi1->value(); if (strcmp(name, "$min") == 0) { return new NetEConst( arg0 < arg1 ? arg0 : arg1); } else if (strcmp(name, "$max") == 0) { return new NetEConst( arg0 < arg1 ? arg1 : arg0); } } if ((tmpi0 || tmpr0) && (tmpi1 || tmpr1)) { double arg0, arg1; if (tmpi0) { arg0 = tmpi0->value().as_double(); } else { arg0 = tmpr0->value().as_double(); } if (tmpi1) { arg1 = tmpi1->value().as_double(); } else { arg1 = tmpr1->value().as_double(); } if (strcmp(name, "$min") == 0) { return new NetECReal(verireal(arg0 < arg1 ? arg0 : arg1)); } else if (strcmp(name, "$max") == 0) { return new NetECReal(verireal(arg0 < arg1 ? arg1 : arg0)); } } return 0; } NetExpr* NetESFunc::eval_tree(int prune_to_width) { /* If we are not targeting at least Verilog-2005, Verilog-AMS * or using the Icarus misc flag then we do not support these * functions as constant. */ if (generation_flag < GN_VER2005 && !gn_icarus_misc_flag && !gn_verilog_ams_flag) { return 0; } const char*nm = name(); NetExpr*rtn = 0; /* Only $clog2 and the builtin mathematical functions can * be a constant system function. */ if (strcmp(nm, "$clog2") == 0 || strcmp(nm, "$ln") == 0 || strcmp(nm, "$log10") == 0 || strcmp(nm, "$exp") == 0 || strcmp(nm, "$sqrt") == 0 || strcmp(nm, "$floor") == 0 || strcmp(nm, "$ceil") == 0 || strcmp(nm, "$sin") == 0 || strcmp(nm, "$cos") == 0 || strcmp(nm, "$tan") == 0 || strcmp(nm, "$asin") == 0 || strcmp(nm, "$acos") == 0 || strcmp(nm, "$atan") == 0 || strcmp(nm, "$sinh") == 0 || strcmp(nm, "$cosh") == 0 || strcmp(nm, "$tanh") == 0 || strcmp(nm, "$asinh") == 0 || strcmp(nm, "$acosh") == 0 || strcmp(nm, "$atanh") == 0) { if (nparms() != 1 || parm(0) == 0) { cerr << get_fileline() << ": error: " << nm << " takes a single argument." << endl; return 0; } NetExpr*arg = parm(0)->dup_expr(); if (strcmp(nm, "$clog2") == 0) { rtn = evaluate_clog2(arg); } else { rtn = evaluate_math_one_arg(arg, nm); } delete arg; } if (strcmp(nm, "$pow") == 0 || strcmp(nm, "$atan2") == 0 || strcmp(nm, "$hypot") == 0) { if (nparms() != 2 || parm(0) == 0 || parm(1) == 0) { cerr << get_fileline() << ": error: " << nm << " takes two arguments." << endl; return 0; } NetExpr*arg0 = parm(0)->dup_expr(); NetExpr*arg1 = parm(1)->dup_expr(); rtn = evaluate_math_two_args(arg0, arg1, nm); delete arg0; delete arg1; } if ((gn_icarus_misc_flag || gn_verilog_ams_flag) && (strcmp(nm, "$abs") == 0)) { if (nparms() != 1 || parm(0) == 0) { cerr << get_fileline() << ": error: " << nm << " takes a single argument." << endl; return 0; } NetExpr*arg = parm(0)->dup_expr(); rtn = evaluate_abs(arg); delete arg; } if ((gn_icarus_misc_flag || gn_verilog_ams_flag) && (strcmp(nm, "$min") == 0 || strcmp(nm, "$max") == 0)) { if (nparms() != 2 || parm(0) == 0 || parm(1) == 0) { cerr << get_fileline() << ": error: " << nm << " takes two arguments." << endl; return 0; } NetExpr*arg0 = parm(0)->dup_expr(); NetExpr*arg1 = parm(1)->dup_expr(); rtn = evaluate_min_max(arg0, arg1, nm); delete arg0; delete arg1; } if (rtn != 0) { rtn->set_line(*this); if (debug_eval_tree) { cerr << get_fileline() << ": debug: Evaluate constant " << nm << "." << endl; } } return rtn; } NetExpr* NetEUFunc::eval_tree(int prune_to_width) { if (need_constant_expr) { cerr << get_fileline() << ": sorry: constant user " "functions are not currently supported: " << func_->basename() << "()." << endl; } return 0; } verilog-0.9.7/PaxHeaders.14238/cprop.cc0000644000202500001440000000005012204466647015662 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/cprop.cc0000644000202500001440000006540012204466647015211 0ustar00steveusers00000000000000/* * Copyright (c) 1998-2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include # include "netlist.h" # include "netmisc.h" # include "functor.h" # include "compiler.h" # include "ivl_assert.h" /* * The cprop function below invokes constant propagation where * possible. The elaboration generates NetConst objects. I can remove * these and replace the gates connected to it with simpler ones. I * may even be able to replace nets with a new constant. */ struct cprop_functor : public functor_t { unsigned count; virtual void signal(Design*des, NetNet*obj); virtual void lpm_add_sub(Design*des, NetAddSub*obj); virtual void lpm_compare(Design*des, NetCompare*obj); virtual void lpm_compare_eq_(Design*des, NetCompare*obj); virtual void lpm_ff(Design*des, NetFF*obj); virtual void lpm_logic(Design*des, NetLogic*obj); virtual void lpm_mux(Design*des, NetMux*obj); }; void cprop_functor::signal(Design*des, NetNet*obj) { } void cprop_functor::lpm_add_sub(Design*des, NetAddSub*obj) { } void cprop_functor::lpm_compare(Design*des, NetCompare*obj) { if (obj->pin_AEB().is_linked()) { assert( ! obj->pin_AGB().is_linked() ); assert( ! obj->pin_AGEB().is_linked() ); assert( ! obj->pin_ALB().is_linked() ); assert( ! obj->pin_ALEB().is_linked() ); assert( ! obj->pin_AGB().is_linked() ); assert( ! obj->pin_ANEB().is_linked() ); lpm_compare_eq_(des, obj); return; } } void cprop_functor::lpm_compare_eq_(Design*des, NetCompare*obj) { #if 0 /* XXXX Need to reimplement this code to account for vectors. */ NetScope*scope = obj->scope(); unsigned const_count = 0; bool unknown_flag = false; /* First, look for the case where constant bits on matching A and B inputs are different. This this is so, the device can be completely eliminated and replaced with a constant 0. */ for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) { if (! obj->pin_DataA(idx).nexus()->drivers_constant()) continue; if (! obj->pin_DataB(idx).nexus()->drivers_constant()) continue; const_count += 1; verinum::V abit = obj->pin_DataA(idx).nexus()->driven_value(); verinum::V bbit = obj->pin_DataB(idx).nexus()->driven_value(); if ((abit == verinum::V0) && (bbit == verinum::V0)) continue; if ((abit == verinum::V1) && (bbit == verinum::V1)) continue; unknown_flag = true; if ((abit == verinum::Vz) || (abit == verinum::Vx)) continue; if ((bbit == verinum::Vz) || (bbit == verinum::Vx)) continue; NetConst*zero = new NetConst(scope, obj->name(), verinum::V0); connect(zero->pin(0), obj->pin_AEB()); delete obj; des->add_node(zero); count += 1; return; } /* If all the inputs are constant, then at this point the result is either V1 or Vx. */ if (const_count == obj->width()) { NetConst*val = new NetConst(scope, obj->name(), unknown_flag ? verinum::Vx : verinum::V1); connect(val->pin(0), obj->pin_AEB()); delete obj; des->add_node(val); count += 1; return; } /* Still may need the gate. Run through the inputs again, and look for pairs of constants. Those inputs can be removed. */ unsigned top = obj->width(); for (unsigned idx = 0 ; idx < top ; ) { if (! obj->pin_DataA(idx).nexus()->drivers_constant()) { idx += 1; continue; } if (! obj->pin_DataB(idx).nexus()->drivers_constant()) { idx += 1; continue; } obj->pin_DataA(idx).unlink(); obj->pin_DataB(idx).unlink(); top -= 1; for (unsigned jj = idx ; jj < top ; jj += 1) { connect(obj->pin_DataA(jj), obj->pin_DataA(jj+1)); connect(obj->pin_DataB(jj), obj->pin_DataB(jj+1)); obj->pin_DataA(jj+1).unlink(); obj->pin_DataB(jj+1).unlink(); } } /* If we wound up disconnecting all the inputs, then remove the device and replace it with a constant. */ if (top == 0) { NetConst*one = new NetConst(scope, obj->name(), verinum::V1); connect(one->pin(0), obj->pin_AEB()); delete obj; des->add_node(one); count += 1; return; } /* If there is only one bit left, then replace the comparator with a simple XOR gate. */ if (top == 1) { NetLogic*tmp = new NetLogic(scope, obj->name(), 3, NetLogic::XNOR, 1); connect(tmp->pin(0), obj->pin_AEB()); connect(tmp->pin(1), obj->pin_DataA(0)); connect(tmp->pin(2), obj->pin_DataB(0)); delete obj; des->add_node(tmp); count += 1; return; } if (top == obj->width()) return; NetCompare*tmp = new NetCompare(scope, obj->name(), top); connect(tmp->pin_AEB(), obj->pin_AEB()); for (unsigned idx = 0 ; idx < top ; idx += 1) { connect(tmp->pin_DataA(idx), obj->pin_DataA(idx)); connect(tmp->pin_DataB(idx), obj->pin_DataB(idx)); } delete obj; des->add_node(tmp); count += 1; #endif } void cprop_functor::lpm_ff(Design*des, NetFF*obj) { // Look for and count unlinked FF outputs. Note that if the // Data and Q pins are connected together, they can be removed // from the circuit, since it doesn't do anything. if (connected(obj->pin_Data(), obj->pin_Q()) && (! obj->pin_Sclr().is_linked()) && (! obj->pin_Sset().is_linked()) && (! obj->pin_Aclr().is_linked()) && (! obj->pin_Aset().is_linked())) { obj->pin_Data().unlink(); obj->pin_Q().unlink(); delete obj; } } void cprop_functor::lpm_logic(Design*des, NetLogic*obj) { #if 0 NetScope*scope = obj->scope(); #endif switch (obj->type()) { #if 0 /* XXXX This old code assumed that the individual bit slices could be replaced with different gates. They cannot when the device takes atomic vectors, so this needs to be rewritten. XXXX */ case NetLogic::NAND: case NetLogic::AND: { unsigned top = obj->pin_count(); unsigned idx = 1; unsigned xs = 0; /* Eliminate all the 1 inputs. They have no effect on the output of an AND gate. */ while (idx < top) { if (! obj->pin(idx).nexus()->drivers_constant()) { idx += 1; continue; } if (obj->pin(idx).nexus()->driven_value()==verinum::V1) { obj->pin(idx).unlink(); top -= 1; if (idx < top) { connect(obj->pin(idx), obj->pin(top)); obj->pin(top).unlink(); } continue; } if (obj->pin(idx).nexus()->driven_value() != verinum::V0) { idx += 1; xs += 1; continue; } /* Oops! We just stumbled on a driven-0 input to the AND gate. That means we can replace the whole bloody thing with a constant driver and exit now. */ NetConst*tmp; switch (obj->type()) { case NetLogic::AND: tmp = new NetConst(scope, obj->name(), verinum::V0); break; case NetLogic::NAND: tmp = new NetConst(scope, obj->name(), verinum::V1); break; default: assert(0); } tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); connect(obj->pin(0), tmp->pin(0)); delete obj; count += 1; return; } /* If all the inputs were eliminated, then replace the gate with a constant 1 and I am done. */ if (top == 1) { NetConst*tmp; switch (obj->type()) { case NetLogic::AND: tmp = new NetConst(scope, obj->name(), verinum::V1); break; case NetLogic::NAND: tmp = new NetConst(scope, obj->name(), verinum::V0); break; default: assert(0); } tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); connect(obj->pin(0), tmp->pin(0)); delete obj; count += 1; return; } /* If all the inputs are unknowns, then replace the gate with a Vx. */ if (xs == (top-1)) { NetConst*tmp; tmp = new NetConst(scope, obj->name(), verinum::Vx); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); connect(obj->pin(0), tmp->pin(0)); delete obj; count += 1; return; } /* If we are down to only one input, then replace the AND with a BUF and exit now. */ if (top == 2) { NetLogic*tmp; switch (obj->type()) { case NetLogic::AND: tmp = new NetLogic(scope, obj->name(), 2, NetLogic::BUF, 1); break; case NetLogic::NAND: tmp = new NetLogic(scope, obj->name(), 2, NetLogic::NOT, 1); break; default: assert(0); } tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); connect(obj->pin(0), tmp->pin(0)); connect(obj->pin(1), tmp->pin(1)); delete obj; count += 1; return; } /* Finally, this cleans up the gate by creating a new [N]AND gate that has the right number of inputs, connected in the right place. */ if (top < obj->pin_count()) { NetLogic*tmp = new NetLogic(scope, obj->name(), top, obj->type(), 1); tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); for (unsigned idx = 0 ; idx < top ; idx += 1) connect(tmp->pin(idx), obj->pin(idx)); delete obj; count += 1; return; } break; } #endif #if 0 /* XXXX This old code assumed that the individual bit slices could be replaced with different gates. They cannot when the device takes atomic vectors, so this needs to be rewritten. XXXX */ case NetLogic::NOR: case NetLogic::OR: { unsigned top = obj->pin_count(); unsigned idx = 1; /* Eliminate all the 0 inputs. They have no effect on the output of an OR gate. */ while (idx < top) { if (! obj->pin(idx).nexus()->drivers_constant()) { idx += 1; continue; } if (obj->pin(idx).nexus()->driven_value() == verinum::V0) { obj->pin(idx).unlink(); top -= 1; if (idx < top) { connect(obj->pin(idx), obj->pin(top)); obj->pin(top).unlink(); } continue; } if (obj->pin(idx).nexus()->driven_value() != verinum::V1) { idx += 1; continue; } /* Oops! We just stumbled on a driven-1 input to the OR gate. That means we can replace the whole bloody thing with a constant driver and exit now. */ NetConst*tmp; switch (obj->type()) { case NetLogic::OR: tmp = new NetConst(scope, obj->name(), verinum::V1); break; case NetLogic::NOR: tmp = new NetConst(scope, obj->name(), verinum::V0); break; default: assert(0); } tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); connect(obj->pin(0), tmp->pin(0)); delete obj; count += 1; return; } /* If all the inputs were eliminated, then replace the gate with a constant 0 and I am done. */ if (top == 1) { NetConst*tmp; switch (obj->type()) { case NetLogic::OR: tmp = new NetConst(scope, obj->name(), verinum::V0); break; case NetLogic::NOR: tmp = new NetConst(scope, obj->name(), verinum::V1); break; default: assert(0); } tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); connect(obj->pin(0), tmp->pin(0)); delete obj; count += 1; return; } /* If we are down to only one input, then replace the OR with a BUF and exit now. */ if (top == 2) { NetLogic*tmp; switch (obj->type()) { case NetLogic::OR: tmp = new NetLogic(scope, obj->name(), 2, NetLogic::BUF, 1); break; case NetLogic::NOR: tmp = new NetLogic(scope, obj->name(), 2, NetLogic::NOT, 1); break; default: assert(0); } tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); connect(obj->pin(0), tmp->pin(0)); connect(obj->pin(1), tmp->pin(1)); delete obj; count += 1; return; v } /* Finally, this cleans up the gate by creating a new [N]OR gate that has the right number of inputs, connected in the right place. */ if (top < obj->pin_count()) { NetLogic*tmp = new NetLogic(scope, obj->name(), top, obj->type(), 1); tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); for (unsigned idx = 0 ; idx < top ; idx += 1) connect(tmp->pin(idx), obj->pin(idx)); delete obj; count += 1; return; } break; } #endif #if 0 /* XXXX This old code assumed that the individual bit slices could be replaced with different gates. They cannot when the device takes atomic vectors, so this needs to be rewritten. XXXX */ case NetLogic::XNOR: case NetLogic::XOR: { unsigned top = obj->pin_count(); unsigned idx = 1; /* Eliminate all the 0 inputs. They have no effect on the output of an XOR gate. The eliminate works by unlinking the current input and relinking the last input to this position. It's like bubbling all the 0 inputs to the end. */ while (idx < top) { if (! obj->pin(idx).nexus()->drivers_constant()) { idx += 1; continue; } if (obj->pin(idx).nexus()->driven_value() == verinum::V0) { obj->pin(idx).unlink(); top -= 1; if (idx < top) { connect(obj->pin(idx), obj->pin(top)); obj->pin(top).unlink(); } } else { idx += 1; } } /* Look for pairs of constant 1 inputs. If I find a pair, then eliminate both. Each iteration through the loop, the `one' variable holds the index to the previous V1, or 0 if there is none. The `ones' variable counts the number of V1 inputs. After this loop completes, `ones' will be 0 or 1. */ unsigned one = 0, ones = 0; idx = 1; while (idx < top) { if (! obj->pin(idx).nexus()->drivers_constant()) { idx += 1; continue; } if (obj->pin(idx).nexus()->driven_value() == verinum::V1) { if (one == 0) { one = idx; ones += 1; idx += 1; continue; } /* Here we found two constant V1 inputs. Unlink both. */ obj->pin(idx).unlink(); top -= 1; if (idx < top) { connect(obj->pin(idx), obj->pin(top)); obj->pin(top).unlink(); } obj->pin(one).unlink(); top -= 1; if (one < top) { connect(obj->pin(one), obj->pin(top)); obj->pin(top).unlink(); } /* Reset ones counter and one index, start looking for the next pair. */ assert(ones == 1); ones = 0; one = 0; continue; } idx += 1; } /* If all the inputs were eliminated, then replace the gate with a constant value and I am done. */ if (top == 1) { verinum::V out = obj->type()==NetLogic::XNOR ? verinum::V1 : verinum::V0; NetConst*tmp = new NetConst(scope, obj->name(), out); tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); connect(obj->pin(0), tmp->pin(0)); delete obj; count += 1; return; } /* If there is a stray V1 input and only one other input, then replace the gate with an inverter and we are done. */ if ((top == 3) && (ones == 1)) { unsigned save; if (! obj->pin(1).nexus()->drivers_constant()) save = 1; else if (obj->pin(1).nexus()->driven_value() != verinum::V1) save = 1; else save = 2; NetLogic*tmp; if (obj->type() == NetLogic::XOR) tmp = new NetLogic(scope, obj->name(), 2, NetLogic::NOT, 1); else tmp = new NetLogic(scope, obj->name(), 2, NetLogic::BUF, 1); tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); connect(obj->pin(0), tmp->pin(0)); connect(obj->pin(save), tmp->pin(1)); delete obj; count += 1; return; } /* If we are down to only one input, then replace the XOR with a BUF and exit now. */ if (top == 2) { NetLogic*tmp; if (obj->type() == NetLogic::XOR) tmp = new NetLogic(scope, obj->name(), 2, NetLogic::BUF, 1); else tmp = new NetLogic(scope, obj->name(), 2, NetLogic::NOT, 1); tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); connect(obj->pin(0), tmp->pin(0)); connect(obj->pin(1), tmp->pin(1)); delete obj; count += 1; return; } /* Finally, this cleans up the gate by creating a new XOR gate that has the right number of inputs, connected in the right place. */ if (top < obj->pin_count()) { NetLogic*tmp = new NetLogic(scope, obj->name(), top, obj->type(), 1); des->add_node(tmp); tmp->pin(0).drive0(obj->pin(0).drive0()); tmp->pin(0).drive1(obj->pin(0).drive1()); for (unsigned idx = 0 ; idx < top ; idx += 1) connect(tmp->pin(idx), obj->pin(idx)); delete obj; count += 1; return; } break; } #endif default: break; } } #if 0 static void replace_with_mos(Design*des, NetMux*obj, NetLogic::TYPE type) { NetScope*scope = obj->scope(); NetLogic*tmp = new NetLogic(obj->scope(), scope->local_symbol(), 3, type, obj->width()); des->add_node(tmp); connect(obj->pin_Result(), tmp->pin(0)); connect(obj->pin_Data(type==NetLogic::PMOS? 0 : 1), tmp->pin(1)); if (obj->width() == 1) { /* Special case that the expression is 1 bit wide. Connect the select directly to the enable. */ connect(obj->pin_Sel(), tmp->pin(2)); } else { /* General case that the expression is arbitrarily wide. Replicate the enable signal (which we assume is 1 bit wide) to match the expression, and connect the enable vector to the enable input of the gate. */ NetReplicate*rtmp = new NetReplicate(scope, scope->local_symbol(), obj->width(), obj->width()); des->add_node(rtmp); connect(obj->pin_Sel(), rtmp->pin(1)); connect(tmp->pin(2), rtmp->pin(0)); NetNet*rsig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, obj->width()); rsig->local_flag(true); rsig->data_type(IVL_VT_LOGIC); connect(tmp->pin(2), rsig->pin(0)); } delete obj; } #endif /* * This detects the case where the mux selects between a value and * Vz. In this case, replace the device with a mos with the sel * input used to enable the output. */ void cprop_functor::lpm_mux(Design*des, NetMux*obj) { if (obj->size() != 2) return; if (obj->sel_width() != 1) return; #if 0 /* * This is slower than the actual MUXZ so we are skipping this for now. * If we had a half mux functor this could be faster and more compact * so I'm leaving the code for future reference. */ /* If the first input is all constant Vz, then replace the NetMux with an array of NMOS devices, with the enable connected to the select input. */ if (obj->pin_Data(0).nexus()->drivers_constant() && obj->pin_Data(0).nexus()->driven_value() == verinum::Vz) { replace_with_mos(des, obj, NetLogic::NMOS); count += 1; return; } /* If instead the second input is all constant Vz, replace the NetMux with an array of PMOS devices. */ if (obj->pin_Data(1).nexus()->drivers_constant() && obj->pin_Data(1).nexus()->driven_value() == verinum::Vz) { replace_with_mos(des, obj, NetLogic::PMOS); count += 1; return; } #endif /* If the select input is constant, then replace with a BUFZ */ bool flag = obj->pin_Sel().nexus()->drivers_constant(); /* Note that this cannot be constant if there are assignments to this nexus. (Assignments include "force" to nets.) */ flag &= !obj->pin_Sel().nexus()->assign_lval(); verinum::V sel_val = flag? obj->pin_Sel().nexus()->driven_value() : verinum::Vx; if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) { NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width()); tmp->set_line(*obj); if (debug_optimizer) cerr << obj->get_fileline() << ": debug: " << "Replace binary MUX with constant select=" << sel_val << " with a BUFZ to the selected input." << endl; tmp->rise_time(obj->rise_time()); tmp->fall_time(obj->fall_time()); tmp->decay_time(obj->decay_time()); connect(tmp->pin(0), obj->pin_Result()); if (sel_val == verinum::V1) connect(tmp->pin(1), obj->pin_Data(1)); else connect(tmp->pin(1), obj->pin_Data(0)); delete obj; des->add_node(tmp); count += 1; } } /* * This functor looks to see if the constant is connected to nothing * but signals. If that is the case, delete the dangling constant and * the now useless signals. This functor is applied after the regular * functor to clean up dangling constants that might be left behind. */ struct cprop_dc_functor : public functor_t { virtual void lpm_const(Design*des, NetConst*obj); }; void cprop_dc_functor::lpm_const(Design*des, NetConst*obj) { // 'bz constant values drive high impedance to whatever is // connected to it. In other words, it is a noop. But that is // only true if *all* the bits of the vectors. { unsigned tmp = 0; ivl_assert(*obj, obj->pin_count()==1); for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) { if (obj->value(idx) == verinum::Vz) { tmp += 1; } } if (tmp == obj->width()) { delete obj; return; } } // For each bit, if this is the only driver, then set the // initial value of all the signals to this value. for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) { if (count_outputs(obj->pin(idx)) > 1) continue; Nexus*nex = obj->pin(idx).nexus(); for (Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { NetPins*cur; unsigned pin; clnk->cur_link(cur, pin); NetNet*tmp = dynamic_cast(cur); if (tmp == 0) continue; tmp->pin(pin).set_init(obj->value(idx)); } } // If there are any links that take input, the constant is // used structurally somewhere. for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) if (count_inputs(obj->pin(idx)) > 0) return; // Look for signals that have NetESignal nodes attached to // them. If I find any, then this constant is used by a // behavioral expression somewhere. for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) { Nexus*nex = obj->pin(idx).nexus(); for (Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { NetPins*cur; unsigned pin; clnk->cur_link(cur, pin); NetNet*tmp = dynamic_cast(cur); if (tmp == 0) continue; assert(tmp->scope()); // If the net is a signal name from the source, // then users will probably want to see it in the // waveform dump, so unhooking the constant will // make it look wrong. if (! tmp->local_flag()) return; // If the net has an eref, then there is an // expression somewhere that reads this signal. So // the constant does get read. if (tmp->peek_eref() > 0) return; // If the net is a port of the root module, then // the constant may be driving something outside // the design, so do not eliminate it. if ((tmp->port_type() != NetNet::NOT_A_PORT) && (tmp->scope()->parent() == 0)) return; } } // Done. Delete me. delete obj; } void cprop(Design*des) { // Continually propagate constants until a scan finds nothing // to do. cprop_functor prop; do { prop.count = 0; des->functor(&prop); } while (prop.count > 0); cprop_dc_functor dc; des->functor(&dc); } verilog-0.9.7/PaxHeaders.14238/developer-quick-start.txt0000644000202500001440000000005012204466647021223 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/developer-quick-start.txt0000644000202500001440000001410712204466647020550 0ustar00steveusers00000000000000 Developer Quick Start for Icarus Verilog The documentation for getting, building and installing Icarus Verilog is kept and maintained at the iverilog documentation wiki at . See the Installation Guide for getting the current source from the git repository (and how to use the git repository) and see the Developer Guide for instructions on participating in the Icarus Verilog development process. That information will not be repeated here. What this documentation *will* cover is the gross structure of the Icarus Verilog compiler source. This will help orient you to the source code itself, so that you can find the global parts where you can look for even better detail. * Compiler Components - The compiler driver (driver/) This is the binary that is installed as "iverilog". This program takes the command line arguments and assembles invocations of all the other subcommands to perform the steps of compilation. - The preprocessor (ivlpp/) This implements the Verilog pre-processor. In Icarus Verilog, the compiler directives `define, `include, `ifdef and etc. are implemented in an external program. The ivlpp/ directory contains the source for this program. - The core compiler (this directory) The "ivl" program is the core that does all the Verilog compiler processing that is not handled elsewhere. This is the main core of the Icarus Verilog compiler, not the runtime. See below for more details on the core itself. - The loadable code generators (tgt-*/) This core compiler, after it is finished with parsing and semantic analysis, uses loadable code generators to emit code for supported targets. The tgt-*/ directories contains the source for the target code generators that are bundled with Icarus Verilog. The tgt-vvp/ directory in particular contains the code generator for the vvp runtime. * Runtime Components - The vvp runtime (vvp/) This program implements the runtime environment for Icarus Verilog. It implements the "vvp" command described in the user documentation. See the vvp/ subdirectory for further developer documentation. - The system tasks implementations (vpi/) The standard Verilog system tasks are implemented using VPI (PLI-2) and the source is in this subdirectory. - The PLI-1 compatibility library (libveriuser/) The Icarus Verilog support for the deprecated PLI-1 is in this subdirectory. The vvp runtime does not directly support the PLI-1. Instead, the libveriuser library emulates it using the builtin PLI-2 support. - The Cadence PLI module compatibility module (cadpli/) It is possible in some specialized situations to load and execute PLI-1 code written for Verilog-XL. This directory contains the source for the module that provides the Cadence PLI interface. * The Core Compiler The "ivl" binary is the core compiler that does the heavy lifting of compiling the Verilog source (including libraries) and generating the output. This is the most complex component of the Icarus Verilog compilation system. The process in the abstract starts with the Verilog lexical analysis and parsing to generate an internal "pform". The pform is then translated by elaboration into the "netlist" form. The netlist is processed by some functors (which include some optimizations and optional synthesis) then is translated into the ivl_target internal form. And finally, the ivl_target form is passed via the ivl_target.h API to the code generators. - Lexical Analysis Lexical analysis and parsing use the tools "flex", "gperf", and "bison". The "flex" input file "lexor.lex" recognizes the tokens in the input stream. This is called "lexical analysis". The lexical analyzer also does some processing of compiler directives that are not otherwise taken care of by the external preprocessor. The lexical analyzer uses a table of keywords that is generated using the "gperf" program and the input file "lexor_keywords.gperf". This table allows the lexical analyzer to efficiently check input words with the rather large set of potential keywords. - Parsing The parser input file "parse.y" is passed to the "bison" program to generate the parser. The parser uses the functions in parse*.h, parse*.cc, pform.h, and pform*.cc to generate the pform from the stream of input tokens. The pform is what compiler writers call a "decorated parse tree". The pform itself is described by the classes in the header files "PScope.h", "Module.h", "PGenerate.h", "Statement.h", and "PExpr.h". The implementations of the classes in those header files are in the similarly named C++ files. - Elaboration Elaboration transforms the pform to the netlist form. Elaboration is conceptually divided into several major steps: Scope elaboration, parameter overrides and defparam propagation, signal elaboration, and statement and expression elaboration. The elaboration of scopes and parameter overrides and defparam propagation are conceptually separate, but are in practice intermingled. The elaboration of scopes scans the pform to find and instantiate all the scopes of the design. New scopes are created by instantiation of modules (starting with the root instances) by user defined tasks and functions, named blocks, and generate schemes. The elaborate_scope methods implement scope elaboration, and the elab_scope.cc source file has the implementations of those methods. The elaborate.cc source file contains the initial calls to the elaborate_scope for the root scopes to get the process started. In particular, see the "elaborate" function near the bottom of the elaborate.cc source file. The calls to Design::make_root_scope create the initial root scopes, and the creation and enqueue of the elaborate_root_scope_t work items primes the scope elaboration work list. Intermingled in the work list are defparms work items that call the Design::run_defparams and Design::evaluate_parameters methods that override and evaluate parameters. The override and evaluation of parameters must be intermingled with the elaboration of scopes because the exact values of parameters may impact the scopes created (imagine generate schemes and instance arrays) and the created scopes in turn create new parameters that need override and evaluation. verilog-0.9.7/PaxHeaders.14238/vpi_user.h0000644000202500001440000000005012204466647016235 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/vpi_user.h0000644000202500001440000004570312204466647015570 0ustar00steveusers00000000000000#ifndef __vpi_user_H #define __vpi_user_H /* * Copyright (c) 1999-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if defined(__MINGW32__) || defined (__CYGWIN32__) # define DLLEXPORT __declspec(dllexport) #else # define DLLEXPORT #endif #ifdef __cplusplus # define EXTERN_C_START extern "C" { # define EXTERN_C_END } #else # define EXTERN_C_START # define EXTERN_C_END #endif #ifndef __GNUC__ # undef __attribute__ # define __attribute__(x) #endif EXTERN_C_START # include # include # include "_pli_types.h" typedef struct __vpiHandle *vpiHandle; /* * This structure is created by the VPI application to provide hooks * into the application that the compiler/simulator can access. */ typedef struct t_vpi_systf_data { PLI_INT32 type; PLI_INT32 sysfunctype; const char *tfname; PLI_INT32 (*calltf) (PLI_BYTE8*); PLI_INT32 (*compiletf)(PLI_BYTE8*); PLI_INT32 (*sizetf) (PLI_BYTE8*); PLI_BYTE8 *user_data; } s_vpi_systf_data, *p_vpi_systf_data; /* The type in the above structure can have one of the following values: */ #define vpiSysTask 1 #define vpiSysFunc 2 typedef struct t_vpi_vlog_info { PLI_INT32 argc; char **argv; char *product; char *version; } s_vpi_vlog_info, *p_vpi_vlog_info; typedef struct t_vpi_time { /* Type can be : vpiScaledRealTime == 1 vpiSimTime == 2 vpiSuppressTime == 3 */ PLI_INT32 type; PLI_UINT32 high; PLI_UINT32 low; double real; } s_vpi_time, *p_vpi_time; #define vpiScaledRealTime 1 #define vpiSimTime 2 #define vpiSuppressTime 3 typedef struct t_vpi_vecval { PLI_INT32 aval, bval; /* ab encoding: 00=0, 10=1, 11=X, 01=Z */ } s_vpi_vecval, *p_vpi_vecval; typedef struct t_vpi_strengthval { PLI_INT32 logic; PLI_INT32 s0, s1; } s_vpi_strengthval, *p_vpi_strengthval; /* * This structure holds values that are passed back and forth between * the simulator and the application. */ typedef struct t_vpi_value { PLI_INT32 format; union { char *str; PLI_INT32 scalar; PLI_INT32 integer; double real; struct t_vpi_time *time; struct t_vpi_vecval *vector; struct t_vpi_strengthval *strength; char *misc; } value; } s_vpi_value, *p_vpi_value; /* Conform the IEEE 1364, We add the Standard vpi_delay structure to enable the modpath delay values Conform IEEE 1364, Pg 670 : The "da" field of the s_vpi_delay structure shall be a user allocated array of "s_vpi_time" structure The array shall store delay values returned by vpi_get_delay(). The number of elements in the array shall be determined by (1) The number of delays to be retrieved ( normally this is used in vpi_get_delays (..) ) { (1.1) Set by "no_of_delays" field (1.2) For the primitive_object, the no_of_delays shall be 2 or 3 (1.3) For path_delay object the no_of_delays shall be 1,2,3,6, 12 (1.4) For timing_check_object, the no_of_delays shall be match the number of limits existing in the Time Check (1.5) For intermodule_path object, the no_of_delays shall be 2 or 3 } (2) The "mtm_flag" && "pulsere_flag" Normally, if you set mtm = X, pulsere = Y then, you will need allocate (num * no_of_delay) s_vpi_time elements for 'da' array before calling the vpi_get/put_delays (..) --------------------------------------------------------------------------- | | | | | mtm_flag | No of s_vpi_time array | order in which delay | | pulsere_flag | element required by the | elements shall be filed | | | s_vpi_delay->da | | | | | | |----------------|-------------------------|------------------------------| | | | 1o delay da[0]--> 1o delay | | mtm = false | no_of_delay | 2o delay da[1]--> 2o delay | | pulere = false | | | | | | | |----------------|-------------------------|------------------------------| | | | 1o delay da[0]--> min delay | | mtm = true | | da[1]--> typ delay | | pulere = false | 3*no_of_delay | da[2]--> max delay | | | | 2o delay da[3]--> min delay | | | | da[4]--> typ delay | | | | .... | |----------------|-------------------------|------------------------------| | | | 1o delay da[0]--> delay | | mtm = false | | da[1]--> rej limit | | pulere = true | 3*no_of_delay | da[2]--> err limit | | | | 2o delay da[3]--> delay | | | | da[4]--> rej limit | | | | .... | |----------------|-------------------------|------------------------------| | | | 1o delay da[0]--> min delay | | mtm = true | | da[1]--> typ delay | | pulere = true | 9*no_of_delay | da[2]--> max delay | | | | da[3]--> min delay | | | | da[4]--> typ delay | | | | da[5]--> max delay | | | | da[6]--> min delay | | | | da[7]--> typ delay | | | | da[8]--> max delay | | | | 2o delay da[9]--> min delay | | | | .... | ------------------------------------------------------------------------- IMPORTANT : The delay Structure has to be allocated before passing a pointer to "vpi_get_delays ( )". */ typedef struct t_vpi_delay { struct t_vpi_time *da; /* Array of delay data */ PLI_INT32 no_of_delays ; PLI_INT32 time_type; /* vpiScaledRealTime, vpiSimTime */ PLI_INT32 mtm_flag; PLI_INT32 append_flag; PLI_INT32 plusere_flag; } s_vpi_delay, *p_vpi_delay; /* These are valid codes for the format of the t_vpi_value structure. */ #define vpiBinStrVal 1 #define vpiOctStrVal 2 #define vpiDecStrVal 3 #define vpiHexStrVal 4 #define vpiScalarVal 5 #define vpiIntVal 6 #define vpiRealVal 7 #define vpiStringVal 8 #define vpiVectorVal 9 #define vpiStrengthVal 10 #define vpiTimeVal 11 #define vpiObjTypeVal 12 #define vpiSuppressVal 13 /* SCALAR VALUES */ #define vpi0 0 #define vpi1 1 #define vpiZ 2 #define vpiX 3 #define vpiH 4 #define vpiL 5 #define vpiDontCare 6 /* STRENGTH VALUES */ #define vpiSupplyDrive 0x80 #define vpiStrongDrive 0x40 #define vpiPullDrive 0x20 #define vpiLargeCharge 0x10 #define vpiWeakDrive 0x08 #define vpiMediumCharge 0x04 #define vpiSmallCharge 0x02 #define vpiHiZ 0x01 /* OBJECT CODES */ #define vpiConstant 7 #define vpiFunction 20 #define vpiIntegerVar 25 #define vpiIterator 27 #define vpiMemory 29 #define vpiMemoryWord 30 #define vpiModPath 31 #define vpiModule 32 #define vpiNamedBegin 33 #define vpiNamedEvent 34 #define vpiNamedFork 35 #define vpiNet 36 #define vpiParameter 41 #define vpiPartSelect 42 #define vpiPathTerm 43 #define vpiRealVar 47 #define vpiReg 48 #define vpiSysFuncCall 56 #define vpiSysTaskCall 57 #define vpiTask 59 #define vpiTimeVar 63 #define vpiNetArray 114 #define vpiIndex 78 #define vpiLeftRange 79 #define vpiParent 81 #define vpiRightRange 83 #define vpiScope 84 #define vpiSysTfCall 85 #define vpiArgument 89 #define vpiInternalScope 92 #define vpiModPathIn 95 #define vpiModPathOut 96 #define vpiVariables 100 #define vpiExpr 102 #define vpiCallback 1000 /* PROPERTIES */ #define vpiUndefined (-1) #define vpiType 1 #define vpiName 2 #define vpiFullName 3 #define vpiSize 4 #define vpiFile 5 #define vpiLineNo 6 #define vpiTopModule 7 #define vpiCellInstance 8 #define vpiDefName 9 #define vpiTimeUnit 11 #define vpiTimePrecision 12 #define vpiDefFile 15 #define vpiDefLineNo 16 #define vpiNetType 22 # define vpiWire 1 # define vpiWand 2 # define vpiWor 3 # define vpiTri 4 # define vpiTri0 5 # define vpiTri1 6 # define vpiTriReg 7 # define vpiTriAnd 8 # define vpiTriOr 9 # define vpiSupply1 10 # define vpiSupply0 11 #define vpiArray 28 #define vpiEdge 36 # define vpiNoEdge 0x00 /* No edge */ # define vpiEdge01 0x01 /* 0 --> 1 */ # define vpiEdge10 0x02 /* 1 --> 0 */ # define vpiEdge0x 0x04 /* 0 --> x */ # define vpiEdgex1 0x08 /* x --> 1 */ # define vpiEdge1x 0x10 /* 1 --> x */ # define vpiEdgex0 0x20 /* x --> 0 */ # define vpiPosedge (vpiEdgex1|vpiEdge01|vpiEdge0x) # define vpiNegedge (vpiEdgex0|vpiEdge10|vpiEdge1x) # define vpiAnyEdge (vpiPosedge|vpiNegedge) #define vpiConstType 40 # define vpiDecConst 1 # define vpiRealConst 2 # define vpiBinaryConst 3 # define vpiOctConst 4 # define vpiHexConst 5 # define vpiStringConst 6 #define vpiFuncType 44 # define vpiIntFunc 1 # define vpiRealFunc 2 # define vpiTimeFunc 3 # define vpiSizedFunc 4 # define vpiSizedSignedFunc 5 #define vpiSysFuncType vpiFuncType # define vpiSysFuncInt vpiIntFunc # define vpiSysFuncReal vpiRealFunc # define vpiSysFuncTime vpiTimeFunc # define vpiSysFuncSized vpiSizedFunc #define vpiAutomatic 50 #define vpiConstantSelect 53 #define vpiSigned 65 /* IVL private properties, also see vvp/vpi_priv.h for other properties */ #define _vpiNexusId 0x1000000 /* DELAY MODES */ #define vpiNoDelay 1 #define vpiInertialDelay 2 #define vpiTransportDelay 3 #define vpiPureTransportDelay 4 #define vpiForceFlag 5 #define vpiReleaseFlag 6 #define vpiReturnEvent 0x1000 /* VPI FUNCTIONS */ extern void vpi_register_systf(const struct t_vpi_systf_data*ss); /* I/O routines */ extern PLI_UINT32 vpi_mcd_open(char *name); extern PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd); extern char *vpi_mcd_name(PLI_UINT32 mcd); extern PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, const char*fmt, ...) __attribute__((format (printf,2,3))); extern PLI_INT32 vpi_printf(const char*fmt, ...) __attribute__((format (printf,1,2))); extern PLI_INT32 vpi_vprintf(const char*fmt, va_list ap); extern PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, const char*fmt, va_list ap); extern PLI_INT32 vpi_flush(void); extern PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd); /* proposed extensions */ /* * These functions are proposed extensions to Verilog, and * are described by the Verilog PLI task force as issue#347. * * The vpi_fopen() function is exactly the same as the $fopen system * function. That is, it takes a path string and a mode string, and * opens the file. The result is a 32bit value with bit 31 set, the * remaining bits made up a small integer to represent the file. * * The vpi_get_file(fd) function takes as input a descriptor as * returned by vpi_fopen or $fopen. Bit 31 must be set. The result * is the C FILE* that represents the file. */ extern PLI_INT32 vpi_fopen(const char*name, const char*mode); extern FILE *vpi_get_file(PLI_INT32 fd); /* * support for VPI callback functions. */ typedef struct t_cb_data { PLI_INT32 reason; PLI_INT32 (*cb_rtn)(struct t_cb_data*cb); vpiHandle obj; p_vpi_time time; p_vpi_value value; PLI_INT32 index; char *user_data; } s_cb_data, *p_cb_data; #define cbValueChange 1 #define cbStmt 2 #define cbForce 3 #define cbRelease 4 #define cbAtStartOfSimTime 5 #define cbReadWriteSynch 6 #define cbReadOnlySynch 7 #define cbNextSimTime 8 #define cbAfterDelay 9 #define cbEndOfCompile 10 #define cbStartOfSimulation 11 #define cbEndOfSimulation 12 #define cbError 13 #define cbTchkViolation 14 #define cbStartOfSave 15 #define cbEndOfSave 16 #define cbStartOfRestart 17 #define cbEndOfRestart 18 #define cbStartOfReset 19 #define cbEndOfReset 20 #define cbEnterInteractive 21 #define cbExitInteractive 22 #define cbInteractiveScopeChange 23 #define cbUnresolvedSystf 24 extern vpiHandle vpi_register_cb(p_cb_data data); extern PLI_INT32 vpi_remove_cb(vpiHandle ref); /* * This function allows a vpi application to control the simulation * engine. The operation parameter specifies the function to * perform. The remaining parameters (if any) are interpreted by the * operation. The vpi_sim_control definition (now named vpi_control) * was added to P1364-2000 14 July 1999. See PLI Task Force ID: PTF-161 * * vpiFinish - perform the $finish operation, as soon as the user * function returns. This operation takes a single * parameter, a diagnostic exit code. * * vpiStop - * vpiReset - * vpiSetInteractiveScope - */ extern void vpi_control(PLI_INT32 operation, ...); /************* vpi_control() constants (added with 1364-2000) *************/ #define vpiStop 66 /* execute simulator's $stop */ #define vpiFinish 67 /* execute simulator's $finish */ #define vpiReset 68 /* execute simulator's $reset */ #define vpiSetInteractiveScope 69 /* set simulator's interactive scope */ #define __ivl_legacy_vpiStop 1 #define __ivl_legacy_vpiFinish 2 /* vpi_sim_control is the incorrect name for vpi_control. */ extern void vpi_sim_control(PLI_INT32 operation, ...); extern vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref); extern vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle ref); extern vpiHandle vpi_scan(vpiHandle iter); extern vpiHandle vpi_handle_by_index(vpiHandle ref, PLI_INT32 idx); extern vpiHandle vpi_handle_by_name(const char*name, vpiHandle scope); extern void vpi_get_time(vpiHandle obj, s_vpi_time*t); extern PLI_INT32 vpi_get(int property, vpiHandle ref); extern char *vpi_get_str(PLI_INT32 property, vpiHandle ref); extern void vpi_get_value(vpiHandle expr, p_vpi_value value); /* * This function puts a value into the object referenced by the * handle. This assumes that the value supports having its value * written to. The time parameter specifies when the assignment is to * take place. This allows you to schedule an assignment to happen in * the future. * * The flags value specifies the delay model to use in assigning the * value. This specifies how the time value is to be used. * * vpiNoDelay -- Set the value immediately. The p_vpi_time parameter * may be NULL, in this case. This is like a blocking assignment * in behavioral code. * * vpiInertialDelay -- Set the value using the transport delay. The * p_vpi_time parameter is required and specifies when the * assignment is to take place. This is like a non-blocking * assignment in behavioral code. */ extern vpiHandle vpi_put_value(vpiHandle obj, p_vpi_value value, p_vpi_time when, PLI_INT32 flags); extern PLI_INT32 vpi_free_object(vpiHandle ref); extern PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p); /* These Routines will enable the modpath vpiHandle to read/write delay values */ extern void vpi_get_delays(vpiHandle expr, p_vpi_delay delays); extern void vpi_put_delays(vpiHandle expr, p_vpi_delay delays); /* * These functions support attaching user data to an instance of a * system task or function. These functions only apply to * vpiSysTaskCall or vpiSysFuncCall handles. */ extern PLI_INT32 vpi_put_userdata(vpiHandle obj, void*data); extern void*vpi_get_userdata(vpiHandle obj); /* * Support for handling errors. */ typedef struct t_vpi_error_info { PLI_INT32 state; PLI_INT32 level; char *message; char *product; char *code; char *file; PLI_INT32 line; } s_vpi_error_info, *p_vpi_error_info; /* error_info states */ # define vpiCompile 1 # define vpiPLI 2 # define vpiRun 3 /* error_info levels */ # define vpiNotice 1 # define vpiWarning 2 # define vpiError 3 # define vpiSystem 4 # define vpiInternal 5 extern PLI_INT32 vpi_chk_error(p_vpi_error_info info); /* This is the table of startup routines included in each module. */ extern DLLEXPORT void (*vlog_startup_routines[])(void); /* * ICARUS VERILOG EXTENSIONS * * The vpip_* functions are Icarus Verilog extensions. They are not * standard VPI functions, so use these at your own risk. * * The vpip_format_* functions format values in string format in the * manner of the $display system task. */ /* Format a scalar a la %v. The str points to a 4byte character buffer. The value must be a vpiStrengthVal. */ extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit); extern void vpip_set_return_value(int value); extern s_vpi_vecval vpip_calc_clog2(vpiHandle arg); /* * Stopgap fix for br916. We need to reject any attempt to pass a thread * variable to $strobe or $monitor. To do this, we use some private VPI * properties that are normally only used by the VVP thread cleanup code. * Normally the following definitions are provided by vvp/vpi_priv.h, but * for the stopgap fix we need to make them more widely available. */ #define BR916_STOPGAP_FIX #ifdef BR916_STOPGAP_FIX #define _vpiFromThr 0x1000001 # define _vpiNoThr 0 # define _vpiString 1 # define _vpiVThr 2 # define _vpiWord 3 # define _vpi_at_PV 4 # define _vpi_at_A 5 # define _vpi_at_APV 6 #endif EXTERN_C_END #endif verilog-0.9.7/PaxHeaders.14238/examples0000644000202500001440000000005012204466647015771 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/0000755000202500001440000000000012204466647015370 5ustar00steveusers00000000000000verilog-0.9.7/examples/PaxHeaders.14238/sqrt-virtex.v0000644000202500001440000000005012204466647020545 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/sqrt-virtex.v0000644000202500001440000002740612204466647020100 0ustar00steveusers00000000000000/* * Copyright (c) 2002 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * $Id: sqrt-virtex.v,v 1.5 2007/03/22 16:08:18 steve Exp $" */ /* * This module is a synthesizable square-root function. It is also a * detailed example of how to target Xilinx Virtex parts using * Icarus Verilog. In fact, for no particular reason other than to * be excessively specific, I will step through the process of * generating a design for a Spartan-II XC2S15-VQ100, and also how to * generate a generic library part for larger Virtex designs. * * In addition to Icarus Verilog, you will need implementation * software from Xilinx. As of this writing, this example was tested * with Foundation 4.2i, but it should work the same with ISE and * WebPACK software. * * This example source contains all the Verilog needed to do * everything described below. We use conditional compilation to * select the bits of Verilog that are needed to perform each specific * task. * * SIMULATE THE DESIGN * * This source file includes a simulation test bench. To compile the * program to include this test bench, use the command line: * * iverilog -DSIMULATE=1 -oa.out sqrt-virtex.v * * This generates the file "a.out" that can then be executed with the * command: * * vvp a.out * * This causes the simulation to run a long set of example sqrt * calculations. Each result is checked by the test bench to assure * that the result is valid. When it is done, the program prints * "PASSED" and finishes the simulation. * * When you take a close look at the "main" module below, you will see * that it uses Verilog constructs that are not synthesizable. This * is fine, as we will never try to synthesize it. * * LIBRARY PARTS * * One can use the sqrt32 module to generate an EDIF file suitable for * use as a library part. This part can be imported to the Xilinx * schematic editor, then placed like any other pre-existing * macro. One can also pass the generated EDIF as a precompiled macro * that other designers may use as they see fit. * * To make an EDIF file from the sqrt32 module, execute the command: * * iverilog -osqrt32.edf -tfpga -parch=virtex sqrt-virtex.v * * The -parch=virtex tells the code generator to generate code for the * virtex architecture family (we don't yet care what specific part) * and the -osqrt32.edf places the output into the file * sqrt32.edf. * * Without any preprocessor directives, the only module is the sqrt32 * module, so sqrt32 is compiled as the root. The ports of the module * are automatically made into ports of the sqrt32.edf netlist, and * the contents of the sqrt32 module are connected appropriately. * * COMPLETE CHIP DESIGNS * * To make a complete chip design, there are other bits that need to * be accounted for. Signals must be assigned to pins, and some * special devices may need to be created. We also want to write into * the EDIF file complete part information so that the implementation * tools know how to route the complete design. The command to compile * for our target part is: * * iverilog -ochip.edf -tfpga \ * -parch=virtex -ppart=XC2S15-VQ100 \ * -DMAKE_CHIP=1 sqrt-virtex.v * * This command uses the "chip" module as the root. This module in * turn has ports that are destined to be the pins of the completed * part. The -ppart= option gives complete part information, that is * in turn written into the EDIF file. This saves us the drudgery of * repeating that part number for later commands. * * The next steps involve Xilinx software, and to talk to Xilinx * software, the netlist must be in the form of an "ngd" file, a * binary netlist format. The command: * * ngdbuild chip.edf chip.ngd * * does the trick. The input to ngdbuild is the chip.edf file created * by Icarus Verilog, and the output is the chip.ngd file that the * implementation tools may read. From this point, it is best to refer * to Xilinx documentation for the software you are using, but the * quick summary is: * * map -o map.ncd chip.ngd * par -w map.ncd chip.ncd * * The result of this sequence of commands is the chip.ncd file that * is ready to be viewed by FPGA Edit, or converted to a bit stream, * or whatever. * * POST MAP SIMULATION * * Warm fuzzies are good, and retesting your design after the part * is mapped by the Xilinx backend tools is a cheap source of fuzzies. * The command to make a Verilog file out of the mapped design is: * * ngd2ver chip.ngd chip_root.v * * This command creates from the chip.ngd the file "chip_root.v" that * contains Verilog code that simulates the mapped design. This output * Verilog has the single root module "chip_root", which came from the * name of the root module when we were making the EDIF file in the * first place. The module has ports named just line the ports of the * chip_root module below. * * The generated Verilog uses the library in the directory * $(XILINX)/verilog/src/simprims. This directory comes with the ISE * WebPACK installation that you are using. Icarus Verilog is able to * simulate using that library. * * To compile a post-map simulation of the chip_root.v, use the * command: * * iverilog -DSIMULATE -DPOST_MAP -ob.out \ * -y $(XILINX)/verilog/src/simprims \ * sqrt-virtex.v chip_root.v \ * $(XILINX)/verilog/src/glbl.v * * This command line generates b.out from the source files * sqrt-virtex.v and chip_root.v (the latter from ngd2ver) * and the "-y " flag specifies the library directory that will * be needed. The glbl.v source file is also included to provide the * GSR and related signals. * * The POST_MAP compiler directive causes the GSR manipulations * included in the test bench to be compiled in, to simulate the chip * startup. Other than that, the test bench runs the post-map design * the same way the pre-synthesis design works. * * Run this design with the command: * * vvp b.out * * And there you go. */ `ifndef POST_MAP /* * This module approximates the square root of an unsigned 32bit * number. The algorithm works by doing a bit-wise binary search. * Starting from the most significant bit, the accumulated value * tries to put a 1 in the bit position. If that makes the square * too big for the input, the bit is left zero, otherwise it is set * in the result. This continues for each bit, decreasing in * significance, until all the bits are calculated or all the * remaining bits are zero. * * Since the result is an integer, this function really calculates * value of the expression: * * x = floor(sqrt(y)) * * where sqrt(y) is the exact square root of y and floor(N) is the * largest integer <= N. * * For 32 bit numbers, this will never run more than 16 iterations, * which amounts to 16 clocks. */ module sqrt32(clk, rdy, reset, x, .y(acc)); input clk; output rdy; input reset; input [31:0] x; output [15:0] acc; // acc holds the accumulated result, and acc2 is the accumulated // square of the accumulated result. reg [15:0] acc; reg [31:0] acc2; // Keep track of which bit I'm working on. reg [4:0] bitl; wire [15:0] bit = 1 << bitl; wire [31:0] bit2 = 1 << (bitl << 1); // The output is ready when the bitl counter underflows. wire rdy = bitl[4]; // guess holds the potential next values for acc, and guess2 holds // the square of that guess. The guess2 calculation is a little bit // subtle. The idea is that: // // guess2 = (acc + bit) * (acc + bit) // = (acc * acc) + 2*acc*bit + bit*bit // = acc2 + 2*acc*bit + bit2 // = acc2 + 2 * (acc< ((y + 1)*(y + 1))) begin $display("ERROR: y is too small"); $finish; end end $display("PASSED"); $finish; end endmodule // main `endif `ifdef MAKE_CHIP /* * This module represents the chip packaging that we intend to * generate. We bind pins here, and route the clock to the global * clock buffer. */ module chip_root(clk, rdy, reset, x, y); input clk; output rdy; input reset; input [31:0] x; output [15:0] y; wire clk_int; (* cellref="BUFG:O,I" *) buf gbuf (clk_int, clk); sqrt32 dut(.clk(clk_int), .reset(reset), .rdy(rdy), .x(x), .y(y)); /* Assign the clk to GCLK0, which is on pin P39. */ $attribute(clk, "PAD", "P39"); // We don't care where the remaining pins go, so set the pin number // to 0. This tells the implementation tools that we want a PAD, // but we don't care which. Also note the use of a comma (,) // separated list to assign pins to the bits of a vector. $attribute(rdy, "PAD", "0"); $attribute(reset, "PAD", "0"); $attribute(x, "PAD", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"); $attribute(y, "PAD", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"); endmodule // chip_root `endif verilog-0.9.7/examples/PaxHeaders.14238/hello_vpi.vl0000644000202500001440000000005012204466647020372 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/hello_vpi.vl0000644000202500001440000000320312204466647017712 0ustar00steveusers00000000000000/* * Copyright (c) 2002 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * Here we have the canonical "Hello, World" program written in Verilog, * with VPI. It uses the hello_vpi.vpi module that is compiled from * the hello_vpi.c program also in this directory. See the * hello_vpi.c for instructions on how to compile it. * * Compile this program with the command: * * iverilog -ohello_vpi hello_vpi.vl * * After churning for a little while, the program will create the output * file "hello" which is compiled, linked and ready to run. Run this * program like so: * * vvp -M. -mhello_vpi hello_vpi * * and the program will print the message to its output. Easy! For * more on how to make the iverilog command work, see the iverilog * manual page. */ module main(); initial begin $my_hello; $finish ; end endmodule verilog-0.9.7/examples/PaxHeaders.14238/pal_reg.v0000644000202500001440000000005012204466647017646 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/pal_reg.v0000644000202500001440000001041612204466647017172 0ustar00steveusers00000000000000/* * Copyright (c) 2000 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * This example shows how to use Icarus Verilog to generate PLD output. * The design is intended to fit into a 22v10 in a PLCC package, with * pin assignments locked down by design. The command to compile this * into a jedec file is; * * iverilog -tpal -ppart=generic-22v10-plcc -opal_reg.jed pal_reg.v * * The output file name (passed through the -o switch) can be * any file you desire. If the compilation and fitting all succeed, the * output file will be a JEDEC file that you can take to your favorite * PROM programmer to program the part. * * This source demonstrates some important principles of synthesizing * a design for a PLD, including how to specify synchronous logic, and * how to assign signals to pins. The pin assignment in particular is * part specific, and must be right for the fitting to succeed. */ /* * The register module is an 8 bit register that copies the input to * the output registers on the rising edge of the clk input. The * always statement creates a simple d-type flip-flop that is loaded * on the rising edge of the clock. * * The output drivers are controlled by a single active low output * enable. I used bufif0 devices in this example, but the exact same * thing can be achieved with a continuous assignment like so: * * assign out = oe? 8'hzz : Q; * * Many people prefer the expression form. It is true that it does * seem to express the intent a bit more clearly. */ module register (out, val, clk, oe); output [7:0] out; input [7:0] val; input clk, oe; reg [7:0] Q; wire [7:0] out; bufif0 drv[7:0](out, Q, oe); always @(posedge clk) Q = val; endmodule /* * The module pal is used to attach pin information to all the pins of * the device. We use this to lock down the pin assignments of the * synthesized result. The pin number assignments are for a 22v10 in * a PLCC package. * * Note that this module has no logic in it. It is a convention I use * that I put all the functionality in a separate module (seen above) * and isolate the Icarus Verilog specific $attribute madness into a * top-level module. The advantage of this style is that the entire * module can be `ifdef'ed out when doing simulation and you don't * need to worry that functionality will be affected. */ module pal; wire out7, out6, out5, out4, out3, out2, out1, out0; wire inp7, inp6, inp5, inp4, inp3, inp2, inp1, inp0; wire clk, oe; // The PAD attributes attach the wires to pins of the // device. Output pins are prefixed by a 'o', and input pins by an // 'i'. If not all the available output pins are used, then the // remaining are available for the synthesizer to drop internal // registers or extra logic layers. $attribute(out7, "PAD", "o27"); $attribute(out6, "PAD", "o26"); $attribute(out5, "PAD", "o25"); $attribute(out4, "PAD", "o24"); $attribute(out3, "PAD", "o23"); $attribute(out2, "PAD", "o21"); $attribute(out1, "PAD", "o20"); $attribute(out0, "PAD", "o19"); $attribute(inp7, "PAD", "i10"); $attribute(inp6, "PAD", "i9"); $attribute(inp5, "PAD", "i7"); $attribute(inp4, "PAD", "i6"); $attribute(inp3, "PAD", "i5"); $attribute(inp2, "PAD", "i4"); $attribute(inp1, "PAD", "i3"); $attribute(inp0, "PAD", "i2"); //$attribute(clk, "PAD", "CLK"); $attribute(oe, "PAD", "i13"); register dev({out7, out6, out5, out4, out3, out2, out1, out0}, {inp7, inp6, inp5, inp4, inp3, inp2, inp1, inp0}, clk, oe); endmodule // pal verilog-0.9.7/examples/PaxHeaders.14238/outff.v0000644000202500001440000000005012204466647017360 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/outff.v0000644000202500001440000000541212204466647016704 0ustar00steveusers00000000000000/* * Copyright (c) 1998-1999 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * IVL should generate an AND gate, and should make an OBUF and two * IBUF objects, along with the PAD objects. * * To compile this for XNF, try a command like this: * * iverilog -txnf -ppart=XC4010XLPQ160 -ooutff.xnf -pncf=outff.ncf outff.v * * That command causes an outff.xnf and outff.ncf file to be created. * Next, make the outff.ngd file with the command: * * xnf2ngd -l xilinxun -u outff.xnf outff.ngo * ngdbuild outff.ngo outff.ngd * * Finally, map the file to fully render it in the target part. The * par command is the step that actually optimizes the design and tries * to meet timing constraints. * * map -o map.ncd outff.ngd * par -w map.ncd outff.ncd * * At this point, you can use the FPGA Editor to edit the outff.ncd * file to see that the AND gate is in a CLB and the IOB for pin 150 * has its flip-flop in use, and that gbuf is a global buffer. */ module main; wire clk, iclk; wire i0, i1; wire out; reg o0; // This simple logic gate get turned into a function unit. // The par program will map this into a CLB F or G unit. and (out, i0, i1); // This creates a global clock buffer. Notice how I attach an // attribute to the named gate to force it to be mapped to the // desired XNF device. This device will not be pulled into the // IOB associated with iclk because of the attribute. buf gbuf(clk, iclk); $attribute(gbuf, "XNF-LCA", "GCLK:O,I"); // This is mapped to a DFF. Since o0 is connected to a PAD, it // is turned into a OUTFF so that it get placed into an IOB. always @(posedge clk) o0 = out; // These attribute commands assign pins to the listed wires. // This can be done to wires and registers, as internally both // are treated as named signals. $attribute(o0, "PAD", "o150"); $attribute(i0, "PAD", "i152"); $attribute(i1, "PAD", "i153"); $attribute(iclk,"PAD", "i154"); endmodule /* main */ verilog-0.9.7/examples/PaxHeaders.14238/sqrt.vl0000644000202500001440000000005012204466647017402 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/sqrt.vl0000644000202500001440000000766012204466647016735 0ustar00steveusers00000000000000/* * Copyright (c) 1999 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * $Id: sqrt.vl,v 1.5 2007/03/22 16:08:18 steve Exp $" */ /* * This example shows that Icarus Verilog can run non-trivial * programs, too. This uses a variety of Verilog language features * to implement the module of a square-root device. The program * uses IEEE1364-1995 language features and should work correctly * on any Verilog compiler. * * Run the file with Icarus Verilog under UNIX using the command: * * % iverilog -osqrt sqrt.v * % ./sqrt */ /* * This module approximates the square root of an unsigned 32bit * number. The algorithm works by doing a bit-wise binary search. * Starting from the most significant bit, the accumulated value * tries to put a 1 in the bit position. If that makes the square * to big for the input, the bit is left zero, otherwise it is set * in the result. This continues for each bit, decreasing in * significance, until all the bits are calculated or all the * remaining bits are zero. * * Since the result is an integer, this function really calculates * value of the expression: * * x = floor(sqrt(y)) * * where sqrt(y) is the exact square root of y and floor(N) is the * largest integer <= N. * * For 32 bit numbers, this will never run more than 16 iterations, * which amounts to 16 clocks. */ module sqrt32(clk, rdy, reset, x, .y(acc)); input clk; output rdy; input reset; input [31:0] x; output [15:0] acc; // acc holds the accumulated result, and acc2 is the accumulated // square of the accumulated result. reg [15:0] acc; reg [31:0] acc2; // Keep track of which bit I'm working on. reg [4:0] bitl; wire [15:0] bit = 1 << bitl; wire [31:0] bit2 = 1 << (bitl << 1); // The output is ready when the bitl counter underflows. wire rdy = bitl[4]; // guess holds the potential next values for acc, and guess2 holds // the square of that guess. The guess2 calculation is a little bit // subtle. The idea is that: // // guess2 = (acc + bit) * (acc + bit) // = (acc * acc) + 2*acc*bit + bit*bit // = acc2 + 2*acc*bit + bit2 // = acc2 + 2 * (acc< %d", value, result); $finish; end initial begin clk = 0; reset = 1; $monitor($time,,"%m.acc = %b", root.acc); #100 value = 63; reset = 0; end endmodule /* main */ verilog-0.9.7/examples/PaxHeaders.14238/hello_vpi.c0000644000202500001440000000005012204466647020173 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/hello_vpi.c0000644000202500001440000000447112204466647017523 0ustar00steveusers00000000000000/* * Copyright (c) 2002 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: hello_vpi.c,v 1.5 2007/01/17 05:35:48 steve Exp $" #endif /* * This file contains an example VPI module to demonstrate the tools * to create vpi modules. To compile this module, use the iverilog-vpi * command like so: * * iverilog-vpi hello_vpi.c * * The result is the hello_vpi.vpi module. See the hello_vpi.vl * program for example Verilog code to call this module. */ # include static PLI_INT32 my_hello_calltf(char *xx) { vpi_printf("Hello World, from VPI.\n"); return 0; } static void my_hello_register() { s_vpi_systf_data tf_data; tf_data.type = vpiSysTask; tf_data.tfname = "$my_hello"; tf_data.calltf = my_hello_calltf; tf_data.compiletf = 0; tf_data.sizetf = 0; vpi_register_systf(&tf_data); } /* * This is a table of register functions. This table is the external * symbol that the simulator looks for when loading this .vpi module. */ void (*vlog_startup_routines[])() = { my_hello_register, 0 }; /* * $Log: hello_vpi.c,v $ * Revision 1.5 2007/01/17 05:35:48 steve * Fix typo is hello_vpi.c example. * * Revision 1.4 2006/10/30 22:46:25 steve * Updates for Cygwin portability (pr1585922) * * Revision 1.3 2002/08/12 01:35:01 steve * conditional ident string using autoconfig. * * Revision 1.2 2002/08/11 23:47:04 steve * Add missing Log and Ident strings. * * Revision 1.1 2002/04/18 03:25:16 steve * More examples. * */ verilog-0.9.7/examples/PaxHeaders.14238/show_vcd.vl0000644000202500001440000000005012204466647020225 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/show_vcd.vl0000644000202500001440000000750712204466647017560 0ustar00steveusers00000000000000/* * Copyright (c) 1999 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * This example program simulates a 16x1 ram, and is used as an * example for using VCD output and waveform viewers. * * Like any other Verilog simulation, compile this program with the * command: * * iverilog show_vcd.vl * * This will generate the show_vcd command in the current directory. * When you run the command, you will see the output from all the * calls to $display, but also there will be a dump file ``show_vcd.vcd''. * The name of this file is set by the statement: * * $dumpfile("show_vcd.vcd"); * * in the main module. The output file uses the standard VCD file format * so can be viewed using off-the-shelf waveform viewers. The remaining * steps describe how to use GTKWave to view the file. If you are using * a different viewer, see the documentation for that tool. * * To view the output generated by running show_vcd, start the GTKWave * viewer with the command: * * gtkwave show_vcd.vcd * * The GTKWave program will display its main window, and show in a small * status box (upper left corner) that it succeeded in loading the dump * file. However, there are no waveforms displayed yet. Select signals to * add to the waveform display using the menu selection: * * "Search --> Signal Search Tree" * * This will bring up a dialog box that shows in directory tree format * the signals of the program. Select the signals you wish to view, and * click one of the buttons on the bottom of the dialog box to display * the selected signals in the waveform window. Click "Exit" on the box * to get rid of it. * * The magic that makes all this work is contained in the $dumpfile and * $dumpvars system tasks. The $dumpfile task tells the simulation where * to write the VCD output. This task must be called once before the * $dumpvars task is called. * * The $dumpvars task tells the simulation what variables to write to * the VCD output. The first parameter is how far to descend while * scanning a scope, and the remaining parameters are signals or scope * names to include in the dump. If a scope name is given, all the * signals within the scope are dumped. If a wire or register name is * given, that signal is included. */ module ram16x1 (q, d, a, we, wclk); output q; input d; input [3:0] a; input we; input wclk; reg mem[15:0]; assign q = mem[a]; always @(posedge wclk) if (we) mem[a] = d; endmodule /* ram16x1 */ module main; wire q; reg d; reg [3:0] a; reg we, wclk; ram16x1 r1 (q, d, a, we, wclk); initial begin $dumpfile("show_vcd.vcd"); $dumpvars(1, main.r1); wclk = 0; we = 1; for (a = 0 ; a < 4'hf ; a = a + 1) begin d = a[0]; #1 wclk = 1; #1 wclk = 0; $display("r1[%x] == %b", a, q); end for (a = 0 ; a < 4'hf ; a = a + 1) #1 if (q !== a[0]) begin $display("FAILED -- mem[%h] !== %b", a, a[0]); $finish; end $display("PASSED"); end endmodule /* main */ verilog-0.9.7/examples/PaxHeaders.14238/clbff.v0000644000202500001440000000005012204466647017311 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/clbff.v0000644000202500001440000000645312204466647016643 0ustar00steveusers00000000000000/* * Copyright (c) 2000 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * This source file demonstrates how to synthesize CLB flip-flops from * Icarus Verilog, including giving the device an initial value. * * To compile this for XNF, try a command like this: * * iverilog -txnf -ppart=XC4010XLPQ160 -pncf=clbff.ncf -oclbff.xnf clbff.v * * That command causes an clbff.xnf and clbff.ncf file to be created. * Next, make the clbff.ngd file with the command: * * xnf2ngd -l xilinxun -u clbff.xnf clbff.ngo * ngdbuild clbff.ngo clbff.ngd * * Finally, map the file to fully render it in the target part. The * par command is the step that actually optimizes the design and tries * to meet timing constraints. * * map -o map.ncd clbff.ngd * par -w map.ncd clbff.ncd * * At this point, you can use the FPGA Editor to edit the clbff.ncd * file. Notice that the design uses two CLB flip-flops (possibly in * the same CLB) with their outputs ANDed together. If you go into the * block editor, you will see that the FF connected to main/Q<0> is * configured so start up reset, and the FF connected to main/Q<1> is * configured to start up set. */ module main; wire clk, iclk; wire i0, i1; wire out; wire [1:0] D = {i1, i0}; // This statement declares Q to be a 2 bit reg vector. The // initial assignment will cause the synthesized device to take // on an initial value specified here. Without the assignment, // the initial value is unspecified. (Verilog simulates it as 2'bx.) reg [1:0] Q = 2'b10; // This simple logic gate get turned into a function unit. // The par program will map this into a CLB F or G unit. and (out, Q[0], Q[1]); // This creates a global clock buffer. Notice how I attach an // attribute to the named gate to force it to be mapped to the // desired XNF device. This device will not be pulled into the // IOB associated with iclk because of the attribute. buf gbuf(clk, iclk); $attribute(gbuf, "XNF-LCA", "GCLK:O,I"); // This is mapped to a DFF. Since Q and D are two bits wide, the // code generator actually makes two DFF devices that share a // clock input. always @(posedge clk) Q <= D; // These attribute commands assign pins to the listed wires. // This can be done to wires and registers, as internally both // are treated as named signals. $attribute(out, "PAD", "o150"); $attribute(i0, "PAD", "i152"); $attribute(i1, "PAD", "i153"); $attribute(iclk,"PAD", "i154"); endmodule /* main */ verilog-0.9.7/examples/PaxHeaders.14238/hello.vl0000644000202500001440000000005012204466647017514 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/hello.vl0000644000202500001440000000314012204466647017034 0ustar00steveusers00000000000000/* * Copyright (c) 1998 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * Here we have the canonical "Hello, World" program written in Verilog. * We simply print to the program output a simple message. This example * demonstrates the process of compiling and executing a program with * Icarus Verilog. * * Compile this program with the command: * * iverilog -ohello hello.vl * * After churning for a little while, the program will create the output * file "hello" which is compiled, linked and ready to run. Run this * program like so: * * vvp hello * * and the program will print the message to its output. Easy! For * more on how to make the iverilog command work, see the iverilog * manual page. */ module main(); initial begin $display("Hello, World"); $finish ; end endmodule verilog-0.9.7/examples/PaxHeaders.14238/xnf_add.vl0000644000202500001440000000005012204466647020014 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/xnf_add.vl0000644000202500001440000000723112204466647017341 0ustar00steveusers00000000000000/* * Copyright (c) 1999 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * This example demonstrates Icarus Verilog's ability to synthesize * efficient adders for Xilinx 4000 series FPGAs. The synthesis and * code generation makes an adder and translates that into XOR gates * and fast carry chain hardware. * * To compile this for XNF, try a command like this: * * iverilog -txnf -ppart=XC4010XLPQ160 -pncf=xnf_add.ncf -oxnf_add.xnf xnf_add.v * * That command causes an xnf_add.xnf and xnf_add.ncf file to be created. * Next, Use Xilinx Alliance or Foundation tools to make the xnf_add.ngd * file with the command: * * xnf2ngd -l xilinxun -u xnf_add.xnf xnf_add.ngo * ngdbuild xnf_add.ngo xnf_add.ngd * * Finally, map the file to fully render it in the target part. The * par command is the step that actually optimizes the design and tries * to meet timing constraints. * * map -o map.ncd xnf_add.ngd * par -w map.ncd xnf_add.ncd * * At this point, you can use the Xilinx FPGA Editor to edit the xnf_add.ncd * file and see the carry chains made up to support the adder. */ module main; wire [3:0] a, b; wire [3:0] out; wire carry; wire a0, a1, a2, a3, b0, b1, b2, b3; wire out0, out1, out2, out3; // This creates the actual adder. Note that we also create a link // to the carry output. The principle adder is 4 bits wide, so two // IOBs are used to to the actual addition. PAR will place them in // order along carry lines. An extra carry cell from below a[0] is // used in FORCE-0 mode to load the bottom carry node. // // The carry signal from the top CY device is used to drive the // main.carry wire shown here. It is managed in this case by using // an ADD-FG-CI CY device for the top pair and using the CLB above // the carry chain, with its CY in EXAMINE-CI mode, to put the carry // out through its G function unit. assign {carry, out} = a + b; // These attribute commands assign pins to the listed wires. // This can be done to wires and registers, as internally both // are treated as named signals. It doesn't work (yet) on vectors, // though, so break out the vectors with scalar assignments. assign a[0] = a0; assign a[1] = a1; assign a[2] = a2; assign a[3] = a3; $attribute(a0, "PAD", "i150"); $attribute(a1, "PAD", "i152"); $attribute(a2, "PAD", "i153"); $attribute(a3, "PAD", "i154"); assign b[0] = b0; assign b[1] = b1; assign b[2] = b2; assign b[3] = b3; $attribute(b0, "PAD", "i155"); $attribute(b1, "PAD", "i156"); $attribute(b2, "PAD", "i157"); $attribute(b3, "PAD", "i158"); assign out0 = out[0]; assign out1 = out[1]; assign out2 = out[2]; assign out3 = out[3]; $attribute(out0, "PAD", "o71"); $attribute(out1, "PAD", "o72"); $attribute(out2, "PAD", "o73"); $attribute(out3, "PAD", "o74"); $attribute(carry, "PAD", "o75"); endmodule /* main */ verilog-0.9.7/examples/PaxHeaders.14238/xram16x1.v0000644000202500001440000000005012204466647017624 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/examples/xram16x1.v0000644000202500001440000000263412204466647017153 0ustar00steveusers00000000000000/* * Copyright (c) 1999 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ // This example describes a 16x1 RAM that can be synthesized into // a CLB ram in a Xilinx FPGA. module ram16x1 (q, d, a, we, wclk); output q; input d; input [3:0] a; input we; input wclk; reg mem[15:0]; assign q = mem[a]; always @(posedge wclk) if (we) mem[a] = d; endmodule /* ram16x1 */ module main; wire q; reg d; reg [3:0] a; reg we, wclk; ram16x1 r1 (q, d, a, we, wclk); initial begin $monitor("q = %b", q); d = 0; wclk = 0; a = 5; we = 1; #1 wclk = 1; #1 wclk = 0; end endmodule /* main */ verilog-0.9.7/PaxHeaders.14238/AStatement.cc0000644000202500001440000000005012204466647016604 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/AStatement.cc0000644000202500001440000000203612204466647016127 0ustar00steveusers00000000000000/* * Copyright (c) 2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "AStatement.h" AContrib::AContrib(PExpr*lv, PExpr*rv) : lval_(lv), rval_(rv) { } AContrib::~AContrib() { delete lval_; delete rval_; } AProcess::~AProcess() { } verilog-0.9.7/PaxHeaders.14238/net_nex_output.cc0000644000202500001440000000005012204466647017617 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/net_nex_output.cc0000644000202500001440000000632312204466647017145 0ustar00steveusers00000000000000/* * Copyright (c) 2002-2007 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include # include # include # include "netlist.h" # include "netmisc.h" void NetProc::nex_output(NexusSet&out) { cerr << get_fileline() << ": internal error: NetProc::nex_output not implemented" << endl; cerr << get_fileline() << ": : on object type " << typeid(*this).name() << endl; } /* * Assignments have as output all the bits of the concatenated signals * of the l-value. */ void NetAssignBase::nex_output(NexusSet&out) { for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) { if (NetNet*lsig = cur->sig()) { out.add(lsig->pin(0).nexus()); } else { /* Quoting from netlist.h comments for class NetMemory: * "This is not a node because memory objects can only be * accessed by behavioral code." */ cerr << get_fileline() << ": internal error: " << "NetAssignBase::nex_output on unsupported lval "; dump_lval(cerr); cerr << endl; } } } void NetBlock::nex_output(NexusSet&out) { if (last_ == 0) return; NetProc*cur = last_; do { cur = cur->next_; cur->nex_output(out); } while (cur != last_); } void NetCase::nex_output(NexusSet&out) { for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) { // Empty statements clearly have no output. if (items_[idx].statement == 0) continue; assert(items_[idx].statement); items_[idx].statement->nex_output(out); } } void NetCondit::nex_output(NexusSet&out) { if (if_ != 0) if_->nex_output(out); if (else_ != 0) else_->nex_output(out); } void NetEvWait::nex_output(NexusSet&out) { assert(statement_); statement_->nex_output(out); } void NetPDelay::nex_output(NexusSet&out) { if (statement_) statement_->nex_output(out); } /* * For the purposes of synthesis, system task calls have no output at * all. This is OK because most system tasks are not synthesizable in * the first place. */ void NetSTask::nex_output(NexusSet&out) { } /* * Consider a task call to not have any outputs. This is not quite * right, we should be listing as outputs all the output ports, but for * the purposes that this method is used, this will do for now. */ void NetUTask::nex_output(NexusSet&out) { } void NetWhile::nex_output(NexusSet&out) { if (proc_ != 0) proc_->nex_output(out); } verilog-0.9.7/PaxHeaders.14238/glossary.txt0000644000202500001440000000005012204466647016634 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/glossary.txt0000644000202500001440000000245512204466647016164 0ustar00steveusers00000000000000 Throughout Icarus Verilog descriptions and source code, I use a variety of terms and acronyms that might be specific to Icarus Verilog, have an Icarus Verilog specific meaning, or just aren't widely known. So here I define these terms. LRM - Language Reference Manual This is a generic acronym, but in the Verilog world we sometimes mean *the* language reference manual, the IEEE1364 standard. PLI - Programming Language Interface This is a C API into Verilog simulators that is defined by the IEEE1364. There are two major interfaces, sometimes called PLI 1 and PLI 2. PLI 2 is also often called VPI. UDP - User Defined Primitive These are objects that Verilog programmers define with the "primitive" keyword. They are truth-table based devices. The syntax for defining them is described in the LRM. VPI - This is the C API that is defined by the Verilog standard, and that Icarus Verilog partially implements. See also PLI. VVM - Verilog Virtual Machine This is the Icarus Verilog runtime that works with the code generator that generates C++. VVP - Verilog Virtual Processor This is the Icarus Verilog runtime that reads in custom code in a form that I call "VVP Assembly". See the vvp/ directory for documentation on that. verilog-0.9.7/PaxHeaders.14238/pform_analog.cc0000644000202500001440000000005012204466647017203 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/pform_analog.cc0000644000202500001440000000420512204466647016526 0ustar00steveusers00000000000000/* * Copyright (c) 2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include "compiler.h" # include "pform.h" # include "parse_misc.h" # include "AStatement.h" AContrib* pform_contribution_statement(const struct vlltype&loc, PExpr*lval, PExpr*rval) { AContrib*tmp = new AContrib(lval, rval); FILE_NAME(tmp, loc); return tmp; } void pform_make_analog_behavior(const struct vlltype&loc, ivl_process_type_t pt, Statement*statement) { AProcess*proc = new AProcess(pt, statement); FILE_NAME(proc, loc); pform_put_behavior_in_scope(proc); } PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, char*name, char*n1, char*n2) { vector parms (2); parms[0] = new PEIdent(lex_strings.make(n1)); FILE_NAME(parms[0], loc); parms[1] = new PEIdent(lex_strings.make(n2)); FILE_NAME(parms[1], loc); PECallFunction*res = new PECallFunction(lex_strings.make(name), parms); FILE_NAME(res, loc); return res; } PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, char*name, char*branch_name) { vector parms (1); parms[0] = new PEIdent(lex_strings.make(branch_name)); FILE_NAME(parms[0], loc); PECallFunction*res = new PECallFunction(lex_strings.make(name), parms); FILE_NAME(res, loc); return res; } verilog-0.9.7/PaxHeaders.14238/tgt-null0000644000202500001440000000005012204466647015721 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-null/0000755000202500001440000000000012204466647015320 5ustar00steveusers00000000000000verilog-0.9.7/tgt-null/PaxHeaders.14238/null-s.conf0000644000202500001440000000005012204466647020057 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-null/null-s.conf0000644000202500001440000000010112204466647017371 0ustar00steveusers00000000000000functor:synth2 functor:synth functor:syn-rules flag:DLL=null.tgt verilog-0.9.7/tgt-null/PaxHeaders.14238/null.conf0000644000202500001440000000005012204466647017617 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-null/null.conf0000644000202500001440000000002212204466647017133 0ustar00steveusers00000000000000flag:DLL=null.tgt verilog-0.9.7/tgt-null/PaxHeaders.14238/Makefile.in0000644000202500001440000000005012204466647020043 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-null/Makefile.in0000644000202500001440000000500712204466647017367 0ustar00steveusers00000000000000# # This source code is free software; you can redistribute it # and/or modify it in source code form under the terms of the GNU # Library General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # SHELL = /bin/sh suffix = @install_suffix@ prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ VPATH = $(srcdir) bindir = @bindir@ libdir = @libdir@ CC = @CC@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ CPPFLAGS = -I.. -I$(srcdir)/.. -I$(srcdir) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ all: dep null.tgt check: all dep: mkdir dep %.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep O = null.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl TGTDEPLIBS=../libivl.a else TGTLDFLAGS= TGTDEPLIBS= endif null.tgt: $O $(TGTDEPLIBS) $(CC) @shared@ -o $@ $O $(LDFLAGS) $(TGTLDFLAGS) clean: rm -rf *.o dep null.tgt distclean: clean rm -f Makefile config.log Makefile: $(srcdir)/Makefile.in ../config.status cd ..; ./config.status --file=tgt-null/$@ install: all installdirs $(libdir)/ivl$(suffix)/null.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/null.conf $(libdir)/ivl$(suffix)/null-s.conf $(libdir)/ivl$(suffix)/null.tgt: ./null.tgt $(INSTALL_PROGRAM) ./null.tgt "$(DESTDIR)$(libdir)/ivl$(suffix)/null.tgt" $(libdir)/ivl$(suffix)/null.conf: $(srcdir)/null.conf $(INSTALL_DATA) $(srcdir)/null.conf "$(DESTDIR)$(libdir)/ivl$(suffix)/null.conf" $(libdir)/ivl$(suffix)/null-s.conf: $(srcdir)/null-s.conf $(INSTALL_DATA) $(srcdir)/null-s.conf "$(DESTDIR)$(libdir)/ivl$(suffix)/null-s.conf" installdirs: $(srcdir)/../mkinstalldirs $(srcdir)/../mkinstalldirs "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)/ivl$(suffix)" uninstall: rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/null.tgt" rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/null.conf" rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/null-s.conf" -include $(patsubst %.o, dep/%.d, $O) verilog-0.9.7/tgt-null/PaxHeaders.14238/null.c0000644000202500001440000000005012204466647017114 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-null/null.c0000644000202500001440000000414512204466647016442 0ustar00steveusers00000000000000/* * Copyright (c) 2000-2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "version_base.h" # include "version_tag.h" # include "config.h" # include /* * This is a null target module. It does nothing. */ # include "ivl_target.h" static const char*version_string = "Icarus Verilog NULL Code Generator " VERSION " (" VERSION_TAG ")\n\n" "Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com)\n\n" " This program is free software; you can redistribute it and/or modify\n" " it under the terms of the GNU General Public License as published by\n" " the Free Software Foundation; either version 2 of the License, or\n" " (at your option) any later version.\n" "\n" " This program is distributed in the hope that it will be useful,\n" " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" " GNU General Public License for more details.\n" "\n" " You should have received a copy of the GNU General Public License along\n" " with this program; if not, write to the Free Software Foundation, Inc.,\n" " 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n" ; int target_design(ivl_design_t des) { return 0; } const char* target_query(const char*key) { if (strcmp(key,"version") == 0) return version_string; return 0; } verilog-0.9.7/PaxHeaders.14238/README.txt0000644000202500001440000000005012204466647015726 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/README.txt0000644000202500001440000004244712204466647015263 0ustar00steveusers00000000000000 THE ICARUS VERILOG COMPILATION SYSTEM Copyright 2000-2004 Stephen Williams 1.0 What is ICARUS Verilog? Icarus Verilog is intended to compile ALL of the Verilog HDL as described in the IEEE-1364 standard. Of course, it's not quite there yet. It does currently handle a mix of structural and behavioral constructs. For a view of the current state of Icarus Verilog, see its home page at . Icarus Verilog is not aimed at being a simulator in the traditional sense, but a compiler that generates code employed by back-end tools. For instructions on how to run Icarus Verilog, see the ``iverilog'' man page. 2.0 Building/Installing Icarus Verilog From Source If you are starting from source, the build process is designed to be as simple as practical. Someone basically familiar with the target system and C/C++ compilation should be able to build the source distribution with little effort. Some actual programming skills are not required, but helpful in case of problems. If you are building for Windows, see the mingw.txt file. 2.1 Compile Time Prerequisites You need the following software to compile Icarus Verilog from source on a UNIX-like system: - GNU Make The Makefiles use some GNU extensions, so a basic POSIX make will not work. Linux systems typically come with a satisfactory make. BSD based systems (i.e., NetBSD, FreeBSD) typically have GNU make as the gmake program. - ISO C++ Compiler The ivl and ivlpp programs are written in C++ and make use of templates and some of the standard C++ library. egcs and recent gcc compilers with the associated libstdc++ are known to work. MSVC++ 5 and 6 are known to definitely *not* work. - bison and flex - gperf 2.7 The lexical analyzer doesn't recognize keywords directly, but instead matches symbols and looks them up in a hash table in order to get the proper lexical code. The gperf program generates the lookup table. A version problem with this program is the most common cause of difficulty. See the Icarus Verilog FAQ. - readline 4.2 On Linux systems, this usually means the readline-devel rpm. In any case, it is the development headers of readline that are needed. - termcap The readline library in turn uses termcap. If you are building from CVS, you will also need software to generate the configure scripts. - autoconf 2.53 This generates configure scripts from configure.in. The 2.53 or later versions are known to work, autoconf 2.13 is reported to *not* work. 2.2 Compilation Unpack the tar-ball and cd into the verilog-######### directory (presumably that is how you got to this README) and compile the source with the commands: ./configure make Normally, this command automatically figures out everything it needs to know. It generally works pretty well. There are a few flags to the configure script that modify its behavior: --prefix= The default is /usr/local, which causes the tool suite to be compiled for install in /usr/local/bin, /usr/local/share/ivl, etc. I recommend that if you are configuring for precompiled binaries, use --prefix=/usr. On Solaris systems, it is common to use --prefix=/opt. You can configure for a non-root install with --prefix=$HOME. --enable-suffix --enable-suffix= --disable-suffix Enable/disable changing the names of install files to use a suffix string so that this version or install can co- exist with other versions. This renames the installed commands (iverilog, iverilog-vpi, vvp) and the installed library files and include directory so that installations with the same prefix but different suffix are guaranteed to not interfere with each other. 2.3 (Optional) Testing To run a simple test before installation, execute make check The commands printed by this run might help you in running Icarus Verilog on your own Verilog sources before the package is installed by root. 2.4 Installation Now install the files in an appropriate place. (The makefiles by default install in /usr/local unless you specify a different prefix with the --prefix= flag to the configure command.) You may need to do this as root to gain access to installation directories. make install 2.5 Uninstallation The generated Makefiles also include the uninstall target. This should remove all the files that ``make install'' creates. 3.0 How Icarus Verilog Works This tool includes a parser which reads in Verilog (plus extensions) and generates an internal netlist. The netlist is passed to various processing steps that transform the design to more optimal/practical forms, then is passed to a code generator for final output. The processing steps and the code generator are selected by command line switches. 3.1 Preprocessing There is a separate program, ivlpp, that does the preprocessing. This program implements the `include and `define directives producing output that is equivalent but without the directives. The output is a single file with line number directives, so that the actual compiler only sees a single input file. See ivlpp/ivlpp.txt for details. 3.2 Parse The Verilog compiler starts by parsing the Verilog source file. The output of the parse is a list of Module objects in "pform". The pform (see pform.h) is mostly a direct reflection of the compilation step. There may be dangling references, and it is not yet clear which module is the root. One can see a human readable version of the final pform by using the ``-P '' flag to the ``ivl'' subcommand. This will cause ivl to dump the pform into the file named . (Note that this is not normally done, unless debugging the ``ivl'' subcommand.) 3.3 Elaboration This phase takes the pform and generates a netlist. The driver selects (by user request or lucky guess) the root module to elaborate, resolves references and expands the instantiations to form the design netlist. (See netlist.txt.) Final semantic checks are performed during elaboration, and some simple optimizations are performed. The netlist includes all the behavioral descriptions, as well as gates and wires. The elaborate() function performs the elaboration. One can see a human readable version of the final, elaborated and optimized netlist by using the ``-N '' flag to the compiler. If elaboration succeeds, the final netlist (i.e., after optimizations but before code generation) will be dumped into the file named . Elaboration is actually performed in two steps: scopes and parameters first, followed by the structural and behavioral elaboration. 3.3.1 Scope Elaboration This pass scans through the pform looking for scopes and parameters. A tree of NetScope objects is built up and placed in the Design object, with the root module represented by the root NetScope object. The elab_scope.cc and elab_pexpr.cc files contain most of the code for handling this phase. The tail of the elaborate_scope behavior (after the pform is traversed) includes a scan of the NetScope tree to locate defparam assignments that were collected during scope elaboration. This is when the defparam overrides are applied to the parameters. 3.3.2 Netlist Elaboration After the scopes and parameters are generated and the NetScope tree fully formed, the elaboration runs through the pform again, this time generating the structural and behavioral netlist. Parameters are elaborated and evaluated by now so all the constants of code generation are now known locally, so the netlist can be generated by simply passing through the pform. 3.4 Optimization This is actually a collection of processing steps that perform optimizations that do not depend on the target technology. Examples of some useful transformations are - eliminate null effect circuitry - combinational reduction - constant propagation The actual functions performed are specified on the ivl command line by the -F flags (see below). 3.5 Code Generation This step takes the design netlist and uses it to drive the code generator (see target.h). This may require transforming the design to suit the technology. The emit() method of the Design class performs this step. It runs through the design elements, calling target functions as need arises to generate actual output. The user selects the target code generator with the -t flag on the command line. 3.6 ATTRIBUTES NOTE: The $attribute syntax will soon be deprecated in favor of the Verilog-2001 attribute syntax, which is cleaner and standardized. The parser accepts, as an extension to Verilog, the $attribute module item. The syntax of the $attribute item is: $attribute (, , ); The $attribute keyword looks like a system task invocation. The difference here is that the parameters are more restricted then those of a system task. The must be an identifier. This will be the item to get an attribute. The and are strings, not expressions, that give the key and the value of the attribute to be attached to the identified object. Attributes are [ ] pairs and are used to communicate with the various processing steps. See the documentation for the processing step for a list of the pertinent attributes. Attributes can also be applied to gate types. When this is done, the attribute is given to every instantiation of the primitive. The syntax for the attribute statement is the same, except that the names a primitive earlier in the compilation unit and the statement is placed in global scope, instead of within a module. The semicolon is not part of a type attribute. Note that attributes are also occasionally used for communication between processing steps. Processing steps that are aware of others may place attributes on netlist objects to communicate information to later steps. Icarus Verilog also accepts the Verilog 2001 syntax for attributes. They have the same general meaning as with the $attribute syntax, but they are attached to objects by position instead of by name. Also, the key is a Verilog identifier instead of a string. 4.0 Running iverilog The preferred way to invoke the compiler is with the iverilog(1) command. This program invokes the preprocessor (ivlpp) and the compiler (ivl) with the proper command line options to get the job done in a friendly way. See the iverilog(1) man page for usage details. 4.1 EXAMPLES Example: Compiling "hello.vl" ------------------------ hello.vl ---------------------------- module main(); initial begin $display("Hi there"); $finish ; end endmodule -------------------------------------------------------------- Ensure that "iverilog" is on your search path, and the vpi library is available. To compile the program: iverilog hello.vl (The above presumes that /usr/local/include and /usr/local/lib are part of the compiler search path, which is usually the case for gcc.) To run the program: ./a.out You can use the "-o" switch to name the output command to be generated by the compiler. See the iverilog(1) man page. 5.0 Unsupported Constructs Icarus Verilog is in development - as such it still only supports a (growing) subset of Verilog. Below is a description of some of the currently unsupported Verilog features. This list is not exhaustive, and does not account for errors in the compiler. See the Icarus Verilog web page for the current state of support for Verilog, and in particular, browse the bug report database for reported unsupported constructs. - System functions are supported, but the return value is a little tricky. See SYSTEM FUNCTION TABLE FILES in the iverilog man page. - Specify blocks are parsed but ignored in general. - trireg is not supported. tri0 and tri1 are supported. - tran primitives, i.e. tran, tranif1, tranif0, rtran, rtranif1 and rtranif0 are not supported. - Net delays, of the form "wire #N foo;" do not work. Delays in every other context do work properly, including the V2001 form "wire #5 foo = bar;" - Event controls inside non-blocking assignments are not supported. i.e.: a <= @(posedge clk) b; - Macro arguments are not supported. `define macros are supported, but they cannot take arguments. 5.1 Nonstandard Constructs or Behaviors Icarus Verilog includes some features that are not part of the IEEE1364 standard, but have well defined meaning, and also sometimes gives nonstandard (but extended) meanings to some features of the language that are defined. See the "extensions.txt" documentation for more details. $is_signed() This system function returns 1 if the expression contained is signed, or 0 otherwise. This is mostly of use for compiler regression tests. $sizeof() $bits() The $bits system function returns the size in bits of the expression that is its argument. The result of this function is undefined if the argument doesn't have a self-determined size. The $sizeof function is deprecated in favor of $bits, which is the same thing, but included in the SystemVerilog definition. $simtime The $simtime system function returns as a 64bit value the simulation time, unscaled by the time units of local scope. This is different from the $time and $stime functions which return the scaled times. This function is added for regression testing of the compiler and run time, but can be used by applications who really want the simulation time. Note that the simulation time can be confusing if there are lots of different `timescales within a design. It is not in general possible to predict what the simulation precision will turn out to be. $mti_random() $mti_dist_uniform These functions are similar to the IEEE1364 standard $random functions, but they use the Mersenne Twister (MT19937) algorithm. This is considered an excellent random number generator, but does not generate the same sequence as the standardized $random. Builtin system functions Certain of the system functions have well defined meanings, so can theoretically be evaluated at compile time, instead of using runtime VPI code. Doing so means that VPI cannot override the definitions of functions handled in this manner. On the other hand, this makes them synthesizable, and also allows for more aggressive constant propagation. The functions handled in this manner are: $bits $signed $sizeof $unsigned Implementations of these system functions in VPI modules will be ignored. Preprocessing Library Modules Icarus Verilog does preprocess modules that are loaded from libraries via the -y mechanism. However, the only macros defined during compilation of that file are those that it defines itself (or includes) or that are defined on the command line or command file. Specifically, macros defined in the non-library source files are not remembered when the library module is loaded. This is intentional. If it were otherwise, then compilation results might vary depending on the order that libraries are loaded, and that is too unpredictable. It is said that some commercial compilers do allow macro definitions to span library modules. That's just plain weird. Width in %t Time Formats Standard Verilog does not allow width fields in the %t formats of display strings. For example, this is illegal: $display("Time is %0t", %time); Standard Verilog instead relies on the $timeformat to completely specify the format. Icarus Verilog allows the programmer to specify the field width. The "%t" format in Icarus Verilog works exactly as it does in standard Verilog. However, if the programmer chooses to specify a minimum width (i.e., "%5t"), then for that display Icarus Verilog will override the $timeformat minimum width and use the explicit minimum width. vpiScope iterator on vpiScope objects. In the VPI, the normal way to iterate over vpiScope objects contained within a vpiScope object, is the vpiInternalScope iterator. Icarus Verilog adds support for the vpiScope iterator of a vpiScope object, that iterates over *everything* the is contained in the current scope. This is useful in cases where one wants to iterate over all the objects in a scope without iterating over all the contained types explicitly. time 0 race resolution. Combinational logic is routinely modeled using always blocks. However, this can lead to race conditions if the inputs to the combinational block are initialized in initial statements. Icarus Verilog slightly modifies time 0 scheduling by arranging for always statements with ANYEDGE sensitivity lists to be scheduled before any other threads. This causes combinational always blocks to be triggered when the values in the sensitivity list are initialized by initial threads. Nets with Types Icarus Verilog support an extension syntax that allows nets and regs to be explicitly typed. The currently supported types are logic, bool and real. This implies that "logic" and "bool" are new keywords. Typical syntax is: wire real foo = 1.0; reg logic bar, bat; ... and so forth. The syntax can be turned off by using the -g2 flag to iverilog, and turned on explicitly with the -g2x flag to iverilog. 6.0 CREDITS Except where otherwise noted, Icarus Verilog, ivl and ivlpp are Copyright Stephen Williams. The proper notices are in the head of each file. However, I have early on received aid in the form of fixes, Verilog guidance, and especially testing from many people. Testers in particular include a larger community of people interested in a GPL Verilog for Linux. verilog-0.9.7/PaxHeaders.14238/pform_types.cc0000644000202500001440000000005012204466647017106 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/pform_types.cc0000644000202500001440000000155612204466647016437 0ustar00steveusers00000000000000/* * Copyright (c) 2007-2008 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "pform_types.h" verilog-0.9.7/PaxHeaders.14238/swift.txt0000644000202500001440000000005012204466647016125 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/swift.txt0000644000202500001440000000453112204466647015452 0ustar00steveusers00000000000000 SWIFT MODEL SUPPORT FOR Icarus Verilog (PRELIMINARY) Copyright 2003 Stephen Williams NOTE: SWIFT support does not work yet, these are provisional instructions, intended to show what's supposed to happen when I get it working. Icarus Verilog support for SWIFT models is based on the LMTV interface module from Synopsys. This module is normally distributed along with the SWIFT models proper. This module can be linked with Icarus Verilog via the cadpli compatibility object. (See cadpli.txt.) * Preliminaries First, you need the LMC_HOME environment variable set to point to the installed directory for your SWIFT software. This setup is documented in your SWIFT model documentation. * Compilation When compiling your Verilog design to include a SWIFT model, you need to include wrappers for the model you intend to use. You may choose to use ncverilog or verilogxl compatible wrappers, they work the same. Locate your smartmodel directory, and include it in your command file like so: +libdir+.../smartmodel/sol/wrappers/verilogxl The wrappers directory includes Verilog modules that wrap your SWIFT module, and with this +libdir+ statement in your command file, the Icarus Verilog compiler will be able to locate these wrappers. The wrappers in turn invoke the $lm_model system tasks that are the LMTV support for your model. NOTE: This example uses the solaris directory of VerilogXL support files as a source of wrappers. The files of interest, however, are written in Verilog and are identical for all supported platforms, so long as you choose the verilogxl or ncverilog files. * Execution After your simulation is compiled, run the simulation with the vvp command, like this: % vvp -mcadpli a.out -cadpli=$LMC_HOME/lib/x86_linux.lib/swiftpli.so:swift_boot What this command line means is: -mcadpli Include the cadpli compatibility module a.out This is your compiled vvp file -cadpli=$LMC_HOME/lib/x86_linux.lib/swiftpli.so:swift_boot This tells the cadpli module to load the swiftpli.so shared object, and boot it. This is code that comes with your SWIFT modules, and provides the generic SWIFT capabilities (lm_* system tasks) needed by the module itself. Once you start the vvp command, the SWIFT infrastructure will be initialized as part of the simulation setup, and all should work normally from here. verilog-0.9.7/PaxHeaders.14238/util.h0000644000202500001440000000005012204466647015356 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/util.h0000644000202500001440000000264712204466647014711 0ustar00steveusers00000000000000#ifndef __util_H #define __util_H /* * Copyright (c) 2000-2004 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include # include "StringHeap.h" # include "verinum.h" class PExpr; class Design; class NetScope; /* * This file attempts to locate a module in a file. It operates by * looking for a plausible Verilog file to hold the module, and * invoking the parser to bring in that file's contents. */ extern bool load_module(const char*type); struct attrib_list_t { perm_string key; verinum val; }; extern attrib_list_t* evaluate_attributes(const map&att, unsigned&natt, Design*des, NetScope*scope); #endif verilog-0.9.7/PaxHeaders.14238/lexor_keyword.gperf0000644000202500001440000000005012204466647020152 xustar000000000000000020 atime=1376939566 20 ctime=1376939565 verilog-0.9.7/lexor_keyword.gperf0000644000202500001440000002004412204466647017474 0ustar00steveusers00000000000000%{ /* Command-line: gperf -o -i 1 -C -k 1-3,$ -L C -H keyword_hash -N check_identifier -tT lexor_keyword.gperf */ #include "config.h" #include "parse_misc.h" #include "parse.h" #include #include "lexor_keyword.h" #include "compiler.h" %} struct lexor_keyword { const char*name; int mask; int tokenType; }; %% abs, GN_KEYWORDS_VAMS_2_3, K_abs abstol, GN_KEYWORDS_VAMS_2_3, K_abstol access, GN_KEYWORDS_VAMS_2_3, K_access acos, GN_KEYWORDS_VAMS_2_3, K_acos acosh, GN_KEYWORDS_VAMS_2_3, K_acosh always, GN_KEYWORDS_1364_1995, K_always always_comb, GN_KEYWORDS_1800_2005, K_always_comb always_ff, GN_KEYWORDS_1800_2005, K_always_ff always_latch, GN_KEYWORDS_1800_2005, K_always_latch analog, GN_KEYWORDS_VAMS_2_3, K_analog and, GN_KEYWORDS_1364_1995, K_and asin, GN_KEYWORDS_VAMS_2_3, K_asin asinh, GN_KEYWORDS_VAMS_2_3, K_asinh assert, GN_KEYWORDS_1800_2005, K_assert assign, GN_KEYWORDS_1364_1995, K_assign atan, GN_KEYWORDS_VAMS_2_3, K_atan atan2, GN_KEYWORDS_VAMS_2_3, K_atan2 atanh, GN_KEYWORDS_VAMS_2_3, K_atanh automatic, GN_KEYWORDS_1364_2001, K_automatic begin, GN_KEYWORDS_1364_1995, K_begin bool, GN_KEYWORDS_ICARUS, K_bool buf, GN_KEYWORDS_1364_1995, K_buf bufif0, GN_KEYWORDS_1364_1995, K_bufif0 bufif1, GN_KEYWORDS_1364_1995, K_bufif1 case, GN_KEYWORDS_1364_1995, K_case casex, GN_KEYWORDS_1364_1995, K_casex casez, GN_KEYWORDS_1364_1995, K_casez ceil, GN_KEYWORDS_VAMS_2_3, K_ceil cell, GN_KEYWORDS_1364_2001_CONFIG, K_cell cmos, GN_KEYWORDS_1364_1995, K_cmos config, GN_KEYWORDS_1364_2001_CONFIG, K_config continuous, GN_KEYWORDS_VAMS_2_3, K_continuous cos, GN_KEYWORDS_VAMS_2_3, K_cos cosh, GN_KEYWORDS_VAMS_2_3, K_cosh ddt_nature, GN_KEYWORDS_VAMS_2_3, K_ddt_nature deassign, GN_KEYWORDS_1364_1995, K_deassign default, GN_KEYWORDS_1364_1995, K_default defparam, GN_KEYWORDS_1364_1995, K_defparam design, GN_KEYWORDS_1364_2001_CONFIG, K_design disable, GN_KEYWORDS_1364_1995, K_disable discipline, GN_KEYWORDS_VAMS_2_3, K_discipline discrete, GN_KEYWORDS_VAMS_2_3, K_discrete domain, GN_KEYWORDS_VAMS_2_3, K_domain edge, GN_KEYWORDS_1364_1995, K_edge else, GN_KEYWORDS_1364_1995, K_else end, GN_KEYWORDS_1364_1995, K_end endcase, GN_KEYWORDS_1364_1995, K_endcase endconfig, GN_KEYWORDS_1364_2001_CONFIG, K_endconfig enddiscipline, GN_KEYWORDS_VAMS_2_3, K_enddiscipline endfunction, GN_KEYWORDS_1364_1995, K_endfunction endgenerate, GN_KEYWORDS_1364_2001, K_endgenerate endmodule, GN_KEYWORDS_1364_1995, K_endmodule endnature, GN_KEYWORDS_VAMS_2_3, K_endnature endprimitive, GN_KEYWORDS_1364_1995, K_endprimitive endspecify, GN_KEYWORDS_1364_1995, K_endspecify endtable, GN_KEYWORDS_1364_1995, K_endtable endtask, GN_KEYWORDS_1364_1995, K_endtask event, GN_KEYWORDS_1364_1995, K_event exclude, GN_KEYWORDS_VAMS_2_3, K_exclude exp, GN_KEYWORDS_VAMS_2_3, K_exp floor, GN_KEYWORDS_VAMS_2_3, K_floor flow, GN_KEYWORDS_VAMS_2_3, K_flow for, GN_KEYWORDS_1364_1995, K_for force, GN_KEYWORDS_1364_1995, K_force forever, GN_KEYWORDS_1364_1995, K_forever fork, GN_KEYWORDS_1364_1995, K_fork from, GN_KEYWORDS_VAMS_2_3, K_from function, GN_KEYWORDS_1364_1995, K_function generate, GN_KEYWORDS_1364_2001, K_generate genvar, GN_KEYWORDS_1364_2001, K_genvar ground, GN_KEYWORDS_VAMS_2_3, K_ground highz0, GN_KEYWORDS_1364_1995, K_highz0 highz1, GN_KEYWORDS_1364_1995, K_highz1 hypot, GN_KEYWORDS_VAMS_2_3, K_hypot idt_nature, GN_KEYWORDS_VAMS_2_3, K_idt_nature if, GN_KEYWORDS_1364_1995, K_if ifnone, GN_KEYWORDS_1364_1995, K_ifnone incdir, GN_KEYWORDS_1364_2001_CONFIG, K_incdir include, GN_KEYWORDS_1364_2001_CONFIG, K_include inf, GN_KEYWORDS_VAMS_2_3, K_inf initial, GN_KEYWORDS_1364_1995, K_initial inout, GN_KEYWORDS_1364_1995, K_inout input, GN_KEYWORDS_1364_1995, K_input instance, GN_KEYWORDS_1364_2001_CONFIG, K_instance integer, GN_KEYWORDS_1364_1995, K_integer join, GN_KEYWORDS_1364_1995, K_join large, GN_KEYWORDS_1364_1995, K_large liblist, GN_KEYWORDS_1364_2001_CONFIG, K_liblist library, GN_KEYWORDS_1364_2001_CONFIG, K_library ln, GN_KEYWORDS_VAMS_2_3, K_ln localparam, GN_KEYWORDS_1364_2001, K_localparam log, GN_KEYWORDS_VAMS_2_3, K_log logic, GN_KEYWORDS_ICARUS, K_logic macromodule, GN_KEYWORDS_1364_1995, K_macromodule max, GN_KEYWORDS_VAMS_2_3, K_max medium, GN_KEYWORDS_1364_1995, K_medium min, GN_KEYWORDS_VAMS_2_3, K_min module, GN_KEYWORDS_1364_1995, K_module nand, GN_KEYWORDS_1364_1995, K_nand nature, GN_KEYWORDS_VAMS_2_3, K_nature negedge, GN_KEYWORDS_1364_1995, K_negedge nmos, GN_KEYWORDS_1364_1995, K_nmos nor, GN_KEYWORDS_1364_1995, K_nor noshowcancelled, GN_KEYWORDS_1364_2001, K_noshowcancelled not, GN_KEYWORDS_1364_1995, K_not notif0, GN_KEYWORDS_1364_1995, K_notif0 notif1, GN_KEYWORDS_1364_1995, K_notif1 or, GN_KEYWORDS_1364_1995, K_or output, GN_KEYWORDS_1364_1995, K_output parameter, GN_KEYWORDS_1364_1995, K_parameter pmos, GN_KEYWORDS_1364_1995, K_pmos posedge, GN_KEYWORDS_1364_1995, K_posedge potential, GN_KEYWORDS_VAMS_2_3, K_potential pow, GN_KEYWORDS_VAMS_2_3, K_pow primitive, GN_KEYWORDS_1364_1995, K_primitive pull0, GN_KEYWORDS_1364_1995, K_pull0 pull1, GN_KEYWORDS_1364_1995, K_pull1 pulldown, GN_KEYWORDS_1364_1995, K_pulldown pullup, GN_KEYWORDS_1364_1995, K_pullup pulsestyle_onevent, GN_KEYWORDS_1364_2001, K_pulsestyle_onevent pulsestyle_ondetect, GN_KEYWORDS_1364_2001, K_pulsestyle_ondetect rcmos, GN_KEYWORDS_1364_1995, K_rcmos real, GN_KEYWORDS_1364_1995, K_real realtime, GN_KEYWORDS_1364_1995, K_realtime reg, GN_KEYWORDS_1364_1995, K_reg release, GN_KEYWORDS_1364_1995, K_release repeat, GN_KEYWORDS_1364_1995, K_repeat rnmos, GN_KEYWORDS_1364_1995, K_rnmos rpmos, GN_KEYWORDS_1364_1995, K_rpmos rtran, GN_KEYWORDS_1364_1995, K_rtran rtranif0, GN_KEYWORDS_1364_1995, K_rtranif0 rtranif1, GN_KEYWORDS_1364_1995, K_rtranif1 scalared, GN_KEYWORDS_1364_1995, K_scalared showcancelled, GN_KEYWORDS_1364_2001, K_showcancelled signed, GN_KEYWORDS_1364_2001, K_signed sin, GN_KEYWORDS_VAMS_2_3, K_sin sinh, GN_KEYWORDS_VAMS_2_3, K_sinh small, GN_KEYWORDS_1364_1995, K_small specify, GN_KEYWORDS_1364_1995, K_specify specparam, GN_KEYWORDS_1364_1995, K_specparam sqrt, GN_KEYWORDS_VAMS_2_3, K_sqrt string, GN_KEYWORDS_VAMS_2_3, K_string strong0, GN_KEYWORDS_1364_1995, K_strong0 strong1, GN_KEYWORDS_1364_1995, K_strong1 supply0, GN_KEYWORDS_1364_1995, K_supply0 supply1, GN_KEYWORDS_1364_1995, K_supply1 table, GN_KEYWORDS_1364_1995, K_table tan, GN_KEYWORDS_VAMS_2_3, K_tan tanh, GN_KEYWORDS_VAMS_2_3, K_tanh task, GN_KEYWORDS_1364_1995, K_task time, GN_KEYWORDS_1364_1995, K_time tran, GN_KEYWORDS_1364_1995, K_tran tranif0, GN_KEYWORDS_1364_1995, K_tranif0 tranif1, GN_KEYWORDS_1364_1995, K_tranif1 tri, GN_KEYWORDS_1364_1995, K_tri tri0, GN_KEYWORDS_1364_1995, K_tri0 tri1, GN_KEYWORDS_1364_1995, K_tri1 triand, GN_KEYWORDS_1364_1995, K_triand trior, GN_KEYWORDS_1364_1995, K_trior trireg, GN_KEYWORDS_1364_1995, K_trireg units, GN_KEYWORDS_VAMS_2_3, K_units # Reserved for future use! unsigned, GN_KEYWORDS_1364_2001, K_unsigned use, GN_KEYWORDS_1364_2001_CONFIG, K_use uwire, GN_KEYWORDS_1364_2005, K_uwire vectored, GN_KEYWORDS_1364_1995, K_vectored wait, GN_KEYWORDS_1364_1995, K_wait wand, GN_KEYWORDS_1364_1995, K_wand weak0, GN_KEYWORDS_1364_1995, K_weak0 weak1, GN_KEYWORDS_1364_1995, K_weak1 while, GN_KEYWORDS_1364_1995, K_while wire, GN_KEYWORDS_1364_1995, K_wire # This is the name originally proposed for uwire and is deprecated! wone, GN_KEYWORDS_1364_2005, K_wone wor, GN_KEYWORDS_1364_1995, K_wor xnor, GN_KEYWORDS_1364_1995, K_xnor xor, GN_KEYWORDS_1364_1995, K_xor %% int lexor_keyword_mask = 0; int lexor_keyword_code(const char*str, unsigned nstr) { const struct lexor_keyword*rc = check_identifier(str, nstr); if (rc == 0) return IDENTIFIER; else if ((rc->mask & lexor_keyword_mask) == 0) return IDENTIFIER; else return rc->tokenType; } verilog-0.9.7/PaxHeaders.14238/solaris0000644000202500001440000000005012204466647015627 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/solaris/0000755000202500001440000000000012204466647015226 5ustar00steveusers00000000000000verilog-0.9.7/solaris/PaxHeaders.14238/pkginfo0000644000202500001440000000005012204466647017264 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/solaris/pkginfo0000644000202500001440000000027112204466647016606 0ustar00steveusers00000000000000PKG="IVLver" NAME="verilog" ARCH="sparc" VERSION="0.7" CATEGORY="application" VENDOR="Icarus.com" EMAIL="steve@icarus.com" PSTAMP="Stephen Williams" BASEDIR="/usr/local" CLASSES="none" verilog-0.9.7/solaris/PaxHeaders.14238/README-solaris_pkg.txt0000644000202500001440000000005012204466647021715 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/solaris/README-solaris_pkg.txt0000644000202500001440000000243312204466647021241 0ustar00steveusers00000000000000Notes about the solaris package. I. Installing a prebuilt solaris package ----------------------------------------- To install the solaris package do the following as root on your machine: 1) uncompress the package using: cp package_name.gz /tmp cd /tmp gunzip package_name.gz where "package_name.gz" is the compressed binary package. It will be named something like "verilog-0.3-SunOS-5.6-sparc.gz" 2) install the package using: cd /tmp pkgadd -d package_name this will install the package. The package will be registered under the name "IVLver" II. Uninstalling the solaris package ------------------------------------- To uninstall an installed solaris package do the following as root on your machine: pkgrm IVLver III. Notes on building a solaris package from sources ------------------------------------------------------ 1) build and install verilog. Be sure and pick where the package should install with the "--prefix=" argument to 'configure' 2) edit the 'pkginfo' file to update the version number and also set BASEDIR to the same as the argument to "--prefix=" 3) edit the 'prototype' file to add/removed files/directories from the list of installed components. 4) run the 'mksolpkg' script to create the solaris package verilog-0.9.7/solaris/PaxHeaders.14238/prototype0000644000202500001440000000005012204466647017674 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/solaris/prototype0000644000202500001440000000156012204466647017220 0ustar00steveusers00000000000000i pkginfo=./pkginfo d none bin 0755 bin bin f none bin/iverilog 0755 bin bin f none bin/iverilog-vpi 0755 bin bin f none bin/vvp 0755 bin bin d none include 0755 bin bin f none include/acc_user.h 0644 bin bin f none include/ivl_target.h 0644 bin bin f none include/veriuser.h 0644 bin bin f none include/vpi_user.h 0644 bin bin d none lib 0755 bin bin d none lib/ivl 0755 bin bin f none lib/ivl/fpga.tgt 0644 bin bin f none lib/ivl/iverilog.conf 0644 bin bin f none lib/ivl/ivl 0755 bin bin f none lib/ivl/ivlpp 0755 bin bin f none lib/ivl/null.tgt 0644 bin bin f none lib/ivl/system.vpi 0644 bin bin f none lib/ivl/vvp.tgt 0644 bin bin f none lib/libveriuser.a 0644 bin bin f none lib/libvpi.a 0644 bin bin d none man 0755 bin bin d none man/man1 0755 bin bin f none man/man1/iverilog.1 0644 bin bin f none man/man1/iverilog-vpi.1 0644 bin bin f none man/man1/vvp.1 0644 bin bin verilog-0.9.7/solaris/PaxHeaders.14238/mksolpkg0000644000202500001440000000005012204466647017456 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/solaris/mksolpkg0000755000202500001440000000205212204466647017002 0ustar00steveusers00000000000000#!/bin/sh # # mksolpkg # a script to generate a native solaris package # if [ `whoami` != "root" ]; then echo "you must be root to run this script" exit 1 fi # an ugly hack to get various bits of info ver=`grep VERSION pkginfo | sed 's/"/ /g' | awk '{print $2}'` basedir=`grep BASEDIR pkginfo | sed 's/"/ /g' | awk '{print $2}'` name=`grep NAME pkginfo | sed 's/"/ /g' | awk '{print $2}'` pkg=`grep PKG pkginfo | sed 's/"/ /g' | awk '{print $2}'` arch=`grep ARCH pkginfo | sed 's/"/ /g' | awk '{print $2}'` march=`uname -p` if [ "$arch" != "$march" ]; then echo "Warning: you have listed \"$arch\" in the pkginfo file but this machine" echo " has a \"$march\" processor" exit 1 fi oslabel=`uname -s`-`uname -r`-$march fname=$name-$ver-$oslabel cp -f prototype $basedir cp -f pkginfo $basedir cd $basedir pkgmk -o -r `pwd` cd /var/spool/pkg pkgtrans -s `pwd` /tmp/$fname all cd /tmp gzip -f $fname echo "Your $oslabel package is left in /tmp/$fname.gz" # cleanup rm -f $basedir/prototype $basedir/pkginfo rm -fr /var/spool/pkg/$pkg verilog-0.9.7/PaxHeaders.14238/tgt-fpga0000644000202500001440000000005012204466647015664 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/0000755000202500001440000000000012204466647015263 5ustar00steveusers00000000000000verilog-0.9.7/tgt-fpga/PaxHeaders.14238/fpga-s.conf0000644000202500001440000000005012204466647017765 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/fpga-s.conf0000644000202500001440000000014712204466647017311 0ustar00steveusers00000000000000functor:synth2 functor:synth functor:syn-rules functor:cprop functor:nodangle -t:dll flag:DLL=fpga.tgt verilog-0.9.7/tgt-fpga/PaxHeaders.14238/generic.c0000644000202500001440000000005012204466647017521 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/generic.c0000644000202500001440000000256412204466647017052 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: generic.c,v 1.3 2003/08/26 16:26:02 steve Exp $" #endif # include "generic.h" edif_t edf = 0; edif_xlibrary_t xlib = 0; edif_cell_t cell_0 = 0; edif_cell_t cell_1 = 0; edif_cell_t cell_ipad = 0; edif_cell_t cell_opad = 0; edif_cell_t cell_iopad = 0; /* * $Log: generic.c,v $ * Revision 1.3 2003/08/26 16:26:02 steve * ifdef idents correctly. * * Revision 1.2 2003/07/03 17:46:33 steve * IOPAD support. * * Revision 1.1 2003/06/25 02:55:57 steve * Virtex and Virtex2 share much code. * */ verilog-0.9.7/tgt-fpga/PaxHeaders.14238/d-lpm.c0000644000202500001440000000005012204466647017116 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/d-lpm.c0000644000202500001440000006027112204466647016446 0ustar00steveusers00000000000000/* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: d-lpm.c,v 1.12 2004/10/04 01:10:56 steve Exp $" #endif /* * This is the driver for a purely generic LPM module writer. This * uses LPM version 2 1 0 devices, without particularly considering * the target technology. * * The LPM standard is EIA-IS/103-A October 1996 * The output is EDIF 2 0 0 format. */ # include "device.h" # include "fpga_priv.h" # include "edif.h" # include "generic.h" # include # include static edif_cell_t lpm_cell_buf(void) { static edif_cell_t tmp = 0; if (tmp != 0) return tmp; tmp = edif_xcell_create(xlib, "BUF", 2); edif_cell_portconfig(tmp, 0, "Result", IVL_SIP_OUTPUT); edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT); /* A buffer is an inverted inverter. */ edif_cell_port_pstring(tmp, 0, "LPM_Polarity", "INVERT"); edif_cell_pstring(tmp, "LPM_TYPE", "LPM_INV"); edif_cell_pinteger(tmp, "LPM_Width", 1); edif_cell_pinteger(tmp, "LPM_Size", 1); return tmp; } static edif_cell_t lpm_cell_inv(void) { static edif_cell_t tmp = 0; if (tmp != 0) return tmp; tmp = edif_xcell_create(xlib, "INV", 2); edif_cell_portconfig(tmp, 0, "Result", IVL_SIP_OUTPUT); edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT); edif_cell_pstring(tmp, "LPM_TYPE", "LPM_INV"); edif_cell_pinteger(tmp, "LPM_Width", 1); edif_cell_pinteger(tmp, "LPM_Size", 1); return tmp; } static edif_cell_t lpm_cell_bufif0(void) { static edif_cell_t tmp = 0; if (tmp != 0) return tmp; tmp = edif_xcell_create(xlib, "BUFIF1", 3); edif_cell_portconfig(tmp, 0, "TriData", IVL_SIP_OUTPUT); edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT); edif_cell_portconfig(tmp, 2, "EnableDT", IVL_SIP_INPUT); edif_cell_port_pstring(tmp, 2, "LPM_Polarity", "INVERT"); edif_cell_pstring(tmp, "LPM_TYPE", "LPM_BUSTRI"); edif_cell_pinteger(tmp, "LPM_Width", 1); return tmp; } static edif_cell_t lpm_cell_bufif1(void) { static edif_cell_t tmp = 0; if (tmp != 0) return tmp; tmp = edif_xcell_create(xlib, "BUFIF1", 3); edif_cell_portconfig(tmp, 0, "TriData", IVL_SIP_OUTPUT); edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT); edif_cell_portconfig(tmp, 2, "EnableDT", IVL_SIP_INPUT); edif_cell_pstring(tmp, "LPM_TYPE", "LPM_BUSTRI"); edif_cell_pinteger(tmp, "LPM_Width", 1); return tmp; } static edif_cell_t lpm_cell_or(unsigned siz) { unsigned idx; edif_cell_t cell; char name[32]; sprintf(name, "or%u", siz); cell = edif_xlibrary_findcell(xlib, name); if (cell != 0) return cell; cell = edif_xcell_create(xlib, strdup(name), siz+1); edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT); for (idx = 0 ; idx < siz ; idx += 1) { sprintf(name, "Data%ux0", idx); edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT); } edif_cell_pstring(cell, "LPM_TYPE", "LPM_OR"); edif_cell_pinteger(cell, "LPM_Width", 1); edif_cell_pinteger(cell, "LPM_Size", siz); return cell; } static edif_cell_t lpm_cell_and(unsigned siz) { unsigned idx; edif_cell_t cell; char name[32]; sprintf(name, "and%u", siz); cell = edif_xlibrary_findcell(xlib, name); if (cell != 0) return cell; cell = edif_xcell_create(xlib, strdup(name), siz+1); edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT); for (idx = 0 ; idx < siz ; idx += 1) { sprintf(name, "Data%ux0", idx); edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT); } edif_cell_pstring(cell, "LPM_TYPE", "LPM_AND"); edif_cell_pinteger(cell, "LPM_Width", 1); edif_cell_pinteger(cell, "LPM_Size", siz); return cell; } static edif_cell_t lpm_cell_xor(unsigned siz) { unsigned idx; edif_cell_t cell; char name[32]; sprintf(name, "xor%u", siz); cell = edif_xlibrary_findcell(xlib, name); if (cell != 0) return cell; cell = edif_xcell_create(xlib, strdup(name), siz+1); edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT); for (idx = 0 ; idx < siz ; idx += 1) { sprintf(name, "Data%ux0", idx); edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT); } edif_cell_pstring(cell, "LPM_TYPE", "LPM_XOR"); edif_cell_pinteger(cell, "LPM_Width", 1); edif_cell_pinteger(cell, "LPM_Size", siz); return cell; } static edif_cell_t lpm_cell_nor(unsigned siz) { unsigned idx; edif_cell_t cell; char name[32]; sprintf(name, "nor%u", siz); cell = edif_xlibrary_findcell(xlib, name); if (cell != 0) return cell; cell = edif_xcell_create(xlib, strdup(name), siz+1); edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT); edif_cell_port_pstring(cell, 0, "LPM_Polarity", "INVERT"); for (idx = 0 ; idx < siz ; idx += 1) { sprintf(name, "Data%ux0", idx); edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT); } edif_cell_pstring(cell, "LPM_TYPE", "LPM_OR"); edif_cell_pinteger(cell, "LPM_Width", 1); edif_cell_pinteger(cell, "LPM_Size", siz); return cell; } static void lpm_show_header(ivl_design_t des) { unsigned idx; ivl_scope_t root = ivl_design_root(des); unsigned sig_cnt = ivl_scope_sigs(root); unsigned nports = 0, pidx; /* Count the ports I'm going to use. */ for (idx = 0 ; idx < sig_cnt ; idx += 1) { ivl_signal_t sig = ivl_scope_sig(root, idx); if (ivl_signal_port(sig) == IVL_SIP_NONE) continue; if (ivl_signal_attr(sig, "PAD") != 0) continue; nports += ivl_signal_pins(sig); } /* Create the base edf object. */ edf = edif_create(ivl_scope_basename(root), nports); pidx = 0; for (idx = 0 ; idx < sig_cnt ; idx += 1) { edif_joint_t jnt; ivl_signal_t sig = ivl_scope_sig(root, idx); if (ivl_signal_port(sig) == IVL_SIP_NONE) continue; if (ivl_signal_attr(sig, "PAD") != 0) continue; if (ivl_signal_pins(sig) == 1) { edif_portconfig(edf, pidx, ivl_signal_basename(sig), ivl_signal_port(sig)); assert(ivl_signal_pins(sig) == 1); jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, 0)); edif_port_to_joint(jnt, edf, pidx); } else { const char*name = ivl_signal_basename(sig); ivl_signal_port_t dir = ivl_signal_port(sig); char buf[128]; unsigned bit; for (bit = 0 ; bit < ivl_signal_pins(sig) ; bit += 1) { const char*tmp; sprintf(buf, "%s[%u]", name, bit); tmp = strdup(buf); edif_portconfig(edf, pidx+bit, tmp, dir); jnt = edif_joint_of_nexus(edf,ivl_signal_pin(sig,bit)); edif_port_to_joint(jnt, edf, pidx+bit); } } pidx += ivl_signal_pins(sig); } assert(pidx == nports); xlib = edif_xlibrary_create(edf, "LPM_LIBRARY"); } static void lpm_show_footer(ivl_design_t des) { edif_print(xnf, edf); } static void hookup_logic_gate(ivl_net_logic_t net, edif_cell_t cell) { unsigned pin, idx; edif_joint_t jnt; edif_cellref_t ref = edif_cellref_create(edf, cell); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); pin = edif_cell_port_byname(cell, "Result0"); edif_add_to_joint(jnt, ref, pin); for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { char name[32]; jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx)); sprintf(name, "Data%ux0", idx-1); pin = edif_cell_port_byname(cell, name); edif_add_to_joint(jnt, ref, pin); } } static void lpm_logic(ivl_net_logic_t net) { edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; switch (ivl_logic_type(net)) { case IVL_LO_BUFZ: case IVL_LO_BUF: assert(ivl_logic_pins(net) == 2); cell = lpm_cell_buf(); ref = edif_cellref_create(edf, cell); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, ref, 0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, ref, 1); break; case IVL_LO_BUFIF0: assert(ivl_logic_pins(net) == 3); cell = lpm_cell_bufif0(); ref = edif_cellref_create(edf, cell); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, ref, 0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, ref, 1); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2)); edif_add_to_joint(jnt, ref, 2); break; case IVL_LO_BUFIF1: assert(ivl_logic_pins(net) == 3); cell = lpm_cell_bufif1(); ref = edif_cellref_create(edf, cell); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, ref, 0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, ref, 1); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2)); edif_add_to_joint(jnt, ref, 2); break; case IVL_LO_NOT: assert(ivl_logic_pins(net) == 2); cell = lpm_cell_inv(); ref = edif_cellref_create(edf, cell); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, ref, 0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, ref, 1); break; case IVL_LO_OR: cell = lpm_cell_or(ivl_logic_pins(net)-1); hookup_logic_gate(net, cell); break; case IVL_LO_NOR: cell = lpm_cell_nor(ivl_logic_pins(net)-1); hookup_logic_gate(net, cell); break; case IVL_LO_AND: cell = lpm_cell_and(ivl_logic_pins(net)-1); hookup_logic_gate( net, cell); break; case IVL_LO_XOR: cell = lpm_cell_xor(ivl_logic_pins(net)-1); hookup_logic_gate( net, cell); break; default: fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n", ivl_logic_type(net)); break; } } static void lpm_show_dff(ivl_lpm_t net) { char name[64]; edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; unsigned idx; unsigned pin, wid = ivl_lpm_width(net); sprintf(name, "fd%s%s%s%s%s%u", ivl_lpm_enable(net)? "ce" : "", ivl_lpm_async_clr(net)? "cl" : "", ivl_lpm_sync_clr(net)? "sc" : "", ivl_lpm_async_set(net)? "se" : "", ivl_lpm_sync_set(net)? "ss" : "", wid); cell = edif_xlibrary_findcell(xlib, name); if (cell == 0) { unsigned nports = 2 * wid + 1; pin = 0; if (ivl_lpm_enable(net)) nports += 1; if (ivl_lpm_async_clr(net)) nports += 1; if (ivl_lpm_sync_clr(net)) nports += 1; if (ivl_lpm_async_set(net)) nports += 1; if (ivl_lpm_sync_set(net)) nports += 1; cell = edif_xcell_create(xlib, strdup(name), nports); edif_cell_pstring(cell, "LPM_Type", "LPM_FF"); edif_cell_pinteger(cell, "LPM_Width", wid); for (idx = 0 ; idx < wid ; idx += 1) { sprintf(name, "Q%u", idx); edif_cell_portconfig(cell, idx*2+0, strdup(name), IVL_SIP_OUTPUT); sprintf(name, "Data%u", idx); edif_cell_portconfig(cell, idx*2+1, strdup(name), IVL_SIP_INPUT); } pin = wid*2; if (ivl_lpm_enable(net)) { edif_cell_portconfig(cell, pin, "Enable", IVL_SIP_INPUT); pin += 1; } if (ivl_lpm_async_clr(net)) { edif_cell_portconfig(cell, pin, "Aclr", IVL_SIP_INPUT); pin += 1; } if (ivl_lpm_sync_clr(net)) { edif_cell_portconfig(cell, pin, "Sclr", IVL_SIP_INPUT); pin += 1; } if (ivl_lpm_async_set(net)) { edif_cell_portconfig(cell, pin, "Aset", IVL_SIP_INPUT); pin += 1; } if (ivl_lpm_sync_set(net)) { edif_cell_portconfig(cell, pin, "Sset", IVL_SIP_INPUT); pin += 1; } edif_cell_portconfig(cell, pin, "Clock", IVL_SIP_INPUT); pin += 1; assert(pin == nports); } ref = edif_cellref_create(edf, cell); pin = edif_cell_port_byname(cell, "Clock"); jnt = edif_joint_of_nexus(edf, ivl_lpm_clk(net)); edif_add_to_joint(jnt, ref, pin); if (ivl_lpm_enable(net)) { pin = edif_cell_port_byname(cell, "Enable"); jnt = edif_joint_of_nexus(edf, ivl_lpm_enable(net)); edif_add_to_joint(jnt, ref, pin); } if (ivl_lpm_async_clr(net)) { pin = edif_cell_port_byname(cell, "Aclr"); jnt = edif_joint_of_nexus(edf, ivl_lpm_async_clr(net)); edif_add_to_joint(jnt, ref, pin); } if (ivl_lpm_sync_clr(net)) { pin = edif_cell_port_byname(cell, "Sclr"); jnt = edif_joint_of_nexus(edf, ivl_lpm_sync_clr(net)); edif_add_to_joint(jnt, ref, pin); } if (ivl_lpm_async_set(net)) { pin = edif_cell_port_byname(cell, "Aset"); jnt = edif_joint_of_nexus(edf, ivl_lpm_async_set(net)); edif_add_to_joint(jnt, ref, pin); } if (ivl_lpm_sync_set(net)) { ivl_expr_t svalue = ivl_lpm_sset_value(net); pin = edif_cell_port_byname(cell, "Sset"); jnt = edif_joint_of_nexus(edf, ivl_lpm_sync_set(net)); edif_add_to_joint(jnt, ref, pin); edif_cellref_pinteger(ref, "LPM_Svalue", ivl_expr_uvalue(svalue)); } for (idx = 0 ; idx < wid ; idx += 1) { sprintf(name, "Q%u", idx); pin = edif_cell_port_byname(cell, name); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, ref, pin); sprintf(name, "Data%u", idx); pin = edif_cell_port_byname(cell, name); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, ref, pin); } } static void lpm_show_mux(ivl_lpm_t net) { edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; unsigned idx, rdx; char cellname[32]; unsigned wid_r = ivl_lpm_width(net); unsigned wid_s = ivl_lpm_selects(net); unsigned wid_z = ivl_lpm_size(net); sprintf(cellname, "mux%u_%u_%u", wid_r, wid_s, wid_z); cell = edif_xlibrary_findcell(xlib, cellname); if (cell == 0) { unsigned pins = wid_r + wid_s + wid_r*wid_z; cell = edif_xcell_create(xlib, strdup(cellname), pins); /* Make the output ports. */ for (idx = 0 ; idx < wid_r ; idx += 1) { sprintf(cellname, "Result%u", idx); edif_cell_portconfig(cell, idx, strdup(cellname), IVL_SIP_OUTPUT); } /* Make the select ports. */ for (idx = 0 ; idx < wid_s ; idx += 1) { sprintf(cellname, "Sel%u", idx); edif_cell_portconfig(cell, wid_r+idx, strdup(cellname), IVL_SIP_INPUT); } for (idx = 0 ; idx < wid_z ; idx += 1) { unsigned base = wid_r + wid_s + wid_r * idx; unsigned rdx; for (rdx = 0 ; rdx < wid_r ; rdx += 1) { sprintf(cellname, "Data%ux%u", idx, rdx); edif_cell_portconfig(cell, base+rdx, strdup(cellname), IVL_SIP_INPUT); } } edif_cell_pstring(cell, "LPM_Type", "LPM_MUX"); edif_cell_pinteger(cell, "LPM_Width", wid_r); edif_cell_pinteger(cell, "LPM_WidthS", wid_s); edif_cell_pinteger(cell, "LPM_Size", wid_z); } ref = edif_cellref_create(edf, cell); /* Connect the pins of the instance to the nexa. Access the cell pins by name. */ for (idx = 0 ; idx < wid_r ; idx += 1) { unsigned pin; sprintf(cellname, "Result%u", idx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, ref, pin); } for (idx = 0 ; idx < wid_s ; idx += 1) { unsigned pin; sprintf(cellname, "Sel%u", idx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, idx)); edif_add_to_joint(jnt, ref, pin); } for (idx = 0 ; idx < wid_z ; idx += 1) { for (rdx = 0 ; rdx < wid_r ; rdx += 1) { unsigned pin; sprintf(cellname, "Data%ux%u", idx, rdx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, idx, rdx)); edif_add_to_joint(jnt, ref, pin); } } } static void lpm_show_add(ivl_lpm_t net) { unsigned idx; unsigned cell_width; char cellname[32]; edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; const char*type = "ADD"; if (ivl_lpm_type(net) == IVL_LPM_SUB) type = "SUB"; /* Figure out the width of the cell. Normally, it is the LPM width known by IVL. But if the top data input bits are unconnected, then we really have a width one less, and we can use the cout to fill out the output width. */ cell_width = ivl_lpm_width(net); if ( (ivl_lpm_data(net,cell_width-1) == 0) && (ivl_lpm_datab(net,cell_width-1) == 0) ) cell_width -= 1; /* Find the correct ADD/SUB device in the library, search by name. If the device is not there, then create it and put it in the library. */ sprintf(cellname, "%s%u", type, cell_width); cell = edif_xlibrary_findcell(xlib, cellname); if (cell == 0) { unsigned pins = cell_width * 3 + 1; cell = edif_xcell_create(xlib, strdup(cellname), pins); for (idx = 0 ; idx < cell_width ; idx += 1) { sprintf(cellname, "Result%u", idx); edif_cell_portconfig(cell, idx*3+0, strdup(cellname), IVL_SIP_OUTPUT); sprintf(cellname, "DataA%u", idx); edif_cell_portconfig(cell, idx*3+1, strdup(cellname), IVL_SIP_INPUT); sprintf(cellname, "DataB%u", idx); edif_cell_portconfig(cell, idx*3+2, strdup(cellname), IVL_SIP_INPUT); } edif_cell_portconfig(cell, pins-1, "Cout", IVL_SIP_OUTPUT); edif_cell_pstring(cell, "LPM_Type", "LPM_ADD_SUB"); edif_cell_pstring(cell, "LPM_Direction", type); edif_cell_pinteger(cell, "LPM_Width", ivl_lpm_width(net)); } ref = edif_cellref_create(edf, cell); /* Connect the pins of the instance to the nexa. Access the cell pins by name. */ for (idx = 0 ; idx < cell_width ; idx += 1) { unsigned pin; sprintf(cellname, "Result%u", idx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, ref, pin); sprintf(cellname, "DataA%u", idx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, ref, pin); sprintf(cellname, "DataB%u", idx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx)); edif_add_to_joint(jnt, ref, pin); } if (cell_width < ivl_lpm_width(net)) { unsigned pin = edif_cell_port_byname(cell, "Cout"); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, cell_width)); edif_add_to_joint(jnt, ref, pin); } } static void lpm_show_mult(ivl_lpm_t net) { char name[64]; unsigned idx; edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; sprintf(name, "mult%u", ivl_lpm_width(net)); cell = edif_xlibrary_findcell(xlib, name); if (cell == 0) { cell = edif_xcell_create(xlib, strdup(name), 3 * ivl_lpm_width(net)); for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { sprintf(name, "Result%u", idx); edif_cell_portconfig(cell, idx*3+0, strdup(name), IVL_SIP_OUTPUT); sprintf(name, "DataA%u", idx); edif_cell_portconfig(cell, idx*3+1, strdup(name), IVL_SIP_INPUT); sprintf(name, "DataB%u", idx); edif_cell_portconfig(cell, idx*3+2, strdup(name), IVL_SIP_INPUT); } edif_cell_pstring(cell, "LPM_Type", "LPM_MULT"); edif_cell_pinteger(cell, "LPM_WidthP", ivl_lpm_width(net)); edif_cell_pinteger(cell, "LPM_WidthA", ivl_lpm_width(net)); edif_cell_pinteger(cell, "LPM_WidthB", ivl_lpm_width(net)); } ref = edif_cellref_create(edf, cell); for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { unsigned pin; ivl_nexus_t nex; sprintf(name, "Result%u", idx); pin = edif_cell_port_byname(cell, name); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, ref, pin); if ( (nex = ivl_lpm_data(net, idx)) ) { sprintf(name, "DataA%u", idx); pin = edif_cell_port_byname(cell, name); jnt = edif_joint_of_nexus(edf, nex); edif_add_to_joint(jnt, ref, pin); } if ( (nex = ivl_lpm_datab(net, idx)) ) { sprintf(name, "DataB%u", idx); pin = edif_cell_port_byname(cell, name); jnt = edif_joint_of_nexus(edf, nex); edif_add_to_joint(jnt, ref, pin); } } } static void lpm_show_constant(ivl_net_const_t net) { edif_cell_t cell0 = edif_xlibrary_findcell(xlib, "cell0"); edif_cell_t cell1 = edif_xlibrary_findcell(xlib, "cell1"); edif_cellref_t ref0 = 0, ref1 = 0; const char*bits; unsigned idx; if (cell0 == 0) { cell0 = edif_xcell_create(xlib, "cell0", 1); edif_cell_portconfig(cell0, 0, "Result0", IVL_SIP_OUTPUT); edif_cell_pstring(cell0, "LPM_Type", "LPM_CONSTANT"); edif_cell_pinteger(cell0, "LPM_Width", 1); edif_cell_pinteger(cell0, "LPM_CValue", 0); } if (cell1 == 0) { cell1 = edif_xcell_create(xlib, "cell1", 1); edif_cell_portconfig(cell1, 0, "Result0", IVL_SIP_OUTPUT); edif_cell_pstring(cell1, "LPM_Type", "LPM_CONSTANT"); edif_cell_pinteger(cell1, "LPM_Width", 1); edif_cell_pinteger(cell1, "LPM_CValue", 1); } bits = ivl_const_bits(net); for (idx = 0 ; idx < ivl_const_pins(net) ; idx += 1) { if (bits[idx] == '1') { if (ref1 == 0) ref1 = edif_cellref_create(edf, cell1); } else { if (ref0 == 0) ref0 = edif_cellref_create(edf, cell0); } } for (idx = 0 ; idx < ivl_const_pins(net) ; idx += 1) { edif_joint_t jnt; jnt = edif_joint_of_nexus(edf, ivl_const_pin(net,idx)); if (bits[idx] == '1') edif_add_to_joint(jnt, ref1, 0); else edif_add_to_joint(jnt, ref0, 0); } } const struct device_s d_lpm_edif = { lpm_show_header, lpm_show_footer, 0, 0, lpm_logic, lpm_show_dff, /* show_dff */ 0, 0, 0, 0, /* show_cmp_gt */ lpm_show_mux, /* show_mux */ lpm_show_add, /* show_add */ lpm_show_add, /* show_sub */ 0, /* show_shiftl */ 0, /* show_shiftr */ lpm_show_mult, /* show_mult */ lpm_show_constant /* show_constant */ }; /* * $Log: d-lpm.c,v $ * Revision 1.12 2004/10/04 01:10:56 steve * Clean up spurious trailing white space. * * Revision 1.11 2003/11/12 03:20:14 steve * devices need show_cmp_gt * * Revision 1.10 2003/10/31 03:45:50 steve * Handle adders that use Cout for the top bit. * * Revision 1.9 2003/10/27 02:18:27 steve * Emit constants for LPM device. * * Revision 1.8 2003/09/03 23:34:09 steve * Support synchronous set of LPM_FF devices. * * Revision 1.7 2003/08/26 04:45:47 steve * iverilog-vpi support --cflags a la gtk. * * Revision 1.6 2003/08/15 02:23:53 steve * Add synthesis support for synchronous reset. * * Revision 1.5 2003/08/10 16:42:23 steve * Add async clear to LPM_FF devices. * * Revision 1.4 2003/08/09 03:23:03 steve * Add support for IVL_LPM_MULT device. * * Revision 1.3 2003/08/09 02:40:50 steve * Generate LPM_FF devices. * * Revision 1.2 2003/08/07 05:18:04 steve * Add support for OR/NOR/bufif0/bufif1. * * Revision 1.1 2003/08/07 04:04:01 steve * Add an LPM device type. * */ verilog-0.9.7/tgt-fpga/PaxHeaders.14238/fpga.txt0000644000202500001440000000005012204466647017417 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/fpga.txt0000644000202500001440000001425312204466647016746 0ustar00steveusers00000000000000 FPGA LOADABLE CODE GENERATOR FOR Icarus Verilog Copyright 2001 Stephen Williams The FPGA code generator supports a variety of FPGA devices, writing XNF or EDIF depending on the target. You can select the architecture of the device, and the detailed part name. The architecture is used to select library primitives, and the detailed part name is written into the generated file for the use of downstream tools. INVOKING THE FPGA TARGET The code generator is invoked with the -tfpga flag to iverilog. It understands the part= and the arch= parameters, which can be set with the -p flag of iverilog: iverilog -parch=virtex -ppart=v50-pq240-6 -tfpga foo.vl This example selects the Virtex architecture, and give the detailed part number as v50-pq240-6. The output is written into a.out unless a different output file is specified with the -o flag. The following is a list of architecture types that this code generator supports. * arch=lpm This is a device independent format, where the gates are device types as defined by the LPM 2 1 0 specification. Some backend tools may take this format, or users may write interface libraries to connect these netlists to the device in question. * arch=generic-edif (obsolete) This is generic EDIF code. It doesn't necessarily work because the external library is not available to the code generator. But, what it does is generate generic style gates that a portability library can map to target gates if desired. * arch=generic-xnf (obsolete) If this is selected, then the output is formatted as an XNF file, suitable for most any type of device. The devices that it emits are generic devices from the unified library. Some devices are macros, you may need to further resolve the generated XNF to get working code for your part. * arch=virtex If this is selected, then the output is formatted as an EDIF 200 file, suitable for Virtex class devices. This is supposed to know that you are targeting a Virtex part, so can generate primitives instead of using external macros. It includes the VIRTEX internal library, and should work properly for any Virtex part. * arch=virtex2 If this is selected, then the output is EDIF 2 0 0 suitable for Virtex-II and Virtex-II Pro devices. It uses the VIRTEX2 library, but is very similar to the Virtex target. XNF ROOT PORTS NOTE: As parts are moved over to EDIF format, XNF support will be phased out. Current Xilinx implementation tools will accept EDIF format files even for the older parts, and non-Xilinx implementation tools accept nothing else. When the output format is XNF, the code generator will generate "SIG" records for the signals that are ports of the root module. The name is declared as an external pin that this macro makes available. The name given to the macro pin is generated from the base name of the signal. If the signal is one bit wide, then the pin name is exactly the module port name. If the port is a vector, then the pin number is given as a vector. For example, the module: module main(out, in); output out; input [2:0] in; [...] endmodule leads to these SIG, records: SIG, main/out, PIN=out SIG, main/in<2>, PIN=in2 SIG, main/in<1>, PIN=in1 SIG, main/in<0>, PIN=in0 EDIF ROOT PORTS The EDIF format is more explicit about the interface into an EDIF file. The code generator uses that control to generate an explicit interface definition into the design. (This is *not* the same as the PADS of a part.) The generated EDIF interface section contains port definitions, including the proper direction marks. With the (rename ...) s-exp in EDIF, it is possible to assign arbitrary text to port names. The EDIF code generator therefore does not resort to the mangling that is needed for the XNF target. The base name of the signal that is an input or output is used as the name of the port, complete with the proper case. However, since the ports are single bit ports, the name of vectors includes the string "[0]" where the number is the bit number. For example, the module: module main(out, in); output out; input [2:0] in; [...] endmodule creates these ports: out OUTPUT in[0] INPUT in[1] INPUT in[2] INPUT Target tools, including Xilinx Foundation tools, understand the [] characters in the name and recollect the signals into a proper bus when presenting the vector to the user. PADS AND PIN ASSIGNMENT The ports of a root module may be assigned to specific pins, or to a generic pad. If a signal (that is a port) has a PAD attribute, then the value of that attribute is a list of locations, one for each bit of the signal, that specifies the pin for each bit of the signal. For example: module main( (* PAD = "P10" *) output out, (* PAD = "P20,P21,P22" *) input [2:0] in); [...] endmodule In this example, port ``out'' is assigned to pin 10, and port ``in'' is assigned to pins 20-22. If the architecture supports it, a pin number of 0 means let the back end tools choose a pin. The format of the pin number depends on the architecture family being targeted, so for example Xilinx family devices take the name that is associated with the "LOC" attribute. NOTE: If a module port is assigned to a pin (and therefore attached to a PAD) then it is *not* connected to a port of the EDIF file. This is because the PAD (and possibly IBUF or OBUF) would become an extra driver to the port. An error. SPECIAL DEVICES The code generator supports the "cellref" attribute attached to logic devices to cause specific device types be generated, instead of the usual device that the code generator might generate. For example, to get a clock buffer out of a Verilog buf: buf my_gbuf(out, in); $attribute(my_buf, "cellref", "GBUF:O,I"); The "cellref" attribute tells the code generator to use the given cell. The syntax of the value is: :,... The cell type is the name of the library part to use. The pin names are the names of the type in the library, in the order that the logic device pins are connected. COMPILING WITH XILINX FOUNDATION Compile a single-file design with command line tools like so: % iverilog -parch=virtex -o foo.edf foo.vl % edif2ngd foo.edf foo.ngo % ngdbuild -p v50-pq240 foo.ngo foo.ngd % map -o map.ncd foo.ngd % par -w map.ncd foo.ncd verilog-0.9.7/tgt-fpga/PaxHeaders.14238/d-generic.c0000644000202500001440000000005012204466647017742 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/d-generic.c0000644000202500001440000003541012204466647017267 0ustar00steveusers00000000000000/* * Copyright (c) 2001 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: d-generic.c,v 1.14 2003/11/12 03:20:14 steve Exp $" #endif # include "device.h" # include "fpga_priv.h" # include /* * This is the device emitter for the most generic FPGA. It doesn't * know anything special about device types, so can't handle complex * logic. */ static void xnf_draw_pin(ivl_nexus_t nex, const char*nam, char dir) { const char*use_name = nam; const char*nex_name = xnf_mangle_nexus_name(nex); int invert = 0; if (use_name[0] == '~') { invert = 1; use_name += 1; } fprintf(xnf, " PIN, %s, %c, %s", use_name, dir, nex_name); if (invert) fprintf(xnf, ",,INV"); fprintf(xnf, "\n"); } static void show_root_ports_xnf(ivl_scope_t root) { unsigned cnt = ivl_scope_sigs(root); unsigned idx; for (idx = 0 ; idx < cnt ; idx += 1) { ivl_signal_t sig = ivl_scope_sig(root, idx); const char*use_name; if (ivl_signal_port(sig) == IVL_SIP_NONE) continue; use_name = ivl_signal_basename(sig); if (ivl_signal_pins(sig) == 1) { ivl_nexus_t nex = ivl_signal_pin(sig, 0); fprintf(xnf, "SIG, %s, PIN=%s\n", xnf_mangle_nexus_name(nex), use_name); } else { unsigned pin; for (pin = 0 ; pin < ivl_signal_pins(sig); pin += 1) { ivl_nexus_t nex = ivl_signal_pin(sig, pin); fprintf(xnf, "SIG, %s, PIN=%s%u\n", xnf_mangle_nexus_name(nex), use_name, pin); } } } } static void show_design_consts_xnf(ivl_design_t des) { unsigned idx; for (idx = 0 ; idx < ivl_design_consts(des) ; idx += 1) { unsigned pin; ivl_net_const_t net = ivl_design_const(des, idx); const char*val = ivl_const_bits(net); for (pin = 0 ; pin < ivl_const_pins(net) ; pin += 1) { ivl_nexus_t nex = ivl_const_pin(net, pin); fprintf(xnf, "PWR,%c,%s\n", val[pin], xnf_mangle_nexus_name(nex)); } } } static void generic_show_header(ivl_design_t des) { ivl_scope_t root = ivl_design_root(des); fprintf(xnf, "LCANET,6\n"); fprintf(xnf, "PROG,iverilog,$Name: $,\"Icarus Verilog/fpga.tgt\"\n"); if (part && (part[0]!=0)) { fprintf(xnf, "PART,%s\n", part); } show_root_ports_xnf(root); } static void generic_show_footer(ivl_design_t des) { show_design_consts_xnf(des); fprintf(xnf, "EOF\n"); } static void generic_show_logic(ivl_net_logic_t net) { char name[1024]; ivl_nexus_t nex; unsigned idx; xnf_mangle_logic_name(net, name, sizeof name); switch (ivl_logic_type(net)) { case IVL_LO_AND: fprintf(xnf, "SYM, %s, AND, LIBVER=2.0.0\n", name); nex = ivl_logic_pin(net, 0); xnf_draw_pin(nex, "O", 'O'); for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { char ipin[32]; nex = ivl_logic_pin(net, idx); sprintf(ipin, "I%u", idx-1); xnf_draw_pin(nex, ipin, 'I'); } fprintf(xnf, "END\n"); break; case IVL_LO_BUF: assert(ivl_logic_pins(net) == 2); fprintf(xnf, "SYM, %s, BUF, LIBVER=2.0.0\n", name); nex = ivl_logic_pin(net, 0); xnf_draw_pin(nex, "O", 'O'); nex = ivl_logic_pin(net, 1); xnf_draw_pin(nex, "I", 'I'); fprintf(xnf, "END\n"); break; case IVL_LO_NAND: fprintf(xnf, "SYM, %s, NAND, LIBVER=2.0.0\n", name); nex = ivl_logic_pin(net, 0); xnf_draw_pin(nex, "O", 'O'); for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { char ipin[32]; nex = ivl_logic_pin(net, idx); sprintf(ipin, "I%u", idx-1); xnf_draw_pin(nex, ipin, 'I'); } fprintf(xnf, "END\n"); break; case IVL_LO_NOR: fprintf(xnf, "SYM, %s, NOR, LIBVER=2.0.0\n", name); nex = ivl_logic_pin(net, 0); xnf_draw_pin(nex, "O", 'O'); for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { char ipin[32]; nex = ivl_logic_pin(net, idx); sprintf(ipin, "I%u", idx-1); xnf_draw_pin(nex, ipin, 'I'); } fprintf(xnf, "END\n"); break; case IVL_LO_NOT: assert(ivl_logic_pins(net) == 2); fprintf(xnf, "SYM, %s, INV, LIBVER=2.0.0\n", name); nex = ivl_logic_pin(net, 0); xnf_draw_pin(nex, "O", 'O'); nex = ivl_logic_pin(net, 1); xnf_draw_pin(nex, "I", 'I'); fprintf(xnf, "END\n"); break; case IVL_LO_OR: fprintf(xnf, "SYM, %s, OR, LIBVER=2.0.0\n", name); nex = ivl_logic_pin(net, 0); xnf_draw_pin(nex, "O", 'O'); for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { char ipin[32]; nex = ivl_logic_pin(net, idx); sprintf(ipin, "I%u", idx-1); xnf_draw_pin(nex, ipin, 'I'); } fprintf(xnf, "END\n"); break; case IVL_LO_XOR: fprintf(xnf, "SYM, %s, XOR, LIBVER=2.0.0\n", name); nex = ivl_logic_pin(net, 0); xnf_draw_pin(nex, "O", 'O'); for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { char ipin[32]; nex = ivl_logic_pin(net, idx); sprintf(ipin, "I%u", idx-1); xnf_draw_pin(nex, ipin, 'I'); } fprintf(xnf, "END\n"); break; case IVL_LO_XNOR: fprintf(xnf, "SYM, %s, XNOR, LIBVER=2.0.0\n", name); nex = ivl_logic_pin(net, 0); xnf_draw_pin(nex, "O", 'O'); for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { char ipin[32]; nex = ivl_logic_pin(net, idx); sprintf(ipin, "I%u", idx-1); xnf_draw_pin(nex, ipin, 'I'); } fprintf(xnf, "END\n"); break; case IVL_LO_BUFIF0: fprintf(xnf, "SYM, %s, TBUF, LIBVER=2.0.0\n", name); nex = ivl_logic_pin(net, 0); xnf_draw_pin(nex, "O", 'O'); nex = ivl_logic_pin(net, 1); xnf_draw_pin(nex, "I", 'I'); nex = ivl_logic_pin(net, 2); xnf_draw_pin(nex, "~T", 'I'); fprintf(xnf, "END\n"); break; case IVL_LO_BUFIF1: fprintf(xnf, "SYM, %s, TBUF, LIBVER=2.0.0\n", name); nex = ivl_logic_pin(net, 0); xnf_draw_pin(nex, "O", 'O'); nex = ivl_logic_pin(net, 1); xnf_draw_pin(nex, "I", 'I'); nex = ivl_logic_pin(net, 2); xnf_draw_pin(nex, "T", 'I'); fprintf(xnf, "END\n"); break; default: fprintf(stderr, "fpga.tgt: unknown logic type %u\n", ivl_logic_type(net)); break; } } static void generic_show_dff(ivl_lpm_t net) { char name[1024]; ivl_nexus_t nex; xnf_mangle_lpm_name(net, name, sizeof name); fprintf(xnf, "SYM, %s, DFF, LIBVER=2.0.0\n", name); nex = ivl_lpm_q(net, 0); xnf_draw_pin(nex, "Q", 'O'); nex = ivl_lpm_data(net, 0); xnf_draw_pin(nex, "D", 'I'); nex = ivl_lpm_clk(net); xnf_draw_pin(nex, "C", 'I'); if ((nex = ivl_lpm_enable(net))) xnf_draw_pin(nex, "CE", 'I'); fprintf(xnf, "END\n"); } /* * The generic == comparator uses EQN records to generate 2-bit * comparators, that are then connected together by a wide AND gate. */ static void generic_show_cmp_eq(ivl_lpm_t net) { ivl_nexus_t nex; unsigned idx; char name[1024]; /* Make this many dual pair comparators, and */ unsigned deqn = ivl_lpm_width(net) / 2; /* Make this many single pair comparators. */ unsigned seqn = ivl_lpm_width(net) % 2; xnf_mangle_lpm_name(net, name, sizeof name); for (idx = 0 ; idx < deqn ; idx += 1) { fprintf(xnf, "SYM, %s/CD%u, EQN, " "EQN=(~((I0 @ I1) + (I2 @ I3)))\n", name, idx); fprintf(xnf, " PIN, O, O, %s/CDO%u\n", name, idx); nex = ivl_lpm_data(net, 2*idx); xnf_draw_pin(nex, "I0", 'I'); nex = ivl_lpm_datab(net, 2*idx); xnf_draw_pin(nex, "I1", 'I'); nex = ivl_lpm_data(net, 2*idx+1); xnf_draw_pin(nex, "I2", 'I'); nex = ivl_lpm_datab(net, 2*idx+1); xnf_draw_pin(nex, "I3", 'I'); fprintf(xnf, "END\n"); } if (seqn != 0) { fprintf(xnf, "SYM, %s/CT, XNOR, LIBVER=2.0.0\n", name); fprintf(xnf, " PIN, O, O, %s/CTO\n", name); nex = ivl_lpm_data(net, 2*deqn); xnf_draw_pin(nex, "I0", 'I'); nex = ivl_lpm_datab(net, 2*deqn); xnf_draw_pin(nex, "I1", 'I'); fprintf(xnf, "END\n"); } if (ivl_lpm_type(net) == IVL_LPM_CMP_EQ) fprintf(xnf, "SYM, %s/OUT, AND, LIBVER=2.0.0\n", name); else fprintf(xnf, "SYM, %s/OUT, NAND, LIBVER=2.0.0\n", name); nex = ivl_lpm_q(net, 0); xnf_draw_pin(nex, "O", 'O'); for (idx = 0 ; idx < deqn ; idx += 1) fprintf(xnf, " PIN, I%u, I, %s/CDO%u\n", idx, name, idx); for (idx = 0 ; idx < seqn ; idx += 1) fprintf(xnf, " PIN, I%u, I, %s/CTO\n", deqn+idx, name); fprintf(xnf, "END\n"); } /* * This function draws N-bit wide binary mux devices. These are so * very popular because they are the result of such expressions as: * * x = sel? a : b; * * This code only supports the case where sel is a single bit. It * works by drawing for each bit of the width an EQN device that takes * as inputs I0 and I1 the alternative inputs, and I2 the select. The * select bit is common with all the generated mux devices. */ static void generic_show_mux(ivl_lpm_t net) { char name[1024]; ivl_nexus_t nex, sel; unsigned idx; xnf_mangle_lpm_name(net, name, sizeof name); /* Access the single select bit. This is common to the whole width of the mux. */ assert(ivl_lpm_selects(net) == 1); sel = ivl_lpm_select(net, 0); for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { fprintf(xnf, "SYM, %s/M%u, EQN, " "EQN=((I0 * ~I2) + (I1 * I2))\n", name, idx); nex = ivl_lpm_q(net, idx); xnf_draw_pin(nex, "O", 'O'); nex = ivl_lpm_data2(net, 0, idx); xnf_draw_pin(nex, "I0", 'I'); nex = ivl_lpm_data2(net, 1, idx); xnf_draw_pin(nex, "I1", 'I'); xnf_draw_pin(sel, "I2", 'I'); fprintf(xnf, "END\n"); } } /* * This code cheats and just generates ADD4 devices enough to support * the add. Make no effort to optimize, because we have no idea what * kind of device we have. */ static void generic_show_add(ivl_lpm_t net) { char name[1024]; ivl_nexus_t nex; unsigned idx, nadd4, tail; xnf_mangle_lpm_name(net, name, sizeof name); /* Make this many ADD4 devices. */ nadd4 = ivl_lpm_width(net) / 4; tail = ivl_lpm_width(net) % 4; for (idx = 0 ; idx < nadd4 ; idx += 1) { fprintf(xnf, "SYM, %s/A%u, ADD4\n", name, idx); if (idx > 0) fprintf(xnf, " PIN, CI, I, %s/CO%u\n", name, idx-1); nex = ivl_lpm_q(net, idx*4+0); xnf_draw_pin(nex, "S0", 'O'); nex = ivl_lpm_q(net, idx*4+1); xnf_draw_pin(nex, "S1", 'O'); nex = ivl_lpm_q(net, idx*4+2); xnf_draw_pin(nex, "S2", 'O'); nex = ivl_lpm_q(net, idx*4+3); xnf_draw_pin(nex, "S3", 'O'); nex = ivl_lpm_data(net, idx*4+0); xnf_draw_pin(nex, "A0", 'I'); nex = ivl_lpm_data(net, idx*4+1); xnf_draw_pin(nex, "A1", 'I'); nex = ivl_lpm_data(net, idx*4+2); xnf_draw_pin(nex, "A2", 'I'); nex = ivl_lpm_data(net, idx*4+3); xnf_draw_pin(nex, "A3", 'I'); nex = ivl_lpm_datab(net, idx*4+0); xnf_draw_pin(nex, "B0", 'I'); nex = ivl_lpm_datab(net, idx*4+1); xnf_draw_pin(nex, "B1", 'I'); nex = ivl_lpm_datab(net, idx*4+2); xnf_draw_pin(nex, "B2", 'I'); nex = ivl_lpm_datab(net, idx*4+3); xnf_draw_pin(nex, "B3", 'I'); if ((idx*4+4) < ivl_lpm_width(net)) fprintf(xnf, " PIN, CO, O, %s/CO%u\n", name, idx); fprintf(xnf, "END\n"); } if (tail > 0) { fprintf(xnf, "SYM, %s/A%u, ADD4\n", name, nadd4); if (nadd4 > 0) fprintf(xnf, " PIN, CI, I, %s/CO%u\n", name, nadd4-1); switch (tail) { case 3: nex = ivl_lpm_data(net, nadd4*4+2); xnf_draw_pin(nex, "A2", 'I'); nex = ivl_lpm_datab(net, nadd4*4+2); xnf_draw_pin(nex, "B2", 'I'); nex = ivl_lpm_q(net, nadd4*4+2); xnf_draw_pin(nex, "S2", 'O'); case 2: nex = ivl_lpm_data(net, nadd4*4+1); xnf_draw_pin(nex, "A1", 'I'); nex = ivl_lpm_datab(net, nadd4*4+1); xnf_draw_pin(nex, "B1", 'I'); nex = ivl_lpm_q(net, nadd4*4+1); xnf_draw_pin(nex, "S1", 'O'); case 1: nex = ivl_lpm_data(net, nadd4*4+0); xnf_draw_pin(nex, "A0", 'I'); nex = ivl_lpm_datab(net, nadd4*4+0); xnf_draw_pin(nex, "B0", 'I'); nex = ivl_lpm_q(net, nadd4*4+0); xnf_draw_pin(nex, "S0", 'O'); } fprintf(xnf, "END\n"); } } const struct device_s d_generic = { generic_show_header, generic_show_footer, 0, /* show_scope */ 0, /* show_pad not implemented */ generic_show_logic, generic_show_dff, generic_show_cmp_eq, generic_show_cmp_eq, 0, /* ge not implemented */ 0, /* gt not implemented */ generic_show_mux, generic_show_add, 0, /* subtract not implemented */ 0, 0 }; /* * $Log: d-generic.c,v $ * Revision 1.14 2003/11/12 03:20:14 steve * devices need show_cmp_gt * * Revision 1.13 2003/06/24 03:55:00 steve * Add ivl_synthesis_cell support for virtex2. * * Revision 1.12 2002/10/28 02:05:56 steve * Add Virtex code generators for left shift, * subtraction, and GE comparators. * * Revision 1.11 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.10 2002/08/11 23:47:04 steve * Add missing Log and Ident strings. * * Revision 1.9 2001/09/16 01:48:16 steve * Suppor the PAD attribute on signals. * * Revision 1.8 2001/09/02 21:33:07 steve * Rearrange the XNF code generator to be generic-xnf * so that non-XNF code generation is also possible. * * Start into the virtex EDIF output driver. * * Revision 1.7 2001/09/01 04:30:44 steve * Generic ADD code. * * Revision 1.6 2001/09/01 02:28:42 steve * Generate code for MUX devices. * * Revision 1.5 2001/09/01 02:01:30 steve * identity compare, and PWR records for constants. * * Revision 1.4 2001/08/31 23:02:13 steve * Relax pin count restriction on logic gates. * * Revision 1.3 2001/08/31 04:17:56 steve * Many more logic gate types. * * Revision 1.2 2001/08/31 02:59:06 steve * Add root port SIG records. * * Revision 1.1 2001/08/28 04:14:20 steve * Add the fpga target. * */ verilog-0.9.7/tgt-fpga/PaxHeaders.14238/edif.c0000644000202500001440000000005012204466647017014 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/edif.c0000644000202500001440000003676012204466647016352 0ustar00steveusers00000000000000/* * Copyright (c) 2003-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "edif.h" # include # include # include typedef enum property_e { PRP_NONE = 0, PRP_STRING, PRP_INTEGER } property_t; struct cellref_property_ { const char*name; property_t ptype; union { const char*str; long num; } value_; struct cellref_property_*next; }; struct edif_s { const char*name; /* List the ports of the design. */ unsigned nports; struct __cell_port*ports; /* All the external libraries attached to me. */ edif_xlibrary_t xlibs; /* list the cellref instances. */ edif_cellref_t celref; /* The root instance has cellref properties as well. */ struct cellref_property_*property; /* Keep a list of all the nexa */ struct edif_joint_s*nexa; }; struct edif_xlibrary_s { /* Name of this library. */ const char*name; /* The cells that are contained in this library. */ struct edif_cell_s*cells; /* point to the optional celltable. */ const struct edif_xlib_celltable*celltable; /* used to list libraries in an edif_t. */ struct edif_xlibrary_s*next; }; struct __cell_port { const char*name; const char*ename; struct cellref_property_*property; ivl_signal_port_t dir; }; struct edif_cell_s { const char*name; edif_xlibrary_t xlib; unsigned nports; struct __cell_port*ports; struct cellref_property_*property; struct edif_cell_s*next; }; struct edif_cellref_s { struct edif_cell_s* cell; unsigned u; struct cellref_property_*property; struct edif_cellref_s* next; }; struct joint_cell_ { struct edif_cellref_s*cell; unsigned port; struct joint_cell_*next; }; struct edif_joint_s { const char*name; struct joint_cell_*links; struct edif_joint_s*next; }; static int is_edif_name(const char*text) { static const char*edif_name_chars = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; return (strspn(text, edif_name_chars) == strlen(text)); } edif_t edif_create(const char*design_name, unsigned nports) { edif_t edf = malloc(sizeof(struct edif_s)); edf->name = design_name; edf->nports= nports; edf->ports = nports? calloc(nports, sizeof(struct __cell_port)) : 0; edf->celref= 0; edf->xlibs = 0; edf->property = 0; edf->nexa = 0; return edf; } void edif_portconfig(edif_t edf, unsigned idx, const char*name, ivl_signal_port_t dir) { assert(idx < edf->nports); edf->ports[idx].name = name; if (is_edif_name(name)) { edf->ports[idx].ename = 0; } else { char buf[16]; sprintf(buf, "PORT%u", idx); edf->ports[idx].ename = strdup(buf); } edf->ports[idx].dir = dir; } void edif_port_to_joint(edif_joint_t jnt, edif_t edf, unsigned port) { struct joint_cell_* jc = malloc(sizeof(struct joint_cell_)); jc->cell = 0; jc->port = port; jc->next = jnt->links; jnt->links = jc; } void edif_pstring(edif_t edf, const char*name, const char*value) { struct cellref_property_*prp = malloc(sizeof(struct cellref_property_)); prp->name = name; prp->ptype = PRP_STRING; prp->value_.str = value; prp->next = edf->property; edf->property = prp; } edif_xlibrary_t edif_xlibrary_create(edif_t edf, const char*name) { edif_xlibrary_t xlib = malloc(sizeof(struct edif_xlibrary_s)); xlib->name = name; xlib->cells = 0; xlib->celltable = 0; xlib->next = edf->xlibs; edf->xlibs = xlib; return xlib; } void edif_xlibrary_set_celltable(edif_xlibrary_t xlib, const struct edif_xlib_celltable*tab) { assert(xlib->celltable == 0); xlib->celltable = tab; } edif_cell_t edif_xlibrary_findcell(edif_xlibrary_t xlib, const char*cell_name) { const struct edif_xlib_celltable*tcur; edif_cell_t cur; for (cur = xlib->cells ; cur ; cur = cur->next) { if (strcmp(cell_name, cur->name) == 0) return cur; } if (xlib->celltable == 0) return 0; for (tcur = xlib->celltable ; tcur->cell_name ; tcur += 1) if (strcmp(cell_name, tcur->cell_name) == 0) { return (tcur->cell_func)(xlib); } return 0; } edif_cell_t edif_xlibrary_scope_cell(edif_xlibrary_t xlib, ivl_scope_t scope) { unsigned port_count, idx; edif_cell_t cur; /* Check to see if the cell is already somehow defined. */ cur = edif_xlibrary_findcell(xlib, ivl_scope_tname(scope)); if (cur) return cur; /* Count the ports of the scope. */ port_count = 0; for (idx = 0 ; idx < ivl_scope_sigs(scope) ; idx += 1) { ivl_signal_t sig = ivl_scope_sig(scope, idx); if (ivl_signal_port(sig) == IVL_SIP_NONE) continue; port_count += 1; } cur = edif_xcell_create(xlib, ivl_scope_tname(scope), port_count); port_count = 0; for (idx = 0 ; idx < ivl_scope_sigs(scope) ; idx += 1) { ivl_signal_t sig = ivl_scope_sig(scope, idx); if (ivl_signal_port(sig) == IVL_SIP_NONE) continue; edif_cell_portconfig(cur, port_count, ivl_signal_basename(sig), ivl_signal_port(sig)); port_count += 1; } return cur; } edif_cell_t edif_xcell_create(edif_xlibrary_t xlib, const char*name, unsigned nports) { unsigned idx; edif_cell_t cell = malloc(sizeof(struct edif_cell_s)); cell->name = name; cell->xlib = xlib; cell->nports = nports; cell->ports = calloc(nports, sizeof(struct __cell_port)); cell->property = 0; for (idx = 0 ; idx < nports ; idx += 1) { cell->ports[idx].name = "?"; cell->ports[idx].dir = IVL_SIP_NONE; cell->ports[idx].property = 0; } cell->next = xlib->cells; xlib->cells = cell; return cell; } void edif_cell_portconfig(edif_cell_t cell, unsigned idx, const char*name, ivl_signal_port_t dir) { assert(idx < cell->nports); cell->ports[idx].name = name; cell->ports[idx].dir = dir; } void edif_cell_port_pstring(edif_cell_t cell, unsigned idx, const char*name, const char*value) { struct cellref_property_*prp = malloc(sizeof(struct cellref_property_)); prp->name = name; prp->ptype = PRP_STRING; prp->value_.str = value; prp->next = cell->ports[idx].property; cell->ports[idx].property = prp; } unsigned edif_cell_port_byname(edif_cell_t cell, const char*name) { unsigned idx = 0; for (idx = 0 ; idx < cell->nports ; idx += 1) if (strcmp(name, cell->ports[idx].name) == 0) break; return idx; } void edif_cell_pstring(edif_cell_t cell, const char*name, const char*value) { struct cellref_property_*prp = malloc(sizeof(struct cellref_property_)); prp->name = name; prp->ptype = PRP_STRING; prp->value_.str = value; prp->next = cell->property; cell->property = prp; } void edif_cell_pinteger(edif_cell_t cell, const char*name, int value) { struct cellref_property_*prp = malloc(sizeof(struct cellref_property_)); prp->name = name; prp->ptype = PRP_INTEGER; prp->value_.num = value; prp->next = cell->property; cell->property = prp; } edif_cellref_t edif_cellref_create(edif_t edf, edif_cell_t cell) { static unsigned u_number = 0; edif_cellref_t ref = malloc(sizeof(struct edif_cellref_s)); u_number += 1; assert(cell); assert(edf); ref->u = u_number; ref->cell = cell; ref->property = 0; ref->next = edf->celref; edf->celref = ref; return ref; } void edif_cellref_pstring(edif_cellref_t ref, const char*name, const char*value) { struct cellref_property_*prp = malloc(sizeof(struct cellref_property_)); prp->name = name; prp->ptype = PRP_STRING; prp->value_.str = value; prp->next = ref->property; ref->property = prp; } void edif_cellref_pinteger(edif_cellref_t ref, const char*name, int value) { struct cellref_property_*prp = malloc(sizeof(struct cellref_property_)); prp->name = name; prp->ptype = PRP_INTEGER; prp->value_.num = value; prp->next = ref->property; ref->property = prp; } edif_joint_t edif_joint_create(edif_t edf) { edif_joint_t jnt = malloc(sizeof(struct edif_joint_s)); jnt->name = 0; jnt->links = 0; jnt->next = edf->nexa; edf->nexa = jnt; return jnt; } edif_joint_t edif_joint_of_nexus(edif_t edf, ivl_nexus_t nex) { void*tmp = ivl_nexus_get_private(nex); edif_joint_t jnt; if (tmp == 0) { jnt = edif_joint_create(edf); ivl_nexus_set_private(nex, jnt); return jnt; } jnt = (edif_joint_t) tmp; return jnt; } void edif_joint_rename(edif_joint_t jnt, const char*name) { assert(jnt->name == 0); jnt->name = name; } void edif_add_to_joint(edif_joint_t jnt, edif_cellref_t cell, unsigned port) { struct joint_cell_* jc = malloc(sizeof(struct joint_cell_)); jc->cell = cell; jc->port = port; jc->next = jnt->links; jnt->links = jc; } static void fprint_property(FILE*fd, const struct cellref_property_*prp) { fprintf(fd, "(property %s ", prp->name); switch (prp->ptype) { case PRP_NONE: break; case PRP_STRING: fprintf(fd, "(string \"%s\")", prp->value_.str); break; case PRP_INTEGER: fprintf(fd, "(integer %ld)", prp->value_.num); break; } fprintf(fd, ")"); } /* * This function takes all the data structures that have been * assembled by the code generator, and writes them into an EDIF * formatted file. */ void edif_print(FILE*fd, edif_t edf) { edif_xlibrary_t xlib; edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; struct cellref_property_*prp; unsigned idx; fprintf(fd, "(edif %s\n", edf->name); fprintf(fd, " (edifVersion 2 0 0)\n"); fprintf(fd, " (edifLevel 0)\n"); fprintf(fd, " (keywordMap (keywordLevel 0))\n"); fprintf(fd, " (status\n"); fprintf(fd, " (written\n"); fprintf(fd, " (timeStamp 0 0 0 0 0 0)\n"); fprintf(fd, " (author \"unknown\")\n"); fprintf(fd, " (program \"Icarus Verilog/fpga.tgt\")))\n"); fflush(fd); for (xlib = edf->xlibs ; xlib ; xlib = xlib->next) { fprintf(fd, " (external %s " "(edifLevel 0) " "(technology (numberDefinition))\n", xlib->name); for (cell = xlib->cells ; cell ; cell = cell->next) { fprintf(fd, " (cell %s (cellType GENERIC)\n", cell->name); fprintf(fd, " (view net\n" " (viewType NETLIST)\n" " (interface"); for (idx = 0 ; idx < cell->nports ; idx += 1) { struct __cell_port*pp = cell->ports + idx; fprintf(fd, "\n (port %s", pp->name); switch (pp->dir) { case IVL_SIP_INPUT: fprintf(fd, " (direction INPUT)"); break; case IVL_SIP_OUTPUT: fprintf(fd, " (direction OUTPUT)"); break; case IVL_SIP_INOUT: fprintf(fd, " (direction INOUT)"); break; default: break; } for (prp = pp->property ; prp ; prp=prp->next) { fprintf(fd, " "); fprint_property(fd, prp); } fprintf(fd, ")"); } for (prp = cell->property ; prp ; prp = prp->next) { fprintf(fd, "\n "); fprint_property(fd, prp); } fprintf(fd, ")))\n"); } fprintf(fd, " )\n"); /* terminate (external ...) sexp */ } fflush(fd); /* Write out the library header */ fprintf(fd, " (library DESIGN\n"); fprintf(fd, " (edifLevel 0)\n"); fprintf(fd, " (technology (numberDefinition))\n"); /* The root module is a cell in the library. */ fprintf(fd, " (cell %s\n", edf->name); fprintf(fd, " (cellType GENERIC)\n"); fprintf(fd, " (view net\n"); fprintf(fd, " (viewType NETLIST)\n"); fprintf(fd, " (interface\n"); for (idx = 0 ; idx < edf->nports ; idx += 1) { fprintf(fd, " (port "); if (edf->ports[idx].ename == 0) fprintf(fd, "%s ", edf->ports[idx].name); else fprintf(fd, "(rename %s \"%s\") ", edf->ports[idx].ename, edf->ports[idx].name); switch (edf->ports[idx].dir) { case IVL_SIP_INPUT: fprintf(fd, "(direction INPUT)"); break; case IVL_SIP_OUTPUT: fprintf(fd, "(direction OUTPUT)"); break; case IVL_SIP_INOUT: fprintf(fd, "(direction INOUT)"); break; default: break; } fprintf(fd, ")\n"); } fprintf(fd, " )\n"); /* end the (interface ) sexp */ fflush(fd); fprintf(fd, " (contents\n"); /* Display all the instances. */ for (ref = edf->celref ; ref ; ref = ref->next) { assert(ref->cell); fprintf(fd, "(instance U%u (viewRef net " "(cellRef %s (libraryRef %s)))", ref->u, ref->cell->name, ref->cell->xlib->name); for (prp = ref->property ; prp ; prp = prp->next) { fprintf(fd, " "); fprint_property(fd, prp); } fprintf(fd, ")\n"); } fflush(fd); /* Display all the joints. */ idx = 0; for (jnt = edf->nexa ; jnt ; jnt = jnt->next, idx += 1) { struct joint_cell_*jc; fprintf(fd, "(net "); if (jnt->name != 0) fprintf(fd, "(rename N%u \"%s\")", idx, jnt->name); else fprintf(fd, "N%u", idx); fprintf(fd, " (joined"); for (jc = jnt->links ; jc ; jc = jc->next) { if (jc->cell) { fprintf(fd, " (portRef %s (instanceRef U%u))", jc->cell->cell->ports[jc->port].name, jc->cell->u); } else { /* Reference to a port of the main cell. */ if (edf->ports[jc->port].ename) fprintf(fd, " (portRef %s)", edf->ports[jc->port].ename); else fprintf(fd, " (portRef %s)", edf->ports[jc->port].name); } } fprintf(fd, "))\n"); } fprintf(fd, " )\n"); /* end the (contents...) sexp */ fprintf(fd, " )\n"); /* end the (view ) sexp */ fprintf(fd, " )\n"); /* end the (cell ) sexp */ fprintf(fd, " )\n"); /* end the (library DESIGN) sexp */ /* Make an instance of the defined object */ fprintf(fd, " (design %s\n", edf->name); fprintf(fd, " (cellRef %s (libraryRef DESIGN))\n", edf->name); for (prp = edf->property ; prp ; prp = prp->next) { fprintf(fd, " "); fprint_property(fd, prp); fprintf(fd, "\n"); } fprintf(fd, " )\n"); fprintf(fd, ")\n"); fflush(fd); } verilog-0.9.7/tgt-fpga/PaxHeaders.14238/xilinx.h0000644000202500001440000000005012204466647017425 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/xilinx.h0000644000202500001440000001222712204466647016753 0ustar00steveusers00000000000000#ifndef __xilinx_H #define __xilinx_H /* * Copyright (c) 2003 Stephen Williams (steve at 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: xilinx.h,v 1.9 2007/02/26 19:49:50 steve Exp $" #endif /* * This header file includes XILINX library support functions. They * manage the creation and reference of cells from the library. Use * the xilinx_cell_* functions to get an edif_cell_t from the * library. The function will create the cell in the library if * needed, or will return the existing cell if it was already called. */ # include "edif.h" /* === BUF Devices === */ /* Buffer types of devices have the BUF_O and BUF_I pin assignments. The BUF, INV, and certain specialized devices fit in this category. */ extern edif_cell_t xilinx_cell_buf (edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_bufe(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_bufg(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_buft(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_inv (edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_ibuf(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_obuf(edif_xlibrary_t xlib); #define BUF_O 0 #define BUF_I 1 /* Only bufe and buft buffers have this input. */ #define BUF_T 2 /* === LUT Devices === */ /* Most Xilinx devices have LUT2/3/4 devices that take, respectively, 2, 3 or 4 inputs. All forms have a single bit output. Also, the real behavior of the device will need to be specified by an INIT parameter string. */ extern edif_cell_t xilinx_cell_lut2(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_lut3(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib); #define LUT_O 0 #define LUT_I0 1 #define LUT_I1 2 #define LUT_I2 3 #define LUT_I3 4 /* === Flip-Flop Devices === */ /* * These are flip-flops of various sort, but similar pinouts. */ extern edif_cell_t xilinx_cell_fdce(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_fdcpe(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib); #define FDCE_Q 0 #define FDCE_C 1 #define FDCE_D 2 #define FDCE_CE 3 #define FDCE_CLR 4 #define FDCE_PRE 5 /* === Virtex/Virtex2 Carry Chain Logic === */ extern edif_cell_t xilinx_cell_mult_and(edif_xlibrary_t xlib); #define MULT_AND_LO 0 #define MULT_AND_I0 1 #define MULT_AND_I1 2 extern edif_cell_t xilinx_cell_muxcy(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_muxcy_l(edif_xlibrary_t xlib); #define MUXCY_O 0 #define MUXCY_DI 1 #define MUXCY_CI 2 #define MUXCY_S 3 extern edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib); #define XORCY_O 0 #define XORCY_CI 1 #define XORCY_LI 2 /* === Virtex/Virtex2 MUX devices */ extern edif_cell_t xilinx_cell_muxf5(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_muxf6(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_muxf7(edif_xlibrary_t xlib); extern edif_cell_t xilinx_cell_muxf8(edif_xlibrary_t xlib); #define MUXF_O 0 #define MUXF_I0 1 #define MUXF_I1 2 #define MUXF_S 3 /* === Inheritable Methods === */ extern void virtex_logic(ivl_net_logic_t net); extern void virtex_generic_dff(ivl_lpm_t net); extern void virtex_eq(ivl_lpm_t net); extern void virtex_ge(ivl_lpm_t net); extern void virtex_mux(ivl_lpm_t net); extern void virtex_add(ivl_lpm_t net); extern void xilinx_common_header(ivl_design_t des); extern void xilinx_show_footer(ivl_design_t des); extern void xilinx_show_scope(ivl_scope_t scope); extern void xilinx_pad(ivl_signal_t, const char*str); extern void xilinx_logic(ivl_net_logic_t net); extern void xilinx_mux(ivl_lpm_t net); extern void xilinx_add(ivl_lpm_t net); extern void xilinx_shiftl(ivl_lpm_t net); /* * $Log: xilinx.h,v $ * Revision 1.9 2007/02/26 19:49:50 steve * Spelling fixes (larry doolittle) * * Revision 1.8 2003/08/15 02:23:53 steve * Add synthesis support for synchronous reset. * * Revision 1.7 2003/07/04 00:10:09 steve * Generate MUXF5 based 4-input N-wide muxes. * * Revision 1.6 2003/07/02 03:02:15 steve * More xilinx common code. * * Revision 1.5 2003/07/02 00:25:40 steve * Add xilinx support for bufif1. * * Revision 1.4 2003/06/28 04:18:47 steve * Add support for wide OR/NOR gates. * * Revision 1.3 2003/06/26 03:57:05 steve * Add Xilinx support for A/B MUX devices. * * Revision 1.2 2003/06/25 02:55:57 steve * Virtex and Virtex2 share much code. * * Revision 1.1 2003/04/05 05:53:34 steve * Move library cell management to common file. * */ #endif verilog-0.9.7/tgt-fpga/PaxHeaders.14238/generic.h0000644000202500001440000000005012204466647017526 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/generic.h0000644000202500001440000000335112204466647017052 0ustar00steveusers00000000000000#ifndef __generic_H #define __generic_H /* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: generic.h,v 1.3 2003/08/26 16:26:02 steve Exp $" #endif # include "edif.h" extern edif_t edf; extern edif_xlibrary_t xlib; /* * The cell_* variables below are the various kinds of devices that * this family supports as primitives. If the cell type is used at * least once, then the edif_cell_t is non-zero and will also be * included in the library declaration. The constants underneath are * pin assignments for the cell. */ extern edif_cell_t cell_0; extern edif_cell_t cell_1; extern edif_cell_t cell_ipad; extern edif_cell_t cell_opad; extern edif_cell_t cell_iopad; /* * $Log: generic.h,v $ * Revision 1.3 2003/08/26 16:26:02 steve * ifdef idents correctly. * * Revision 1.2 2003/07/03 17:46:33 steve * IOPAD support. * * Revision 1.1 2003/06/25 02:55:57 steve * Virtex and Virtex2 share much code. * */ #endif verilog-0.9.7/tgt-fpga/PaxHeaders.14238/d-generic-edif.c0000644000202500001440000000005012204466647020647 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/d-generic-edif.c0000644000202500001440000003331112204466647020172 0ustar00steveusers00000000000000/* * Copyright (c) 2001-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "device.h" # include "fpga_priv.h" # include # include # include struct nexus_recall { struct nexus_recall*next; ivl_nexus_t nex; char* joined; }; static struct nexus_recall*net_list = 0; static unsigned edif_uref = 0; static void edif_set_nexus_joint(ivl_nexus_t nex, const char*joint) { size_t newlen; struct nexus_recall*rec; rec = (struct nexus_recall*)ivl_nexus_get_private(nex); if (rec == 0) { rec = malloc(sizeof(struct nexus_recall)); rec->nex = nex; rec->joined = malloc(8); rec->joined[0] = 0; rec->next = net_list; net_list = rec; ivl_nexus_set_private(nex, rec); } newlen = strlen(rec->joined) + strlen(joint) + 2; rec->joined = realloc(rec->joined, newlen); strcat(rec->joined, " "); strcat(rec->joined, joint); } static void show_root_ports_edif(ivl_scope_t root) { char jbuf[1024]; unsigned cnt = ivl_scope_sigs(root); unsigned idx; for (idx = 0 ; idx < cnt ; idx += 1) { ivl_signal_t sig = ivl_scope_sig(root, idx); const char*use_name; const char*dir = 0; if (ivl_signal_attr(sig, "PAD") != 0) continue; switch (ivl_signal_port(sig)) { case IVL_SIP_NONE: continue; case IVL_SIP_INPUT: dir = "INPUT"; break; case IVL_SIP_OUTPUT: dir = "OUTPUT"; break; case IVL_SIP_INOUT: dir = "INOUT"; break; } use_name = ivl_signal_basename(sig); if (ivl_signal_pins(sig) == 1) { fprintf(xnf, " (port %s (direction %s))\n", use_name, dir); sprintf(jbuf, "(portRef %s)", use_name); edif_set_nexus_joint(ivl_signal_pin(sig, 0), jbuf); } else { unsigned pin; for (pin = 0 ; pin < ivl_signal_pins(sig); pin += 1) { fprintf(xnf, " (port (rename %s_%u " "\"%s[%u]\") (direction %s))\n", use_name, pin, use_name, pin, dir); sprintf(jbuf, "(portRef %s_%u)", use_name, pin); edif_set_nexus_joint(ivl_signal_pin(sig, pin), jbuf); } } } } static void edif_show_header_generic(ivl_design_t des, const char*library) { ivl_scope_t root = ivl_design_root(des); /* write the primitive header */ fprintf(xnf, "(edif %s\n", ivl_scope_name(root)); fprintf(xnf, " (edifVersion 2 0 0)\n"); fprintf(xnf, " (edifLevel 0)\n"); fprintf(xnf, " (keywordMap (keywordLevel 0))\n"); fprintf(xnf, " (status\n"); fprintf(xnf, " (written\n"); fprintf(xnf, " (timeStamp 0 0 0 0 0 0)\n"); fprintf(xnf, " (author \"unknown\")\n"); fprintf(xnf, " (program \"Icarus Verilog/fpga.tgt\")))\n"); /* Write out the external references here? */ fputs(library, xnf); /* Write out the library header */ fprintf(xnf, " (library DESIGN\n"); fprintf(xnf, " (edifLevel 0)\n"); fprintf(xnf, " (technology (numberDefinition))\n"); /* The root module is a cell in the library. */ fprintf(xnf, " (cell %s\n", ivl_scope_name(root)); fprintf(xnf, " (cellType GENERIC)\n"); fprintf(xnf, " (view net\n"); fprintf(xnf, " (viewType NETLIST)\n"); fprintf(xnf, " (interface\n"); show_root_ports_edif(root); fprintf(xnf, " )\n"); /* end the (interface ) sexp */ fprintf(xnf, " (contents\n"); } static const char*external_library_text = " (external VIRTEX (edifLevel 0) (technology (numberDefinition))\n" " (cell AND2 (cellType GENERIC)\n" " (view net\n" " (viewType NETLIST)\n" " (interface\n" " (port O (direction OUTPUT))\n" " (port I0 (direction INPUT))\n" " (port I1 (direction INPUT)))))\n" " (cell BUF (cellType GENERIC)\n" " (view net\n" " (viewType NETLIST)\n" " (interface\n" " (port O (direction OUTPUT))\n" " (port I (direction INPUT)))))\n" " (cell FDCE (cellType GENERIC)\n" " (view net\n" " (viewType NETLIST)\n" " (interface\n" " (port Q (direction OUTPUT))\n" " (port D (direction INPUT))\n" " (port C (direction INPUT))\n" " (port CE (direction INPUT))\n" " (port CLR (direction INPUT)))))\n" " (cell FDCPE (cellType GENERIC)\n" " (view net\n" " (viewType NETLIST)\n" " (interface\n" " (port Q (direction OUTPUT))\n" " (port D (direction INPUT))\n" " (port C (direction INPUT))\n" " (port CE (direction INPUT))\n" " (port PRE (direction INPUT))\n" " (port CLR (direction INPUT)))))\n" " (cell GND (cellType GENERIC)\n" " (view net\n" " (viewType NETLIST)\n" " (interface (port G (direction OUTPUT)))))\n" " (cell NOR2 (cellType GENERIC)\n" " (view net\n" " (viewType NETLIST)\n" " (interface\n" " (port O (direction OUTPUT))\n" " (port I0 (direction INPUT))\n" " (port I1 (direction INPUT)))))\n" " (cell NOR3 (cellType GENERIC)\n" " (view net\n" " (viewType NETLIST)\n" " (interface\n" " (port O (direction OUTPUT))\n" " (port I0 (direction INPUT))\n" " (port I1 (direction INPUT))\n" " (port I2 (direction INPUT)))))\n" " (cell VCC (cellType GENERIC)\n" " (view net\n" " (viewType NETLIST)\n" " (interface (port P (direction OUTPUT)))))\n" " )\n" ; static void edif_show_header(ivl_design_t des) { edif_show_header_generic(des, external_library_text); } static void edif_show_consts(ivl_design_t des) { unsigned idx; char jbuf[128]; for (idx = 0 ; idx < ivl_design_consts(des) ; idx += 1) { unsigned pin; ivl_net_const_t net = ivl_design_const(des, idx); const char*val = ivl_const_bits(net); for (pin = 0 ; pin < ivl_const_pins(net) ; pin += 1) { ivl_nexus_t nex = ivl_const_pin(net, pin); const char*name; const char*port; edif_uref += 1; switch (val[pin]) { case '0': name = "GND"; port = "GROUND"; break; case '1': name = "VCC"; port = "VCC"; break; default: name = "???"; port = "?"; break; } fprintf(xnf, "(instance U%u " "(viewRef net" " (cellRef %s (libraryRef VIRTEX))))\n", edif_uref, name); sprintf(jbuf, "(portRef %s (instanceRef U%u))", port, edif_uref); edif_set_nexus_joint(nex, jbuf); } } } static void edif_show_footer(ivl_design_t des) { unsigned nref = 0; struct nexus_recall*cur; ivl_scope_t root = ivl_design_root(des); edif_show_consts(des); for (cur = net_list ; cur ; cur = cur->next) { fprintf(xnf, "(net (rename N%u \"%s\") (joined %s))\n", nref, ivl_nexus_name(cur->nex), cur->joined); nref += 1; } fprintf(xnf, " )\n"); /* end the (contents ) sexp */ fprintf(xnf, " )\n"); /* end the (view ) sexp */ fprintf(xnf, " )\n"); /* end the (cell ) sexp */ fprintf(xnf, " )\n"); /* end the (library ) sexp */ /* Make an instance of the defined object */ fprintf(xnf, " (design %s\n", ivl_scope_name(root)); fprintf(xnf, " (cellRef %s (libraryRef DESIGN))\n", ivl_scope_name(root)); if (part) fprintf(xnf, " (property PART (string \"%s\"))\n", part); fprintf(xnf, " )\n"); fprintf(xnf, ")\n"); /* end the (edif ) sexp */ } static void edif_show_logic(ivl_net_logic_t net) { char jbuf[1024]; unsigned idx; edif_uref += 1; switch (ivl_logic_type(net)) { case IVL_LO_AND: assert(ivl_logic_pins(net) <= 10); assert(ivl_logic_pins(net) >= 3); fprintf(xnf, "(instance (rename U%u \"%s\")", edif_uref, ivl_logic_name(net)); fprintf(xnf, " (viewRef net" " (cellRef AND%u (libraryRef VIRTEX))))\n", ivl_logic_pins(net) - 1); sprintf(jbuf, "(portRef O (instanceRef U%u))", edif_uref); edif_set_nexus_joint(ivl_logic_pin(net, 0), jbuf); for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { sprintf(jbuf, "(portRef I%u (instanceRef U%u))", idx-1, edif_uref); edif_set_nexus_joint(ivl_logic_pin(net, idx), jbuf); } break; case IVL_LO_BUF: assert(ivl_logic_pins(net) == 2); fprintf(xnf, "(instance (rename U%u \"%s\")", edif_uref, ivl_logic_name(net)); fprintf(xnf, " (viewRef net" " (cellRef BUF (libraryRef VIRTEX))))\n"); sprintf(jbuf, "(portRef O (instanceRef U%u))", edif_uref); edif_set_nexus_joint(ivl_logic_pin(net, 0), jbuf); sprintf(jbuf, "(portRef I (instanceRef U%u))", edif_uref); edif_set_nexus_joint(ivl_logic_pin(net, 1), jbuf); break; case IVL_LO_BUFZ: { static int bufz_warned_once=0; if (!bufz_warned_once) { fprintf (stderr, "0:0: internal warning: BUFZ objects found " "in EDIF netlist.\n"); fprintf (stderr, "0:0: : I'll make BUFs for them.\n"); bufz_warned_once=1; } assert(ivl_logic_pins(net) == 2); fprintf(xnf, "(instance (rename U%u \"%s\")", edif_uref, ivl_logic_name(net)); fprintf(xnf, " (viewRef net" " (cellRef BUF (libraryRef VIRTEX))))\n"); sprintf(jbuf, "(portRef O (instanceRef U%u))", edif_uref); edif_set_nexus_joint(ivl_logic_pin(net, 0), jbuf); sprintf(jbuf, "(portRef I (instanceRef U%u))", edif_uref); edif_set_nexus_joint(ivl_logic_pin(net, 1), jbuf); } break; case IVL_LO_NOR: assert(ivl_logic_pins(net) <= 10); assert(ivl_logic_pins(net) >= 3); fprintf(xnf, "(instance (rename U%u \"%s\")", edif_uref, ivl_logic_name(net)); fprintf(xnf, " (viewRef net" " (cellRef NOR%u (libraryRef VIRTEX))))\n", ivl_logic_pins(net) - 1); sprintf(jbuf, "(portRef O (instanceRef U%u))", edif_uref); edif_set_nexus_joint(ivl_logic_pin(net, 0), jbuf); for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { sprintf(jbuf, "(portRef I%u (instanceRef U%u))", idx-1, edif_uref); edif_set_nexus_joint(ivl_logic_pin(net, idx), jbuf); } break; default: fprintf(stderr, "UNSUPPORT LOGIC TYPE: %u\n", ivl_logic_type(net)); } } static void edif_show_generic_dff(ivl_lpm_t net) { ivl_nexus_t nex; char jbuf[1024]; unsigned idx; ivl_nexus_t aclr = ivl_lpm_async_clr(net); ivl_nexus_t aset = ivl_lpm_async_set(net); ivl_expr_t avalue = 0; const char*abits = 0; const char*fdcell = "FDCE"; if (aset != 0) { fdcell = "FDCPE"; avalue = ivl_lpm_aset_value(net); assert(avalue); abits = ivl_expr_bits(avalue); assert(abits); } for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { edif_uref += 1; fprintf(xnf, "(instance (rename U%u \"%s.%s[%u]\")", edif_uref, ivl_scope_name(ivl_lpm_scope(net)), ivl_lpm_basename(net), idx); fprintf(xnf, " (viewRef net" " (cellRef %s (libraryRef VIRTEX))))\n", fdcell); nex = ivl_lpm_q(net, idx); sprintf(jbuf, "(portRef Q (instanceRef U%u))", edif_uref); edif_set_nexus_joint(nex, jbuf); nex = ivl_lpm_data(net, idx); sprintf(jbuf, "(portRef D (instanceRef U%u))", edif_uref); edif_set_nexus_joint(nex, jbuf); nex = ivl_lpm_clk(net); sprintf(jbuf, "(portRef C (instanceRef U%u))", edif_uref); edif_set_nexus_joint(nex, jbuf); if ((nex = ivl_lpm_enable(net))) { sprintf(jbuf, "(portRef CE (instanceRef U%u))", edif_uref); edif_set_nexus_joint(nex, jbuf); } if (aclr) { sprintf(jbuf, "(portRef CLR (instanceRef U%u))", edif_uref); edif_set_nexus_joint(aclr, jbuf); } if (aset) { if (abits[idx] == '1') { sprintf(jbuf, "(portRef PRE (instanceRef U%u))", edif_uref); edif_set_nexus_joint(aset, jbuf); } else { assert(aclr == 0); sprintf(jbuf, "(portRef CLR (instanceRef U%u))", edif_uref); edif_set_nexus_joint(aset, jbuf); } } } } const struct device_s d_generic_edif = { edif_show_header, edif_show_footer, 0, /* show_cell_scope not implemented. */ 0, /* draw_pad not implemented */ edif_show_logic, edif_show_generic_dff, 0, /* show_cmp_eq */ 0, /* show_cmp_ne */ 0, /* show_cmp_ge */ 0, /* show_cmp_gt */ 0, 0, /* show_add */ 0, /* show_sub */ 0, /* show_shiftl */ 0 /* show_shiftr */ }; verilog-0.9.7/tgt-fpga/PaxHeaders.14238/fpga.c0000644000202500001440000000005012204466647017022 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/fpga.c0000644000202500001440000001164512204466647016353 0ustar00steveusers00000000000000/* * Copyright (c) 2001 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: fpga.c,v 1.10 2003/10/27 02:18:28 steve Exp $" #endif # include "config.h" /* * This is the FPGA target module. */ # include # include # include "fpga_priv.h" # include /* This is the opened xnf file descriptor. It is the output that this code generator writes to. */ FILE*xnf = 0; const char*part = 0; const char*arch = 0; device_t device = 0; int scope_has_attribute(ivl_scope_t s, const char *name) { int i; const struct ivl_attribute_s *a; for (i=0; ikey,name) == 0) return 1; } return 0; } static int show_process(ivl_process_t net, void*x) { ivl_scope_t scope = ivl_process_scope(net); /* Ignore processes that are within scopes that are cells. The cell_scope will generate a cell to represent the entire scope. */ if (scope_has_attribute(scope, "ivl_synthesis_cell")) return 0; fprintf(stderr, "fpga target: unsynthesized behavioral code\n"); return 0; } static void show_pads(ivl_scope_t scope) { unsigned idx; if (device->show_pad == 0) return; for (idx = 0 ; idx < ivl_scope_sigs(scope) ; idx += 1) { ivl_signal_t sig = ivl_scope_sig(scope, idx); const char*pad; if (ivl_signal_port(sig) == IVL_SIP_NONE) continue; pad = ivl_signal_attr(sig, "PAD"); if (pad == 0) continue; assert(device->show_pad); device->show_pad(sig, pad); } } static void show_constants(ivl_design_t des) { unsigned idx; if (device->show_constant == 0) return; for (idx = 0 ; idx < ivl_design_consts(des) ; idx += 1) { ivl_net_const_t con = ivl_design_const(des, idx); device->show_constant(con); } } /* * This is the main entry point that ivl uses to invoke me, the code * generator. */ int target_design(ivl_design_t des) { ivl_scope_t root = ivl_design_root(des); const char*path = ivl_design_flag(des, "-o"); xnf = fopen(path, "w"); if (xnf == 0) { perror(path); return -1; } part = ivl_design_flag(des, "part"); if (part && (part[0] == 0)) part = 0; arch = ivl_design_flag(des, "arch"); if (arch && (arch[0] == 0)) arch = 0; if (arch == 0) arch = "lpm"; device = device_from_arch(arch); if (device == 0) { fprintf(stderr, "Unknown architecture arch=%s\n", arch); return -1; } /* Call the device driver to generate the netlist header. */ device->show_header(des); /* Catch any behavioral code that is left, and write warnings that it is not supported. */ ivl_design_process(des, show_process, 0); /* Get the pads from the design, and draw them to connect to the associated signals. */ show_pads(root); /* Scan the scopes, looking for gates to draw into the output netlist. */ show_scope_gates(root, 0); show_constants(des); /* Call the device driver to close out the file. */ device->show_footer(des); fclose(xnf); xnf = 0; return 0; } /* * $Log: fpga.c,v $ * Revision 1.10 2003/10/27 02:18:28 steve * Emit constants for LPM device. * * Revision 1.9 2003/08/07 04:04:01 steve * Add an LPM device type. * * Revision 1.8 2003/06/25 01:49:06 steve * Spelling fixes. * * Revision 1.7 2003/06/24 03:55:00 steve * Add ivl_synthesis_cell support for virtex2. * * Revision 1.6 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.5 2001/09/16 01:48:16 steve * Suppor the PAD attribute on signals. * * Revision 1.4 2001/09/02 21:33:07 steve * Rearrange the XNF code generator to be generic-xnf * so that non-XNF code generation is also possible. * * Start into the virtex EDIF output driver. * * Revision 1.3 2001/09/01 02:01:30 steve * identity compare, and PWR records for constants. * * Revision 1.2 2001/08/31 02:59:06 steve * Add root port SIG records. * * Revision 1.1 2001/08/28 04:14:20 steve * Add the fpga target. * */ verilog-0.9.7/tgt-fpga/PaxHeaders.14238/mangle.c0000644000202500001440000000005012204466647017350 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/mangle.c0000644000202500001440000000520112204466647016670 0ustar00steveusers00000000000000/* * Copyright (c) 2001-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "fpga_priv.h" # include # include static size_t xnf_mangle_scope_name(ivl_scope_t net, char*buf, size_t nbuf) { unsigned cnt = 0; ivl_scope_t parent = ivl_scope_parent(net); if (parent) { cnt = xnf_mangle_scope_name(parent, buf, nbuf); buf += cnt; nbuf -= cnt; *buf++ = '/'; nbuf -= 1; cnt += 1; } strcpy(buf, ivl_scope_basename(net)); cnt += strlen(buf); return cnt; } void xnf_mangle_logic_name(ivl_net_logic_t net, char*buf, size_t nbuf) { size_t cnt = xnf_mangle_scope_name(ivl_logic_scope(net), buf, nbuf); buf[cnt++] = '/'; strcpy(buf+cnt, ivl_logic_basename(net)); } void xnf_mangle_lpm_name(ivl_lpm_t net, char*buf, size_t nbuf) { size_t cnt = xnf_mangle_scope_name(ivl_lpm_scope(net), buf, nbuf); buf[cnt++] = '/'; strcpy(buf+cnt, ivl_lpm_basename(net)); } /* * Nexus names are used in pin records to connect things together. It * almost doesn't matter what the nexus name is, but for readability * we choose a name that is close to the nexus name. This function * converts the existing name to a name that XNF can use. * * For speed, this function saves the calculated string into the real * nexus by using the private pointer. Every nexus is used at least * twice, so this cuts the mangling time in half at least. */ const char* xnf_mangle_nexus_name(ivl_nexus_t net) { char*name = ivl_nexus_get_private(net); char*cp; if (name != 0) { return name; } name = malloc(strlen(ivl_nexus_name(net)) + 1); strcpy(name, ivl_nexus_name(net)); for (cp = name ; *cp ; cp += 1) switch (*cp) { case '.': *cp = '/'; break; default: break; } ivl_nexus_set_private(net, name); return name; } verilog-0.9.7/tgt-fpga/PaxHeaders.14238/fpga.conf0000644000202500001440000000005012204466647017525 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/fpga.conf0000644000202500001440000000014712204466647017051 0ustar00steveusers00000000000000functor:synth2 functor:synth functor:syn-rules functor:cprop functor:nodangle -t:dll flag:DLL=fpga.tgt verilog-0.9.7/tgt-fpga/PaxHeaders.14238/device.h0000644000202500001440000000005012204466647017351 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/device.h0000644000202500001440000001052012204466647016671 0ustar00steveusers00000000000000#ifndef __device_H #define __device_H /* * Copyright (c) 2001-2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: device.h,v 1.15 2007/02/26 19:49:49 steve Exp $" #endif # include /* * This code generator supports a variety of device types. It does * this by keeping a device "driver" structure for each device * type. The device structure contains pointers to functions that emit * the proper XNF for a given type of device. * * If a device supports a method, the function pointer is filled in * with a pointer to the proper function. * * If a device does not support the method, then the pointer is null. */ typedef const struct device_s* device_t; struct device_s { /* These methods draw leading and trailing format text. */ void (*show_header)(ivl_design_t des); void (*show_footer)(ivl_design_t des); /* Draw scopes marked by ivl_synthesis_cell */ void (*show_cell_scope)(ivl_scope_t net); /* Draw pads connected to the specified signal. */ void (*show_pad)(ivl_signal_t sig, const char*str); /* Draw basic logic devices. */ void (*show_logic)(ivl_net_logic_t net); /* This method emits a D type Flip-Flop */ void (*show_dff)(ivl_lpm_t net); /* These methods show various comparators */ void (*show_cmp_eq)(ivl_lpm_t net); void (*show_cmp_ne)(ivl_lpm_t net); void (*show_cmp_ge)(ivl_lpm_t net); void (*show_cmp_gt)(ivl_lpm_t net); /* This method draws MUX devices */ void (*show_mux)(ivl_lpm_t net); /* This method draws ADD devices */ void (*show_add)(ivl_lpm_t net); void (*show_sub)(ivl_lpm_t net); /* These methods draw SHIFT devices */ void (*show_shiftl)(ivl_lpm_t net); void (*show_shiftr)(ivl_lpm_t net); /* Multipliers */ void (*show_mult)(ivl_lpm_t net); /* Constants */ void (*show_constant)(ivl_net_const_t net); }; /* * Return the device_t cookie given the name of the architecture. If * the device is not found, return 0. * * This function is used if the user specifies the architecture * explicitly, with the -parch=name flag. */ extern device_t device_from_arch(const char*arch); /* * $Log: device.h,v $ * Revision 1.15 2007/02/26 19:49:49 steve * Spelling fixes (larry doolittle) * * Revision 1.14 2003/11/12 03:20:14 steve * devices need show_cmp_gt * * Revision 1.13 2003/10/27 02:18:27 steve * Emit constants for LPM device. * * Revision 1.12 2003/08/09 03:23:03 steve * Add support for IVL_LPM_MULT device. * * Revision 1.11 2003/06/24 03:55:00 steve * Add ivl_synthesis_cell support for virtex2. * * Revision 1.10 2002/10/28 02:05:56 steve * Add Virtex code generators for left shift, * subtraction, and GE comparators. * * Revision 1.9 2002/08/12 01:35:02 steve * conditional ident string using autoconfig. * * Revision 1.8 2002/08/11 23:47:04 steve * Add missing Log and Ident strings. * * Revision 1.7 2001/09/16 01:48:16 steve * Suppor the PAD attribute on signals. * * Revision 1.6 2001/09/02 21:33:07 steve * Rearrange the XNF code generator to be generic-xnf * so that non-XNF code generation is also possible. * * Start into the virtex EDIF output driver. * * Revision 1.5 2001/09/01 04:30:44 steve * Generic ADD code. * * Revision 1.4 2001/09/01 02:28:42 steve * Generate code for MUX devices. * * Revision 1.3 2001/09/01 02:01:30 steve * identity compare, and PWR records for constants. * * Revision 1.2 2001/08/31 02:59:06 steve * Add root port SIG records. * * Revision 1.1 2001/08/28 04:14:20 steve * Add the fpga target. * */ #endif verilog-0.9.7/tgt-fpga/PaxHeaders.14238/Makefile.in0000644000202500001440000000005012204466647020006 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/Makefile.in0000644000202500001440000000676212204466647017343 0ustar00steveusers00000000000000# # Copyright 2003 Stephen Williams (steve at 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 # Library General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # SHELL = /bin/sh suffix = @install_suffix@ prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ mandir = @mandir@ datarootdir = @datarootdir@ VPATH = $(srcdir) bindir = @bindir@ libdir = @libdir@ includedir = $(prefix)/include CC = @CC@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ CPPFLAGS = -I.. -I$(srcdir) -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ all: dep fpga.tgt dep: mkdir dep %.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep D = d-generic.o d-generic-edif.o d-lpm.o d-virtex.o d-virtex2.o O = edif.o fpga.o gates.o mangle.o tables.o generic.o xilinx.o $D ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl TGTDEPLIBS=../libivl.a else TGTLDFLAGS= TGTDEPLIBS= endif fpga.tgt: $O $(TGTDEPLIBS) $(CC) @shared@ -o $@ $O $(LDFLAGS) $(TGTLDFLAGS) iverilog-fpga.ps: $(srcdir)/iverilog-fpga.man man -t $(srcdir)/iverilog-fpga.man > iverilog-fpga.ps iverilog-fpga.pdf: iverilog-fpga.ps ps2pdf iverilog-fpga.ps iverilog-fpga.pdf Makefile: $(srcdir)/Makefile.in ../config.status ../config.status --file=$@ clean: rm -rf *.o dep fpga.tgt distclean: clean rm -f Makefile config.log check: all ifeq (@WIN32@,yes) INSTALL_DOC = $(prefix)/iverilog-fpga$(suffix).pdf $(mandir)/man1/iverilog-fpga$(suffix).1 INSTALL_DOCDIR = $(mandir)/man1 all: iverilog-fpga.pdf else INSTALL_DOC = $(mandir)/man1/iverilog-fpga$(suffix).1 INSTALL_DOCDIR = $(mandir)/man1 endif install: all installdirs $(libdir)/ivl$(suffix)/fpga.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/fpga.conf $(libdir)/ivl$(suffix)/fpga-s.conf $(libdir)/ivl$(suffix)/fpga.tgt: ./fpga.tgt $(INSTALL_PROGRAM) ./fpga.tgt "$(DESTDIR)$(libdir)/ivl$(suffix)/fpga.tgt" $(libdir)/ivl$(suffix)/fpga.conf: $(srcdir)/fpga.conf $(INSTALL_DATA) $(srcdir)/fpga.conf "$(DESTDIR)$(libdir)/ivl$(suffix)/fpga.conf" $(libdir)/ivl$(suffix)/fpga-s.conf: $(srcdir)/fpga-s.conf $(INSTALL_DATA) $(srcdir)/fpga-s.conf "$(DESTDIR)$(libdir)/ivl$(suffix)/fpga-s.conf" $(mandir)/man1/iverilog-fpga$(suffix).1: $(srcdir)/iverilog-fpga.man $(INSTALL_DATA) $(srcdir)/iverilog-fpga.man "$(DESTDIR)$(mandir)/man1/iverilog-fpga$(suffix).1" $(prefix)/iverilog-fpga$(suffix).pdf: iverilog-fpga.pdf $(INSTALL_DATA) iverilog-fpga.pdf "$(DESTDIR)$(prefix)/iverilog-fpga$(suffix).pdf" installdirs: $(srcdir)/../mkinstalldirs $(srcdir)/../mkinstalldirs "$(DESTDIR)$(libdir)/ivl$(suffix)" uninstall: rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/fpga.tgt" rm -f "$(DESTDIR)$(INSTALL_DOC)" rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/fpga-s.conf" rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/fpga.conf" -include $(patsubst %.o, dep/%.d, $O) verilog-0.9.7/tgt-fpga/PaxHeaders.14238/xilinx.c0000644000202500001440000000005012204466647017420 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/xilinx.c0000644000202500001440000006471012204466647016752 0ustar00steveusers00000000000000/* * Copyright (c) 2003-2010 Stephen Williams (steve at 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "edif.h" # include "generic.h" # include "xilinx.h" # include "fpga_priv.h" # include # include # include edif_cell_t xilinx_cell_buf(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell) return cell; cell = edif_xcell_create(xlib, "BUF", 2); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_bufe(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell) return cell; cell = edif_xcell_create(xlib, "BUFE", 3); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); edif_cell_portconfig(cell, BUF_T, "E", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_bufg(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell) return cell; cell = edif_xcell_create(xlib, "BUFG", 2); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_buft(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell) return cell; cell = edif_xcell_create(xlib, "BUFT", 3); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); edif_cell_portconfig(cell, BUF_T, "T", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_ibuf(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell) return cell; cell = edif_xcell_create(xlib, "IBUF", 2); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_inv(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell) return cell; cell = edif_xcell_create(xlib, "INV", 2); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_muxf5(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell) return cell; cell = edif_xcell_create(xlib, "MUXF5", 4); edif_cell_portconfig(cell, MUXF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, MUXF_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXF_I1, "I1", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXF_S, "S", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_muxf6(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell) return cell; cell = edif_xcell_create(xlib, "MUXF6", 4); edif_cell_portconfig(cell, MUXF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, MUXF_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXF_I1, "I1", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXF_S, "S", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_obuf(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell) return cell; cell = edif_xcell_create(xlib, "OBUF", 2); edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_lut2(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell != 0) return cell; cell = edif_xcell_create(xlib, "LUT2", 3); edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_lut3(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell != 0) return cell; cell = edif_xcell_create(xlib, "LUT3", 4); edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT); edif_cell_portconfig(cell, LUT_I2, "I2", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell != 0) return cell; cell = edif_xcell_create(xlib, "LUT4", 5); edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT); edif_cell_portconfig(cell, LUT_I2, "I2", IVL_SIP_INPUT); edif_cell_portconfig(cell, LUT_I3, "I3", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_fdce(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell != 0) return cell; cell = edif_xcell_create(xlib, "FDCE", 5); edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_CE, "CE", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_CLR,"CLR", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_fdcpe(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell != 0) return cell; cell = edif_xcell_create(xlib, "FDCPE", 6); edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_CE, "CE", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_CLR,"CLR", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_PRE,"PRE", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell != 0) return cell; cell = edif_xcell_create(xlib, "FDRE", 5); edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_CE, "CE", IVL_SIP_INPUT); edif_cell_portconfig(cell, FDCE_CLR,"R", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_mult_and(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell != 0) return cell; cell = edif_xcell_create(xlib, "MULT_AND", 3); edif_cell_portconfig(cell, MULT_AND_LO, "LO", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, MULT_AND_I0, "I0", IVL_SIP_INPUT); edif_cell_portconfig(cell, MULT_AND_I1, "I1", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_muxcy(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell != 0) return cell; cell = edif_xcell_create(xlib, "MUXCY", 4); edif_cell_portconfig(cell, MUXCY_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, MUXCY_DI, "DI", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXCY_CI, "CI", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXCY_S, "S", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_muxcy_l(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell != 0) return cell; cell = edif_xcell_create(xlib, "MUXCY_L", 4); edif_cell_portconfig(cell, MUXCY_O, "LO", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, MUXCY_DI, "DI", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXCY_CI, "CI", IVL_SIP_INPUT); edif_cell_portconfig(cell, MUXCY_S, "S", IVL_SIP_INPUT); return cell; } edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib) { static edif_cell_t cell = 0; if (cell != 0) return cell; cell = edif_xcell_create(xlib, "XORCY", 3); edif_cell_portconfig(cell, XORCY_O, "O", IVL_SIP_OUTPUT); edif_cell_portconfig(cell, XORCY_CI, "CI", IVL_SIP_INPUT); edif_cell_portconfig(cell, XORCY_LI, "LI", IVL_SIP_INPUT); return cell; } /* * This function does a lot of the stuff common to the header * functions of various Xilinx families. This includes creating the edf * object that holds the netlist. */ void xilinx_common_header(ivl_design_t des) { unsigned idx; ivl_scope_t root = ivl_design_root(des); unsigned sig_cnt = ivl_scope_sigs(root); unsigned nports = 0, pidx; /* Count the ports I'm going to use. */ for (idx = 0 ; idx < sig_cnt ; idx += 1) { ivl_signal_t sig = ivl_scope_sig(root, idx); if (ivl_signal_port(sig) == IVL_SIP_NONE) continue; if (ivl_signal_attr(sig, "PAD") != 0) continue; nports += ivl_signal_pins(sig); } edf = edif_create(ivl_scope_basename(root), nports); pidx = 0; for (idx = 0 ; idx < sig_cnt ; idx += 1) { edif_joint_t jnt; ivl_signal_t sig = ivl_scope_sig(root, idx); if (ivl_signal_port(sig) == IVL_SIP_NONE) continue; if (ivl_signal_attr(sig, "PAD") != 0) continue; if (ivl_signal_pins(sig) == 1) { edif_portconfig(edf, pidx, ivl_signal_basename(sig), ivl_signal_port(sig)); assert(ivl_signal_pins(sig) == 1); jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, 0)); edif_port_to_joint(jnt, edf, pidx); } else { const char*name = ivl_signal_basename(sig); ivl_signal_port_t dir = ivl_signal_port(sig); char buf[128]; unsigned bit; for (bit = 0 ; bit < ivl_signal_pins(sig) ; bit += 1) { const char*tmp; sprintf(buf, "%s[%u]", name, bit); tmp = strdup(buf); edif_portconfig(edf, pidx+bit, tmp, dir); jnt = edif_joint_of_nexus(edf,ivl_signal_pin(sig,bit)); edif_port_to_joint(jnt, edf, pidx+bit); } } pidx += ivl_signal_pins(sig); } assert(pidx == nports); } void xilinx_show_footer(ivl_design_t des) { unsigned idx; for (idx = 0 ; idx < ivl_design_consts(des) ; idx += 1) { unsigned pin; ivl_net_const_t net = ivl_design_const(des, idx); const char*val = ivl_const_bits(net); for (pin = 0 ; pin < ivl_const_pins(net) ; pin += 1) { edif_joint_t jnt; edif_cellref_t pad; jnt = edif_joint_of_nexus(edf, ivl_const_pin(net, pin)); switch (val[pin]) { case '0': pad = edif_cellref_create(edf, cell_0); break; case '1': pad = edif_cellref_create(edf, cell_1); break; default: assert(0); break; } edif_add_to_joint(jnt, pad, 0); } } edif_print(xnf, edf); } /* * Make (or retrieve) a cell in the external library that reflects the * scope with its ports. */ void xilinx_show_scope(ivl_scope_t scope) { edif_cell_t cell; edif_cellref_t ref; unsigned port, idx; cell = edif_xlibrary_scope_cell(xlib, scope); ref = edif_cellref_create(edf, cell); for (idx = 0 ; idx < ivl_scope_sigs(scope) ; idx += 1) { edif_joint_t jnt; ivl_signal_t sig = ivl_scope_sig(scope, idx); if (ivl_signal_port(sig) == IVL_SIP_NONE) continue; port = edif_cell_port_byname(cell, ivl_signal_basename(sig)); jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, 0)); edif_add_to_joint(jnt, ref, port); } } void xilinx_pad(ivl_signal_t sig, const char*str) { unsigned idx; char**pins; if (cell_ipad == 0) { cell_ipad = edif_xcell_create(xlib, "IPAD", 1); edif_cell_portconfig(cell_ipad, 0, "IPAD", IVL_SIP_OUTPUT); } if (cell_opad == 0) { cell_opad = edif_xcell_create(xlib, "OPAD", 1); edif_cell_portconfig(cell_opad, 0, "OPAD", IVL_SIP_INPUT); } if (cell_iopad == 0) { cell_iopad = edif_xcell_create(xlib, "IOPAD", 1); edif_cell_portconfig(cell_iopad, 0, "IOPAD", IVL_SIP_INOUT); } /* Collect an array of pin assignments from the attribute string passed in as str. The format is a comma separated list of location names. */ pins = calloc(ivl_signal_pins(sig), sizeof(char*)); for (idx = 0 ; idx < ivl_signal_pins(sig) ; idx += 1) { const char*tmp = strchr(str, ','); if (tmp == 0) tmp = str+strlen(str); pins[idx] = malloc(tmp-str+1); strncpy(pins[idx], str, tmp-str); pins[idx][tmp-str] = 0; if (*tmp != 0) tmp += 1; str = tmp; } /* Now go through the pins of the signal, creating pads and bufs and joining them to the signal nexus. */ for (idx = 0 ; idx < ivl_signal_pins(sig) ; idx += 1) { edif_joint_t jnt; edif_cellref_t pad, buf; const char*name_str = ivl_signal_basename(sig); if (ivl_signal_pins(sig) > 1) { char name_buf[128]; sprintf(name_buf, "%s[%u]", name_str, idx); name_str = strdup(name_buf); } switch (ivl_signal_port(sig)) { case IVL_SIP_INPUT: pad = edif_cellref_create(edf, cell_ipad); buf = edif_cellref_create(edf, xilinx_cell_ibuf(xlib)); jnt = edif_joint_create(edf); edif_joint_rename(jnt, name_str); edif_add_to_joint(jnt, pad, 0); edif_add_to_joint(jnt, buf, BUF_I); jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, idx)); edif_add_to_joint(jnt, buf, BUF_O); break; case IVL_SIP_OUTPUT: pad = edif_cellref_create(edf, cell_opad); buf = edif_cellref_create(edf, xilinx_cell_obuf(xlib)); jnt = edif_joint_create(edf); edif_joint_rename(jnt, name_str); edif_add_to_joint(jnt, pad, 0); edif_add_to_joint(jnt, buf, BUF_O); jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, idx)); edif_add_to_joint(jnt, buf, BUF_I); break; case IVL_SIP_INOUT: pad = edif_cellref_create(edf, cell_iopad); jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, idx)); edif_add_to_joint(jnt, pad, 0); break; default: assert(0); } if (pins[idx]) edif_cellref_pstring(pad, "LOC", pins[idx]); } /* Don't free the allocated pad name strings. The edif_cellref_pstring function attached the string to the LOC attribute, so the reference is permanent. */ free(pins); } /* * This function handles the case where the user specifies the cell to * use by attribute. */ static void edif_cellref_logic(ivl_net_logic_t net, const char*def) { char*str = strdup(def); char*pins; edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; unsigned idx, port; pins = strchr(str, ':'); assert(pins); *pins++ = 0; /* Locate the cell in the library, lookup by name. */ cell = edif_xlibrary_findcell(xlib, str); assert(cell); ref = edif_cellref_create(edf, cell); for (idx = 0 ; idx < ivl_logic_pins(net) ; idx += 1) { char*tmp; assert(pins); tmp = strchr(pins,','); if (tmp != 0) *tmp++ = 0; else tmp = 0; port = edif_cell_port_byname(cell, pins); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx)); edif_add_to_joint(jnt, ref, port); pins = tmp; } free(str); } static void lut_logic(ivl_net_logic_t net, const char*init3, const char*init4, const char*init5) { edif_cellref_t lut = NULL; /* initialization shuts up gcc -Wall */ edif_joint_t jnt; const char* init = NULL; /* ditto */ assert(ivl_logic_pins(net) <= 5); assert(ivl_logic_pins(net) >= 3); switch (ivl_logic_pins(net)) { case 3: lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); init = init3; break; case 4: lut = edif_cellref_create(edf, xilinx_cell_lut3(xlib)); init = init4; break; case 5: lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib)); init = init5; break; } edif_cellref_pstring(lut, "INIT", init); switch (ivl_logic_pins(net)) { case 5: jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 4)); edif_add_to_joint(jnt, lut, LUT_I3); case 4: jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 3)); edif_add_to_joint(jnt, lut, LUT_I2); case 3: jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2)); edif_add_to_joint(jnt, lut, LUT_I1); } jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, lut, LUT_O); } void xilinx_logic(ivl_net_logic_t net) { edif_cellref_t obj; edif_joint_t jnt; { const char*cellref_attribute = ivl_logic_attr(net, "cellref"); if (cellref_attribute != 0) { edif_cellref_logic(net, cellref_attribute); return; } } switch (ivl_logic_type(net)) { case IVL_LO_BUF: case IVL_LO_BUFZ: assert(ivl_logic_pins(net) == 2); obj = edif_cellref_create(edf, xilinx_cell_buf(xlib)); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, obj, BUF_O); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, obj, BUF_I); break; case IVL_LO_BUFIF0: /* The Xilinx BUFT devices is a BUF that adds a T input. The output is tri-stated if the T input is 1. In other words, it acts just like bufif0. */ assert(ivl_logic_pins(net) == 3); obj = edif_cellref_create(edf, xilinx_cell_buft(xlib)); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, obj, BUF_O); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, obj, BUF_I); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2)); edif_add_to_joint(jnt, obj, BUF_T); break; case IVL_LO_BUFIF1: /* The Xilinx BUFE devices is a BUF that adds an enable input. The output is tri-stated if the E input is 0. In other words, it acts just like bufif1. */ assert(ivl_logic_pins(net) == 3); obj = edif_cellref_create(edf, xilinx_cell_bufe(xlib)); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, obj, BUF_O); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, obj, BUF_I); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2)); edif_add_to_joint(jnt, obj, BUF_T); break; case IVL_LO_NOT: assert(ivl_logic_pins(net) == 2); obj = edif_cellref_create(edf, xilinx_cell_inv(xlib)); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, obj, BUF_O); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, obj, BUF_I); break; case IVL_LO_AND: assert(ivl_logic_pins(net) <= 5); assert(ivl_logic_pins(net) >= 3); lut_logic(net, "8", "80", "8000"); break; case IVL_LO_NOR: assert(ivl_logic_pins(net) <= 5); assert(ivl_logic_pins(net) >= 3); lut_logic(net, "1", "01", "0001"); break; case IVL_LO_OR: assert(ivl_logic_pins(net) <= 5); assert(ivl_logic_pins(net) >= 3); lut_logic(net, "E", "FE", "FFFE"); break; case IVL_LO_XNOR: assert(ivl_logic_pins(net) <= 5); assert(ivl_logic_pins(net) >= 3); lut_logic(net, "9", "69", "9669"); break; case IVL_LO_XOR: assert(ivl_logic_pins(net) <= 5); assert(ivl_logic_pins(net) >= 3); lut_logic(net, "6", "96", "6996"); break; default: fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n", ivl_logic_type(net)); break; } } /* * A fully generic Xilinx MUX is implemented entirely from LUT * devices. */ void xilinx_mux(ivl_lpm_t net) { unsigned idx; edif_cellref_t lut; edif_joint_t jnt; assert(ivl_lpm_selects(net) == 1); /* A/B Mux devices are made from LUT3 devices. I0 is connected to A, I1 to B, and I2 to the Select input. Create as many as are needed to implement the requested width. S B A | Q ------+-- 0 0 0 | 0 0 0 1 | 1 0 1 0 | 0 0 1 1 | 1 1 0 0 | 0 1 0 1 | 0 1 1 0 | 1 1 1 1 | 1 INIT = "CA" */ for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { lut = edif_cellref_create(edf, xilinx_cell_lut3(xlib)); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 0, idx)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 1, idx)); edif_add_to_joint(jnt, lut, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, 0)); edif_add_to_joint(jnt, lut, LUT_I2); edif_cellref_pstring(lut, "INIT", "CA"); } } /* * Any Xilinx device works with this adder. * Generic Xilinx add only works for single bit slices. */ void xilinx_add(ivl_lpm_t net) { const char*ha_init = 0; edif_cellref_t lut; edif_joint_t jnt; switch (ivl_lpm_type(net)) { case IVL_LPM_ADD: ha_init = "6"; break; case IVL_LPM_SUB: ha_init = "9"; break; default: assert(0); } /* If this is a single bit wide, then generate only a half-adder. Normally this is an XOR, but if this is a SUB then it is an XNOR. */ if (ivl_lpm_width(net) == 1) { lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); edif_add_to_joint(jnt, lut, LUT_I1); edif_cellref_pstring(lut, "INIT", ha_init); return; } assert(0); } /* * The left shift is implemented as a matrix of MUX2_1 devices. The * matrix has as many rows as the device width, and a column for each * select. */ void xilinx_shiftl(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); unsigned nsel = 0, swid = 0; unsigned sdx, qdx; edif_cellref_t* cells; edif_cellref_t**table; edif_cellref_t pad0_cell; edif_joint_t pad0; /* First, find out how many select inputs we really need. We can only use the selects that are enough to shift out the entire width of the device. The excess can be used as an enable for the last column. When disabled, the last column emits zeros. */ while (nsel < ivl_lpm_selects(net)) { nsel += 1; swid = 1 << nsel; if (swid >= width) break; } assert(nsel > 0); /* Allocate a matrix of edif_cellref_t variables. A devices will be addressed by the expression table[sdx][qdx]; This should make the algorithm code easier to read. */ cells = calloc(nsel * width, sizeof(edif_cellref_t)); table = calloc(nsel, sizeof(edif_cellref_t*)); for (sdx = 0 ; sdx < nsel ; sdx += 1) table[sdx] = cells + sdx*width; /* Make a 0 valued pad bit. I will use this for all the shift in values that are beyond the input. */ pad0_cell = edif_cellref_create(edf, cell_0); pad0 = edif_joint_create(edf); edif_add_to_joint(pad0, pad0_cell, 0); /* The LUT matrix is columns of devices, with the last column a LUT4 devices. The extra input of the LUT4s in the last column are used as an enable to collect all the excess select inputs. */ /* Allocate the LUT devices of the matrix, and connect the select inputs to I2 of all the devices of the column. */ for (sdx = 0 ; sdx < nsel ; sdx += 1) { const char*init_string = 0; ivl_nexus_t nex = ivl_lpm_select(net,sdx); edif_joint_t sdx_jnt = edif_joint_of_nexus(edf, nex); edif_cell_t lut; if (((sdx+1) == nsel) && (nsel < ivl_lpm_selects(net))) { lut = xilinx_cell_lut4(xlib); init_string = "00CA"; } else { lut = xilinx_cell_lut3(xlib); init_string = "CA"; } for (qdx = 0 ; qdx < width ; qdx += 1) { table[sdx][qdx] = edif_cellref_create(edf, lut); edif_add_to_joint(sdx_jnt, table[sdx][qdx], LUT_I2); edif_cellref_pstring(table[sdx][qdx], "INIT", init_string); } } /* Connect the inputs of the SHIFTL device to the column 0 LUT inputs. The slice on the low end shifts in a 0 for a select input. */ for (qdx = 0 ; qdx < width ; qdx += 1) { ivl_nexus_t nex0, nex1; edif_joint_t jnt0; edif_joint_t jnt1; nex0 = ivl_lpm_data(net,qdx); jnt0 = edif_joint_of_nexus(edf, nex0); if (qdx > 0) { nex1 = ivl_lpm_data(net,qdx-1); jnt1 = edif_joint_of_nexus(edf, nex1); } else { jnt1 = pad0; } edif_add_to_joint(jnt0, table[0][qdx], LUT_I0); edif_add_to_joint(jnt1, table[0][qdx], LUT_I1); } /* Make the inner connections between LUT devices. Each column connects to the previous column, shifted by the power of the column value. If the shifted input falls off the end, then pad with zero. */ for (sdx = 1 ; sdx < nsel ; sdx += 1) { for (qdx = 0 ; qdx < width ; qdx += 1) { unsigned shift = 1 << sdx; edif_joint_t jnt0 = edif_joint_create(edf); edif_joint_t jnt1 = (qdx >= shift) ? edif_joint_create(edf) : pad0; edif_add_to_joint(jnt0, table[sdx][qdx], LUT_I0); edif_add_to_joint(jnt1, table[sdx][qdx], LUT_I1); edif_add_to_joint(jnt0, table[sdx-1][qdx], LUT_O); if (qdx >= shift) edif_add_to_joint(jnt1, table[sdx-1][qdx-shift], LUT_O); } } /* Connect the output of the last column to the output of the SHIFTL device. */ for (qdx = 0 ; qdx < width ; qdx += 1) { ivl_nexus_t nex = ivl_lpm_q(net,qdx); edif_joint_t jnt = edif_joint_of_nexus(edf, nex); edif_add_to_joint(jnt, table[nsel-1][qdx], LUT_O); } /* Connect the excess select inputs to the enable inputs of the LUT4 devices in the last column. */ if (nsel < ivl_lpm_selects(net)) { edif_joint_t jnt; /* XXXX Only support 1 excess bit for now. */ assert((nsel + 1) == ivl_lpm_selects(net)); jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net,nsel)); for (qdx = 0 ; qdx < width ; qdx += 1) edif_add_to_joint(jnt, table[nsel-1][qdx], LUT_I3); } free(cells); free(table); } verilog-0.9.7/tgt-fpga/PaxHeaders.14238/gates.c0000644000202500001440000000005012204466647017210 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/gates.c0000644000202500001440000001263412204466647016540 0ustar00steveusers00000000000000/* * Copyright (c) 2001 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: gates.c,v 1.14 2003/11/12 03:20:14 steve Exp $" #endif # include # include "fpga_priv.h" # include static void show_cell_scope(ivl_scope_t scope) { if (device->show_cell_scope == 0) { fprintf(stderr, "fpga.tgt: ivl_synthesis_cell(scope)" " not supported by this target.\n"); return; } device->show_cell_scope(scope); } static void show_gate_logic(ivl_net_logic_t net) { if (device->show_logic == 0) { fprintf(stderr, "fpga.tgt: IVL LOGIC not supported" " by this target.\n"); return; } assert(device->show_logic); device->show_logic(net); } static void show_gate_lpm(ivl_lpm_t net) { switch (ivl_lpm_type(net)) { case IVL_LPM_ADD: if (device->show_add == 0) { fprintf(stderr, "fpga.tgt: IVL_LPM_ADD not supported" " by this target.\n"); return; } device->show_add(net); break; case IVL_LPM_SUB: if (device->show_sub == 0) { fprintf(stderr, "fpga.tgt: IVL_LPM_SUB not supported" " by this target.\n"); return; } device->show_sub(net); break; case IVL_LPM_CMP_EQ: if (device->show_cmp_eq == 0) { fprintf(stderr, "fpga.tgt: IVL_LPM_CMP_EQ not supported" " by this target.\n"); return; } device->show_cmp_eq(net); break; case IVL_LPM_CMP_NE: if (device->show_cmp_ne == 0) { fprintf(stderr, "fpga.tgt: IVL_LPM_CMP_NE not supported" " by this target.\n"); return; } device->show_cmp_ne(net); break; case IVL_LPM_CMP_GE: if (device->show_cmp_ge == 0) { fprintf(stderr, "fpga.tgt: IVL_LPM_CMP_GE not supported" " by this target.\n"); return; } device->show_cmp_ge(net); break; case IVL_LPM_CMP_GT: if (device->show_cmp_gt == 0) { fprintf(stderr, "fpga.tgt: IVL_LPM_CMP_GT not supported" " by this target.\n"); return; } device->show_cmp_gt(net); break; case IVL_LPM_FF: if (device->show_dff == 0) { fprintf(stderr, "fpga.tgt: IVL_LPM_FF not supported" " by this target.\n"); return; } device->show_dff(net); break; case IVL_LPM_MUX: if (device->show_mux == 0) { fprintf(stderr, "fpga.tgt: IVL_LPM_MUX not supported" " by this target.\n"); return; } device->show_mux(net); break; case IVL_LPM_MULT: if (device->show_mult == 0) { fprintf(stderr, "fpga.tgt: IVL_LPM_MULT not supported" " by this target.\n"); return; } device->show_mult(net); break; case IVL_LPM_SHIFTL: if (device->show_shiftl == 0) { fprintf(stderr, "fpga.tgt: IVL_LPM_SHIFTL not supported" " by this target.\n"); return; } device->show_shiftl(net); break; case IVL_LPM_SHIFTR: if (device->show_shiftr == 0) { fprintf(stderr, "fpga.tgt: IVL_LPM_SHIFTR not supported" " by this target.\n"); return; } device->show_shiftr(net); break; default: fprintf(stderr, "fpga.tgt: unknown LPM type %u\n", ivl_lpm_type(net)); break; } } int show_scope_gates(ivl_scope_t net, void*x) { unsigned idx; if (scope_has_attribute(net, "ivl_synthesis_cell")) { show_cell_scope(net); return 0; } for (idx = 0 ; idx < ivl_scope_logs(net) ; idx += 1) show_gate_logic(ivl_scope_log(net, idx)); for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1) show_gate_lpm(ivl_scope_lpm(net, idx)); return ivl_scope_children(net, show_scope_gates, 0); } /* * $Log: gates.c,v $ * Revision 1.14 2003/11/12 03:20:14 steve * devices need show_cmp_gt * * Revision 1.13 2003/08/09 03:23:03 steve * Add support for IVL_LPM_MULT device. * * Revision 1.12 2003/08/07 04:04:01 steve * Add an LPM device type. * * Revision 1.11 2003/06/24 03:55:01 steve * Add ivl_synthesis_cell support for virtex2. * * Revision 1.10 2002/10/28 02:05:56 steve * Add Virtex code generators for left shift, * subtraction, and GE comparators. * * Revision 1.9 2002/08/12 01:35:03 steve * conditional ident string using autoconfig. * * Revision 1.8 2002/08/11 23:47:04 steve * Add missing Log and Ident strings. * * Revision 1.7 2001/09/09 22:23:28 steve * Virtex support for mux devices and adders * with carry chains. Also, make Virtex specific * implementations of primitive logic. * * Revision 1.6 2001/09/02 21:33:07 steve * Rearrange the XNF code generator to be generic-xnf * so that non-XNF code generation is also possible. * * Start into the virtex EDIF output driver. */ verilog-0.9.7/tgt-fpga/PaxHeaders.14238/d-virtex.c0000644000202500001440000000005012204466647017647 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/d-virtex.c0000644000202500001440000006133012204466647017174 0ustar00steveusers00000000000000/* * Copyright (c) 2003-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "device.h" # include "fpga_priv.h" # include "edif.h" # include "generic.h" # include "xilinx.h" # include # include # include /* * This is a table of cell types that are accessible via the cellref * attribute to a gate. */ const static struct edif_xlib_celltable virtex_celltable[] = { { "BUFG", xilinx_cell_bufg }, { "MULT_AND", xilinx_cell_mult_and }, { 0, 0} }; /* * The show_header function is called before any of the devices of the * netlist are scanned. * * In this function, we look at the ports of the root module to decide * if they are to be made into ports. Modules that have PAD attributes * are *not* to be used as ports, they will be connected to special * PAD devices instead. */ static void virtex_show_header(ivl_design_t des) { const char*part_str = 0; xilinx_common_header(des); xlib = edif_xlibrary_create(edf, "VIRTEX"); edif_xlibrary_set_celltable(xlib, virtex_celltable); if ( (part_str = ivl_design_flag(des, "part")) && (part_str[0] != 0) ) { edif_pstring(edf, "PART", part_str); } cell_0 = edif_xcell_create(xlib, "GND", 1); edif_cell_portconfig(cell_0, 0, "GROUND", IVL_SIP_OUTPUT); cell_1 = edif_xcell_create(xlib, "VCC", 1); edif_cell_portconfig(cell_1, 0, "VCC", IVL_SIP_OUTPUT); } static void virtex_or_wide(ivl_net_logic_t net) { edif_cell_t cell_muxcy_l = xilinx_cell_muxcy_l(xlib); edif_cell_t cell_muxcy = xilinx_cell_muxcy(xlib); edif_cell_t cell_lut4 = xilinx_cell_lut4(xlib); edif_cellref_t true_out, false_out; edif_cellref_t lut, muxcy, muxcy_down=NULL; edif_joint_t jnt; unsigned idx, inputs, lut4_cnt; if (ivl_logic_type(net) == IVL_LO_OR) { true_out = edif_cellref_create(edf, cell_1); false_out = edif_cellref_create(edf, cell_0); } else { true_out = edif_cellref_create(edf, cell_0); false_out = edif_cellref_create(edf, cell_1); } inputs = ivl_logic_pins(net) - 1; lut4_cnt = (inputs-1)/4; for (idx = 0 ; idx < lut4_cnt ; idx += 1) { muxcy = edif_cellref_create(edf, cell_muxcy_l); lut = edif_cellref_create(edf, cell_lut4); edif_cellref_pstring(lut, "INIT", "0001"); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, lut, LUT_O); edif_add_to_joint(jnt, muxcy, MUXCY_S); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, true_out, 0); edif_add_to_joint(jnt, muxcy, MUXCY_DI); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+1)); edif_add_to_joint(jnt, lut, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+2)); edif_add_to_joint(jnt, lut, LUT_I2); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+3)); edif_add_to_joint(jnt, lut, LUT_I3); if (idx > 0) { jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxcy, MUXCY_CI); edif_add_to_joint(jnt, muxcy_down, MUXCY_O); } else { jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxcy, MUXCY_CI); edif_add_to_joint(jnt, false_out, 0); } muxcy_down = muxcy; } muxcy = edif_cellref_create(edf, cell_muxcy); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, true_out, 0); edif_add_to_joint(jnt, muxcy, MUXCY_DI); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxcy, MUXCY_CI); edif_add_to_joint(jnt, muxcy_down, MUXCY_O); switch (ivl_logic_pins(net) - 1 - lut4_cnt*4) { case 1: lut = edif_cellref_create(edf, xilinx_cell_inv(xlib)); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0)); edif_add_to_joint(jnt, lut, BUF_I); break; case 2: lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); edif_cellref_pstring(lut, "INIT", "1"); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1)); edif_add_to_joint(jnt, lut, LUT_I1); break; case 3: lut = edif_cellref_create(edf, xilinx_cell_lut3(xlib)); edif_cellref_pstring(lut, "INIT", "01"); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1)); edif_add_to_joint(jnt, lut, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+2)); edif_add_to_joint(jnt, lut, LUT_I2); break; case 4: lut = edif_cellref_create(edf, cell_lut4); edif_cellref_pstring(lut, "INIT", "0001"); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1)); edif_add_to_joint(jnt, lut, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+2)); edif_add_to_joint(jnt, lut, LUT_I2); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+3)); edif_add_to_joint(jnt, lut, LUT_I3); break; default: assert(0); } jnt = edif_joint_create(edf); edif_add_to_joint(jnt, lut, LUT_O); edif_add_to_joint(jnt, muxcy, MUXCY_S); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, muxcy, MUXCY_O); } /* * Pick off the cases where there is a Virtex specific implementation * that is better then the generic Xilinx implementation. Route the * remaining to the base xilinx_logic implementation. */ void virtex_logic(ivl_net_logic_t net) { /* Nothing I can do if the user expresses a specific opinion. The cellref attribute forces me to let the base xilinx_logic take care of it. */ if (ivl_logic_attr(net, "cellref")) { xilinx_logic(net); return; } switch (ivl_logic_type(net)) { case IVL_LO_OR: case IVL_LO_NOR: if (ivl_logic_pins(net) <= 5) { xilinx_logic(net); } else { virtex_or_wide(net); } break; default: xilinx_logic(net); break; } } void virtex_generic_dff(ivl_lpm_t net) { unsigned idx; ivl_nexus_t aclr = ivl_lpm_async_clr(net); ivl_nexus_t aset = ivl_lpm_async_set(net); ivl_nexus_t sclr = ivl_lpm_sync_clr(net); ivl_nexus_t sset = ivl_lpm_sync_set(net); const char*abits = 0; if (aset) { ivl_expr_t avalue = ivl_lpm_aset_value(net); assert(avalue); abits = ivl_expr_bits(avalue); assert(abits); } /* XXXX Can't handle both synchronous and asynchronous clear. */ assert( ! (aclr && sclr) ); /* XXXX Can't handle synchronous set at all. */ assert( ! sset ); for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { edif_cellref_t obj; ivl_nexus_t nex; edif_joint_t jnt; /* If there is a preset, then select an FDCPE instead of an FDCE device. */ if (aset && (abits[idx] == '1')) { obj = edif_cellref_create(edf, xilinx_cell_fdcpe(xlib)); } else if (aclr) { obj = edif_cellref_create(edf, xilinx_cell_fdce(xlib)); } else if (sclr) { obj = edif_cellref_create(edf, xilinx_cell_fdre(xlib)); } else { obj = edif_cellref_create(edf, xilinx_cell_fdce(xlib)); } jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, obj, FDCE_Q); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, obj, FDCE_D); jnt = edif_joint_of_nexus(edf, ivl_lpm_clk(net)); edif_add_to_joint(jnt, obj, FDCE_C); if ( (nex = ivl_lpm_enable(net)) ) { jnt = edif_joint_of_nexus(edf, nex); edif_add_to_joint(jnt, obj, FDCE_CE); } if (aclr) { jnt = edif_joint_of_nexus(edf, aclr); edif_add_to_joint(jnt, obj, FDCE_CLR); } else if (sclr) { jnt = edif_joint_of_nexus(edf, sclr); edif_add_to_joint(jnt, obj, FDCE_CLR); } if (aset) { if (abits[idx] == '1') { jnt = edif_joint_of_nexus(edf, aset); edif_add_to_joint(jnt, obj, FDCE_PRE); } else { assert(aclr == 0); jnt = edif_joint_of_nexus(edf, aset); edif_add_to_joint(jnt, obj, FDCE_CLR); } } } } /* * This method handles both == and != operators, the identity * comparison operators. * * If the identity compare is applied to small enough input vectors, * it is shoved into a single LUT. Otherwise, it is strung out into a * row of LUT devices chained together by carry muxes. The output of * the comparison is the output of the last mux. * * When the compare is small, a LUT is generated with the appropriate * truth table to cause an == or != result. * * When the compare is too wide for a single LUT, then it is made into * a chain connected by a string of carry mux devices. Each LUT * implements == for up to two pairs of bits, even if the final output * is supposed to be !=. The LUT output is connected to an associated * MUX select input. The CO output of each muxcy is passed up to the * next higher order bits of the compare. * * For identity == compare, a != output from the LUT selects the DI * input of the muxcy, generating a 0 output that is passed up. Since * the next higher muxcy now gets a 0 input to both DI and CI, the * output of the next higher muxcy is guaranteed to be 0, and so on to * the final output of the carry chain. If the output from a LUT is ==, * then the CI input of the muxcy is selected and the truth of this * level depends on lower order bits. The least significant muxcy is * connected to GND and VCC so that its CO follows the least * significant LUT. * * Identity != is the same as == except that the output is * inverted. To get that effect without putting an inverter on the * output of the top muxcy pin CO (which would cost a LUT) the DI * inputs are all connected to VCC instead of GND, and the CI of the * least significant muxcy is connected to GND instead of VCC. The LUT * expressions for the chained compare are configured for ==, with the * changed CI/DI inputs performing the inversion. */ void virtex_eq(ivl_lpm_t net) { edif_cellref_t lut, mux, mux_prev; edif_joint_t jnt, jnt_di; unsigned idx; /* True if I'm implementing CMP_EQ instead of CMP_NE */ int eq = 1; assert(ivl_lpm_width(net) >= 1); if (ivl_lpm_type(net) == IVL_LPM_CMP_NE) eq = 0; switch (ivl_lpm_width(net)) { case 1: lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); edif_cellref_pstring(lut, "INIT", eq? "9" : "6"); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); edif_add_to_joint(jnt, lut, LUT_I1); return; case 2: lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib)); edif_cellref_pstring(lut, "INIT", eq? "9009" : "6FF6"); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); edif_add_to_joint(jnt, lut, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 1)); edif_add_to_joint(jnt, lut, LUT_I2); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 1)); edif_add_to_joint(jnt, lut, LUT_I3); return; default: { edif_cellref_t di; di = edif_cellref_create(edf, eq? cell_0 : cell_1); jnt_di = edif_joint_create(edf); edif_add_to_joint(jnt_di, di, 0); } mux_prev = 0; for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 2) { int subwid = 2; if ((idx + 1) == ivl_lpm_width(net)) subwid = 1; mux = edif_cellref_create(edf, xilinx_cell_muxcy(xlib)); if (subwid == 2) { lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib)); edif_cellref_pstring(lut, "INIT", "9009"); } else { lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); edif_cellref_pstring(lut, "INIT", "9"); } jnt = edif_joint_create(edf); edif_add_to_joint(jnt, lut, LUT_O); edif_add_to_joint(jnt, mux, MUXCY_S); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx)); edif_add_to_joint(jnt, lut, LUT_I1); if (subwid > 1) { jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx+1)); edif_add_to_joint(jnt, lut, LUT_I2); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx+1)); edif_add_to_joint(jnt, lut, LUT_I3); } edif_add_to_joint(jnt_di, mux, MUXCY_DI); if (mux_prev) { jnt = edif_joint_create(edf); edif_add_to_joint(jnt, mux, MUXCY_CI); edif_add_to_joint(jnt, mux_prev, MUXCY_O); } else { edif_cellref_t ci; ci = edif_cellref_create(edf, eq? cell_1 : cell_0); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, ci, 0); edif_add_to_joint(jnt, mux, MUXCY_CI); } mux_prev = mux; } jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, mux_prev, MUXCY_O); return; } } /* * Implement hardware for the device (A >= B). We use LUT devices if * it can handle the slices, or carry chain logic if the slices must * span LUT devices. */ void virtex_ge(ivl_lpm_t net) { edif_cellref_t muxcy_prev; edif_cellref_t lut; edif_joint_t jnt; unsigned idx; if (ivl_lpm_width(net) == 1) { /* If the comparator is a single bit, then use a LUT2 with this truth table: Q A B --+---- 1 | 0 0 0 | 0 1 1 | 1 0 1 | 1 1 Connect the A value to I1 and the B value to I0. */ lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); edif_cellref_pstring(lut, "INIT", "D"); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0)); edif_add_to_joint(jnt, lut, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); edif_add_to_joint(jnt, lut, LUT_I2); return; } /* Handle the case where the device is two slices wide. In this case, we can use a LUT4 to do all the calculation. Use this truth table: Q AA BB --+------ 1 | 00 00 0 | 00 01 0 | 00 10 0 | 00 11 1 | 01 00 1 | 01 01 0 | 01 10 0 | 01 11 1 | 10 00 1 | 10 01 1 | 10 10 0 | 10 11 1 | 11 xx The I3-I0 inputs are A1 A0 B1 B0 in that order. */ assert(ivl_lpm_width(net) >= 2); lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib)); edif_cellref_pstring(lut, "INIT", "F731"); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0)); edif_add_to_joint(jnt, lut, LUT_I2); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 1)); edif_add_to_joint(jnt, lut, LUT_I3); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 1)); edif_add_to_joint(jnt, lut, LUT_I1); /* There are only two slices, so this is all we need. */ if (ivl_lpm_width(net) == 2) { jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, lut, LUT_O); return; } /* The general case requires that we make the >= comparator from slices. This is an iterative design. Each slice has the truth table: An Bn | A >= B ------+------- 0 0 | CI 0 1 | 0 1 0 | 1 1 1 | CI The CI for each slice is the output of the compare of the next less significant bits. We get this truth table by connecting a LUT2 to the S input of a MUXCY. When the S input is (1), it propagates its CI. This suggests that the init value for the LUT be "9" (XNOR). When the MUXCY S input is 0, it propagates a local input. We connect to that input An, and we get the desired and complete truth table for a slice. This iterative definition needs to terminate at the least significant bits. In fact, we have a non-iterative was to deal with the two least significant slices. We take the output of the LUT4 device for the least significant bits, and use that to generate the initial CI for the chain. */ muxcy_prev = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib)); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, lut, LUT_O); edif_add_to_joint(jnt, muxcy_prev, MUXCY_S); { edif_cellref_t p0 = edif_cellref_create(edf, cell_0); edif_cellref_t p1 = edif_cellref_create(edf, cell_1); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, p0, 0); edif_add_to_joint(jnt, muxcy_prev, MUXCY_DI); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, p1, 0); edif_add_to_joint(jnt, muxcy_prev, MUXCY_CI); } for (idx = 2 ; idx < ivl_lpm_width(net) ; idx += 1) { edif_cellref_t muxcy; lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); muxcy = edif_cellref_create(edf, xilinx_cell_muxcy(xlib)); edif_cellref_pstring(lut, "INIT", "9"); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, lut, LUT_O); edif_add_to_joint(jnt, muxcy, MUXCY_S); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxcy, MUXCY_CI); edif_add_to_joint(jnt, muxcy_prev, MUXCY_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, lut, LUT_I0); edif_add_to_joint(jnt, muxcy, MUXCY_DI); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx)); edif_add_to_joint(jnt, lut, LUT_I1); muxcy_prev = muxcy; } jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, muxcy_prev, MUXCY_O); } /* * A 4-input N-wide mux can be made on Virtex devices using MUXF5 and * LUT devices. The MUXF5 selects a LUT device (and is connected to * S[1]) and the LUT devices, connected to S[0], select the input. */ static void virtex_mux4(ivl_lpm_t net) { unsigned idx; assert(ivl_lpm_selects(net) == 2); for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { edif_joint_t jnt; edif_cellref_t lut01; edif_cellref_t lut23; edif_cellref_t muxf5; lut01 = edif_cellref_create(edf, xilinx_cell_lut3(xlib)); edif_cellref_pstring(lut01, "INIT", "CA"); lut23 = edif_cellref_create(edf, xilinx_cell_lut3(xlib)); edif_cellref_pstring(lut23, "INIT", "CA"); muxf5 = edif_cellref_create(edf, xilinx_cell_muxf5(xlib)); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 0, idx)); edif_add_to_joint(jnt, lut01, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 1, idx)); edif_add_to_joint(jnt, lut01, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 2, idx)); edif_add_to_joint(jnt, lut23, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 3, idx)); edif_add_to_joint(jnt, lut23, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, 0)); edif_add_to_joint(jnt, lut01, LUT_I2); edif_add_to_joint(jnt, lut23, LUT_I2); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxf5, MUXF_I0); edif_add_to_joint(jnt, lut01, LUT_O); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxf5, MUXF_I1); edif_add_to_joint(jnt, lut23, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, muxf5, MUXF_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, 1)); edif_add_to_joint(jnt, muxf5, MUXF_S); } } void virtex_mux(ivl_lpm_t net) { switch (ivl_lpm_selects(net)) { case 2: virtex_mux4(net); break; default: xilinx_mux(net); break; } } /* * This function generates ADD/SUB devices for Virtex devices, * based on the documented implementations of ADD8/ADD16, etc., from * the Libraries Guide. * * Each slice of the ADD/SUB device is made from a LUT2 device, an * XORCY device that mixes with the LUT2 to make a full adder, and a * MUXCY_L to propagate the carry. The most significant slice does not * have a carry to propagate, so has no MUXCY_L. * * If the device is a wide adder, then the LUT2 devices are configured * to implement an XOR function and a zero is pumped into the least * significant carry input. * * If the device is really an adder, then the input is turned into an * XNOR, which takes a 1-s complement of the B input. Pump a 1 into * the LSB carry input to finish converting the B input into the 2s * complement. */ void virtex_add(ivl_lpm_t net) { const char*ha_init = 0; edif_cellref_t lut, xorcy, muxcy, pad; edif_joint_t jnt; unsigned idx; if (ivl_lpm_width(net) < 2) { xilinx_add(net); return; } switch (ivl_lpm_type(net)) { case IVL_LPM_ADD: ha_init = "6"; break; case IVL_LPM_SUB: ha_init = "9"; break; default: assert(0); } assert(ivl_lpm_width(net) > 1); lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); xorcy = edif_cellref_create(edf, xilinx_cell_xorcy(xlib)); muxcy = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib)); edif_cellref_pstring(lut, "INIT", ha_init); /* The bottom carry-in takes a constant that primes the add or subtract. */ switch (ivl_lpm_type(net)) { case IVL_LPM_ADD: pad = edif_cellref_create(edf, cell_0); break; case IVL_LPM_SUB: pad = edif_cellref_create(edf, cell_1); break; default: assert(0); } jnt = edif_joint_create(edf); edif_add_to_joint(jnt, pad, 0); edif_add_to_joint(jnt, muxcy, MUXCY_CI); edif_add_to_joint(jnt, xorcy, XORCY_CI); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, xorcy, XORCY_O); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, xorcy, XORCY_LI); edif_add_to_joint(jnt, muxcy, MUXCY_S); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0)); edif_add_to_joint(jnt, lut, LUT_I0); edif_add_to_joint(jnt, muxcy, MUXCY_DI); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); edif_add_to_joint(jnt, lut, LUT_I1); for (idx = 1 ; idx < ivl_lpm_width(net) ; idx += 1) { edif_cellref_t muxcy0 = muxcy; lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); xorcy = edif_cellref_create(edf, xilinx_cell_xorcy(xlib)); edif_cellref_pstring(lut, "INIT", ha_init); /* If this is the last bit, then there is no further propagation in the carry chain, and I can skip the carry mux MUXCY. */ if ((idx+1) < ivl_lpm_width(net)) muxcy = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib)); else muxcy = 0; jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxcy0, MUXCY_O); edif_add_to_joint(jnt, xorcy, XORCY_CI); if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_CI); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, xorcy, XORCY_O); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, xorcy, XORCY_LI); if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_S); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, lut, LUT_I0); if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_DI); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx)); edif_add_to_joint(jnt, lut, LUT_I1); } } const struct device_s d_virtex_edif = { virtex_show_header, xilinx_show_footer, xilinx_show_scope, xilinx_pad, virtex_logic, virtex_generic_dff, virtex_eq, virtex_eq, virtex_ge, 0, /* show_cmp_gt */ virtex_mux, virtex_add, virtex_add, xilinx_shiftl, 0 /* show_shiftr */ }; verilog-0.9.7/tgt-fpga/PaxHeaders.14238/tables.c0000644000202500001440000000005012204466647017357 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/tables.c0000644000202500001440000000476212204466647016712 0ustar00steveusers00000000000000/* * Copyright (c) 2001 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT #ident "$Id: tables.c,v 1.6 2003/08/07 04:04:01 steve Exp $" #endif # include "fpga_priv.h" # include # include extern const struct device_s d_generic; extern const struct device_s d_generic_edif; extern const struct device_s d_lpm_edif; extern const struct device_s d_virtex_edif; extern const struct device_s d_virtex2_edif; const struct device_table_s { const char*name; device_t driver; } device_table[] = { { "generic-edif", &d_generic_edif }, { "generic-xnf", &d_generic }, { "lpm", &d_lpm_edif }, { "virtex", &d_virtex_edif }, { "virtex2", &d_virtex2_edif }, { 0, 0 } }; device_t device_from_arch(const char*arch) { unsigned idx; assert(arch); for (idx = 0 ; device_table[idx].name ; idx += 1) { if (strcmp(arch, device_table[idx].name) == 0) return device_table[idx].driver; } return 0; } /* * $Log: tables.c,v $ * Revision 1.6 2003/08/07 04:04:01 steve * Add an LPM device type. * * Revision 1.5 2003/03/24 00:47:54 steve * Add new virtex2 architecture family, and * also the new edif.h EDIF management functions. * * Revision 1.4 2002/08/12 01:35:03 steve * conditional ident string using autoconfig. * * Revision 1.3 2002/08/11 23:47:04 steve * Add missing Log and Ident strings. * * Revision 1.2 2001/09/06 04:28:40 steve * Separate the virtex and generic-edif code generators. * * Revision 1.1 2001/09/02 21:33:07 steve * Rearrange the XNF code generator to be generic-xnf * so that non-XNF code generation is also possible. * * Start into the virtex EDIF output driver. * */ verilog-0.9.7/tgt-fpga/PaxHeaders.14238/edif.h0000644000202500001440000000005012204466647017021 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/edif.h0000644000202500001440000002243112204466647016345 0ustar00steveusers00000000000000#ifndef __edif_H #define __edif_H /* * Copyright (c) 2003 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include # include /* * These types and functions support the task of generating and * writing out an EDIF 2 0 0 netlist. These functions work by * supporting the creation of an in-core netlist of the design, then * writing the netlist out all at once. The library manages cells with * ports, but does not otherwise interpret cells. They have no * contents. * * The general structure of netlist creation is as follows: * * Create a netlist with edif_create(); * This creates an edif object that represents the design. The * design is given a name, and that name becomes the name of the * single cell that this netlist handles. * * Add ports to the root with edif_portconfig * The design may, if it is a macro to be included in a larger * design, include ports. These are discovered by looking for port * signals in the root module. * * Declare external libraries with edif_xlibrary_create * Normally, this is the single technology library that contains * the primitive cells that the code generator intends to * use. The library is given a name, such as VIRTEX or whatever * the implementation tools expect. Cells are attached to the * library later. An edif netlist may include multiple external * references. * * Declare primitives with edif_xcell_create and edif_cell_portconfig. * These functions create CELL TYPES that are attached to an * external library. The libraries are created by * edif_xlibrary_create. * * Cells can be created at any time before their first use. It * therefore makes the most sense to not create the cell until it * is certain that they are needed by the design. * * Create instances and join them up * The edif_cellref_t objects represent instances of cells, and * are the devices of the generated netlist. These cellrefs are * connected together by the use of edif_joint_t joints. The * joints can be created from ivl_nexus_t objects, or from their * own ether. This instantiating of cells and joining them * together that is the most fun. It is the technology specific * stuff that the code generator does. * * Finally, print the result with edif_print(fd); * This function writes the netlist in memory to an EDIF file on * the stdio stream specified. * * This library is intended to be used once, to build up a netlist and * print it. All the names that are taken as const char* should be * somehow made permanent by the caller. Either they are constant * strings, or they are strduped as necessary to make them * permanent. The library will not duplicate them. */ /* TYPE DECLARATIONS */ /* This represents the entire EDIF design. You only need one of these to hold everything. */ typedef struct edif_s* edif_t; /* Each external library of the design gets one of these. */ typedef struct edif_xlibrary_s* edif_xlibrary_t; /* This represents a type of cell. */ typedef struct edif_cell_s* edif_cell_t; /* A cellref is an *instance* of a cell. */ typedef struct edif_cellref_s* edif_cellref_t; /* This represents a generic joint. Cell ports are connected by being associated with a joint. These can be bound to an ivl_nexus_t object, of stand along. */ typedef struct edif_joint_s* edif_joint_t; /* This structure defines a table that can be attached to an xlibrary to incorporate black-box cells to the library. The cell_name is the name that may be passed to the edif_xlibrary_findcell function, and the function pointer points to a function that creates the cell and defines ports for it. A real celltable is terminated by an entry with a null pointer for the cell_name. */ struct edif_xlib_celltable { const char*cell_name; edif_cell_t (*cell_func)(edif_xlibrary_t xlib); }; /* FUNCTIONS */ /* Start a new EDIF design. The design_name will be used as the name of the top-mode module of the design. */ extern edif_t edif_create(const char*design_name, unsigned nports); /* macro ports to the design are handled by this library similar to cells. The user creates ports with this function. This function configures the sole "port" of the cell with the name and dir passed in. The direction, in this case, is the *interface* direction. */ extern void edif_portconfig(edif_t edf, unsigned idx, const char*name, ivl_signal_port_t dir); /* This is like edif_add_to_joint, but works with the edif port. */ extern void edif_port_to_joint(edif_joint_t jnt, edif_t edf, unsigned port); /* The design may have properties attached to it. These properties will be attached to the instance declared in the footer of the EDIF file. */ extern void edif_pstring(edif_t edf, const char*name, const char*value); /* Create an external library and attach it to the edif design. This will lead to a (external ...) declaration of cells that can be used by the design. */ extern edif_xlibrary_t edif_xlibrary_create(edif_t edf, const char*name); extern void edif_xlibrary_set_celltable(edif_xlibrary_t lib, const struct edif_xlib_celltable*table); /* External libraries can be searched for existing cells, given a string name. This function searches for the cell by name, and returns it. */ extern edif_cell_t edif_xlibrary_findcell(edif_xlibrary_t lib, const char*cell_name); /* Similar to the above, but it gets the information it needs from the ivl_scope_t object. */ extern edif_cell_t edif_xlibrary_scope_cell(edif_xlibrary_t xlib, ivl_scope_t scope); /* Create a new cell, attached to the external library. Specify the number of ports that the cell has. The edif_cell_portconfig function is then used to assign name and direction to each of the ports. The cell has a number of pins that are referenced by their number from 0 to nports-1. You need to remember the pin numbers for the named ports for use when joining that pin to an edif_joint_t. Cellrefs get their port characteristics from the cell that they are created from. So the pinouts of cellrefs match the pinout of the associated cell. */ extern edif_cell_t edif_xcell_create(edif_xlibrary_t, const char*name, unsigned nports); extern void edif_cell_portconfig(edif_cell_t cell, unsigned idx, const char*name, ivl_signal_port_t dir); /* Attach a property to a cell port. */ extern void edif_cell_port_pstring(edif_cell_t cell, unsigned idx, const char*name, const char*value); /* Cells may have properties attached to them. These properties are included in the library declaration for the cell, instead of the cell instances. */ extern void edif_cell_pstring(edif_cell_t cell, const char*name, const char*value); extern void edif_cell_pinteger(edif_cell_t cell, const char*name, int value); /* Ports of cells are normally referenced by their port number. If you forget what that number is, this function can look it up by name. */ extern unsigned edif_cell_port_byname(edif_cell_t cell, const char*name); /* Create and instance from a cell. The instance refers to the cell, which is a type, and contains pips for pins. */ extern edif_cellref_t edif_cellref_create(edif_t edf, edif_cell_t cell); /* Instances can have properties attached to them. The name and value given here are turned into a (property (string "val")) expression attached to the instance. Examples of string properties commonly attached to cellref devices include such things as the INIT= to initialize LUT cells in FPGA devices. */ extern void edif_cellref_pstring(edif_cellref_t ref, const char*name, const char*value); extern void edif_cellref_pinteger(edif_cellref_t ref, const char*name, int value); /* This function gets the joint associated with a nexus. This will create a joint if necessary. */ extern edif_joint_t edif_joint_of_nexus(edif_t edf, ivl_nexus_t nex); /* For linking cells outside the ivl netlist, this function creates an anonymous joint. */ extern edif_joint_t edif_joint_create(edif_t edf); /* Renaming a joint causes it to take on a name when external tools view the EDIF file. */ extern void edif_joint_rename(edif_joint_t jnt, const char*name); /* Given a joint, this function adds the cell reference. */ extern void edif_add_to_joint(edif_joint_t jnt, edif_cellref_t cell, unsigned port); /* * Print the entire design. This should only be done after the design * is completely assembled. */ extern void edif_print(FILE*fd, edif_t design); #endif verilog-0.9.7/tgt-fpga/PaxHeaders.14238/fpga_priv.h0000644000202500001440000000005012204466647020067 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/fpga_priv.h0000644000202500001440000000310212204466647017405 0ustar00steveusers00000000000000#ifndef __fpga_priv_H #define __fpga_priv_H /* * Copyright (c) 2001 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include # include "device.h" /* This is the opened xnf file descriptor. It is the output that this code generator writes to, whether the format is XNF or EDIF. */ extern FILE*xnf; extern int show_scope_gates(ivl_scope_t net, void*x); extern device_t device; extern const char*part; extern const char*arch; /* * Attribute lookup, should this be provided in ivl_target.h? */ int scope_has_attribute(ivl_scope_t s, const char *name); /* * These are mangle functions. */ extern void xnf_mangle_logic_name(ivl_net_logic_t net, char*buf, size_t nbuf); extern void xnf_mangle_lpm_name(ivl_lpm_t net, char*buf, size_t nbuf); extern const char*xnf_mangle_nexus_name(ivl_nexus_t net); #endif verilog-0.9.7/tgt-fpga/PaxHeaders.14238/iverilog-fpga.man0000644000202500001440000000005012204466647021171 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/iverilog-fpga.man0000644000202500001440000001336412204466647020522 0ustar00steveusers00000000000000.TH iverilog-fpga 1 "$Date: 2004/10/04 01:10:57 $" Version "$Date: 2004/10/04 01:10:57 $" .SH NAME iverilog-fpga - FPGA code generator for Icarus Verilog .SH SYNOPSIS .B iverilog -tfpga [iverilog-options] sourcefile .SH DESCRIPTION .PP The FPGA code generator supports a variety of FPGA devices, writing EDIF output depending on the target. You can select the architecture of the device, and the detailed part name. The architecture is used to select library primitives, and the detailed part name is written into the generated file for the use of downstream tools. The code generator is invoked with the \-tfpga flag to iverilog. It understands the part= and the arch= parameters, which can be set with the \-p flag of iverilog: iverilog \-parch=virtex \-ppart=v50\-pq240\-6 \-tfpga foo.vl This example selects the Virtex architecture, and give the detailed part number as v50\-pq240\-6. The output is written into a.out unless a different output file is specified with the \-o flag. .SH OPTIONS \fIiverilog \-tfpga\fP accepts the following options: .TP 8 .B -parch=\fIfamily\fP The \fIfamily\fP setting further specifies the target device family. See FPGA FAMILIES below. .TP 8 .B -ppart=\fIdevice\fP This specifies a specific device in the form of a detailed part number. The format of this number is defined by the part vendor. In most cases, the device string is taken literally and written as is to the EDIF output. .SH "FPGA FAMILIES" The following is a list of architecture types that this code generator supports. .TP 8 .B lpm This is a device independent format, where the gates are device types as defined by the LPM 2 1 0 specification. Some backend tools may take this format, or users may write interface libraries to connect these netlists to the device in question. The \fBlpm\fP family is the default if no other is specified. .TP 8 .B virtex If this is selected, then the output is formatted as an EDIF 2 0 0 file, suitable for Virtex class devices. This is supposed to know that you are targeting a Virtex part, so can generate primitives instead of using external macros. It includes the VIRTEX internal library, and should work properly for any Virtex part. .TP 8 .B virtex2 If this is selected, then the output is EDIF 2 0 0 suitable for Virtex\-II and Virtex\-II Pro devices. It uses the VIRTEX2 library, but is very similar to the Virtex target. .SH "EDIF ROOT PORTS" The EDIF format is explicit about the interface into an EDIF file. The code generator uses that control to generate an explicit interface definition into the design. (This is *not* the same as the PADS of a part.) The generated EDIF interface section contains port definitions, including the proper direction marks. With the (rename ...) s\-exp in EDIF, it is possible to assign arbitrary text to port names. The EDIF code generator therefore does not resort to the mangling that is needed for internal symbols. The base name of the signal that is an input or output is used as the name of the port, complete with the proper case. However, since the ports are single bit ports, the name of vectors includes the string "[0]" where the number is the bit number. For example, the module: .nf module main(out, in); output out; input [2:0] in; [...] endmodule .fi creates these ports: .nf out OUTPUT in[0] INPUT in[1] INPUT in[2] INPUT .fi Target tools, including Xilinx Foundation tools, understand the [] characters in the name and recollect the signals into a proper bus when presenting the vector to the user. .SH "PADS AND PIN ASSIGNMENT" The ports of a root module may be assigned to specific pins, or to a generic pad. If a signal (that is a port) has a PAD attribute, then the value of that attribute is a list of locations, one for each bit of the signal, that specifies the pin for each bit of the signal. For example: .nf module main( (* PAD = "P10" *) output out, (* PAD = "P20,P21,P22" *) input [2:0] in); [...] endmodule .fi In this example, port ``out'' is assigned to pin 10, and port ``in'' is assigned to pins 20\-22. If the architecture supports it, a pin number of 0 means let the back end tools choose a pin. The format of the pin number depends on the architecture family being targeted, so for example Xilinx family devices take the name that is associated with the "LOC" attribute. NOTE: If a module port is assigned to a pin (and therefore attached to a PAD) then it is *not* connected to a port of the EDIF file. This is because the PAD (and possibly IBUF or OBUF) would become an extra driver to the port. An error. .SH "SPECIAL DEVICES" The code generator supports the "cellref" attribute attached to logic devices to cause specific device types be generated, instead of the usual device that the code generator might generate. For example, to get a clock buffer out of a Verilog buf: .nf buf my_gbuf(out, in); $attribute(my_buf, "cellref", "GBUF:O,I"); .fi The "cellref" attribute tells the code generator to use the given cell. The syntax of the value is: .nf :,... .fi The cell type is the name of the library part to use. The pin names are the names of the type in the library, in the order that the logic device pins are connected. .SH EXAMPLES .TB 8 .I COMPILING WITH XILINX FOUNDATION/ISE Compile a single-file design with command line tools like so: .nf % iverilog \-parch=virtex \-o foo.edf foo.vl % edif2ngd foo.edf foo.ngo % ngdbuild \-p v50\-pq240 foo.ngo foo.ngd % map \-o map.ncd foo.ngd % par \-w map.ncd foo.ncd .fi .SH "AUTHOR" .nf Steve Williams (steve@icarus.com) .SH SEE ALSO iverilog(1), .BR "" .SH COPYRIGHT .nf Copyright \(co 2003 Stephen Williams This document can be freely redistributed according to the terms of the GNU General Public License version 2.0 verilog-0.9.7/tgt-fpga/PaxHeaders.14238/d-virtex2.c0000644000202500001440000000005012204466647017731 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/tgt-fpga/d-virtex2.c0000644000202500001440000000506412204466647017260 0ustar00steveusers00000000000000/* * Copyright (c) 2001-2010 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "device.h" # include "fpga_priv.h" # include "edif.h" # include "generic.h" # include "xilinx.h" # include # include # include /* * This is a table of cell types that are accessible via the cellref * attribute to a gate. */ const static struct edif_xlib_celltable virtex2_celltable[] = { { "BUFG", xilinx_cell_bufg }, { "MULT_AND", xilinx_cell_mult_and }, { 0, 0} }; /* * The show_header function is called before any of the devices of the * netlist are scanned. * * In this function, we look at the ports of the root module to decide * if they are to be made into ports. Modules that have PAD attributes * are *not* to be used as ports, they will be connected to special * PAD devices instead. */ static void virtex2_show_header(ivl_design_t des) { const char*part_str = 0; xilinx_common_header(des); xlib = edif_xlibrary_create(edf, "VIRTEX2"); edif_xlibrary_set_celltable(xlib, virtex2_celltable); if ( (part_str = ivl_design_flag(des, "part")) && (part_str[0] != 0) ) { edif_pstring(edf, "PART", part_str); } cell_0 = edif_xcell_create(xlib, "GND", 1); edif_cell_portconfig(cell_0, 0, "GROUND", IVL_SIP_OUTPUT); cell_1 = edif_xcell_create(xlib, "VCC", 1); edif_cell_portconfig(cell_1, 0, "VCC", IVL_SIP_OUTPUT); } const struct device_s d_virtex2_edif = { virtex2_show_header, xilinx_show_footer, xilinx_show_scope, xilinx_pad, virtex_logic, virtex_generic_dff, virtex_eq, virtex_eq, virtex_ge, 0, /* show_cmp_gt */ virtex_mux, virtex_add, virtex_add, xilinx_shiftl, /* show_shiftl */ 0 /* show_shiftr */ }; verilog-0.9.7/PaxHeaders.14238/vvp0000644000202500001440000000005012204466647014766 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/vvp/0000755000202500001440000000000012204466647014365 5ustar00steveusers00000000000000verilog-0.9.7/vvp/PaxHeaders.14238/bufif.h0000644000202500001440000000005012204466647016307 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/vvp/bufif.h0000644000202500001440000000330412204466647015631 0ustar00steveusers00000000000000#ifndef __bufif_H #define __bufif_H /* * Copyright (c) 2001-2005 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 * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "vvp_net.h" /* * The vvp_fun_bufif functor implements the logic of bufif0/1 and * notif0/1 gates. Input 0 is the value to be buffered, and input 1 is * the enable. The gate processes vectors as bit slices handled by an * array of gates. * * The output from the gate is a vvp_vector8_t. The gate adds * strengths to the buffered value, and sends H/L in response to * unknown enable bits. */ class vvp_fun_bufif : public vvp_net_fun_t { public: vvp_fun_bufif(bool en_invert, bool out_invert, unsigned str0, unsigned str1); void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t); private: vvp_vector4_t bit_; vvp_vector4_t en_; unsigned pol_ : 1; unsigned inv_ : 1; unsigned drive0_ : 8; unsigned drive1_ : 8; }; #endif verilog-0.9.7/vvp/PaxHeaders.14238/opcodes.txt0000644000202500001440000000005012204466647017240 xustar000000000000000020 atime=1376939565 20 ctime=1376939565 verilog-0.9.7/vvp/opcodes.txt0000644000202500001440000007400412204466647016567 0ustar00steveusers00000000000000/* * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com) * */ EXECUTABLE INSTRUCTION OPCODES Instruction opcodes all start with a % character and have 0 or more operands. In no case are there more than 3 operands. This chapter describes the specific behavior of each opcode, in enough detail (I hope) that its complete effect can be predicted. General principles of Arithmetic: The binary arithmetic instruction in general takes three parameters, the left operand, the right operand, and the base. The left operand is replaced with the result, which is the same width as the left and right operands. * %abs/wr , This instruction calculates the absolute value of a real value. It uses the fabs() function in the run-time to do the work. * %add , , This instruction adds the right vector into the left vector, the vectors having the width . If any of the bits of either vector are x or z, the result is x. Otherwise, the result is the arithmetic sum. See also the %sub instruction. * %add/wr , This is the real valued version of the %add instruction. The arguments are word indices of the operands. The right operand is added into the left operand. See also the %sub/wr instruction. * %addi , , This instruction adds the immediate value (no x or z bits) into the left vector. The imm value is limited to 16 significant bits, but it is zero extended to match any width. * %alloc This instruction allocates the storage for a new instance of an automatically allocated scope. * %and , , Perform the bitwise AND of the two vectors, and store the result in the left vector. Each bit is calculated independent of other bits. AND means the following: 0 and ? --> 0 ? and 0 --> 0 1 and 1 --> 1 otherwise x * %assign/av , , * %assign/av/d , , * %assign/av/e , The %assign/av instruction assigns a vector value to a word in the labeled array. The is the delay in simulation time to the assignment (0 for non-blocking assignment) and the is the base of the vector to write. The width of the vector is retrieved from index register 0. The base of a part select is retrieved from index register 1. The address of the word in the memory is from index register 3. The address is canonical form. The %assign/av/d variation reads the delay from an integer register that is given by the value. This should not be 0, 1 or 3, of course, since these registers contain the vector width, base part select and word address. The %assign/av/e variation uses the information in the thread event control registers to determine when to perform the assign. %evctl is used to set the event control information. * %assign/v0 , , * %assign/v0/d , , * %assign/v0/e , The %assign/v0 instruction is a vector version of non-blocking assignment. The is the number of clock ticks in the future where the assignment should be schedule, and the is the base of the vector to be assigned to the destination. The vector width is in index register 0. The %assign/v0/d variation gets the delay instead from an integer register that is given by the value. This should not be 0, of course, because integer 0 is taken with the vector width. The %assign/v0/e variation uses the information in the thread event control registers to determine when to perform the assign. %evctl is used to set the event control information. The references a .var object that can receive non-blocking assignments. For blocking assignments, see %set/v. * %assign/v0/x1 , , * %assign/v0/x1/d , , * %assign/v0/x1/e , This is similar to the %assign/v0 instruction, but adds the index-1 index register with the canonical index of the destination where the vector is to be written. This allows for part writes into the vector. * %assign/wr , , * %assign/wr/d , , * %assign/wr/e , This instruction provides a non-blocking assign of the real value given in to the real object addressed by the label after the given . The %assign/wr/d variation gets the delay from integer register . The %assign/wr/e variation uses the information in the thread event control registers to determine when to perform the assign. %evctl is used to set the event control information. * %assign/x0 , , (OBSOLETE -- See %assign/v0x) This does a non-blocking assignment to a functor, similar to the %assign instruction. The identifies the base functor of the affected variable, and the gives the delay when the assignment takes place. The delay may be 0. The actual functor used is calculated by using as a base, and indexing with the index[0] index register. This supports indexed assignment. The is the address of the thread register that contains the bit value to assign. * %blend , , This instruction blends the bits of a vector into the destination in a manner like the expression (x ? : ). The truth table is: 1 1 --> 1 0 0 --> 0 z z --> z x x --> x .... --> x In other words, if the bits are identical, then take that value. Otherwise, the value is x. * %blend/wr , This instruction blends real values for the ternary operator. If the values match return that otherwise return 0.0. * %breakpoint This instruction unconditionally breaks the simulator into the interactive debugger. The idea is to stop the simulator here and give the user a chance to display the state of the simulation using debugger commands. This may not work on all platforms. If run-time debugging is compiled out, then this function is a no-op. * %cassign/v , , Perform a continuous assign of a constant value to the target variable. This is similar to %set, but it uses the cassign port (port-1) of the signal functor instead of the normal assign, so the signal responds differently. See "VARIABLE STATEMENTS" in the README.txt file. * %cassign/wr , Perform a continuous assign of a constant real value to the target variable. See %cassign/v above. * %cassign/x0 , ; , ; , ; , ; , ; In all cases, there are no width limits, so long as the width is fixed. NOTE: The .arith/mult inputs are not necessarily the width of the output. I have not decided how to handle this. These devices support .s and .r suffixes. The .s means the node is a signed vector device, the .r a real valued device. STRUCTURAL COMPARE STATEMENTS: The arithmetic statements handle various arithmetic operators that have wide outputs, but the comparators have single bit output, so they are implemented a bit differently. The syntax, however, is very similar: , ; , ; , ; , ; , ; , ; , ; , ; Whereas the arithmetic statements generate an output the width of , the comparisons produce a single bit vector result. The plain versions do unsigned comparison, but the ".s" versions to signed comparisons. (Equality doesn't need to care about sign.) STRUCTURAL SHIFTER STATEMENTS: Variable shifts in structural context are implemented with .shift statements: