diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d3dc27 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*~ +*.o +nettest diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3c02cc6 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +CXXFLAGS := -std=gnu++11 -Wall -O3 +CC := $(CXX) + +.PHONY: all +all: nettest + +nettest: nettest.o node.o diff --git a/nettest.cc b/nettest.cc new file mode 100644 index 0000000..781d89f --- /dev/null +++ b/nettest.cc @@ -0,0 +1,25 @@ +#include "node.h" + +#include + +int main(int argc, char*argv[]) { + + // Create an 8-bit net + Net a("a", 8); + std::cout << a << std::endl; + + // Slice out the high half and manipulate a bit in it + std::cout << "Manipulating a slice ..." << std::endl; + Bus b = a(7, 4); + b[2] = Node::V0; + std::cout << a << std::endl; + + // Concatenate two duplicates of the slice and give the result a name + std::cout << "Duplicated slice ..." << std::endl; + Net c("c", (b,b)); + std::cout << c << std::endl; + b[0] = Node::V1; + std::cout << c << std::endl; + + return 0; +} diff --git a/node.cc b/node.cc new file mode 100644 index 0000000..3875f17 --- /dev/null +++ b/node.cc @@ -0,0 +1,53 @@ +#include "node.h" + +#include +#include + +std::ostream& operator<<(std::ostream &out, Node const &node) { + char c = '?'; + switch(node.value()) { + case Node::V0: c = '0'; break; + case Node::V1: c = '1'; break; + case Node::VX: c = 'X'; break; + case Node::VZ: c = 'Z'; break; + case Node::VH: c = 'H'; break; + case Node::VL: c = 'L'; break; + } + out << c; + return out; +} + +Bus Bus::slice(unsigned hi, unsigned lo) { + hi = std::min(hi, m_width-1); + if(hi < lo) return Bus(); + + Node *const src = m_nodes.get(); + unsigned const len = hi-lo+1; + Node *const dst = new Node[len]; + std::copy(src+lo, src+hi+1, dst); + return Bus(len, dst); +} + +Bus Bus::concat(Bus& o) { + unsigned const wleft = m_width; + unsigned const wrght = o.m_width; + Node *const res = new Node[wleft+wrght]; + for(unsigned i = 0; i < wrght; i++) res[ i] = o[i]; + for(unsigned i = 0; i < wleft; i++) res[wrght+i] = (*this)[i]; + return Bus(wleft+wrght, res); +} + +Net::Net(std::string const& name, unsigned width) + : Bus(width), m_name(name) {} + +Net::Net(std::string const& name, unsigned width, Node* nodes) + : Bus(width, nodes), m_name(name) {} + +Net::~Net() {} + +std::ostream& operator<<(std::ostream &out, Net const &net) { + out << net.name() << "=\""; + for(auto it = net.end(); --it >= net.begin();) out << *it; + out << '"'; + return out; +} diff --git a/node.h b/node.h new file mode 100644 index 0000000..6ceadeb --- /dev/null +++ b/node.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016 CERN + * @author Thomas B. Preusser + * + * 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 + */ + +#ifndef NODE_H +#define NODE_H + +#include +#include + +/** + * This header defines classes representing the electrical wiring of + * modules: + * + * Node: + * A single physical wire that carries one value at each point in time. + * The possible values are defined by the type Node::value_t. They + * comprise the subset ('0', '1', 'X', 'Z', 'H', 'L') of the VHDL + * std_logic type. + * + * Bus: + * A collection of Nodes for the purpose of making bulk connections. + * Nodes exist on their own right and are not required to be part of a + * Bus. On the other hand, a Node may be named in multiple Busses and, in + * fact, appear multiple times in the same Bus. Electrically, all + * appearances of a Node are indistinguishable. + * + * Net: + * A Bus with a name. This class may become obsolete by using maps + * mapping a name to a Bus in different places of the circuit + * according to the corresponding perspective. The same Bus may be addressed + * through different names, e.g., within an instantiated module and within + * the surrounding instantiating module. + */ + +/** + * @brief Represents a single physical wire and its current value. + * + * This class is a thin wrapper around a canonical internal representative + * of an electrical node. + */ +class Node { + + public: + /** The supported Node values. */ + enum value_t { V0, V1, VX, VZ, VH, VL }; + + private: + /** + * The actual canonical representative of the electrical Node. + * This will be the proper place to attach value change listeners, + * event lists and similar things. + */ + class Box { + friend class Node; + value_t m_val; + public: + Box(value_t val) : m_val(val) {} + ~Box() {} + }; + std::shared_ptr m_canon; + + public: + Node(value_t val = value_t::VX) : m_canon(std::make_shared(val)) {} + Node(Node const &o) : m_canon(o.m_canon) {} + ~Node() {} + + public: + value_t value() const { return m_canon->m_val; } + operator value_t() const { return value(); } + + Node& operator=(value_t val) { + m_canon->m_val = val; + return *this; + } +}; +// class Node + +std::ostream& operator<<(std::ostream &out, Node const &node); + +/** + * @brief Represents a list of Nodes. + */ +class Bus { + unsigned m_width; + std::shared_ptr m_nodes; + + public: + Bus(unsigned width = 0) : Bus(width, new Node[width]) {} + Bus(unsigned width, Node *nodes) + : m_width(width), m_nodes(nodes, [](Node *nodes) { delete [] nodes; }) { + } + ~Bus() {} + + //+ Container of Nodes +++++++++++++++++++++++++++++++++++++++++++++++++++++ + public: + unsigned width() const { return m_width; } + unsigned size() const { return m_width; } + Node* begin() { return m_nodes.get(); } + Node const* begin() const { return m_nodes.get(); } + Node* end() { return m_nodes.get()+m_width; } + Node const* end() const { return m_nodes.get()+m_width; } + + Node& operator[](unsigned idx) { return m_nodes.get()[idx]; } + Node const& operator[](unsigned idx) const { return m_nodes.get()[idx]; } + + Bus slice(unsigned hi, unsigned lo); + Bus operator()(unsigned hi, unsigned lo) { return slice(hi, lo); } + + Bus concat(Bus& o); + Bus operator,(Bus& o) { return concat(o); } +}; +// class Bus + +/** + * @brief Represent a named Bus. + */ +class Net : public Bus { + std::string m_name; + + public: + Net(std::string const& name, unsigned width = 1); + Net(std::string const& name, unsigned width, Node* nodes); + Net(std::string const& name, Bus const &o) : Bus(o), m_name(name) {} + ~Net(); + + public: + std::string const& name() const { return m_name; } +}; +// class Net + +std::ostream& operator<<(std::ostream &out, Net const &net); +#endif