dakies/OSS_Verilog huggingface dataset:
module synapse_matrix_tb;

// Testbench Signals
reg tb_clk;
reg tb_rst;
reg tb_cyc;
reg tb_stb;
reg tb_we;
reg [3:0] tb_sel;
reg [31:0] tb_adr;
reg [31:0] tb_dat;
wire tb_ack;
wire [31:0] tb_neuron_conn;

// Memory to hold the written values for verification
reg [31:0] memory[0:255];

// Error counter
integer error_count;
integer total_tests;

// Instantiate the Device Under Test (DUT)
synapse_matrix DUT (
    .wb_clk_i(tb_clk),
    .wb_rst_i(tb_rst),
    .wbs_cyc_i(tb_cyc),
    .wbs_stb_i(tb_stb),
    .wbs_we_i(tb_we),
    .wbs_sel_i(tb_sel),
    .wbs_adr_i(tb_adr),
    .wbs_dat_i(tb_dat),
    .wbs_ack_o(tb_ack),
    .wbs_dat_o(), // Not used in this module
    .neurons_connections_o(tb_neuron_conn)
);

// Clock generation
always #5 tb_clk = !tb_clk; // Generate a clock with a period of 10ns (100MHz)

// Reset routine
initial begin
    // Initialize the testbench signals and error counter
    tb_clk = 0;
    tb_rst = 1;
    tb_cyc = 0;
    tb_stb = 0;
    tb_we = 0;
    tb_sel = 4'b1111;
    tb_adr = 32'h30000000;
    tb_dat = 0;
    error_count = 0;
    total_tests = 0;

    // Assert reset for a few cycles
    #40;
    tb_rst = 0;
    #20;

    // Start testing after reset deassertion
    perform_write_read_test();
    #100;

    // Report total errors and total test cases
    $display("Test complete with %0d errors out of %0d tests.", error_count, total_tests);
    $stop; // Stop simulation but keep the waveform open for debugging
end

// Test routine to write and read
task perform_write_read_test;
    integer i;
    begin
        for (i = 0; i < 256; i = i + 1) begin
            // Random data to write
            tb_dat = $random;
            tb_adr = 32'h30000000 + (i << 2); // Word aligned addresses
            memory[i] = tb_dat; // Store the data for later verification

            // Write cycle
            @(negedge tb_clk) begin
                tb_cyc <= 1;
                tb_stb <= 1;
                tb_we <= 1;
            end

            // Wait for acknowledgment
            @(posedge tb_clk);
            while (!tb_ack) @(posedge tb_clk);

            // Deassert signals
            @(negedge tb_clk) begin
                tb_cyc <= 0;
                tb_stb <= 0;
                tb_we <= 0;
            end
        end

        // Read and verify cycle
        for (i = 0; i < 256; i = i + 1) begin
            tb_adr = 32'h30000000 + (i << 2); // Word aligned addresses

            // Read cycle
            @(negedge tb_clk) begin
                tb_cyc <= 1;
                tb_stb <= 1;
                tb_we <= 0;
            end

            // Wait for acknowledgment and verify the output
            @(posedge tb_clk);
            while (!tb_ack) @(posedge tb_clk);
            total_tests = total_tests + 1;
            if (tb_neuron_conn !== memory[i]) begin
                $display("Error at address %h: expected %h, got %h", tb_adr, memory[i], tb_neuron_conn);
                error_count = error_count + 1;
            end

            // Deassert signals
            @(negedge tb_clk) begin
                tb_cyc <= 0;
                tb_stb <= 0;
            end
        end
    end
endtask

endmodule
module blink(
		input wire clk,
		input wire rst,
		output wire led,
		output wire clk_pll
	);

	reg [26:0] counter;

	wire clk270, clk180, clk90, clk0, usr_ref_out;
	wire usr_pll_lock_stdy, usr_pll_lock;

	CC_PLL #(
		.REF_CLK("10.0"),    // reference input in MHz
		.OUT_CLK("100.0"),   // pll output frequency in MHz
		.PERF_MD("ECONOMY"), // LOWPOWER, ECONOMY, SPEED
		.LOW_JITTER(1),      // 0: disable, 1: enable low jitter mode
		.CI_FILTER_CONST(2), // optional CI filter constant
		.CP_FILTER_CONST(4)  // optional CP filter constant
	) pll_inst (
		.CLK_REF(clk), .CLK_FEEDBACK(1'b0), .USR_CLK_REF(1'b0),
		.USR_LOCKED_STDY_RST(1'b0), .USR_PLL_LOCKED_STDY(usr_pll_lock_stdy), .USR_PLL_LOCKED(usr_pll_lock),
		.CLK270(clk270), .CLK180(clk180), .CLK90(clk90), .CLK0(clk0), .CLK_REF_OUT(usr_ref_out)
	);

	assign led = counter[26];

 assign clk_pll = clk0;

	always @(posedge clk0)
	begin
		if (!rst) begin
			counter <= 0;
		end else begin
			counter <= counter + 1'b1;
		end
	end

endmodule
module spi_slave(
    (* clkbuf_inhibit *) input i_sclk,
    input i_ss,
    input i_mosi,
    input i_echo,
    input [3:0] i_nib_send,
    output o_miso,
    output reg o_rec_nib_ready,
    output reg [3:0] o_nib_rec
);


reg [3:0] tx_shift_reg;
reg [3:0] rx_shift_reg;
reg [1:0] bit_cnt;


always @(posedge i_sclk) begin
    if (i_ss) begin
        rx_shift_reg <= 0;
    end else begin    
        rx_shift_reg <= {rx_shift_reg[2:0], i_mosi};
    end
end

always @(posedge i_sclk) begin
    if (i_ss) begin
        bit_cnt <= 2'b11;
    end
    else begin
        bit_cnt <= bit_cnt + 1'b1;
    end
end 


always @(negedge i_sclk) 
begin
    if (i_ss) begin
        o_rec_nib_ready <= 0;
        o_nib_rec <= 0;
        tx_shift_reg <= 0;
    end
    else if (bit_cnt == 2'b11) begin
        o_rec_nib_ready <= 1;
        o_nib_rec <= rx_shift_reg;
        if (i_echo) begin
            tx_shift_reg <= rx_shift_reg;
        end else begin
            tx_shift_reg <= i_nib_send;
        end
    end
    else begin
        o_rec_nib_ready <= 0;
        tx_shift_reg <= {tx_shift_reg[2:0], 1'b0};
    end
end

assign o_miso = tx_shift_reg[3];

endmodule
module nedge_edge_detection(
    input i_clk,
    input i_reset,
    input i_signal,
    output reg o_nedge_edge
);


reg signal_old; 

always @(posedge i_clk) begin
    if (!i_reset) begin
        signal_old <= i_signal;
        o_nedge_edge <= 0;
    end else begin
        signal_old <= i_signal;
        o_nedge_edge <= (~i_signal) & signal_old;
    end
end

endmodule
module edge_detection(
    input i_clk,
    input i_reset,
    input i_signal,
    output reg o_post_edge,
    output reg o_nedge_edge
);


reg signal_new, signal_old; 

always @(posedge i_clk) begin
    if (!i_reset) begin
        signal_old <= i_signal;
        signal_new <= i_signal;
        o_post_edge <= 0;
        o_nedge_edge <= 0;
    end else begin
        signal_new <= i_signal;
        signal_old <= signal_new;
        o_post_edge <= signal_new & (~signal_old);
        o_nedge_edge <= (~signal_new) & signal_old;
    end
end

endmodule
module rec_cmd_nib#(
    parameter ADDR = 4'b0000 // Bit Pattern
)
(
    input i_clk,
    input i_wr_en,
    input [3:0] i_nib,
    output reg o_hold
);

wire addr_sig;
assign addr_sig = (ADDR == i_nib);

always @(posedge i_clk) begin
    if (!i_wr_en) begin
        o_hold <= 0;
    end else begin
        o_hold <= addr_sig;
    end
end

endmodule
module blink(
		input wire clk,
		input wire ILA_rst,
		output [24:0] ila_sample_dut,
		output wire led
	);


reg [24:0] counter;

	assign led = counter[24];
	assign ila_sample_dut = counter;

	always @(posedge clk)
	begin
		if (!ILA_rst) begin
			counter <= 0; //-1000; // 27'b010011111111111100000000000;
		end else begin
			counter <= counter + 1'b1;
		end
	end

	
endmodule
module CC_PLL #(
  parameter PLL_CFG = 96'b0,
  parameter REF_CLK = "", // e.g. "10.0"
  parameter OUT_CLK = "", // e.g. "50.0"
  parameter PERF_MD = "", // LOWPOWER, ECONOMY, SPEED
  parameter LOW_JITTER = 1,
  parameter CI_FILTER_CONST = 2,
  parameter CP_FILTER_CONST = 4
  )(
  input CLK_REF, CLK_FEEDBACK, USR_CLK_REF,
  input USR_LOCKED_STDY_RST, USR_SET_SEL,
  output USR_PLL_LOCKED_STDY, USR_PLL_LOCKED,
  output CLK270, CLK180, CLK90, CLK0, CLK_REF_OUT
  );

  //parameter clk_freq = 40000000; // 40 MHz clk 
  reg clk_out;
  always 
  begin  
    clk_out <= 1'b1;
    #25.5;// (1.0/40000000/2);
    clk_out <= 1'b0;
    #25.5;//(1.0/40000000/2);
  end
  assign CLK180 = clk_out;
  assign CLK0 = clk_out;
  endmodule
module CC_BUFG (
   input I,
   output O);
   assign O = I;
 endmodule
module CC_USR_RSTN (
  output reg USR_RSTN);
  initial
    begin
      USR_RSTN <= 0;
      #2000;
      USR_RSTN <= 1;
    end
endmodule
module SPI_master(
    input i_sclk,
    input i_reset,
    output o_ss,
    output o_mosi,
    input i_miso,
    input i_send,
    input[7:0] i_send_byte,
    input i_receive,
    output [7:0] o_receive_byte,
    output o_period,
    output o_cnt_end
);

    parameter [1:0] s_Idle_M = 0,						// Initialization states
                    s_Master_send = 1,
                    s_Master_receive = 2;
    reg [1:0] stCur_master_spi;
    reg [7:0] byte_send;
    reg [2:0] counter;
    reg [7:0] rec_byte;
    reg [7:0] receive_byte_r;
    wire counter_end;
    reg o_ss_r;
    wire counter_end_send;
    always @(posedge i_sclk)
    begin
        if (i_reset == 0) begin
            stCur_master_spi <= s_Idle_M;
            rec_byte <= 8'b00000000;
            byte_send <= 8'b00000000;
            o_ss_r <= 1'b1;
            receive_byte_r <= 0;
        end
        else begin
            case (stCur_master_spi)
                s_Idle_M : begin
                    if (i_send) begin
                        byte_send <= i_send_byte;
                        stCur_master_spi <= s_Master_send;
                        o_ss_r <= 1'b0;
                    end
                    else if (i_receive) begin
                        stCur_master_spi <= s_Master_receive;
                        rec_byte <= {rec_byte[6:0], i_miso};
                        receive_byte_r <= {rec_byte[6:0], i_miso};
                        o_ss_r <= 1'b0;
                    end
                    else if (!o_ss_r) begin
                        o_ss_r <= 1'b1;
                        rec_byte <= {rec_byte[6:0], i_miso};
                        receive_byte_r <= {rec_byte[6:0], i_miso};
                    end 
                end
                s_Master_send : begin
                    byte_send <= {byte_send[6:0], 1'b0};
                    if (counter_end_send) begin
                        stCur_master_spi <= s_Idle_M;
                    end
                end
                s_Master_receive : begin
                    rec_byte <= {rec_byte[6:0], i_miso};
                    if (counter_end) begin
                        stCur_master_spi <= s_Idle_M;
                    end
                end
            endcase
        end
    end

    always @(posedge i_sclk)
    begin
        if (!i_reset) begin
            counter <= 3'b000;
        end 
        else begin
            if (!o_ss_r) begin
                counter <= counter + 1;
            end
            else begin
                counter <= 0;
            end
        end
    end
    assign o_ss = o_ss_r;
    assign o_mosi = byte_send[7];
    assign counter_end = (counter == 3'b111);
    assign counter_end_send = (counter == 3'b110);
    assign o_cnt_end = (stCur_master_spi == s_Idle_M);
    assign o_period = (counter == 3'b001);
    assign o_receive_byte = receive_byte_r;
endmodule
module smp_to_byte#(
    parameter sample_width = 24
)(
    input i_clk_ILA,
    input i_read_active,
    input [(sample_width-1):0] i_ram_sample,
    input i_slave_end_byte_post_edge,
    output reg [3:0] o_send_nib,
    output reg o_rd
);


parameter packages_per_sample = ((sample_width-1)/4)+1;
parameter shift_cnt_width = $clog2(packages_per_sample);
parameter zero_padding_bits = (packages_per_sample*4) - sample_width;
reg [((packages_per_sample*4)-1):0] shift_reg;

wire init_reg;

reg [(shift_cnt_width-1):0] shift_counter;
reg rd;
// The data from the BRAM needs to be shifted
always @(posedge i_clk_ILA) begin
    if (init_reg | (!i_read_active)) begin               
        shift_reg <= {{zero_padding_bits{1'b0}}, i_ram_sample};
        rd <= 0;
    end
    else if (i_slave_end_byte_post_edge) begin
        shift_reg <= {4'b0000, shift_reg[((packages_per_sample*4)-1):4]};
    end
    else begin
        rd <= 1;
    end
end
reg signal_old;
always @(posedge i_clk_ILA) begin
    if (!i_read_active) begin
        signal_old <= rd;
        o_rd <= 0;
    end else begin
        signal_old <= rd;
        o_rd <= rd & (~signal_old);
    end
end


// shift counter 
always @(posedge i_clk_ILA) begin
    if (!i_read_active) begin
        shift_counter <= 0;
    end
    else if (i_slave_end_byte_post_edge) begin
        if (init_reg) begin
            shift_counter <= 0;
        end
        else begin
            shift_counter <= shift_counter + 1;
        end
    end
end

assign init_reg = (shift_counter == (packages_per_sample-1) & i_slave_end_byte_post_edge);
//always @(posedge i_clk_ILA) begin
//    if (!i_read_active) begin
//        rd <= 0;
//    end else begin
//        rd <= init_reg & i_read_active;
//    end
//end
//assign o_rd = rd;


always @(posedge i_clk_ILA) begin
    if (!i_read_active) begin
        o_send_nib <= 0;
    end else begin
        o_send_nib <= shift_reg[3:0];
    end
end


endmodule
module CC_PLL #(
	parameter REF_CLK = "", // e.g. "10.0"
	parameter OUT_CLK = "", // e.g. "50.0"
	parameter PERF_MD = "", // LOWPOWER, ECONOMY, SPEED
	parameter LOW_JITTER = 1,
	parameter CI_FILTER_CONST = 2,
	parameter CP_FILTER_CONST = 4
)(
	input  CLK_REF, CLK_FEEDBACK, USR_CLK_REF,
	input  USR_LOCKED_STDY_RST, USR_SET_SEL,
	output USR_PLL_LOCKED_STDY, USR_PLL_LOCKED,
	output CLK270, CLK180, CLK90, CLK0, CLK_REF_OUT
);

	reg r_user_pll_locked_stdy;
	reg r_user_pll_locked;
	reg r_clk270;
	reg r_clk180;
	reg r_clk90;
	reg r_clk0;
	reg r_clk_ref_out;

	assign USR_PLL_LOCKED_STDY = r_user_pll_locked_stdy;
	assign USR_PLL_LOCKED      = r_user_pll_locked;
	assign CLK270              = r_clk270;
	assign CLK180              = r_clk180;
	assign CLK90               = r_clk90;
	assign CLK0                = r_clk0;
	assign CLK_REF_OUT         = CLK_REF | USR_CLK_REF;

	integer clkcnt = 0;
	initial begin
		r_user_pll_locked_stdy = 1'b0;
		r_user_pll_locked = 1'b0;
		r_clk270 = 1'b0;
		r_clk180 = 1'b0;
		r_clk90 = 1'b0;
		r_clk0 = 1'b0;
	end

	always @(CLK_REF or USR_CLK_REF)
	begin
		if ((clkcnt > 1) && (clkcnt % 2 == 0)) begin
			r_clk0 = ~r_clk0;
		end
		if ((clkcnt > 2) && ((clkcnt-1) % 2 == 0)) begin
			r_clk90 = ~r_clk90;
		end
		if ((clkcnt > 3) && ((clkcnt-2) % 2 == 0)) begin
			r_clk180 = ~r_clk180;
		end
		if ((clkcnt > 4) && ((clkcnt-3) % 2 == 0)) begin
			r_clk270 = ~r_clk270;
		end
		clkcnt = clkcnt + 1;
	end
endmodule
module tb;

	reg clk;
	reg rst;
	wire led;

	initial begin
`ifdef CCSDF
		$sdf_annotate("blink_00.sdf", dut);
`endif
		$dumpfile("sim/blink_tb.vcd");
		$dumpvars(0, tb);
		clk = 0;
		rst = 0;
	end

	always clk = #1 ~clk;

	blink dut (
		.clk(clk),
		.rst(rst),
		.led(led)
	);

	initial begin
		#200;
		rst = 1;
		#500;
		$finish;
	end

endmodule
module blink(
		input wire clk,
		//input wire ILA_rst,
		//output [4:0] ila_sample_dut,
		output wire led
	);

	wire rst;
	CC_USR_RSTN usr_rstn_inst (
   	.USR_RSTN(rst) // reset signal to CPE array
);

reg [24:0] counter;
 wire clk270, clk180, clk90, clk0, usr_ref_out;
 wire usr_pll_lock_stdy, usr_pll_lock;

	CC_PLL #(
		.REF_CLK("10.0"),    // reference input in MHz
		.OUT_CLK("20"),   // pll output frequency in MHz
		.PERF_MD("SPEED"), // LOWPOWER, ECONOMY, SPEED
		.LOW_JITTER(1),      // 0: disable, 1: enable low jitter mode
		.CI_FILTER_CONST(2), // optional CI filter constant
		.CP_FILTER_CONST(4)  // optional CP filter constant
	) pll_inst (
		.CLK_REF(clk), .CLK_FEEDBACK(1'b0), .USR_CLK_REF(1'b0),
		.USR_LOCKED_STDY_RST(1'b0), .USR_PLL_LOCKED_STDY(usr_pll_lock_stdy), .USR_PLL_LOCKED(usr_pll_lock),
		.CLK270(clk270), .CLK180(clk180), .CLK90(clk90), .CLK0(clk0), .CLK_REF_OUT(usr_ref_out)
	);

	assign led = counter[24];

	always @(posedge clk0)
	begin
		if (!rst) begin
			counter <= 0; //-1000; // 27'b010011111111111100000000000;
		end else begin
			counter <= counter + 1'b1;
		end
	end

	
endmodule
module forward_selection_clk
  (input  wire [7:0]  cfg_forward_clk_i,
   
   input  wire        local_1_i,
   input  wire        local_2_i,
   input  wire        local_ab1_i,
   input  wire        local_ab2_i,
   
   input  wire        global_x1_i,
   input  wire        global_x2_i,
   input  wire        global_y1_i,
   input  wire        global_y2_i,
                    
   input  wire        forward_clk_up_i,
   input  wire        forward_clk_low_i,
                    
   output wire        forward_clk_up_o,
   output wire        forward_clk_low_o,
                    
   output wire        ram_clk_o
   );

   wire               local0_clk, local1_clk, local2_clk, local_clk;
   wire               global0_clk, global1_clk, global2_clk, global_clk;
   wire               ram0_clk, ram1_clk; 


   // 1st stage of clk-tree (1st and 2nd stage done in signal_inversion)
   common_clkmux
     clkmux_local0(.I0(local_1_i),
                   .I1(local_2_i),
                   .S (cfg_forward_clk_i[2]),
                   .Z (local0_clk));
   common_clkmux
     clkmux_local1(.I0(local_ab1_i),
                   .I1(local_ab2_i),
                   .S (cfg_forward_clk_i[2]),
                   .Z (local1_clk));
   
   common_clkmux
     clkmux_global0(.I0(global_y1_i),
                    .I1(global_y2_i),
                    .S (cfg_forward_clk_i[4]),
                    .Z (global0_clk));
   common_clkmux
     clkmux_global1(.I0(global_x1_i),
                    .I1(global_x2_i),
                    .S (cfg_forward_clk_i[4]),
                    .Z (global1_clk));
   
   // 2nd stage of clk-tree
   common_clkmux
     clkmux_local2(.I0(local0_clk),
                   .I1(local1_clk),
                   .S (cfg_forward_clk_i[3]),
                   .Z (local2_clk));
   common_clkmux
     clkmux_global2(.I0(global0_clk),
                    .I1(global1_clk),
                    .S (cfg_forward_clk_i[5]),
                    .Z (global2_clk));
   

   // 3rd stage of clk-tree
   // forwarded clocks have already 3 stages, so we require here a buffer
   common_clkbuf
     clkbuf_local(.I(local2_clk),
                  .Z(local_clk));
   common_clkbuf
     clkbuf_global(.I(global2_clk),
                   .Z(global_clk));
   common_clkmux
     clkmux_forwup(.I0(local2_clk),
                   .I1(forward_clk_low_i),
                   .S (cfg_forward_clk_i[7]),
                   .Z (forward_clk_up_o));
   common_clkmux
     clkmux_forwlow(.I0(local2_clk),
                    .I1(forward_clk_up_i),
                    .S (cfg_forward_clk_i[6]),
                    .Z (forward_clk_low_o));
   
   // 4th stage of clk-tree
   common_clkmux
     clkmux_ram0(.I0(local_clk),
                 .I1(forward_clk_low_i),
                 .S (cfg_forward_clk_i[0]),
                 .Z (ram0_clk));
   common_clkmux
     clkmux_ram1(.I0(forward_clk_up_i),
                 .I1(global_clk),
                 .S (cfg_forward_clk_i[0]),
                 .Z (ram1_clk));


   // 5th stage of clk-tree
   common_clkmux
     clkmux_ram2(.I0(ram0_clk),
                 .I1(ram1_clk),
                 .S (cfg_forward_clk_i[1]),
                 .Z (ram_clk_o));
   
endmodule
module forward_selection_ctrl
  (input  wire [7:0]  cfg_forward_ctrl_i,
   
   input  wire        local_1_i,
   input  wire        local_2_i,
   input  wire        local_ab1_i,
   input  wire        local_ab2_i,
   
   input  wire        global_x1_i,
   input  wire        global_x2_i,
   input  wire        global_y1_i,
   input  wire        global_y2_i,
                    
   input  wire        forward_sig_up_i,
   input  wire        forward_sig_low_i,
                    
   output wire        forward_sig_up_o,
   output wire        forward_sig_low_o,
                    
   output wire        ram_sig_o
   );

   wire               local_sel, global_sel;

   assign local_sel = (cfg_forward_ctrl_i[3:2]==2'b00) ? local_1_i : 
                      (cfg_forward_ctrl_i[3:2]==2'b01) ? local_2_i : 
                      (cfg_forward_ctrl_i[3:2]==2'b10) ? local_ab1_i : 
                                                         local_ab2_i; 

   assign global_sel = (cfg_forward_ctrl_i[5:4]==2'b00) ? global_y1_i : 
                       (cfg_forward_ctrl_i[5:4]==2'b01) ? global_y2_i : 
                       (cfg_forward_ctrl_i[5:4]==2'b10) ? global_x1_i : 
                                                          global_x2_i; 

   assign ram_sig_o = (cfg_forward_ctrl_i[1:0]==2'b00) ? local_sel : 
                      (cfg_forward_ctrl_i[1:0]==2'b01) ? forward_sig_low_i : 
                      (cfg_forward_ctrl_i[1:0]==2'b10) ? forward_sig_up_i : 
                                                         global_sel;

   assign forward_sig_up_o  = (cfg_forward_ctrl_i[7]==1'b0) ? local_sel : 
                                                              forward_sig_low_i;

   assign forward_sig_low_o = (cfg_forward_ctrl_i[6]==1'b0) ? local_sel : 
                                                              forward_sig_up_i;
   
endmodule
module ecc_decoding_mux
  #(parameter  CONFIG_TDP_NONSPLIT = 3'd0,
    parameter  CONFIG_TDP_SPLIT    = 3'd1,
    parameter  CONFIG_SDP_NONSPLIT = 3'd2,
    parameter  CONFIG_SDP_SPLIT    = 3'd3,
    parameter  CONFIG_FIFO_ASYNC   = 3'd7,
    parameter  CONFIG_FIFO_SYNC    = 3'd6,
    parameter  CONFIG_CASCADE_UP   = 3'd5,
    parameter  CONFIG_CASCADE_LOW  = 3'd4
    )
   (input  wire [2:0]  cfg_sram_mode_i,
    input  wire [1:0]  cfg_ecc_enable_i,
   
    input  wire [19:0] a0_data_i,
    input  wire [19:0] a1_data_i,
    input  wire [19:0] b0_data_i,
    input  wire [19:0] b1_data_i,
   
    input  wire [19:0] a0_data_ecc_i,
    input  wire [19:0] a1_data_ecc_i,
    input  wire [19:0] b0_data_ecc_i,
    input  wire [19:0] b1_data_ecc_i,
    
    output wire [19:0] a0_data_o,
    output wire [19:0] a1_data_o,
    output wire [19:0] b0_data_o,
    output wire [19:0] b1_data_o
    );

   
   assign a0_data_o    = (cfg_ecc_enable_i[0]==1'b1) ? a0_data_ecc_i : a0_data_i;
   assign a1_data_o    = ((cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_TDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[1]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_SPLIT)) ? a1_data_ecc_i : a1_data_i;
   assign b0_data_o    = (cfg_ecc_enable_i[0]==1'b1) ? b0_data_ecc_i : b0_data_i;
   assign b1_data_o    = ((cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_TDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[1]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_SPLIT)) ? b1_data_ecc_i : b1_data_i;

   
endmodule // ecc_decoding_mux
module ecc_encode(data_in,
                  code_out);

parameter P_DATAWIDTH=32;
parameter P_CODEWIDTH=39;  //  CC changed 38 to 39
parameter P_PARITYWIDTH=7; //  CC changed 6 to 7


input   [P_DATAWIDTH-1:0] data_in;
output  [P_CODEWIDTH-1:0] code_out;

reg [P_CODEWIDTH-1:0] c;
 
integer i,n;

//computation of the Hamming-Code (39,32) with 7 parity bits SECDED
always @(*) begin
    n=0;
    for(i=1;i<P_CODEWIDTH;i=i+1) begin  //  CC changed i<=P_CODEWIDTH to i<P_CODEWIDTH
        if(i!=1 && i!=2 && i!=4 && i!=8 && i!=16 && i!=32) begin
            c[i-1]=data_in[n];
            n=n+1;
        end
        else begin
            c[i-1]=1'b0;
        end
    end 
          
    c[0]=c[2]^c[4]^c[6]^c[8]^c[10]^c[12]^c[14]^c[16]^c[18]^c[20]^c[22]^c[24]^c[26]^c[28]^c[30]^c[32]^c[34]^c[36];
    c[1]=c[2]^c[5]^c[6]^c[9]^c[10]^c[13]^c[14]^c[17]^c[18]^c[21]^c[22]^c[25]^c[26]^c[29]^c[30]^c[33]^c[34]^c[37];
    c[3]=c[4]^c[5]^c[6]^c[11]^c[12]^c[13]^c[14]^c[19]^c[20]^c[21]^c[22]^c[27]^c[28]^c[29]^c[30] ^c[35]^c[36]^c[37];
    c[7]=c[8]^c[9]^c[10]^c[11]^c[12]^c[13]^c[14] ^c[23]^c[24]^c[25]^c[26]^c[27]^c[28]^c[29]^c[30];
    c[15]=c[16]^c[17]^c[18]^c[19]^c[20]^c[21]^c[22]^c[23]^c[24]^c[25]^c[26]^c[27]^c[28]^c[29]^c[30];
    c[31]=c[32]^c[33]^c[34]^c[35]^c[36]^c[37];
            
    c[38]=1'b0; //  CC overall parity for double error detection 
	 
    for(i=1;i<P_CODEWIDTH;i=i+1) begin
        c[38]= c[38]^c[i-1];
    end
     
end //always

assign code_out=c;

endmodule
module RM_GF28SLP_2P_core_1cr (//inputs port
                               A_CLK_I,
                               A_CS_I,
                               A_ADDR_I,
                               A_DW_I,
                               A_BM_I,
                               A_WE_I,
                               A_RE_I,

                               //output port a
                               A_DR_O,

                               //inputs port b
                               B_CLK_I,
                               B_CS_I,
                               B_ADDR_I,
                               B_DW_I,
                               B_BM_I,
                               B_WE_I,
                               B_RE_I,

                               //output port b
                               B_DR_O,

                               A_DLYL_I,
                               A_DLYH_I,
                               A_DLYCLK_I,
                               B_DLYL_I,
                               B_DLYH_I,
                               B_DLYCLK_I,
                               notifier);



   parameter P_DATA_WIDTH =  20;
   parameter P_ADDR_WIDTH =  9;
   parameter P_COUNT =      2**P_ADDR_WIDTH;


   //inputs port a
   input A_CLK_I;
   input A_CS_I;
   input [P_ADDR_WIDTH-1:0] A_ADDR_I;
   input [P_DATA_WIDTH-1:0] A_DW_I;
   input [P_DATA_WIDTH-1:0] A_BM_I;
   input                    A_WE_I;
   input                    A_RE_I;

   //output port a
   output [P_DATA_WIDTH-1:0] A_DR_O;

   //inputs port b
   input                     B_CLK_I;
   input                     B_CS_I;
   input [P_ADDR_WIDTH-1:0]  B_ADDR_I;
   input [P_DATA_WIDTH-1:0]  B_DW_I;
   input [P_DATA_WIDTH-1:0]  B_BM_I;
   input                     B_WE_I;
   input                     B_RE_I;

   //output port b
   output [P_DATA_WIDTH-1:0] B_DR_O;


   input wire [1:0]          A_DLYL_I;
   input wire [1:0]          A_DLYH_I;
   input wire [1:0]          A_DLYCLK_I;

   input wire [1:0]          B_DLYL_I;
   input wire [1:0]          B_DLYH_I;
   input wire [1:0]          B_DLYCLK_I;

   input                     notifier;



    SRAM_2P_behavioral
      #(.P_DATA_WIDTH(P_DATA_WIDTH),
        .P_ADDR_WIDTH(P_ADDR_WIDTH)/*,
        .COLLISION_TIME_DIFFERENCE(1.0) //in ns
                                    */
        )
    SRAM_2P_behavioral_i
      //inputs port A
      (.A_CLK(A_CLK_I),
       .A_MEN(A_CS_I),
       .A_ADDR(A_ADDR_I),
       .A_DIN(A_DW_I),
       .A_BM(A_BM_I),
       .A_WEN(A_WE_I),
       .A_REN(A_RE_I),

       //output port A
       .A_DOUT(A_DR_O),

       //inputs port B
       .B_CLK(B_CLK_I),
       .B_MEN(B_CS_I),
       .B_ADDR(B_ADDR_I),
       .B_DIN(B_DW_I),
       .B_BM(B_BM_I),
       .B_WEN(B_WE_I),
       .B_REN(B_RE_I),

       //output port B
       .B_DOUT(B_DR_O),

       .A_DLY(A_DLYL_I[0]),
       .B_DLY(A_DLYH_I[0])
       );

endmodule
module common_clkbuf (  I,
                        Z
                        );
   
   // synopsys translate_off
   parameter C_DELAY = 0.0;
   // synopsys translate_on
   
   input  I;

   output Z;

   wire   Z;
   
  // synopsys translate_off
  generate
	if (C_DELAY > 0) begin: DELAY
	  assign #C_DELAY Z = I;
	end
	else begin: NO_DELAY
  // synopsys translate_on
	  assign Z = I;
  // synopsys translate_off
    end
  endgenerate
  // synopsys translate_on

endmodule
module ecc_decode(code_in,
                  data_out,
				  single_error,
				  double_error);  //  CC double_error flag

parameter P_DATAWIDTH=32;
parameter P_CODEWIDTH=39;   //  CC changed 38 to 39
parameter P_CHECKBITS_COUNT=7;  //  CC changed 6 to 7


input       [P_CODEWIDTH-1:0] code_in;
output reg  [P_DATAWIDTH-1:0] data_out;
output reg 					  single_error;
output reg 					  double_error;  //  CC double_error

reg [P_CODEWIDTH-1:0] c;
reg [P_CODEWIDTH:0] d;    // data one bit shifted  changed by CCAG
reg [P_CHECKBITS_COUNT-2:0] fail_location; // CC changed P_CHECKBITS_COUNT-1 to P_CHECKBITS_COUNT-2


integer i,n;


reg [P_CHECKBITS_COUNT-1:0]  p;
reg  fail_bit;


always @(*) begin
    fail_location=0;
    c=code_in;
	d={code_in,1'b0};      // changed by CCAG
    single_error=1'b0;
    double_error=1'b0;  // CC

    p[0]=c[2]^c[4]^c[6]^c[8]^c[10]^c[12]^c[14]^c[16]^c[18]^c[20]^c[22]^c[24]^c[26]^c[28]^c[30]^c[32]^c[34]^c[36];
    p[1]=c[2]^c[5]^c[6]^c[9]^c[10]^c[13]^c[14]^c[17]^c[18]^c[21]^c[22]^c[25]^c[26]^c[29]^c[30]^c[33]^c[34]^c[37];
    p[2]=c[4]^c[5]^c[6]^c[11]^c[12]^c[13]^c[14]^c[19]^c[20]^c[21]^c[22]^c[27]^c[28]^c[29]^c[30] ^c[35]^c[36]^c[37];
    p[3]=c[8]^c[9]^c[10]^c[11]^c[12]^c[13]^c[14] ^c[23]^c[24]^c[25]^c[26]^c[27]^c[28]^c[29]^c[30];
    p[4]=c[16]^c[17]^c[18]^c[19]^c[20]^c[21]^c[22]^c[23]^c[24]^c[25]^c[26]^c[27]^c[28]^c[29]^c[30];
    p[5]=c[32]^c[33]^c[34]^c[35]^c[36]^c[37];

    p[6]=1'b0;  // CC overall parity for DED

    for(i=1;i<P_CODEWIDTH;i=i+1) begin
        p[6] = p[6]^c[i-1];
    end


    if(p[0]!=c[0]) fail_location[0]=1'b1;
    if(p[1]!=c[1]) fail_location[1]=1'b1;
    if(p[2]!=c[3]) fail_location[2]=1'b1;
    if(p[3]!=c[7]) fail_location[3]=1'b1;
    if(p[4]!=c[15])fail_location[4]=1'b1;
    if(p[5]!=c[31])fail_location[5]=1'b1;

    //  CC detection and correction logic
    if(fail_location==0 && p[6]!=c[38]) begin
        single_error=1'b1;
        double_error=1'b1;	//  unknown condition three or more errors
    end

    if(fail_location!=0) begin
        if (p[6]!=c[38]) begin
            single_error=1'b1;
        end
        else begin
            double_error=1'b1; // uncorrectable even-number of errors
        end
    end


//    if(fail_location!=0) begin         // changed by CCAG
        fail_bit=d[fail_location];
        d[fail_location]=~fail_bit;      // changed by CCAG
//    end                                // changed by CCAG


    n=0;
    for(i=1;i<P_CODEWIDTH;i=i+1) begin  //  CC changed i<=P_CODEWIDTH to i<P_CODEWIDTH
        if(i!=1 && i!=2 && i!=4 && i!=8 && i!=16 && i!=32) begin
            data_out[n]=d[i];      // changed by CCAG
            n=n+1;
        end
    end

end //always

endmodule
module bit_deselection_mux
  #(parameter CONFIG_1BIT  = 3'd1, //non-split-->32k x 1 bit; split-->16K x 1 bit
    parameter CONFIG_2BIT  = 3'd2, //non-split-->16k x 2 bit; split-->8K x 2 bit
    parameter CONFIG_5BIT  = 3'd3, //non-split-->8k  x 5 bit; split-->4K x 5 bit
    parameter CONFIG_10BIT = 3'd4, //non-split-->4k  x 10 bit; split-->2K x 10 bit
    parameter CONFIG_20BIT = 3'd5, //non-split-->2k  x 20 bit; split-->1K x 20 bit
    parameter CONFIG_40BIT = 3'd6, //non-split-->1K  x 40 bit; split (SPR)-->512 x 40 bit
    parameter CONFIG_80BIT = 3'd7  //non-split(SPR)-->512 x 80 bit; split-->NA
    )
  (// signals from mode_selection
   input  wire [2:0]  output_config_i,
   input  wire [19:0] rddata_i,
   input  wire [19:0] aligned_rddata_i,
   output wire [19:0] rddata_o
   );
       

   assign rddata_o = (output_config_i==CONFIG_20BIT ||
                      output_config_i==CONFIG_40BIT ||
                      output_config_i==CONFIG_80BIT) ? rddata_i : aligned_rddata_i;

endmodule // bit_deselection_mux
module data_forwarding
   (
   input  wire        clk_i,
   input  wire        bist_enable_i,
   input  wire        y_select_i,
   input  wire [39:0] rddata_i,
   input  wire [39:0] bist_rddata_i,
   output wire [39:0] bist_rddata_o
    );


   reg 		      use_own_data;

   always @(posedge clk_i) begin
      use_own_data <= (bist_enable_i == 1'b1) && y_select_i;
   end
   
   assign bist_rddata_o = (use_own_data)? rddata_i : bist_rddata_i;

endmodule //data_forwarding
module common_and2 (   A1,
					   A2,
					   Z
					   );
   
   // synopsys translate_off
   parameter C_DELAY = 0.0;
   // synopsys translate_on

  input A1;
  input A2;
  output Z;
  
  
  // synopsys translate_off
  generate
	if (C_DELAY > 0) begin: DELAY
	  assign #C_DELAY Z = A1&A2;
	end
	else begin: NO_DELAY
  // synopsys translate_on
	  assign Z = A1&A2;
  // synopsys translate_off
    end
  endgenerate
  // synopsys translate_on
	  
endmodule
module ecc_encoding_mux
  #(parameter  CONFIG_TDP_NONSPLIT = 3'd0,
    parameter  CONFIG_TDP_SPLIT    = 3'd1,
    parameter  CONFIG_SDP_NONSPLIT = 3'd2,
    parameter  CONFIG_SDP_SPLIT    = 3'd3,
    parameter  CONFIG_FIFO_ASYNC   = 3'd7,
    parameter  CONFIG_FIFO_SYNC    = 3'd6,
    parameter  CONFIG_CASCADE_UP   = 3'd5,
    parameter  CONFIG_CASCADE_LOW  = 3'd4
    )
   (input  wire [2:0]  cfg_sram_mode_i,
    input  wire [1:0]  cfg_ecc_enable_i,
   
    input  wire [19:0] a0_data_i,
    input  wire [19:0] a1_data_i,
    input  wire [19:0] b0_data_i,
    input  wire [19:0] b1_data_i,
    input  wire [19:0] a0_bitmask_i,
    input  wire [19:0] a1_bitmask_i,
    input  wire [19:0] b0_bitmask_i,
    input  wire [19:0] b1_bitmask_i,
   
    input  wire [19:0] a0_data_ecc_i,
    input  wire [19:0] a1_data_ecc_i,
    input  wire [19:0] b0_data_ecc_i,
    input  wire [19:0] b1_data_ecc_i,   
    
    output wire [19:0] a0_data_o,
    output wire [19:0] a1_data_o,
    output wire [19:0] b0_data_o,
    output wire [19:0] b1_data_o,
    output wire [19:0] a0_bitmask_o,
    output wire [19:0] a1_bitmask_o,
    output wire [19:0] b0_bitmask_o,
    output wire [19:0] b1_bitmask_o
    );

   assign a0_data_o    = (cfg_ecc_enable_i[0]==1'b1) ? a0_data_ecc_i : a0_data_i;
   assign a0_bitmask_o = (cfg_ecc_enable_i[0]==1'b1) ? {20'hfffff}   : a0_bitmask_i;
   
   assign a1_data_o    = ((cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_TDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[1]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_SPLIT)) ? a1_data_ecc_i : a1_data_i;
   assign a1_bitmask_o = ((cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_TDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[1]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_SPLIT)) ? {20'hfffff}   : a1_bitmask_i;
   
   assign b0_data_o    = (cfg_ecc_enable_i[0]==1'b1) ? b0_data_ecc_i : b0_data_i;
   assign b0_bitmask_o = (cfg_ecc_enable_i[0]==1'b1) ? {20'hfffff}   : b0_bitmask_i;
   
   assign b1_data_o    = ((cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_TDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[1]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_SPLIT)) ? b1_data_ecc_i : b1_data_i;
   assign b1_bitmask_o = ((cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_TDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[0]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_NONSPLIT) ||
                          (cfg_ecc_enable_i[1]==1'b1 && cfg_sram_mode_i==CONFIG_SDP_SPLIT)) ? {20'hfffff}   : b1_bitmask_i;
   
endmodule // ecc_encoding_mux
module common_clkmux (
	I0,
	I1,
	S,
	Z
	);

	// synopsys translate_off
	parameter C_DELAY = 0.0;
	// synopsys translate_on

	input I0;
	input I1;
	input S;

	output Z;

	// synopsys translate_off
	generate
	if (C_DELAY > 0) begin: DELAY
		assign #C_DELAY Z = S ? I1 : I0;
	end
	else begin: NO_DELAY
		// synopsys translate_on
		assign Z = S ? I1 : I0;
		// synopsys translate_off
	end
	endgenerate
	// synopsys translate_on
endmodule
module common_clkinv (  I,
	ZN
	);

	// synopsys translate_off
	parameter C_DELAY = 0.0;
	// synopsys translate_on

	input  I;

	output ZN;

	wire   ZN;

	// synopsys translate_off
	generate
	if (C_DELAY > 0) begin: DELAY
		assign #C_DELAY ZN = ~I;
	end
	else begin: NO_DELAY
		// synopsys translate_on
		assign ZN = ~I;
		// synopsys translate_off
	end
	endgenerate
	// synopsys translate_on
endmodule
module forward_selection_addr
  (input  wire [7:0]  cfg_forward_addr_i,
   
   input  wire [15:0] x0_addr1_local_i,
   input  wire [15:0] x0_addr2_local_i,
   input  wire [15:0] x1_addr1_local_i,
   input  wire [15:0] x1_addr2_local_i,
   input  wire [15:0] forward_addr_up_i,
   input  wire [15:0] forward_addr_low_i,
   
   output wire [15:0] forward_addr_up_o,
   output wire [15:0] forward_addr_low_o,
   
   output wire [15:0] x0_addr_o,
   output wire [15:0] x1_addr_o
   );

   wire [15:0] x0_addr_local;
   wire [15:0] x1_addr_local;
                      
   assign x0_addr_local = (cfg_forward_addr_i[6]==1'b0) ? x0_addr1_local_i : x0_addr2_local_i;
   assign x1_addr_local = (cfg_forward_addr_i[7]==1'b0) ? x1_addr1_local_i : x1_addr2_local_i;


   assign x0_addr_o = (cfg_forward_addr_i[1:0]==2'b00) ? x0_addr_local : 
                      (cfg_forward_addr_i[1:0]==2'b01) ? x1_addr_local : 
                      (cfg_forward_addr_i[1:0]==2'b10) ? forward_addr_low_i : 
                                                         forward_addr_up_i;

   assign x1_addr_o = (cfg_forward_addr_i[3:2]==2'b00) ? x1_addr_local : 
                      (cfg_forward_addr_i[3:2]==2'b01) ? x0_addr_local : 
                      (cfg_forward_addr_i[3:2]==2'b10) ? forward_addr_low_i : 
                                                         forward_addr_up_i;

   assign forward_addr_up_o  = (cfg_forward_addr_i[5]==1'b0) ? x0_addr_local : 
                                                               forward_addr_low_i;

   assign forward_addr_low_o = (cfg_forward_addr_i[4]==1'b0) ? x0_addr_local : 
                                                               forward_addr_up_i;
   
endmodule
module common_reset_sync (
               clk_i,
               reset_q_i,
               scan_mode_i,
               sync_reset_q_o
               );

   input  clk_i;
   input  reset_q_i;
   input  scan_mode_i;

   output sync_reset_q_o;

   wire   sync_reset_q_o;
`ifdef FPGA_IMPL
   (* INIT = 1, SHREG_EXTRACT = "NO", RLOC = "X0Y0" *)
`endif
   reg    sync_reset_q_syn0;
`ifdef FPGA_IMPL
   (* INIT = 1, SHREG_EXTRACT = "NO", RLOC = "X0Y0" *)
`endif
   reg    sync_reset_q_syn1;

   always@(posedge clk_i or negedge reset_q_i)
   begin
      if(reset_q_i == 1'b0)
      begin
         sync_reset_q_syn0 <= 1'b0;
         sync_reset_q_syn1 <= 1'b0;
      end
      else
      begin
         sync_reset_q_syn1 <= sync_reset_q_syn0;
         sync_reset_q_syn0 <= 1'b1;
      end
   end

   assign sync_reset_q_o = (scan_mode_i) ? reset_q_i : sync_reset_q_syn1;

endmodule
module ecc_testmodul(
                     set_fail,
                     data_in_i,
                     fail_location_0,
                     fail_location_1,
                     fail_location_2,
                     data_out_o,
					 single_error,
                     double_error
					 );


input [2:0]    set_fail;
input [31:0]   data_in_i;
input [5:0]    fail_location_0;
input [5:0]    fail_location_1;
input [5:0]    fail_location_2;
output [31:0]  data_out_o;
output         single_error;
output         double_error;




reg [38:0]   code_fail;
reg [38:0]   code_reg;

wire [38:0]  code_out_encoder;


ecc_encode encoder(.data_in(data_in_i),
                   .code_out(code_out_encoder));

ecc_decode decoder(.code_in(code_fail),
                   .data_out(data_out_o),
                   .single_error(single_error),
				   .double_error(double_error)
				   );

always @(*)
	begin
    	code_fail=code_out_encoder;
	  	
        if(set_fail[0]==1'b1)
	    	begin
	       		code_fail[fail_location_0]=!code_fail[fail_location_0];
	    	end
            
        if(set_fail[1]==1'b1)
	    	begin
	       		code_fail[fail_location_1]=!code_fail[fail_location_1];
	    	end
            
        if(set_fail[2]==1'b1)
	    	begin
	       		code_fail[fail_location_2]=!code_fail[fail_location_2];
	    	end    
            
  	end




endmodule
module forward_selection_datbm
  (input  wire        cfg_datbm_sel_i,
   input  wire [1:0]  cfg_cascade_enable_i,
   
   input  wire [19:0] data_i,
   input  wire [19:0] bitmask_i,
   
   output wire [19:0] data_o,
   output wire [19:0] bitmask_o,

   input  wire        forward_cascade_data_i,
   output wire        forward_cascade_data_o, 
   input  wire        forward_cascade_bitmask_i,
   output wire        forward_cascade_bitmask_o    
   );

   wire [19:0]        data;
   wire [19:0]        bitmask;
   genvar             geni;
   generate
      for(geni=0;geni<10;geni=geni+1) begin: datbm_flip
         assign bitmask[2*geni+0] = (cfg_datbm_sel_i==1'b1) ? bitmask_i[2*geni+0] : bitmask_i[2*geni+0];
         assign bitmask[2*geni+1] = (cfg_datbm_sel_i==1'b1) ? data_i[2*geni+0]    : bitmask_i[2*geni+1];
         assign data[2*geni+0]    = (cfg_datbm_sel_i==1'b1) ? bitmask_i[2*geni+1] : data_i[2*geni+0];
         assign data[2*geni+1]    = (cfg_datbm_sel_i==1'b1) ? data_i[2*geni+1]    : data_i[2*geni+1];
      end
   endgenerate

   assign bitmask_o = (cfg_cascade_enable_i[0]==1'b1) ? {19'd0,forward_cascade_bitmask_i} : // lower part of cascaded memory
                      bitmask; // upper pat of cascaded memory or no cascade
   assign data_o    = (cfg_cascade_enable_i[0]==1'b1) ? {19'd0,forward_cascade_data_i} : // lower part of cascaded memory
                      data; // upper pat of cascaded memory or no cascade
   assign forward_cascade_data_o    = (cfg_cascade_enable_i[1]==1'b1) ? data[0]    : 1'b0;
   assign forward_cascade_bitmask_o = (cfg_cascade_enable_i[1]==1'b1) ? bitmask[0] : 1'b0;
   
endmodule // forward_selection_datbm
module bit_selection_mux
  #(parameter CONFIG_1BIT  = 3'd1, //non-split-->32k x 1 bit; split-->16K x 1 bit
    parameter CONFIG_2BIT  = 3'd2, //non-split-->16k x 2 bit; split-->8K x 2 bit
    parameter CONFIG_5BIT  = 3'd3, //non-split-->8k  x 5 bit; split-->4K x 5 bit
    parameter CONFIG_10BIT = 3'd4, //non-split-->4k  x 10 bit; split-->2K x 10 bit
    parameter CONFIG_20BIT = 3'd5, //non-split-->2k  x 20 bit; split-->1K x 20 bit
    parameter CONFIG_40BIT = 3'd6, //non-split-->1K  x 40 bit; split (SPR)-->512 x 40 bit
    parameter CONFIG_80BIT = 3'd7  //non-split(SPR)-->512 x 80 bit; split-->NA
    )
  (// signals from mode_selection
   input  wire        bist_active_i,
   input  wire [2:0]  input_config_i,
   input  wire [19:0] wrdata_i,
   input  wire [19:0] aligned_wrdata_i,
   output wire [19:0] wrdata_o,
   input  wire [19:0] bitmask_i,
   input  wire [19:0] aligned_bitmask_i,
   output wire [19:0] bitmask_o
   );
       

   wire 	      mux_sel;
   assign mux_sel = (input_config_i==CONFIG_20BIT ||
                     input_config_i==CONFIG_40BIT ||
                     input_config_i==CONFIG_80BIT) && (bist_active_i==1'b0);

   genvar 	      geni;
   generate
      for(geni=0;geni<20;geni=geni+1) begin: bistMUX
	 common_mux2 
	   i_common_mux2_data(
			    .I0(aligned_wrdata_i[geni]),
			    .I1(wrdata_i[geni]),
			    .S(mux_sel),
			    .Z(wrdata_o[geni])
			    );
	 common_mux2 
	   i_common_mux2_mask(
			    .I0(aligned_bitmask_i[geni]),
			    .I1(bitmask_i[geni]),
			    .S(mux_sel),
			    .Z(bitmask_o[geni])
			    );
      end
   endgenerate

   /*
   assign wrdata_o  = ((input_config_i==CONFIG_20BIT ||
                       input_config_i==CONFIG_40BIT ||
                       input_config_i==CONFIG_80BIT) && (bist_active_i==1'b0)) ? wrdata_i : aligned_wrdata_i;
   assign bitmask_o = ((input_config_i==CONFIG_20BIT ||
                       input_config_i==CONFIG_40BIT ||
                       input_config_i==CONFIG_80BIT) && (bist_active_i==1'b0)) ? bitmask_i : aligned_bitmask_i;
    */

endmodule // bit_selection_mux
module common_mux2 (
    	I0,
	I1,
	S,	
	Z
);

input I0;
input I1;
input S;	
output Z;

assign Z= S ? I1 : I0;

endmodule
module debounce(
	input clk,
	input in,
	output out
);

	wire slow_clk_en;
	wire Q1,Q2,Q2_bar,Q0;

	clock_enable u1(clk,slow_clk_en);
	my_dff_en d0(clk,slow_clk_en,in,Q0);
	my_dff_en d1(clk,slow_clk_en,Q0,Q1);
	my_dff_en d2(clk,slow_clk_en,Q1,Q2);
	
	assign Q2_bar = ~Q2;
	assign out = Q1 & Q2_bar;
endmodule
module clock_enable(
	input Clk_100M,
	output slow_clk_en
);
    reg [26:0]counter=0;
	
    always @(posedge Clk_100M)
    begin
       counter <= (counter>=24999) ? 0 : counter + 1;
    end

    assign slow_clk_en = (counter == 24999) ? 1'b1 : 1'b0;
endmodule
module my_dff_en(
	input DFF_CLOCK, 
	input clock_enable, 
	input D, 
	output reg Q=0
);

    always @ (posedge DFF_CLOCK) 
	begin
		if(clock_enable==1) 
			Q <= D;
    end
	
endmodule
module picosoc_regs (
	input clk, wen,
	input [5:0] waddr,
	input [5:0] raddr1,
	input [5:0] raddr2,
	input [31:0] wdata,
	output [31:0] rdata1,
	output [31:0] rdata2
);
	//reg [31:0] regs [0:31];
	(* ram_style = "distributed" *) reg [31:0] regs [0:31];

	always @(posedge clk)
		if (wen) regs[waddr[4:0]] <= wdata;

	assign rdata1 = regs[raddr1[4:0]];
	assign rdata2 = regs[raddr2[4:0]];
endmodule
module picosoc_mem #(
	parameter integer WORDS = 256
) (
	input clk,
	input [3:0] wen,
	input [21:0] addr,
	input [31:0] wdata,
	output reg [31:0] rdata
);
	//reg [31:0] mem [0:WORDS-1];
	(* ram_style = "distributed" *) reg [31:0] mem [0:WORDS-1];

	//initial $readmemh("firmware.hex", mem);
	always @(posedge clk) begin
		rdata <= mem[addr];
		if (wen[0]) mem[addr][ 7: 0] <= wdata[ 7: 0];
		if (wen[1]) mem[addr][15: 8] <= wdata[15: 8];
		if (wen[2]) mem[addr][23:16] <= wdata[23:16];
		if (wen[3]) mem[addr][31:24] <= wdata[31:24];
	end
endmodule
module simpleuart (
    input clk,
    input resetn,

    output ser_tx,
    input  ser_rx,

    input  [ 3:0] reg_div_we,
    input  [31:0] reg_div_di,
    output [31:0] reg_div_do,

    input         reg_dat_we,
    input         reg_dat_re,
    input  [31:0] reg_dat_di,
    output [31:0] reg_dat_do,
    output        reg_dat_wait
);
  reg [31:0] cfg_divider;

  reg [3:0] recv_state;
  reg [31:0] recv_divcnt;
  reg [7:0] recv_pattern;
  reg [7:0] recv_buf_data;
  reg recv_buf_valid;

  reg [9:0] send_pattern;
  reg [3:0] send_bitcnt;
  reg [31:0] send_divcnt;
  reg send_dummy;

  assign reg_div_do   = cfg_divider;

  assign reg_dat_wait = reg_dat_we && (send_bitcnt || send_dummy);
  assign reg_dat_do   = recv_buf_valid ? recv_buf_data : ~0;

  always @(posedge clk) begin
    if (!resetn) begin
      cfg_divider <= 1;
    end else begin
      if (reg_div_we[0]) cfg_divider[7:0] <= reg_div_di[7:0];
      if (reg_div_we[1]) cfg_divider[15:8] <= reg_div_di[15:8];
      if (reg_div_we[2]) cfg_divider[23:16] <= reg_div_di[23:16];
      if (reg_div_we[3]) cfg_divider[31:24] <= reg_div_di[31:24];
    end
  end

  always @(posedge clk) begin
    if (!resetn) begin
      recv_state <= 0;
      recv_divcnt <= 0;
      recv_pattern <= 0;
      recv_buf_data <= 0;
      recv_buf_valid <= 0;
    end else begin
      recv_divcnt <= recv_divcnt + 1;
      if (reg_dat_re) recv_buf_valid <= 0;
      case (recv_state)
        0: begin
          if (!ser_rx) recv_state <= 1;
          recv_divcnt <= 0;
        end
        1: begin
          if (2 * recv_divcnt > cfg_divider) begin
            recv_state  <= 2;
            recv_divcnt <= 0;
          end
        end
        10: begin
          if (recv_divcnt > cfg_divider) begin
            recv_buf_data <= recv_pattern;
            recv_buf_valid <= 1;
            recv_state <= 0;
          end
        end
        default: begin
          if (recv_divcnt > cfg_divider) begin
            recv_pattern <= {ser_rx, recv_pattern[7:1]};
            recv_state   <= recv_state + 1;
            recv_divcnt  <= 0;
          end
        end
      endcase
    end
  end

  assign ser_tx = send_pattern[0];

  always @(posedge clk) begin
    if (reg_div_we) send_dummy <= 1;
    send_divcnt <= send_divcnt + 1;
    if (!resetn) begin
      send_pattern <= ~0;
      send_bitcnt  <= 0;
      send_divcnt  <= 0;
      send_dummy   <= 1;
    end else begin
      if (send_dummy && !send_bitcnt) begin
        send_pattern <= ~0;
        send_bitcnt  <= 15;
        send_divcnt  <= 0;
        send_dummy   <= 0;
      end else if (reg_dat_we && !send_bitcnt) begin
        send_pattern <= {1'b1, reg_dat_di[7:0], 1'b0};
        send_bitcnt  <= 10;
        send_divcnt  <= 0;
      end else if (send_divcnt > cfg_divider && send_bitcnt) begin
        send_pattern <= {1'b1, send_pattern[9:1]};
        send_bitcnt  <= send_bitcnt - 1;
        send_divcnt  <= 0;
      end
    end
  end
endmodule
module picosoc_regs (
	input clk, wen,
	input [5:0] waddr,
	input [5:0] raddr1,
	input [5:0] raddr2,
	input [31:0] wdata,
	output [31:0] rdata1,
	output [31:0] rdata2
);
	(* ram_style = "distributed" *) reg [31:0] regs [0:31];

	always @(posedge clk)
		if (wen) regs[waddr[4:0]] <= wdata;

	assign rdata1 = regs[raddr1[4:0]];
	assign rdata2 = regs[raddr2[4:0]];
endmodule
module picosoc_mem #(
	parameter integer WORDS = 32
) (
	input clk,
	input [3:0] wen,
	input [21:0] addr,
	input [31:0] wdata,
	output reg [31:0] rdata
);
	(* ram_style = "block" *) reg [31:0] mem [0:WORDS-1];

	//initial $readmemh("firmware.hex", mem);
	always @(posedge clk) begin
		rdata <= mem[addr];
		if (wen[0]) mem[addr][ 7: 0] <= wdata[ 7: 0];
		if (wen[1]) mem[addr][15: 8] <= wdata[15: 8];
		if (wen[2]) mem[addr][23:16] <= wdata[23:16];
		if (wen[3]) mem[addr][31:24] <= wdata[31:24];
	end
endmodule