`default_nettype none
module spiOverJtag
(
`ifndef xilinxultrascale
	output wire csn,

`ifdef spartan6
	output wire sck,
`endif
`ifdef spartan3e
	output wire sck,
`endif
`ifdef virtex6
	output wire sdi_dq0
`else
	output wire sdi_dq0,
	input  wire sdo_dq1,
	output wire wpn_dq2,
	output wire hldn_dq3
`endif
`endif // xilinxultrascale

`ifdef secondaryflash
	output wire sdi_sec_dq0,
	input  wire sdo_sec_dq1,
	output wire wpn_sec_dq2,
	output wire hldn_sec_dq3,
	output wire csn_sec
`endif // secondaryflash
);

	wire capture, drck, sel, update, shift;
	wire tdi, tdo;

`ifndef spartan3e
`ifndef virtex6
	/* Version Interface. */
	wire ver_sel, ver_cap, ver_shift, ver_drck, ver_tdi, ver_tdo;
	wire spi_clk;

	spiOverJtag_core spiOverJtag_core_prim (
		/* JTAG state/controls */
		.sel(sel),
		.capture(capture),
		.update(update),
		.shift(shift),
		.drck(drck),
		.tdi(tdi),
		.tdo(tdo),

		/* JTAG endpoint to version */
		.ver_sel(ver_sel),
		.ver_cap(ver_cap),
		.ver_shift(ver_shift),
		.ver_drck(ver_drck),
		.ver_tdi(ver_tdi),
		.ver_tdo(ver_tdo),

		/* phys */
		.csn(csn),
		.sck(spi_clk),
		.sdi_dq0(sdi_dq0),
		.sdo_dq1(sdo_dq1),
		.wpn_dq2(wpn_dq2),
		.hldn_dq3(hldn_dq3)
	);
`endif /* !virtex6 */
`endif /* !spartan3e */

`ifdef spartan6
	assign sck = spi_clk;
`else // !spartan6
`ifdef spartan3e
	assign sck = drck;
`else // !spartan6 && !spartan3e
`ifdef xilinxultrascale
	assign sck = drck;
	wire [3:0] di;
	assign sdo_dq1 = di[1];
	wire [3:0] do = {hldn_dq3, wpn_dq2, 1'b0, sdi_dq0};
	wire [3:0] dts = 4'b0010;
	// secondary BSCANE3 signals
	wire sel_sec, spi_clk_sec;

	wire sck = (sel_sec) ? spi_clk_sec : spi_clk;

	STARTUPE3 #(
		.PROG_USR("FALSE"),  // Activate program event security feature. Requires encrypted bitstreams.
		.SIM_CCLK_FREQ(0.0)  // Set the Configuration Clock Frequency (ns) for simulation.
	) startupe3_inst (
		.CFGCLK   (),     // 1-bit output: Configuration main clock output.
		.CFGMCLK  (),     // 1-bit output: Configuration internal oscillator clock output.
		.DI       (di),   // 4-bit output: Allow receiving on the D input pin.
		.EOS      (),     // 1-bit output: Active-High output signal indicating the End Of Startup.
		.PREQ     (),     // 1-bit output: PROGRAM request to fabric output.
		.DO       (do),   // 4-bit input: Allows control of the D pin output.
		.DTS      (dts),  // 4-bit input: Allows tristate of the D pin.
		.FCSBO    (csn),  // 1-bit input: Controls the FCS_B pin for flash access.
		.FCSBTS   (1'b0), // 1-bit input: Tristate the FCS_B pin.
		.GSR      (1'b0), // 1-bit input: Global Set/Reset input (GSR cannot be used for the port).
		.GTS      (1'b0), // 1-bit input: Global 3-state input (GTS cannot be used for the port name).
		.KEYCLEARB(1'b0), // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM).
		.PACK     (1'b0), // 1-bit input: PROGRAM acknowledge input.
		.USRCCLKO (sck),  // 1-bit input: User CCLK input.
		.USRCCLKTS(1'b0), // 1-bit input: User CCLK 3-state enable input.
		.USRDONEO (1'b1), // 1-bit input: User DONE pin output control.
		.USRDONETS(1'b1)  // 1-bit input: User DONE 3-state enable output.
	);
`elsif virtex6 // !spartan6 && !spartan3e && !xilinxultrascale
	wire di;

	wire runtest;
	reg fsm_csn;
	// jtag -> spi flash
	assign sdi_dq0 = tdi;
	assign tdo     = (sel) ? di : tdi;
	assign csn     = fsm_csn;

	wire tmp_cap_s = capture && sel;
	wire tmp_up_s  = update && sel;

	always @(posedge drck, posedge runtest) begin
		if (runtest) begin
			fsm_csn <= 1'b1;
		end else begin
			if (tmp_cap_s) begin
				fsm_csn <= 1'b0;
			end else if (tmp_up_s) begin
				fsm_csn <= 1'b1;
			end else begin
				fsm_csn <= fsm_csn;
			end
		end
	end
	STARTUP_VIRTEX6 #(
			.PROG_USR("FALSE")
	) startup_virtex6_inst (
			.CFGCLK(),        // unused
			.CFGMCLK(),       // unused
			.CLK(1'b0),       // unused
			.DINSPI(di),      // data from SPI flash
			.EOS(),
			.GSR(1'b0),       // unused
			.GTS(1'b0),       // unused
			.KEYCLEARB(1'b0),  // not used
			.PACK(1'b1),      // tied low for 'safe' operations
			.PREQ(),          // unused
			.TCKSPI(),        // echo of CCLK from TCK pin
			.USRCCLKO (drck), // user FPGA -> CCLK pin
			.USRCCLKTS(1'b0), // drive CCLK not in high-Z
			.USRDONEO (1'b1), // why both USRDONE are high?
			.USRDONETS(1'b1)  // ??
	);
`else // !spartan6 && !spartan3e && !xilinxultrascale && !virtex6
	STARTUPE2 #(
		.PROG_USR("FALSE"),  // Activate program event security feature. Requires encrypted bitstreams.
		.SIM_CCLK_FREQ(0.0)  // Set the Configuration Clock Frequency(ns) for simulation.
	) startupe2_inst (
		.CFGCLK   (),        // 1-bit output: Configuration main clock output
		.CFGMCLK  (),        // 1-bit output: Configuration internal oscillator clock output
		.EOS      (),        // 1-bit output: Active high output signal indicating the End Of Startup.
		.PREQ     (),        // 1-bit output: PROGRAM request to fabric output
		.CLK      (1'b0),    // 1-bit input: User start-up clock input
		.GSR      (1'b0),    // 1-bit input: Global Set/Reset input (GSR cannot be used for the port name)
		.GTS      (1'b0),    // 1-bit input: Global 3-state input (GTS cannot be used for the port name)
		.KEYCLEARB(1'b0),    // 1-bit input: Clear AES Decrypter Key input from Battery-Backed RAM (BBRAM)
		.PACK     (1'b1),    // 1-bit input: PROGRAM acknowledge input
		.USRCCLKO (spi_clk), // 1-bit input: User CCLK input
		.USRCCLKTS(1'b0),    // 1-bit input: User CCLK 3-state enable input
		.USRDONEO (1'b1),    // 1-bit input: User DONE pin output control
		.USRDONETS(1'b1)     // 1-bit input: User DONE 3-state enable output
	);
`endif
`endif
`endif

`ifdef spartan3e
	wire runtest;
	reg fsm_csn;
	assign wpn_dq2  = 1'b1;
	assign hldn_dq3 = 1'b1;
	// jtag -> spi flash
	assign sdi_dq0 = tdi;
	assign tdo     = (sel) ? sdo_dq1 : tdi;
	assign csn     = fsm_csn;

	wire tmp_cap_s = capture && sel;
	wire tmp_up_s = update && sel;
	assign runtest = tmp_up_s;

	always @(posedge drck, posedge runtest) begin
		if (runtest) begin
			fsm_csn <= 1'b1;
		end else begin
			if (tmp_cap_s) begin
				fsm_csn <= 1'b0;
			end else if (tmp_up_s) begin
				fsm_csn <= 1'b1;
			end else begin
				fsm_csn <= fsm_csn;
			end
		end
	end

	BSCAN_SPARTAN3 bscane2_inst (
		.CAPTURE(capture), // 1-bit output: CAPTURE output from TAP controller.
		.DRCK1	(drck),    // 1-bit output: Gated TCK output. When SEL
						   //               is asserted, DRCK toggles when
						   //               CAPTURE or SHIFT are asserted.
		.DRCK2  (),        // 1-bit output: USER2 function
		.RESET  (),        // 1-bit output: Reset output for TAP controller.
		.SEL1   (sel),     // 1-bit output: USER1 instruction active output.
		.SEL2   (),        // 1-bit output: USER2 instruction active output.
		.SHIFT  (),        // 1-bit output: SHIFT output from TAP controller.
		.TDI    (tdi),     // 1-bit output: Test Data Input (TDI) output
		                   //               from TAP controller.
		.UPDATE (update),  // 1-bit output: UPDATE output from TAP controller
		.TDO1   (tdo),     // 1-bit input: Test Data Output (TDO) input
		                   //              for USER1 function.
		.TDO2   ()         // 1-bit input: USER2 function
	);
`else
`ifdef virtex6
	BSCAN_VIRTEX6 #(
`elsif spartan6
	BSCAN_SPARTAN6 #(
`else
	BSCANE2 #(
`endif
		.JTAG_CHAIN(1)  // Value for USER command.
	) bscane2_inst (
		.CAPTURE(capture), // 1-bit output: CAPTURE output from TAP controller.
		.DRCK	(drck),    // 1-bit output: Gated TCK output. When SEL
						   //               is asserted, DRCK toggles when
						   //               CAPTURE or SHIFT are asserted.
		.RESET  (),        // 1-bit output: Reset output for TAP controller.
`ifdef virtex6
		.RUNTEST(runtest),
`else
		.RUNTEST(),        // 1-bit output: Output asserted when TAP
						   //               controller is in Run Test/Idle state.
`endif
		.SEL	 (sel),    // 1-bit output: USER instruction active output.
		.SHIFT   (shift),  // 1-bit output: SHIFT output from TAP controller.
		.TCK     (),       // 1-bit output: Test Clock output.
		                   //               Fabric connection to TAP Clock pin.
		.TDI     (tdi),    // 1-bit output: Test Data Input (TDI) output
		                   //               from TAP controller.
		.TMS     (),       // 1-bit output: Test Mode Select output.
		                   //               Fabric connection to TAP.
		.UPDATE  (update), // 1-bit output: UPDATE output from TAP controller
		.TDO     (tdo)     // 1-bit input: Test Data Output (TDO) input
		                   //              for USER function.
	);

/* BSCAN for Version Interface. */
`ifndef virtex6
`ifdef spartan6
	BSCAN_SPARTAN6 #(
`else
	BSCANE2 #(
`endif
		.JTAG_CHAIN(4)  // Value for USER command.
	) bscane2_version (
		.CAPTURE(ver_cap),
		.DRCK	(ver_drck),
		.RESET  (),
		.RUNTEST(),
		.SEL	 (ver_sel),
		.SHIFT   (ver_shift),
		.TCK     (),
		.TDI     (ver_tdi),
		.TMS     (),
		.UPDATE  (),
		.TDO     (ver_tdo)
	);
`endif
`endif /* !virtex6 */

`ifdef secondaryflash
	wire drck_sec;

	spiOverJtag_core spiOverJtag_core_sec (
		/* JTAG state/controls */
		.sel(sel_sec),
		.capture(capture),
		.update(update),
		.shift(shift),
		.drck(drck_sec),
		.tdi(tdi),
		.tdo(tdo_sec),

		/* JTAG endpoint to version (Unused) */
		.ver_sel(1'b0),
		.ver_cap(1'b0),
		.ver_shift(1'b0),
		.ver_drck(1'b0),
		.ver_tdi(1'b0),
		.ver_tdo(),

		/* phys */
		.csn(csn_sec),
		.sck(spi_clk_sec),
		.sdi_dq0(sdi_sec_dq0),
		.sdo_dq1(sdo_sec_dq1),
		.wpn_dq2(wpn_sec_dq2),
		.hldn_dq3(hldn_sec_dq3)
	);

	BSCANE2 #(
		.JTAG_CHAIN(2)  // Value for USER command.
	) bscane2_sec_inst (
		.CAPTURE(), // 1-bit output: CAPTURE output from TAP controller.
		.DRCK	(drck_sec),    // 1-bit output: Gated TCK output. When SEL
						   //               is asserted, DRCK toggles when
						   //               CAPTURE or SHIFT are asserted.
		.RESET  (),        // 1-bit output: Reset output for TAP controller.
		.RUNTEST(), // 1-bit output: Output asserted when TAP
						   //               controller is in Run Test/Idle state.
		.SEL	 (sel_sec),    // 1-bit output: USER instruction active output.
		.SHIFT   (),       // 1-bit output: SHIFT output from TAP controller.
		.TCK     (),       // 1-bit output: Test Clock output.
		                   //               Fabric connection to TAP Clock pin.
		.TDI     (),    // 1-bit output: Test Data Input (TDI) output
		                   //               from TAP controller.
		.TMS     (),       // 1-bit output: Test Mode Select output.
		                   //               Fabric connection to TAP.
		.UPDATE  (), // 1-bit output: UPDATE output from TAP controller
		.TDO     (tdo_sec)     // 1-bit input: Test Data Output (TDO) input
		                   //              for USER function.
	);
`endif // secondaryflash

endmodule
