iverilog/vvp/udp.h

242 lines
7.9 KiB
C
Raw Normal View History

#ifndef IVL_udp_H
#define IVL_udp_H
/*
* Copyright (c) 2005-2025 Stephen Williams (steve@icarus.com)
2005-04-01 08:02:45 +02:00
*
* (This is a rewrite of code that was ...
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>)
*
* 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
2012-08-29 03:41:23 +02:00
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "vvp_net.h"
2005-06-09 07:04:45 +02:00
# include "schedule.h"
2005-06-09 06:12:30 +02:00
struct udp_levels_table;
struct vvp_udp_s {
public:
explicit vvp_udp_s(char*label, char*name, unsigned ports,
vvp_bit4_t init, bool type);
2005-06-09 06:12:30 +02:00
virtual ~vvp_udp_s();
// Return the number of input ports for the defined UDP. This
// does *not* include the current output value for a
// sequential UDP.
unsigned port_count() const;
bool is_sequential() const { return seq_; };
char *name() { return name_; }
2005-06-09 06:12:30 +02:00
2005-06-09 07:04:45 +02:00
// Return the initial output value.
vvp_bit4_t get_init() const;
2005-06-09 06:12:30 +02:00
virtual vvp_bit4_t calculate_output(const udp_levels_table&cur,
const udp_levels_table&prev,
vvp_bit4_t cur_out) =0;
private:
char *name_;
2005-06-09 06:12:30 +02:00
unsigned ports_;
2005-06-09 07:04:45 +02:00
vvp_bit4_t init_;
bool seq_;
2005-06-09 06:12:30 +02:00
};
2005-04-01 08:02:45 +02:00
/*
2005-06-09 06:12:30 +02:00
* The vvp_udp_async_s instance represents a *definition* of a
2005-04-01 08:02:45 +02:00
* primitive. netlist instances refer to these definitions.
*
* The ports argument of the constructor is the number of input ports
* to the device. The single output port is not counted. The port
* count must be greater than 0.
2005-04-01 08:02:45 +02:00
*
* A level sensitive UDP has a table that includes all the rows that
* generate a 0 output and another table that includes all the rows
* that generate a 1 output. A set of inputs is tested against the
* entries in both sets, and if there are no matches, the output is
* set to x.
*
* The levels0 and levels1 tables are each an array of levels
* tables. Each levels table is a mask of positions that are supposed
* to be 0, 1 and x. The LSB of each mask represents first port, and
* so on. If the bit is set in mask0, a bit4_0 is expected at that
* position, and similarly for mask1 and maskx. Only exactly 1 bit
* will be set in the three masks for each bit position.
*
* This table structure implies that the number of inputs to the level
2005-06-09 06:12:30 +02:00
* sensitive device is limited to the number of bits in an unsigned
* long.
*
* The array of strings passed to the compile_table method of a
* combinational UDP are strings of port_count()+1 characters. The
* expected inputs are in the order of the UDP inputs, and the output
* is the last character. For example, an AND gate has these strings
* passed to the compile_table function:
*
* 000 (Both inputs are 0)
* 010 (Second input is a 1)
* 100
* 111 (All inputs are 1, so generate a 1 output)
*
* The characters allowed in the input positions are:
*
* 0 -- Expect a 0
* 1 -- Expect a 1
* x -- Expect an x or z
* b -- 0 or 1
* l -- 0 or x
* h -- x or 1
* ? -- 0, x or 1
*
* Only 0, 1 and x characters are allowed in the output position.
2005-04-01 08:02:45 +02:00
*/
2005-04-01 08:02:45 +02:00
struct udp_levels_table {
unsigned long mask0;
unsigned long mask1;
unsigned long maskx;
};
extern std::ostream& operator<< (std::ostream&o, const struct udp_levels_table&t);
2005-04-01 08:02:45 +02:00
2005-06-09 06:12:30 +02:00
class vvp_udp_comb_s : public vvp_udp_s {
2005-04-01 08:02:45 +02:00
public:
vvp_udp_comb_s(char*label, char*name__, unsigned ports);
2005-06-09 06:12:30 +02:00
~vvp_udp_comb_s();
2005-04-01 08:02:45 +02:00
void compile_table(char**tab);
2001-07-24 03:44:50 +02:00
2005-04-01 08:02:45 +02:00
// Test the cur table with the compiled rows, and return the
// bit value that matches.
vvp_bit4_t test_levels(const udp_levels_table&cur);
2005-06-09 06:12:30 +02:00
vvp_bit4_t calculate_output(const udp_levels_table&cur,
const udp_levels_table&prev,
vvp_bit4_t cur_out) override;
2005-06-09 06:12:30 +02:00
private:
2005-04-01 08:02:45 +02:00
// Level sensitive rows of the device.
struct udp_levels_table*levels0_;
struct udp_levels_table*levels1_;
unsigned nlevels0_, nlevels1_;
};
2005-06-09 06:12:30 +02:00
/*
* udp sequential devices are a little more complex in that they have
* an additional output type: no-change. They also have, in addition
* to a table of levels, a table of edges that are similar to levels
* but one of the positions has an edge value.
*
* The port_count() for the device is the number of inputs. Sequential
* devices have an additional phantom port that is the current output
* value. This implies that the maximum port count for sequential
* devices is 1 less than for combinational.
2005-06-09 06:12:30 +02:00
*
* The input table that is passed to the compile_table method is very
* similar to that for the combinational UDP. The differences are that
* there is one extra entry in the beginning of each input row that is
* the current output, and there are more characters accepted at each
* bit position.
*
* The current output bit may contain the same characters as a
* combinational UDP input position. No edges.
*
* The next output position takes the possible values 0, x, 1 and -.
*
* The input bit positions take the combinational input characters,
* plus edge specification characters. Only one input of a row may
* have an edge input.
*
* The edges_table is similar to the levels, table, with the mask?
* bits having the same meaning as with the levels tables. The edge_*
* members specify the edge for a single bit position. In this case,
* the edge_mask* members give the mask of source bits for that
* position, and the edge_position the bit that has shifted. In the
* edge case, the mask* members give the final position and the
* edge_mask* bits the initial position of the bit.
*/
struct udp_edges_table {
unsigned long edge_position : 8;
unsigned long edge_mask0 : 1;
unsigned long edge_mask1 : 1;
unsigned long edge_maskx : 1;
unsigned long mask0;
unsigned long mask1;
unsigned long maskx;
};
class vvp_udp_seq_s : public vvp_udp_s {
public:
vvp_udp_seq_s(char*label, char*name__, unsigned ports, vvp_bit4_t init);
2005-06-09 06:12:30 +02:00
~vvp_udp_seq_s();
void compile_table(char**tab);
vvp_bit4_t calculate_output(const udp_levels_table&cur,
const udp_levels_table&prev,
vvp_bit4_t cur_out) override;
2005-06-09 06:12:30 +02:00
private:
vvp_bit4_t test_levels_(const udp_levels_table&cur);
// Level sensitive rows of the device.
struct udp_levels_table*levels0_;
struct udp_levels_table*levels1_;
struct udp_levels_table*levelsx_;
struct udp_levels_table*levelsL_;
unsigned nlevels0_, nlevels1_, nlevelsx_, nlevelsL_;
vvp_bit4_t test_edges_(const udp_levels_table&cur,
const udp_levels_table&prev);
// Edge sensitive rows of the device
struct udp_edges_table*edges0_;
struct udp_edges_table*edges1_;
struct udp_edges_table*edgesL_;
unsigned nedges0_, nedges1_, nedgesL_;
};
2005-04-01 08:02:45 +02:00
/*
* This looks up a UDP definition from its LABEL.
2005-04-01 08:02:45 +02:00
*/
struct vvp_udp_s *udp_find(const char *label);
2003-09-17 05:39:55 +02:00
/*
2005-04-01 08:02:45 +02:00
* The udp_fun_core is the core of the udp instance in the
* netlist. This core is a vvp_wide_fun_core that takes care of
* dispatching the output. This class also receives the inputs from
* the vvp_wide_fun_t objects and processes them to generate the
* output to be sent.
2003-09-17 05:39:55 +02:00
*/
2005-06-09 07:04:45 +02:00
class vvp_udp_fun_core : public vvp_wide_fun_core, private vvp_gen_event_s {
2005-04-01 08:02:45 +02:00
2003-09-17 05:39:55 +02:00
public:
2005-06-11 18:21:08 +02:00
vvp_udp_fun_core(vvp_net_t*net, vvp_udp_s*def);
2005-04-01 08:02:45 +02:00
~vvp_udp_fun_core();
void recv_vec4_from_inputs(unsigned) override;
2005-04-01 08:02:45 +02:00
private:
void run_run() override;
2005-06-09 07:04:45 +02:00
2005-04-01 08:02:45 +02:00
vvp_udp_s*def_;
2005-04-03 07:45:51 +02:00
vvp_bit4_t cur_out_;
2005-04-01 08:02:45 +02:00
udp_levels_table current_;
};
#endif /* IVL_udp_H */