`timescale 1ns/100ps module ds_group (clk25, reset, active, ack_lines, load_lines, par_bus, err_lines, ds_data_a, ds_str_a, ds_data_b, ds_str_b, ds_data_c, ds_str_c, ds_data_d, ds_str_d, ds_data_e, ds_str_e, ds_data_f, ds_str_f, ds_common, ds_ctrl, id); input clk25, reset, ds_data_a, ds_str_a, ds_data_b, ds_str_b, ds_data_c, ds_str_c, ds_data_d, ds_str_d, ds_data_e, ds_str_e, ds_data_f, ds_str_f, active, ds_common, ds_ctrl; input [5:0] ack_lines; input [1:0] id; output [5:0] load_lines, err_lines; output [31:0] par_bus; /* Arguments to routine clk25 (i) synchronous clock at 25ns period reset (i) global reset connected to GSR ack_lines (i) data acknowledged and taken (1 of 6) (reset load_line) load_lines (o) data present for channel 1 of 6 par_bus (i/o) ack_line selected data from multiplexer (32-bits) err_lines (o) serial error for 6 channels independently ds_data_a (i) serial data input for line a (chan 0) ds_str_a (i) serial strobe input for line a (chan 0) ds_data_b (i) serial data input for line a (chan 1) ds_str_b (i) serial strobe input for line a (chan 1) ds_data_c (i) serial data input for line a (chan 2) ds_str_c (i) serial strobe input for line a (chan 2) ds_data_d (i) serial data input for line a (chan 3) ds_str_d (i) serial strobe input for line a (chan 3) ds_data_e (i) serial data input for line a (chan 4) ds_str_e (i) serial strobe input for line a (chan 4) ds_data_f (i) serial data input for line a (chan 5) ds_str_f (i) serial strobe input for line a (chan 5) active (i) daq system is active, DS chip presents load requests ds_common (i) common control line to all DS chips ds_ctrl (i) individual control line for this DS chip only id[1:0] (i) unique, 2bit ID for this DS chip */ reg [5:0] load_lines; reg [31:0] par_bus_latch; reg [5:0] ack_lines3; wire [5:0] load_lines0; reg par_bus_out, par_bus_out3; wire [31:0] par_bus_in, par_bus; /* Other variables par_bus_latch par_bus one tick after par_bus_in ack_lines3 ack lines at time 3 - one tick after ack_lines load_lines0 load_lines at time 0 par_bus_out par_bus at time 4 - one after par_bus_out3 par_bus_out3 par_bus_out at time 3 - to par_bus if this module selected par_bus_in incoming par_bus from multiplexer par_out_a 32-bit data from chan 0 par_out_b 32-bit data from chan 1 par_out_c 32-bit data from chan 2 par_out_d 32-bit data from chan 3 par_out_e 32-bit data from chan 4 par_out_f 32-bit data from chan 5 */ wire [31:0] par_out_a, par_out_b, par_out_c, par_out_d, par_out_e, par_out_f; wire reset, clk25; wire data_a, data_b, data_c, data_d, data_e, data_f; assign data_a = ds_data_a; assign data_b = ds_data_b; assign data_c = ds_data_c; assign data_d = ds_data_d; assign data_e = ds_data_e; assign data_f = ds_data_f; always @(posedge clk25) begin if (reset) begin // initialization of registers par_bus_latch <= #1 0; par_bus_out <= #1 0; load_lines <= #1 6'b000000; ack_lines3 <= #1 6'b000000; end else begin /* capture mux version of par_bus OR ack_lines to reg to flag this unit is outputting set load_lines at time 1 save ack_lines for time 3 set par_bus output for time 4 which is par_bus if this instantation selected */ par_bus_latch <= #1 par_bus_in; par_bus_out3 <= #1 |ack_lines; load_lines <= #1 load_lines0; ack_lines3 <= #1 ack_lines; par_bus_out <= #1 par_bus_out3; end end // instantiate the 6 serial to parallel units ser_par ser_para(clk25, ds_str_a, reset, data_a, par_out_a, load_lines0[0], ack_lines3[0], err_lines[0], active); ser_par ser_parb(clk25, ds_str_b, reset, data_b, par_out_b, load_lines0[1], ack_lines3[1], err_lines[1], active); ser_par ser_parc(clk25, ds_str_c, reset, data_c, par_out_c, load_lines0[2], ack_lines3[2], err_lines[2], active); ser_par ser_pard(clk25, ds_str_d, reset, data_d, par_out_d, load_lines0[3], ack_lines3[3], err_lines[3], active); ser_par ser_pare(clk25, ds_str_e, reset, data_e, par_out_e, load_lines0[4], ack_lines3[4], err_lines[4], active); ser_par ser_parf(clk25, ds_str_f, reset, data_f, par_out_f, load_lines0[5], ack_lines3[5], err_lines[5], active); // send the 6 parallel 32-bit registers to the mux ts_mux_pos_en par_mux(ack_lines3, par_out_a, par_out_b, par_out_c, par_out_d, par_out_e, par_out_f, par_bus_in); // if this unit is selected (par_bus_out true) output the bus assign #10 par_bus = (par_bus_out) ? par_bus_latch : 32'bZ; STARTUP u0 (.GSR(reset), .GTS(1'b0), .CLK(1'b0)); endmodule `timescale 1ns/100ps module ser_par(clk25, der_clk, reset, data_in, parallel_out, load_out, ack, error, active); parameter CHANNEL = 1; input clk25, der_clk, reset, data_in, ack, active; output [31:0] parallel_out; output load_out, error; /* Arguments clk25 (i) synchronous clock at 25ns period der_clk (i) bit clock reset (i) global reset and await data data_in (i) single bit data input parallel_out (o) assembled 32-bit data load_out (o) have a data unit ready ack (i) data unit read and accepted (acknowledged) error (o) serial data error (parity) active (i) daq system is active, so process incoming data */ reg [31:0] parallel_out_bitwise, parallel_out; reg [5:0] count_bit; reg load, accept, load_out, error, one_back; wire parity, data_in, serial_in; /* Other registers serial_in input data gated with not doing reset parallel_out_bitwise register that accumulates 32-bit word parallel_out register that holds accumulated 32-bit word count_bit counter that steps through 35 values load flag indicating word complete out_in_use parallel_out contains data parity parity of word assembled */ assign #1 serial_in = data_in; // compute parity assign #1 parity = ^parallel_out_bitwise; // sync individual channel clock and reset /* count at 0 says we're waiting for new data word to start load is set with der_clk which is out of phase with clk25 load_out is set synchronously with clk25 if load accept is set synchronously with clk25 bits of parallel_out_bitwise are loaded on der_clk parallel_out is set on der_clk flag setting and resetting is done according to: load is initialized to no (0) with reset load_out is initialized to no (0) with clk25 when reset active high accept is initialized to no (0) with clk25 when reset active high when full data word is sequenced by der_clk load is set if active is high, load_out is set if load set when the data is accepted, ack (acknowledge) is set externally on clk25 edge and when set, accept is set on next clk25 edge when accept is set, load is cleared on next der_clk edge bits are assembled starting with serial_in true as start flag that is also required to be preceeded by a false (idle or stop bit) count_bit set to 34 when start bit is seen on count_bit greater than 2, bits are assembled into parallel_out_bitwise when count_bit = 2, assembled word is moved to parallel_out and parity is tested. error set if wrong or if last load is not cleared. also load is set. when count_bit = 1, a stop bit is demanded and error set if not present */ always @(negedge der_clk or posedge reset) begin if (reset) begin // The count starting at 34 should be examined since reset to non-zero // has been troublesome for other synthesis count_bit <= #1 0; error <= #1 0; load <= #1 0; one_back <= #1 0; end else begin one_back <= #1 serial_in; if (accept) load <= #1 0; if (count_bit == 0) begin if ((serial_in == 1) && (one_back == 0)) count_bit <= #1 34; end else begin if (count_bit > 2) begin parallel_out_bitwise[31:0] <= #1 {parallel_out_bitwise[30:0], serial_in}; end if (count_bit == 2) begin parallel_out <= #1 parallel_out_bitwise; if (active) load <= #1 1; error <= #1 (serial_in != parity); end if (count_bit == 1) error <= #1 (error || serial_in); count_bit <= #1 count_bit - 1; end end end always @(posedge clk25) begin if (reset) begin load_out <= #1 0; accept <= #1 0; end else begin if (ack) accept <= #1 1; if (!load_out) accept <= #1 0; load_out <= #1 load; end end endmodule `timescale 1ns/100ps module ts_mux_pos_en (in_sel, data0, data1, data2, data3, data4, data5, data_out); input [5:0] in_sel; input [31:0] data0, data1, data2, data3, data4, data5; output [31:0] data_out; ts_mux_pos_en_oc ts_mux0(in_sel[0], data0, data_out), ts_mux1(in_sel[1], data1, data_out), ts_mux2(in_sel[2], data2, data_out), ts_mux3(in_sel[3], data3, data_out), ts_mux4(in_sel[4], data4, data_out), ts_mux5(in_sel[5], data5, data_out); endmodule `timescale 1ns/100ps module ts_mux_pos_en_oc(in_sel, data, data_out); input in_sel; input [31:0] data; output [31:0] data_out; assign #5 data_out = in_sel ? data : 32'bz; endmodule