import sys

def generate(filename):
	with open(filename, "w") as f:
		f.write("// **AUTOGENERATED FILE** **DO NOT EDIT**\n")
		f.write(f"// Generated by {sys.argv[0]}\n")

		f.write("`timescale 1ns /10ps\n")
		for a_width in [1,2,4,9,18,36]:
			for b_width in [1,2,4,9,18,36]:
				f.write(f"""
module TDP36K_BRAM_A_X{a_width}_B_X{b_width}_nonsplit (
	RESET_ni,
	WEN_A1_i,   WEN_B1_i,
	REN_A1_i,   REN_B1_i,
	CLK_A1_i,   CLK_B1_i,
	BE_A1_i,    BE_B1_i,
	ADDR_A1_i,  ADDR_B1_i,
	WDATA_A1_i, WDATA_B1_i,
	RDATA_A1_o, RDATA_B1_o,
	FLUSH1_i,
	WEN_A2_i,   WEN_B2_i,
	REN_A2_i,   REN_B2_i,
	CLK_A2_i,   CLK_B2_i,
	BE_A2_i,    BE_B2_i,
	ADDR_A2_i,  ADDR_B2_i,
	WDATA_A2_i, WDATA_B2_i,
	RDATA_A2_o, RDATA_B2_o,
	FLUSH2_i
	);

	parameter [80:0] MODE_BITS = 81'd0;
	parameter [1024*36-1:0] RAM_INIT = 36864'bx;

	input  wire RESET_ni;
	input  wire WEN_A1_i, WEN_B1_i;
	input  wire REN_A1_i, REN_B1_i;
	input  wire WEN_A2_i, WEN_B2_i;
	input  wire REN_A2_i, REN_B2_i;

	(* clkbuf_sink *)
	input  wire CLK_A1_i;
	(* clkbuf_sink *)
	input  wire CLK_B1_i;
	(* clkbuf_sink *)
	input  wire CLK_A2_i;
	(* clkbuf_sink *)
	input  wire CLK_B2_i;

	input  wire [ 1:0] BE_A1_i,    BE_B1_i;
	input  wire [14:0] ADDR_A1_i,  ADDR_B1_i;
	input  wire [17:0] WDATA_A1_i, WDATA_B1_i;
	output wire [17:0] RDATA_A1_o, RDATA_B1_o;

	input  wire FLUSH1_i;

	input  wire [ 1:0] BE_A2_i,    BE_B2_i;
	input  wire [13:0] ADDR_A2_i,  ADDR_B2_i;
	input  wire [17:0] WDATA_A2_i, WDATA_B2_i;
	output wire [17:0] RDATA_A2_o, RDATA_B2_o;

	input  wire FLUSH2_i;

	TDP36K #(.MODE_BITS(MODE_BITS), .RAM_INIT(RAM_INIT)) bram (
		.RESET_ni   (RESET_ni),
		.WEN_A1_i   (WEN_A1_i),   .WEN_B1_i   (WEN_B1_i),
		.REN_A1_i   (REN_A1_i),   .REN_B1_i   (REN_B1_i),
		.CLK_A1_i   (CLK_A1_i),   .CLK_B1_i   (CLK_B1_i),
		.BE_A1_i    (BE_A1_i),    .BE_B1_i    (BE_B1_i),
		.ADDR_A1_i  (ADDR_A1_i),  .ADDR_B1_i  (ADDR_B1_i),
		.WDATA_A1_i (WDATA_A1_i), .WDATA_B1_i (WDATA_B1_i),
		.RDATA_A1_o (RDATA_A1_o), .RDATA_B1_o (RDATA_B1_o),
		.FLUSH1_i   (FLUSH1_i),
		.WEN_A2_i   (WEN_A2_i),   .WEN_B2_i   (WEN_B2_i),
		.REN_A2_i   (REN_A2_i),   .REN_B2_i   (REN_B2_i),
		.CLK_A2_i   (CLK_A2_i),   .CLK_B2_i   (CLK_B2_i),
		.BE_A2_i    (BE_A2_i),    .BE_B2_i    (BE_B2_i),
		.ADDR_A2_i  (ADDR_A2_i),  .ADDR_B2_i  (ADDR_B2_i),
		.WDATA_A2_i (WDATA_A2_i), .WDATA_B2_i (WDATA_B2_i),
		.RDATA_A2_o (RDATA_A2_o), .RDATA_B2_o (RDATA_B2_o),
		.FLUSH2_i   (FLUSH2_i)
	);

	`ifdef SDF_SIM
	specify
		(negedge RESET_ni => (RDATA_A1_o +: WDATA_A1_i)) = 0;
		(negedge RESET_ni => (RDATA_B1_o +: WDATA_B1_i)) = 0;
		(negedge RESET_ni => (RDATA_A2_o +: WDATA_A2_i)) = 0;
		(negedge RESET_ni => (RDATA_B2_o +: WDATA_B2_i)) = 0;
		(posedge CLK_A1_i => (RDATA_A1_o +: WDATA_A1_i)) = 0;
		(posedge CLK_B1_i => (RDATA_B1_o +: WDATA_B1_i)) = 0;
		(posedge CLK_A2_i => (RDATA_A2_o +: WDATA_A2_i)) = 0;
		(posedge CLK_B2_i => (RDATA_B2_o +: WDATA_B2_i)) = 0;
		$setuphold(posedge CLK_A1_i, RESET_ni, 0, 0);
		$setuphold(posedge CLK_A1_i, FLUSH1_i, 0, 0);
		$setuphold(posedge CLK_A1_i, WEN_A1_i, 0, 0);
		$setuphold(posedge CLK_A1_i, REN_A1_i, 0, 0);
		$setuphold(posedge CLK_A1_i, BE_A1_i, 0, 0);
		$setuphold(posedge CLK_A1_i, ADDR_A1_i, 0, 0);
		$setuphold(posedge CLK_A1_i, WDATA_A1_i, 0, 0);
		$setuphold(posedge CLK_B1_i, RESET_ni, 0, 0);
		$setuphold(posedge CLK_B1_i, WEN_B1_i, 0, 0);
		$setuphold(posedge CLK_B1_i, REN_B1_i, 0, 0);
		$setuphold(posedge CLK_B1_i, BE_B1_i, 0, 0);
		$setuphold(posedge CLK_B1_i, ADDR_B1_i, 0, 0);
		$setuphold(posedge CLK_B1_i, WDATA_B1_i, 0, 0);
		$setuphold(posedge CLK_A2_i, RESET_ni, 0, 0);
		$setuphold(posedge CLK_A2_i, FLUSH2_i, 0, 0);
		$setuphold(posedge CLK_A2_i, WEN_A2_i, 0, 0);
		$setuphold(posedge CLK_A2_i, REN_A2_i, 0, 0);
		$setuphold(posedge CLK_A2_i, BE_A2_i, 0, 0);
		$setuphold(posedge CLK_A2_i, ADDR_A2_i, 0, 0);
		$setuphold(posedge CLK_A2_i, WDATA_A2_i, 0, 0);
		$setuphold(posedge CLK_B2_i, RESET_ni, 0, 0);
		$setuphold(posedge CLK_B2_i, WEN_B2_i, 0, 0);
		$setuphold(posedge CLK_B2_i, REN_B2_i, 0, 0);
		$setuphold(posedge CLK_B2_i, BE_B2_i, 0, 0);
		$setuphold(posedge CLK_B2_i, ADDR_B2_i, 0, 0);
		$setuphold(posedge CLK_B2_i, WDATA_B2_i, 0, 0);
	endspecify
	`endif
endmodule
""")

		for a1_width in [1,2,4,9,18]:
			for b1_width in [1,2,4,9,18]:
				for a2_width in [1,2,4,9,18]:
					for b2_width in [1,2,4,9,18]:
						f.write(f"""
module TDP36K_BRAM_A1_X{a1_width}_B1_X{b1_width}_A2_X{a2_width}_B2_X{b2_width}_split (
	RESET_ni,
	WEN_A1_i,   WEN_B1_i,
	REN_A1_i,   REN_B1_i,
	CLK_A1_i,   CLK_B1_i,
	BE_A1_i,    BE_B1_i,
	ADDR_A1_i,  ADDR_B1_i,
	WDATA_A1_i, WDATA_B1_i,
	RDATA_A1_o, RDATA_B1_o,
	FLUSH1_i,
	WEN_A2_i,   WEN_B2_i,
	REN_A2_i,   REN_B2_i,
	CLK_A2_i,   CLK_B2_i,
	BE_A2_i,    BE_B2_i,
	ADDR_A2_i,  ADDR_B2_i,
	WDATA_A2_i, WDATA_B2_i,
	RDATA_A2_o, RDATA_B2_o,
	FLUSH2_i
	);

	parameter [80:0] MODE_BITS = 81'd0;
	parameter [1024*36-1:0] RAM_INIT = 36864'bx;

	input  wire RESET_ni;
	input  wire WEN_A1_i, WEN_B1_i;
	input  wire REN_A1_i, REN_B1_i;
	input  wire WEN_A2_i, WEN_B2_i;
	input  wire REN_A2_i, REN_B2_i;

	(* clkbuf_sink *)
	input  wire CLK_A1_i;
	(* clkbuf_sink *)
	input  wire CLK_B1_i;
	(* clkbuf_sink *)
	input  wire CLK_A2_i;
	(* clkbuf_sink *)
	input  wire CLK_B2_i;

	input  wire [ 1:0] BE_A1_i,    BE_B1_i;
	input  wire [14:0] ADDR_A1_i,  ADDR_B1_i;
	input  wire [17:0] WDATA_A1_i, WDATA_B1_i;
	output wire [17:0] RDATA_A1_o, RDATA_B1_o;

	input  wire FLUSH1_i;

	input  wire [ 1:0] BE_A2_i,    BE_B2_i;
	input  wire [13:0] ADDR_A2_i,  ADDR_B2_i;
	input  wire [17:0] WDATA_A2_i, WDATA_B2_i;
	output wire [17:0] RDATA_A2_o, RDATA_B2_o;

	input  wire FLUSH2_i;

	TDP36K #(.MODE_BITS(MODE_BITS), .RAM_INIT(RAM_INIT)) bram (
		.RESET_ni   (RESET_ni),
		.WEN_A1_i   (WEN_A1_i),   .WEN_B1_i   (WEN_B1_i),
		.REN_A1_i   (REN_A1_i),   .REN_B1_i   (REN_B1_i),
		.CLK_A1_i   (CLK_A1_i),   .CLK_B1_i   (CLK_B1_i),
		.BE_A1_i    (BE_A1_i),    .BE_B1_i    (BE_B1_i),
		.ADDR_A1_i  (ADDR_A1_i),  .ADDR_B1_i  (ADDR_B1_i),
		.WDATA_A1_i (WDATA_A1_i), .WDATA_B1_i (WDATA_B1_i),
		.RDATA_A1_o (RDATA_A1_o), .RDATA_B1_o (RDATA_B1_o),
		.FLUSH1_i   (FLUSH1_i),
		.WEN_A2_i   (WEN_A2_i),   .WEN_B2_i   (WEN_B2_i),
		.REN_A2_i   (REN_A2_i),   .REN_B2_i   (REN_B2_i),
		.CLK_A2_i   (CLK_A2_i),   .CLK_B2_i   (CLK_B2_i),
		.BE_A2_i    (BE_A2_i),    .BE_B2_i    (BE_B2_i),
		.ADDR_A2_i  (ADDR_A2_i),  .ADDR_B2_i  (ADDR_B2_i),
		.WDATA_A2_i (WDATA_A2_i), .WDATA_B2_i (WDATA_B2_i),
		.RDATA_A2_o (RDATA_A2_o), .RDATA_B2_o (RDATA_B2_o),
		.FLUSH2_i   (FLUSH2_i)
	);

	`ifdef SDF_SIM
	specify
		(negedge RESET_ni => (RDATA_A1_o +: WDATA_A1_i)) = 0;
		(negedge RESET_ni => (RDATA_B1_o +: WDATA_B1_i)) = 0;
		(negedge RESET_ni => (RDATA_A2_o +: WDATA_A2_i)) = 0;
		(negedge RESET_ni => (RDATA_B2_o +: WDATA_B2_i)) = 0;
		(posedge CLK_A1_i => (RDATA_A1_o +: WDATA_A1_i)) = 0;
		(posedge CLK_B1_i => (RDATA_B1_o +: WDATA_B1_i)) = 0;
		(posedge CLK_A2_i => (RDATA_A2_o +: WDATA_A2_i)) = 0;
		(posedge CLK_B2_i => (RDATA_B2_o +: WDATA_B2_i)) = 0;
		$setuphold(posedge CLK_A1_i, RESET_ni, 0, 0);
		$setuphold(posedge CLK_A1_i, FLUSH1_i, 0, 0);
		$setuphold(posedge CLK_A1_i, WEN_A1_i, 0, 0);
		$setuphold(posedge CLK_A1_i, REN_A1_i, 0, 0);
		$setuphold(posedge CLK_A1_i, BE_A1_i, 0, 0);
		$setuphold(posedge CLK_A1_i, ADDR_A1_i, 0, 0);
		$setuphold(posedge CLK_A1_i, WDATA_A1_i, 0, 0);
		$setuphold(posedge CLK_B1_i, RESET_ni, 0, 0);
		$setuphold(posedge CLK_B1_i, WEN_B1_i, 0, 0);
		$setuphold(posedge CLK_B1_i, REN_B1_i, 0, 0);
		$setuphold(posedge CLK_B1_i, BE_B1_i, 0, 0);
		$setuphold(posedge CLK_B1_i, ADDR_B1_i, 0, 0);
		$setuphold(posedge CLK_B1_i, WDATA_B1_i, 0, 0);
		$setuphold(posedge CLK_A2_i, RESET_ni, 0, 0);
		$setuphold(posedge CLK_A2_i, FLUSH2_i, 0, 0);
		$setuphold(posedge CLK_A2_i, WEN_A2_i, 0, 0);
		$setuphold(posedge CLK_A2_i, REN_A2_i, 0, 0);
		$setuphold(posedge CLK_A2_i, BE_A2_i, 0, 0);
		$setuphold(posedge CLK_A2_i, ADDR_A2_i, 0, 0);
		$setuphold(posedge CLK_A2_i, WDATA_A2_i, 0, 0);
		$setuphold(posedge CLK_B2_i, RESET_ni, 0, 0);
		$setuphold(posedge CLK_B2_i, WEN_B2_i, 0, 0);
		$setuphold(posedge CLK_B2_i, REN_B2_i, 0, 0);
		$setuphold(posedge CLK_B2_i, BE_B2_i, 0, 0);
		$setuphold(posedge CLK_B2_i, ADDR_B2_i, 0, 0);
		$setuphold(posedge CLK_B2_i, WDATA_B2_i, 0, 0);
	endspecify
	`endif
endmodule
""")

if __name__ == "__main__":
	filename = "bram_types_sim.v"
	if len(sys.argv) > 1:
		filename = sys.argv[1]
	generate(filename)
