#!/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 */