/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package datapath.graph; import java.io.*; import java.util.HashSet; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author jh */ public class MulPipeCreator { public static boolean virtex5 = true; public static void main(String[] args) { Options o = new Options(); o.WA = 15; o.WB = 32; o.WR = 46; o.stages = 4; o.signed = true; HashSet<Options> set = new HashSet<Options>(); set.add(o); c(set); } public static void c(Set<Options> options) { File dir = null; if(virtex5) { dir = new File("/scratch/mul_pipe_virtex5/"); } else { dir = new File("/scratch/mul_pipe_virtex2/"); } dir.mkdirs(); try { BufferedWriter topModule = new BufferedWriter(new FileWriter(new File( dir, "mul_pipe.v"))); topModule.write(createModule(options)); topModule.flush(); topModule.close(); } catch (IOException ex) { Logger.getLogger(MulPipeCreator.class.getName()).log(Level.SEVERE, null, ex); } // create not existing modules with coregen for (Options ops : options) { File f = new File(dir, String.format("mul_pipe_%s_%d_%d_%d.v", ops.signed ? "s" : "u", ops.WA, ops.WB, ops.WR)); if (f.exists()) { System.out.println("skipping creation of " + ops + " because it already exists"); continue; } try { String ls_str; File opts = File.createTempFile("foo", "bar"); opts.deleteOnExit(); BufferedWriter w = new BufferedWriter(new FileWriter(opts)); if(virtex5) { w.write(createVirtex5(ops)); } else w.write(create(ops)); w.flush(); Process ls_proc = Runtime.getRuntime().exec("coregen -b " + opts.getAbsolutePath(), null, dir); // get its output (your input) stream DataInputStream ls_in = new DataInputStream( ls_proc.getInputStream()); try { while ((ls_str = ls_in.readLine()) != null) { System.out.println(ls_str); } } catch (IOException e) { System.exit(0); } } catch (IOException e1) { System.err.println(e1); System.exit(1); } } } private static Set<Options> allOpts(int WA, int WB, int WR) { HashSet<Options> opts = new HashSet(); return opts; } private static String createModule(Set<Options> options) { StringBuffer generate = new StringBuffer(); generate.append("\n"); generate.append("`timescale 1ns / 1ns\n"); generate.append("\n"); generate.append("`ifdef QUOTIENT\n"); generate.append(" `undef QUOTIENT\n"); generate.append("`endif\n"); generate.append("`ifdef REMAINDER\n"); generate.append(" `undef REMAINDER\n"); generate.append("`endif\n"); generate.append("\n"); generate.append("/*\n"); generate.append("`ifdef TARGET_ML507\n"); generate.append(" `define QUOTIENT quotient\n"); generate.append(" `define REMAINDER fractional\n"); generate.append("`else*/\n"); generate.append(" `define QUOTIENT quot\n"); generate.append(" `define REMAINDER remd\n"); generate.append("//`endif\n"); generate.append("\n"); generate.append("module mul_pipe\n"); generate.append("\n"); generate.append(" #(parameter WA = 32, \n"); generate.append(" WB = 32, \n"); generate.append(" WR = 32,\n"); generate.append(" DEPTH = 0,\n"); generate.append(" QDEPTH = 16,\n"); generate.append(" STATIC_CT = 0,\n"); generate.append(" START_CTRL_IN = 0,\n"); generate.append(" SIGN = 0)\n"); generate.append("\n"); generate.append(" (input wire [(WA-1):0] A, \n"); generate.append(" input wire [(WB-1):0] B, \n"); generate.append(" output wire [(WR-1):0] R,\n"); generate.append(" input wire RESET,\n"); generate.append(" input wire CLK,\n"); generate.append(" input wire CE,\n"); generate.append(" input wire START,\n"); generate.append(" output wire START_RFD,\n"); generate.append(" input wire START_CTRL,\n"); generate.append(" output wire START_CTRL_RFD,\n"); generate.append(" input wire CANCEL,\n"); generate.append(" output reg CANCEL_ACCEPT,\n"); generate.append(" output wire CANCEL_STATE,\n"); generate.append( " input wire CANCEL_STATE_RESET,\n"); generate.append( " output wire CANCEL_STATE_CTRL,\n"); generate.append( " input wire CANCEL_STATE_CTRL_RESET,\n"); generate.append(" output wire RESULT_READY,\n"); generate.append(" input wire RESULT_ACCEPT);\n"); generate.append(" \n"); generate.append(" // define LATENCY of this module (operator only) \n"); generate.append( " localparam LATENCY = (WA <= 16) ? 2 : (WA <= 32) ? 4 : 6; // 32b mod: 34 clocks + 2 clocks if signed\n"); generate.append( " // CANCEL BITS depending on LATENCY and shift register DEPTH \n"); generate.append( " localparam CANCEL_BITS = min_1(ceil_log2(LATENCY+DEPTH-1));\n"); generate.append(" // QDEPTH_INT has to be at least 16\n"); generate.append(" localparam QDEPTH_INT = min_16(QDEPTH);\n"); generate.append(" // set QBITS accordingly\n"); generate.append( " localparam QBITS = (QDEPTH == 0) ? 0 : ceil_log2(QDEPTH_INT-1);\n"); generate.append( " // COMPUTATION_BITS depending on LATENCY shift register DEPTH and queue QDEPTH\n"); generate.append( " localparam COMPUTATION_BITS = min_1(ceil_log2(LATENCY+DEPTH+QDEPTH_INT-1));\n"); generate.append(" \n"); generate.append(" \n"); generate.append(" wire rfd;\n"); generate.append(" wire ce_comp;\n"); generate.append(" \n"); generate.append(" wire write;\n"); generate.append(" wire read;\n"); generate.append(" wire full;\n"); generate.append(" wire empty;\n"); generate.append(" wire result_ready_sr;\n"); generate.append(" wire increase;\n"); generate.append(" wire decrease;\n"); generate.append(" wire increase_comp;\n"); generate.append(" wire decrease_comp;\n"); generate.append(" \n"); generate.append(" wire [(WR-1) :0] r_queue;\n"); generate.append(" wire [(WR-1) :0] r_sr;\n"); generate.append(" reg [(CANCEL_BITS-1) :0] cancel_count; \n"); generate.append( " reg [(COMPUTATION_BITS-1):0] computation_count;\n"); generate.append( " reg cancel_state_keep;\n"); generate.append( " reg cancel_state_ctrl_keep;\n"); generate.append( " reg cancel_to_process; \n"); generate.append(" \n"); generate.append(" wire [(WR-1):0] quot;\n"); generate.append(" reg [(LATENCY-1):0] RESULT_READY_int;\n"); generate.append("\n"); generate.append("`include \"handshaking_assigns_blackbox_include.v\"\n"); generate.append(" \n"); generate.append(" // synthesis translate_off\n"); generate.append(" // synthesis translate_on\n"); generate.append(" \n"); generate.append(" generate\n"); for (Options op : options) { int WA = op.WA; int WB = op.WB; int WR = op.WR; int sign = op.signed ? 1 : 0; String signString = op.signed ? "s" : "u"; generate.append(String.format( "if ((WA == %d) && (WB == %d) && (WR == %d) && (SIGN == %d)) begin\n", WA, WB, WR, sign)); generate.append("assign rfd = ce_comp;\n"); generate.append(String.format( "mul_pipe_%s_%d_%d_%d mul_pipe_%s_%d_%d_%d (\n", signString, WA, WB, WR, signString, WA, WB, WR)); generate.append(".clk(CLK),\n"); generate.append(".a(A),\n"); generate.append(".b(B),\n"); generate.append(".ce(ce_comp),\n"); generate.append(".sclr(RESET),\n"); generate.append(".p(quot));\n"); generate.append("end\n"); } generate.append(" endgenerate\n"); generate.append("\n"); generate.append("\n"); generate.append(" // shift in RESULT_READY signals based on START\n"); generate.append( " // thus these are aligned with the computation result\n"); generate.append(" always @(posedge CLK, posedge RESET) begin\n"); generate.append(" if (RESET) begin\n"); generate.append(" RESULT_READY_int <= 0;\n"); generate.append(" end else begin\n"); generate.append(" if (ce_comp)\n"); generate.append( " RESULT_READY_int <= (RESULT_READY_int << 1) | (START & START_RFD);\n"); generate.append(" else\n"); generate.append( " RESULT_READY_int <= RESULT_READY_int; \n"); generate.append(" end\n"); generate.append(" end\n"); generate.append("\n"); generate.append(" \n"); generate.append(" // count ongoing computations;\n"); generate.append(" // increase if START & START_RFD,\n"); generate.append( " // decrease if datum is read from the queue, or (in case of empty queue) if new result comes out of\n"); generate.append( " // the pipeline and is cancelled by stored CT or incoming CT\n"); generate.append(" always @(posedge CLK, posedge RESET) begin\n"); generate.append(" if (RESET) begin\n"); generate.append( " computation_count <= {(COMPUTATION_BITS){1'b0}};\n"); generate.append(" end else begin\n"); generate.append(" case ({decrease_comp, increase_comp}) \n"); generate.append( " 2'b00: computation_count <= computation_count;\n"); generate.append( " 2'b01: if (computation_count != {(COMPUTATION_BITS){1'b1}})\n"); generate.append( " computation_count <= computation_count + 1'b1;\n"); generate.append( " 2'b10: if (computation_count != {(COMPUTATION_BITS){1'b0}})\n"); generate.append( " computation_count <= computation_count - 1'b1; \n"); generate.append( " 2'b11: computation_count <= computation_count; \n"); generate.append(" endcase\n"); generate.append(" end\n"); generate.append(" end \n"); generate.append("\n"); generate.append(" \n"); generate.append( " // on CANCEL request the signal CANCEL_ACCEPT is assertet on acceptance\n"); generate.append( " // acceptance is either the increase of an internal counter or the forwarding\n"); generate.append(" always @(posedge CLK, posedge RESET) begin\n"); generate.append(" if (RESET) begin\n"); generate.append(" cancel_count <= {(CANCEL_BITS){1'b0}};\n"); generate.append(" end else if (empty) begin\n"); generate.append(" case ({decrease, increase}) \n"); generate.append(" 2'b00: begin\n"); generate.append(" cancel_count <= cancel_count;\n"); generate.append(" end\n"); generate.append(" 2'b01: begin\n"); generate.append( " if (cancel_count != {(CANCEL_BITS){1'b1}}) begin \n"); generate.append( " cancel_count <= cancel_count + 1'b1;\n"); generate.append(" end\n"); generate.append(" end \n"); generate.append(" 2'b10: begin\n"); generate.append( " if (cancel_count != {(CANCEL_BITS){1'b0}}) begin\n"); generate.append( " cancel_count <= cancel_count - 1'b1;\n"); generate.append(" end\n"); generate.append(" end \n"); generate.append(" 2'b11: begin\n"); generate.append(" cancel_count <= cancel_count;\n"); generate.append(" end\n"); generate.append(" endcase\n"); generate.append(" end\n"); generate.append(" end \n"); generate.append(" \n"); generate.append(" \n"); generate.append(" // shift register instantiation \n"); generate.append(" shiftreg #(.WA(WR), .WR(WR), .DEPTH(DEPTH)) sr (\n"); generate.append(" .A(quot), \n"); generate.append(" .R(r_sr), \n"); generate.append(" .RESET(RESET), \n"); generate.append(" .CLK(CLK), \n"); generate.append( " .CE(~full | read | (~RESULT_READY & ((START_CTRL_IN == 0) | ~result_ready_sr | ~ac_empty))),\n"); generate.append(" .START(RESULT_READY_int[LATENCY-1]), \n"); generate.append(" .RESULT_READY(result_ready_sr));\n"); generate.append(" \n"); generate.append(" // queue instantiation \n"); generate.append( " sr_queue #(.WR(WR), .QDEPTH(QDEPTH_INT), .QBITS(QBITS)) queue_out ( \n"); generate.append(" .CLK(CLK), \n"); generate.append(" .RESET(RESET), \n"); generate.append(" .DIN(r_sr), \n"); generate.append(" .READ(read), \n"); generate.append(" .WRITE(write), \n"); generate.append(" .DOUT(r_queue),\n"); generate.append(" .EMPTY(empty), \n"); generate.append(" .FULL(full)); \n"); generate.append(" \n"); generate.append("\n"); generate.append(" //ceil of the log base 2\n"); generate.append(" function integer ceil_log2;\n"); generate.append(" input [31:0] value;\n"); generate.append( " for (ceil_log2=0; value>0; ceil_log2=ceil_log2+1)\n"); generate.append(" value = value>>1;\n"); generate.append(" endfunction\n"); generate.append(" \n"); generate.append(" // value is at least 16\n"); generate.append(" function integer min_16;\n"); generate.append(" input [31:0] value;\n"); generate.append(" if ((value < 16) & (value > 0))\n"); generate.append(" min_16 = 16;\n"); generate.append(" else\n"); generate.append(" min_16 = value;\n"); generate.append(" endfunction\n"); generate.append(" \n"); generate.append(" // value cannot be less than 1\n"); generate.append(" function integer min_1;\n"); generate.append(" input [31:0] value;\n"); generate.append(" if (value == 0)\n"); generate.append(" min_1 = 1;\n"); generate.append(" else\n"); generate.append(" min_1 = value;\n"); generate.append(" endfunction\n"); generate.append("\n"); generate.append("endmodule\n"); return generate.toString(); } private static String createVirtex5(Options opts) { StringBuffer generate = new StringBuffer(); boolean signed = opts.signed; int WR = opts.WR; int WA = opts.WA; int WB = opts.WB; String sign = signed ? "Signed" : "Unsigned"; generate.append("SET addpads = False\n"); generate.append("SET asysymbol = True\n"); generate.append("SET busformat = BusFormatAngleBracketNotRipped\n"); generate.append("SET createndf = False\n"); generate.append("SET designentry = Verilog\n"); generate.append("SET device = xc5vfx70t\n"); generate.append("SET devicefamily = virtex5\n"); generate.append("SET flowvendor = Other\n"); generate.append("SET formalverification = False\n"); generate.append("SET foundationsym = False\n"); generate.append("SET implementationfiletype = Ngc\n"); generate.append("SET package = ff1136\n"); generate.append("SET removerpms = False\n"); generate.append("SET simulationfiles = Behavioral\n"); generate.append("SET speedgrade = -2\n"); generate.append("SET verilogsim = True\n"); generate.append("SET vhdlsim = False\n"); generate.append("# END Project Options\n"); generate.append("# BEGIN Select\n"); generate.append("SELECT Multiplier family Xilinx,_Inc. 11.2\n"); generate.append("# END Select\n"); generate.append("# BEGIN Parameters\n"); generate.append("CSET ccmimp=Distributed_Memory\n"); generate.append("CSET clockenable=true\n"); generate.append(String.format( "CSET component_name=mul_pipe_%s_%d_%d_%d\n", signed ? "s" : "u", WA, WB, WR)); generate.append("CSET constvalue=129\n"); generate.append("CSET internaluser=0\n"); generate.append("CSET multiplier_construction=Use_Mults\n"); generate.append("CSET multtype=Parallel_Multiplier\n"); generate.append("CSET optgoal=Speed\n"); generate.append(String.format("CSET outputwidthhigh=%d\n",WR-1)); generate.append("CSET outputwidthlow=0\n"); generate.append(String.format("CSET pipestages=%d\n",opts.delay())); generate.append(String.format("CSET portatype=%s\n",sign)); generate.append(String.format("CSET portawidth=%d\n",WA)); generate.append(String.format("CSET portbtype=%s\n",sign)); generate.append(String.format("CSET portbwidth=%d\n",WB)); generate.append("CSET roundpoint=0\n"); generate.append("CSET sclrcepriority=SCLR_Overrides_CE\n"); generate.append("CSET syncclear=true\n"); generate.append("CSET use_custom_output_width=true\n"); generate.append("CSET userounding=false\n"); generate.append("CSET zerodetect=false\n"); generate.append("GENERATE\n"); return generate.toString(); } private static String create(Options opts) { StringBuffer generate = new StringBuffer(); boolean signed = opts.signed; int WR = opts.WR; int WA = opts.WA; int WB = opts.WB; String sign = signed ? "Signed" : "Unsigned"; generate.append("SET addpads = False\n"); generate.append("SET asysymbol = False\n"); generate.append("SET busformat = BusFormatAngleBracketNotRipped\n"); generate.append("SET createndf = False\n"); generate.append("SET designentry = Verilog\n"); generate.append("SET device = xc5vfx70t\n"); generate.append("SET devicefamily = virtex5\n"); // generate.append("SET device = xc2vp30\n"); // generate.append("SET devicefamily = virtex2p\n"); generate.append("SET flowvendor = Other\n"); generate.append("SET formalverification = False\n"); generate.append("SET foundationsym = False\n"); generate.append("SET implementationfiletype = Ngc\n"); // generate.append("SET package = ff896\n"); generate.append("SET package = ff1136\n"); generate.append("SET removerpms = False\n"); generate.append("SET simulationfiles = Structural\n"); // generate.append("SET speedgrade = -6\n"); generate.append("SET speedgrade = -2\n"); generate.append("SET verilogsim = True\n"); generate.append("SET vhdlsim = False\n"); //generate.append("# END Project Options\n"); //generate.append("# BEGIN Select\n"); generate.append("SELECT Multiplier family Xilinx,_Inc. 10.1\n"); //generate.append("# END Select\n"); //generate.append("# BEGIN Parameters\n"); generate.append("CSET ccmimp=Distributed_Memory\n"); generate.append("CSET clockenable=true\n"); //generate.append("CSET component_name=mul_pipe_s_16_32\n"); generate.append(String.format( "CSET component_name=mul_pipe_%s_%d_%d_%d\n", signed ? "s" : "u", WA, WB, WR)); generate.append("CSET constvalue=129\n"); generate.append("CSET internaluser=0\n"); generate.append("CSET multiplier_construction=Use_Mults\n"); generate.append("CSET multtype=Parallel_Multiplier\n"); generate.append("CSET optgoal=Speed\n"); //generate.append("CSET outputwidthhigh=31\n"); generate.append(String.format("CSET outputwidthhigh=%d\n", WR - 1)); generate.append("CSET outputwidthlow=0\n"); //generate.append("CSET pipestages=2\n"); generate.append(String.format("CSET pipestages=%d\n", opts.delay())); //generate.append("CSET portatype=Signed\n"); generate.append(String.format("CSET portatype=%s\n", sign)); //generate.append("CSET portawidth=16\n"); generate.append(String.format("CSET portawidth=%d\n", WA)); //generate.append("CSET portbtype=Signed\n"); generate.append(String.format("CSET portbtype=%s\n", sign)); //generate.append("CSET portbwidth=16\n"); generate.append(String.format("CSET portbwidth=%d\n", WB)); generate.append("CSET roundpoint=0\n"); generate.append("CSET sclrcepriority=SCLR_Overrides_CE\n"); generate.append("CSET syncclear=true\n"); generate.append("CSET use_custom_output_width=true\n"); generate.append("CSET userounding=false\n"); generate.append("CSET zerodetect=false\n"); generate.append("GENERATE\n"); return generate.toString(); } public static class Options { int WA; int WB; int WR; int stages; boolean signed; public int delay() { return stages; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Options other = (Options) obj; if (this.WA != other.WA) { return false; } if (this.WB != other.WB) { return false; } if (this.WR != other.WR) { return false; } if (this.signed != other.signed) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 29 * hash + this.WA; hash = 29 * hash + this.WB; hash = 29 * hash + this.WR; hash = 29 * hash + (this.signed ? 1 : 0); return hash; } @Override public String toString() { return String.format("mul_pipe_%s_%d_%d_%d", signed ? "s" : "u", WA, WB, WR); } } }