#!/usr/bin/env python3 import argparse import os import sys import random debug_mode = False def create_bram(dsc_f, sim_f, ref_f, tb_f, k1, k2, or_next): while True: init = 0 # random.randrange(2) abits = random.randrange(1, 8) dbits = random.randrange(1, 8) groups = random.randrange(2, 5) if random.randrange(2): abits = 2 ** random.randrange(1, 4) if random.randrange(2): dbits = 2 ** random.randrange(1, 4) while True: wrmode = [ random.randrange(0, 2) for i in range(groups) ] if wrmode.count(1) == 0: continue if wrmode.count(0) == 0: continue break if random.randrange(2): maxpol = 4 maxtransp = 1 maxclocks = 4 else: maxpol = None clkpol = random.randrange(4) maxtransp = 2 maxclocks = 1 def generate_enable(i): if wrmode[i]: v = 2 ** random.randrange(0, 4) while dbits < v or dbits % v != 0: v //= 2 return v return 0 def generate_transp(i): if wrmode[i] == 0: return random.randrange(maxtransp) return 0 def generate_clkpol(i): if maxpol is None: return clkpol return random.randrange(maxpol) ports = [ random.randrange(1, 3) for i in range(groups) ] enable = [ generate_enable(i) for i in range(groups) ] transp = [ generate_transp(i) for i in range(groups) ] clocks = [ random.randrange(maxclocks)+1 for i in range(groups) ] clkpol = [ generate_clkpol(i) for i in range(groups) ] break print("bram bram_%02d_%02d" % (k1, k2), file=dsc_f) print(" init %d" % init, file=dsc_f) print(" abits %d" % abits, file=dsc_f) print(" dbits %d" % dbits, file=dsc_f) print(" groups %d" % groups, file=dsc_f) print(" ports %s" % " ".join(["%d" % i for i in ports]), file=dsc_f) print(" wrmode %s" % " ".join(["%d" % i for i in wrmode]), file=dsc_f) print(" enable %s" % " ".join(["%d" % i for i in enable]), file=dsc_f) print(" transp %s" % " ".join(["%d" % i for i in transp]), file=dsc_f) print(" clocks %s" % " ".join(["%d" % i for i in clocks]), file=dsc_f) print(" clkpol %s" % " ".join(["%d" % i for i in clkpol]), file=dsc_f) print("endbram", file=dsc_f) print("match bram_%02d_%02d" % (k1, k2), file=dsc_f) if random.randrange(2): non_zero_enables = [chr(ord('A') + i) for i in range(len(enable)) if enable[i]] if len(non_zero_enables): print(" shuffle_enable %c" % random.choice(non_zero_enables), file=dsc_f) if or_next: print(" or_next_if_better", file=dsc_f) print("endmatch", file=dsc_f) states = set() v_ports = set() v_stmts = list() v_always = dict() tb_decls = list() tb_clocks = list() tb_addr = list() tb_din = list() tb_dout = list() tb_addrlist = list() for i in range(10): tb_addrlist.append(random.randrange(1048576)) t = random.randrange(1048576) for i in range(10): tb_addrlist.append(t ^ (1 << i)) v_stmts.append("(* nomem2reg *) reg [%d:0] memory [0:%d];" % (dbits-1, 2**abits-1)) portindex = 0 last_always_hdr = (-1, "") for p1 in range(groups): for p2 in range(ports[p1]): pf = "%c%d" % (chr(ord("A") + p1), p2 + 1) portindex += 1 v_stmts.append("`ifndef SYNTHESIS") v_stmts.append(" event UPDATE_%s;" % pf) v_stmts.append("`endif") if clocks[p1] and not ("CLK%d" % clocks[p1]) in v_ports: v_ports.add("CLK%d" % clocks[p1]) v_stmts.append("input CLK%d;" % clocks[p1]) tb_decls.append("reg CLK%d = 0;" % clocks[p1]) tb_clocks.append("CLK%d" % clocks[p1]) v_ports.add("%sADDR" % pf) v_stmts.append("input [%d:0] %sADDR;" % (abits-1, pf)) if transp[p1]: v_stmts.append("reg [%d:0] %sADDR_Q;" % (abits-1, pf)) tb_decls.append("reg [%d:0] %sADDR;" % (abits-1, pf)) tb_addr.append("%sADDR" % pf) v_ports.add("%sDATA" % pf) v_stmts.append("%s [%d:0] %sDATA;" % ("input" if wrmode[p1] else "output reg", dbits-1, pf)) if wrmode[p1]: tb_decls.append("reg [%d:0] %sDATA;" % (dbits-1, pf)) tb_din.append("%sDATA" % pf) else: tb_decls.append("wire [%d:0] %sDATA;" % (dbits-1, pf)) tb_decls.append("wire [%d:0] %sDATA_R;" % (dbits-1, pf)) tb_dout.append("%sDATA" % pf) if wrmode[p1] and enable[p1]: v_ports.add("%sEN" % pf) v_stmts.append("input [%d:0] %sEN;" % (enable[p1]-1, pf)) tb_decls.append("reg [%d:0] %sEN;" % (enable[p1]-1, pf)) tb_din.append("%sEN" % pf) assign_op = "<=" if clocks[p1] == 0: always_hdr = "always @* begin" assign_op = "=" elif clkpol[p1] == 0: always_hdr = "always @(negedge CLK%d) begin" % clocks[p1] elif clkpol[p1] == 1: always_hdr = "always @(posedge CLK%d) begin" % clocks[p1] else: if not ("CP", clkpol[p1]) in states: v_stmts.append("parameter CLKPOL%d = 0;" % clkpol[p1]) states.add(("CP", clkpol[p1])) if not ("CPW", clocks[p1], clkpol[p1]) in states: v_stmts.append("wire CLK%d_CLKPOL%d = CLK%d == CLKPOL%d;" % (clocks[p1], clkpol[p1], clocks[p1], clkpol[p1])) states.add(("CPW", clocks[p1], clkpol[p1])) always_hdr = "always @(posedge CLK%d_CLKPOL%d) begin" % (clocks[p1], clkpol[p1]) if last_always_hdr[1] != always_hdr: last_always_hdr = (portindex, always_hdr) v_always[last_always_hdr] = list() if wrmode[p1]: for i in range(enable[p1]): enrange = "[%d:%d]" % ((i+1)*dbits/enable[p1]-1, i*dbits/enable[p1]) v_always[last_always_hdr].append((portindex, pf, "if (%sEN[%d]) memory[%sADDR]%s = %sDATA%s;" % (pf, i, pf, enrange, pf, enrange))) elif transp[p1]: v_always[last_always_hdr].append((sum(ports)+1, pf, "%sADDR_Q %s %sADDR;" % (pf, assign_op, pf))) v_stmts.append("always @* %sDATA = memory[%sADDR_Q];" % (pf, pf)) else: v_always[last_always_hdr].append((0, pf, "%sDATA %s memory[%sADDR];" % (pf, assign_op, pf))) for always_hdr in sorted(v_always): v_stmts.append(always_hdr[1]) triggered_events = set() time_cursor = 0 v_always[always_hdr].sort() for t, p, s in v_always[always_hdr]: if time_cursor != t or not p in triggered_events: v_stmts.append(" `ifndef SYNTHESIS") stmt = "" if time_cursor != t: stmt += " #%d;" % (t-time_cursor) time_cursor = t if not p in triggered_events: stmt += (" -> UPDATE_%s;" % p) triggered_events.add(p) v_stmts.append(" %s" % stmt) v_stmts.append(" `endif") v_stmts.append(" %s" % s) v_stmts.append("end") print("module bram_%02d_%02d(%s);" % (k1, k2, ", ".join(v_ports)), file=sim_f) for stmt in v_stmts: print(" %s" % stmt, file=sim_f) print("endmodule", file=sim_f) print("module bram_%02d_%02d_ref(%s);" % (k1, k2, ", ".join(v_ports)), file=ref_f) for stmt in v_stmts: print(" %s" % stmt, file=ref_f) print("endmo
/*
 *  SubCircuit -- An implementation of the Ullmann Subgraph Isomorphism
 *                algorithm for coarse grain logic networks
 *
 *  Copyright (C) 2013  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#ifndef SUBCIRCUIT_H
#define SUBCIRCUIT_H

#include <string>
#include <vector>
#include <set>
#include <map>

namespace SubCircuit
{
	class SolverWorker;

	class Graph
	{
	protected:
		struct BitRef {
			int nodeIdx, portIdx, bitIdx;
			BitRef(int nodeIdx = -1, int portIdx = -1, int bitIdx = -1) : nodeIdx(nodeIdx), portIdx(portIdx), bitIdx(bitIdx) { };
			bool operator < (const BitRef &other) const;
		};

		struct Edge {
			std::set<BitRef> portBits;
			int constValue;
			bool isExtern;
			Edge() : constValue(0), isExtern(false) { };
		};

		struct PortBit {
			int edgeIdx;
			PortBit() : edgeIdx(-1) { };
		};

		struct Port {
			std::string portId;
			int minWidth;
			std::vector<PortBit> bits;
			Port() : minWidth(-1) { };
		};

		struct Node {
			std::string nodeId, typeId;
			std::map<std::string, int> portMap;
			std::vector<Port> ports;
			void *userData;
			bool shared;
			Node() : userData(NULL), shared(false) { };
		};

		bool allExtern;
		std::map<std::string, int> nodeMap;
		std::vector<Node> nodes;
		std::vector<Edge> edges;

	public:
		Graph() : allExtern(false) { };
		Graph(const Graph &other, const std::vector<std::string> &otherNodes);

		void createNode(std::string nodeId, std::string typeId, void *userData = NULL, bool shared = false);
		void createPort(std::string nodeId, std::string portId, int width = 1, int minWidth = -1);
		void createConnection(std::string fromNodeId, std::string fromPortId, int fromBit, std::string toNodeId, std::string toPortId, int toBit, int width = 1);
		void createConnection(std::string fromNodeId, std::string fromPortId, std::string toNodeId, std::string toPortId);
		void createConstant(std::string toNodeId, std::string toPortId, int toBit, int constValue);
		void createConstant(std::string toNodeId, std::string toPortId, int constValue);
		void markExtern(std::string nodeId, std::string portId, int bit = -1);
		void markAllExtern();
		void print();

		friend class SolverWorker;
	};

	class Solver
	{
	public:
		struct ResultNodeMapping {
			std::string needleNodeId, haystackNodeId;
			void *needleUserData, *haystackUserData;
			std::map<std::string, std::string> portMapping;
		};
		struct Result {
			std::string needleGraphId, haystackGraphId;
			std::map<std::string, ResultNodeMapping> mappings;
		};

		struct MineResultNode {
			std::string nodeId;
			void *userData;
		};
		struct MineResult {
			std::string graphId;
			int totalMatchesAfterLimits;
			std::map<std::string, int> matchesPerGraph;
			std::vector<MineResultNode> nodes;
		};

	private:
		SolverWorker *worker;

	protected:
		virtual bool userCompareNodes(const std::string &needleGraphId, const std::string &needleNodeId, void *needleUserData,
				const std::string &haystackGraphId, const std::string &haystackNodeId, void *haystackUserData, const std::map<std::string, std::string> &portMapping);

		virtual std::string userAnnotateEdge(const std::string &graphId, const std::string &fromNodeId, void *fromUserData, const std::string &toNodeId, void *toUserData);

		virtual bool userCompareEdge(const std::string &needleGraphId, const std::string &needleFromNodeId, void *needleFromUserData, const std::string &needleToNodeId, void *needleToUserData,
				const std::string &haystackGraphId, const std::string &haystackFromNodeId, void *haystackFromUserData, const std::string &haystackToNodeId, void *haystackToUserData);

		virtual bool userCheckSolution(const Result &result);

		friend class SolverWorker;

	public:
		Solver();
		virtual ~Solver();

		void setVerbose();
		void addGraph(std::string graphId, const Graph &graph);
		void addCompatibleTypes(std::string needleTypeId, std::string haystackTypeId);
		void addCompatibleConstants(int needleConstant, int haystackConstant);
		void addSwappablePorts(std::string needleTypeId, std::string portId1, std::string portId2, std::string portId3 = std::string(), std::string portId4 = std::string());
		void addSwappablePorts(std::string needleTypeId, std::set<std::string> ports);
		void addSwappablePortsPermutation(std::string needleTypeId, std::map<std::string, std::string> portMapping);

		void solve(std::vector<Result> &results, std::string needleGraphId, std::string haystackGraphId, bool allowOverlap = true, int maxSolutions = -1);
		void solve(std::vector<Result> &results, std::string needleGraphId, std::string haystackGraphId,
				const std::map<std::string, std::set<std::string>> &initialMapping, bool allowOverlap = true, int maxSolutions = -1);

		void mine(std::vector<MineResult> &results, int minNodes, int maxNodes, int minMatches, int limitMatchesPerGraph = -1);

		void clearOverlapHistory();
		void clearConfig();
	};
}

#endif /* SUBCIRCUIT_H */