/* * Copyright (c) 2005 Stephen Williams (steve@icarus.com) * * (This is a rewrite of code that was ... * Copyright (c) 2001 Stephan Boettcher ) * * 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: udp.cc,v 1.29 2005/04/04 05:13:59 steve Exp $" #endif #include "udp.h" #include "schedule.h" #include "symbols.h" #include "compile.h" #include #ifdef HAVE_MALLOC_H #include #endif #include #include #include static symbol_table_t udp_table; struct vvp_udp_s *udp_find(const char *label) { symbol_value_t v = sym_get_value(udp_table, label); return (struct vvp_udp_s *)v.ptr; } vvp_udp_s::vvp_udp_s(char*label, char*name, unsigned ports, bool sequ) { assert(!sequ); // XXXX sequential UDPs not supported yet. if (!udp_table) udp_table = new_symbol_table(); assert(!udp_find(label)); symbol_value_t v; v.ptr = this; sym_set_value(udp_table, label, v); name_ = name; ports_ = ports; levels0_ = 0; levels1_ = 0; nlevels0_ = 0; nlevels1_ = 0; } vvp_udp_s::~vvp_udp_s() { if (levels0_) delete[] levels0_; if (levels1_) delete[] levels1_; } unsigned vvp_udp_s::port_count() const { return ports_; } /* * The cur table that is passed in must have for every valid bit * position exactly one of the three mask bits set. This represents an * actual vector of inputs to be tested. * * The levels0_ and levels1_ tables have levels_table objects that * eack represent a single row. For the row to match the input vector, * all the bits that are set in the cur table must also be set in the * row being tested. * * It is possible for a row to match multiple different vectors. This * is seen from the compile_table function, where bit positions for * multiple masks can be test for certain row positions. For example, * if the row bit position is '?', then mask 0/1/x are all set in the * row for that bit position. This means it doesn't matter which of * the three bit positions is set in the cur input table, the bit * position will generate a match. */ vvp_bit4_t vvp_udp_s::test_levels(const udp_levels_table&cur) { for (unsigned idx = 0 ; idx < nlevels0_ ; idx += 1) { if (cur.mask0 != (cur.mask0 & levels0_[idx].mask0)) continue; if (cur.mask1 != (cur.mask1 & levels0_[idx].mask1)) continue; if (cur.maskx != (cur.maskx & levels0_[idx].maskx)) continue; return BIT4_0; } for (unsigned idx = 0 ; idx < nlevels1_ ; idx += 1) { if (cur.mask0 != (cur.mask0 & levels1_[idx].mask0)) continue; if (cur.mask1 != (cur.mask1 & levels1_[idx].mask1)) continue; if (cur.maskx != (cur.maskx & levels1_[idx].maskx)) continue; return BIT4_1; } return BIT4_X; } void vvp_udp_s::compile_table(char**tab) { unsigned nrows0 = 0, nrows1 = 0; /* First run through the table to figure out the number of rows I need for each kind of table. */ for (unsigned idx = 0 ; tab[idx] ; idx += 1) { assert(strlen(tab[idx]) == ports_ + 1); switch (tab[idx][ports_]) { case '0': nrows0 += 1; break; case '1': nrows1 += 1; break; case 'x': break; default: assert(0); } } nlevels0_ = nrows0; levels0_ = new udp_levels_table[nlevels0_]; nlevels1_ = nrows1; levels1_ = new udp_levels_table[nlevels1_]; nrows0 = 0; nrows1 = 0; for (unsigned idx = 0 ; tab[idx] ; idx += 1) { struct udp_levels_table cur; cur.mask0 = 0; cur.mask1 = 0; cur.maskx = 0; assert(ports_ <= sizeof(cur.mask0)); for (unsigned pp = 0 ; pp < ports_ ; pp += 1) { unsigned long mask_bit = 1UL << pp; switch (tab[idx][pp]) { case '0': cur.mask0 |= mask_bit; break; case '1': cur.mask1 |= mask_bit; break; case 'x': cur.maskx |= mask_bit; break; case 'b': cur.mask0 |= mask_bit; cur.mask1 |= mask_bit; break; case 'l': cur.mask0 |= mask_bit; cur.maskx |= mask_bit; break; case 'h': cur.maskx |= mask_bit; cur.mask1 |= mask_bit; break; case '?': cur.mask0 |= mask_bit; cur.maskx |= mask_bit; cur.mask1 |= mask_bit; break; default: assert(0); } } switch (tab[idx][ports_]) { case '0': levels0_[nrows0++] = cur; break; case '1': levels1_[nrows1++] = cur; break; default: break; } } assert(nrows0 == nlevels0_); assert(nrows1 == nlevels1_); } vvp_udp_fun_core::vvp_udp_fun_core(vvp_net_t*net, vvp_udp_s*def, vvp_delay_t*del) : vvp_wide_fun_core(net, def->port_count()) { def_ = def; delay_ = del; cur_out_ = BIT4_X; // Assume initially that all the inputs are 1'bx current_.mask0 = 0; current_.mask1 = 0; current_.maskx = ~ ((-1UL) << port_count()); } vvp_udp_fun_core::~vvp_udp_fun_core() { } void vvp_udp_fun_core::recv_vec4_from_inputs(unsigned port) { /* For now, assume udps are 1-bit wide. */ assert(value(port).size() == 1); unsigned long mask = 1UL << port; switch (value(port).value(0)) { case BIT4_0: current_.mask0 |= mask; current_.mask1 &= ~mask; current_.maskx &= ~mask; break; case BIT4_1: current_.mask0 &= ~mask; current_.mask1 |= mask; current_.maskx &= ~mask; break; default: current_.mask0 &= ~mask; current_.mask1 &= ~mask; current_.maskx |= mask; break; } vvp_bit4_t out_bit = def_->test_levels(current_); vvp_vector4_t out (1); out.set_bit(0, out_bit); if (delay_) propagate_vec4(out, delay_->get_delay(cur_out_, out_bit)); else propagate_vec4(out); cur_out_ = out_bit; } /* * This function is called by the parser in response to a .udp * node. We create the nodes needed to integrate the UDP into the * netlist. The definition should be parsed already. */ void compile_udp_functor(char*label, char*type, vvp_delay_t*delay, unsigned argc, struct symb_s*argv) { struct vvp_udp_s *def = udp_find(type); assert(def); free(type); vvp_net_t*ptr = new vvp_net_t; vvp_udp_fun_core*core = new vvp_udp_fun_core(ptr, def, delay); ptr->fun = core; define_functor_symbol(label, ptr); free(label); wide_inputs_connect(core, argc, argv); free(argv); } /* * $Log: udp.cc,v $ * Revision 1.29 2005/04/04 05:13:59 steve * Support row level wildcards. * * Revision 1.28 2005/04/03 05:45:51 steve * Rework the vvp_delay_t class. * * Revision 1.27 2005/04/01 06:02:45 steve * Reimplement combinational UDPs. * */