dakies/OSS_Verilog huggingface dataset:
module adc_clkgen_with_edgedetect(
    input wire ena_in,             // enable signal from the digital clock core. 0 halts the self-clocked loop
    input wire start_conv,         // triggers a conversion once with edge-detection
    input wire ndecision_finish,   // comparator signalizes finished conversion
    output wire clk_dig,           // digital clock
    output wire clk_comp,          // comparator clock
    input wire enable_dlycontrol,  // 0 = max delays, 1 = configurable delays
    input wire [4:0] dlycontrol1,  // delay 1 of 3 in loop
    input wire [4:0] dlycontrol2,  // delay 2 of 3 in loop
    input wire [4:0] dlycontrol3,  // delay 3 of 3 in loop
    input wire [5:0] dlycontrol4,  // edge detect pulse width
    input wire sample_p,           // sample signals for matrix using additional buffers 
    input wire sample_n,
    input wire nsample_p,
    input wire nsample_n,
    output wire sample_p_buf,
    output wire sample_n_buf,
    output wire nsample_p_buf,
    output wire nsample_n_buf
);
   wire _enable_loop_;
   wire _ena_in_buffered_;
   wire _start_conv_buffered_;
   wire _ndecision_finish_buffered_;
   wire _clk_dig_unbuffered_;
   wire _clk_comp_unbuffered_;

   //Input buffers
   sky130_fd_sc_hd__buf_1 inbuf_1 (.A(ena_in),.X(_ena_in_buffered_));
   sky130_fd_sc_hd__buf_1 inbuf_2 (.A(start_conv),.X(_start_conv_buffered_));
   sky130_fd_sc_hd__buf_1 inbuf_3 (.A(ndecision_finish),.X(_ndecision_finish_buffered_));
   
   //Output buffers
   sky130_fd_sc_hd__buf_4 outbuf_1 (.A(_clk_dig_unbuffered_),.X(clk_dig));
   sky130_fd_sc_hd__buf_4 outbuf_2 (.A(_clk_comp_unbuffered_),.X(clk_comp));

   // Output buffers for integrated sample-signal-buffeing
   sky130_fd_sc_hd__buf_4 outbuf_3 (.A(sample_p),.X(sample_p_buf));
   sky130_fd_sc_hd__buf_4 outbuf_4 (.A(sample_n),.X(sample_n_buf));
   sky130_fd_sc_hd__buf_4 outbuf_5 (.A(nsample_p),.X(nsample_p_buf));
   sky130_fd_sc_hd__buf_4 outbuf_6 (.A(nsample_n),.X(nsample_n_buf));
   

   //Circuit
   adc_edge_detect_circuit edgedetect (.start_conv(_start_conv_buffered_),
                                       .ena_in(_ena_in_buffered_),
                                       .ena_out(_enable_loop_),
                                       .enable_dlycontrol(enable_dlycontrol),
                                       .dlycontrol(dlycontrol4));

   adc_clk_generation clkgen (.ndecision_finish(_ndecision_finish_buffered_),
                              .enable_loop(_enable_loop_),
                              .clk_dig(_clk_dig_unbuffered_),
                              .clk_comp(_clk_comp_unbuffered_),
                              .enable_dlycontrol(enable_dlycontrol),
                              .dlycontrol1(dlycontrol1),
                              .dlycontrol2(dlycontrol2),
                              .dlycontrol3(dlycontrol3));
endmodule
module adc_clk_generation(
   input wire ndecision_finish,   // 0 = comparator finished
   input wire enable_loop,        // 1 = self clocked loop enabled
   output wire clk_dig,           // clk for digital core
   output wire clk_comp,          // clk for comparator
   input wire enable_dlycontrol,  // 0 = max delays, 1 = configured delays
   input wire [4:0] dlycontrol1,  // delay1 = N times 5ns up to 100ns
   input wire [4:0] dlycontrol2,  // delay2 = N times 5ns up to 100ns
   input wire [4:0] dlycontrol3   // delay3 = N times 5ns up to 100ns
);
   wire _ndecision_finish_delayed_;
   wire _clk_dig_delayed_;
   wire _net_1_;

   delaycell  #(.Ntimes5ns(20), .ctrlport_width(5)) delay_100ns_1 
   (
        .in(ndecision_finish), 
        .enable_dlycontrol(enable_dlycontrol), 
        .dlycontrol(dlycontrol1), 
        .out(_ndecision_finish_delayed_)
   );
   assign clk_dig = ~_ndecision_finish_delayed_;
   delaycell  #(.Ntimes5ns(20), .ctrlport_width(5)) delay_100ns_2 
   (
        .in(clk_dig),
        .enable_dlycontrol(enable_dlycontrol), 
        .dlycontrol(dlycontrol2), 
        .out(_clk_dig_delayed_)
    );
   nand(_net_1_,_clk_dig_delayed_,~enable_loop);
   delaycell  #(.Ntimes5ns(20), .ctrlport_width(5)) delay_100ns_3 
   (
        .in(_net_1_),
        .enable_dlycontrol(enable_dlycontrol), 
        .dlycontrol(dlycontrol3), 
        .out(clk_comp)
    );
endmodule
module adc_edge_detect_circuit(
    input wire start_conv,          // Tell the ADC to start a conversion
    input wire ena_in,              // signal from the digital core to enable the self-clocked-loop
    output wire ena_out,            // enable the self-clocked-loop
    input wire enable_dlycontrol,   // 0 = max delays, 1 = configured delays
    input wire [5:0] dlycontrol     // delay = N times 5ns up to 200ns
);   
   // Internal wires
    wire _start_conv_delayed_;
    wire _start_conv_edge_;
   
   //combinatoric process
    delaycell  #(.Ntimes5ns(40), .ctrlport_width(6)) dly200cell 
    (
        .in(start_conv), 
        .enable_dlycontrol(enable_dlycontrol), 
        .dlycontrol(dlycontrol), 
        .out(_start_conv_delayed_)
    );
                           
    nor(_start_conv_edge_,~start_conv,_start_conv_delayed_);
    or(ena_out,_start_conv_edge_,ena_in);
endmodule
module delaycell #(parameter Ntimes5ns = 20, parameter ctrlport_width = 5)
(
    input wire in,
    input wire enable_dlycontrol,
    input wire [ctrlport_width-1:0] dlycontrol,
    output wire out
);

    // Conversion from binary (dlycontrol) 
    // to inverted thermo-code (_bypass_)
    // with enable   
    wire [Ntimes5ns-1:0] _bypass_ = enable_dlycontrol ? {Ntimes5ns{1'b1}}<<dlycontrol : {Ntimes5ns{1'b1}};
    
    // Generate delaycell with bypass function
    //                                ___________               bypass[j]
    //              _____            |           |              |-------\
    // bypass[j]--o| AND |--sigb[j]--| Delay 5ns |----sigc[j]---|0 mux   |--sigd[j]--
    //  siga[j]-.--|_____|           |___________|   .--siga[j]-|1______/
    //           \__________________________________/
    //
    wire [Ntimes5ns-1:0] _siga_;
    wire [Ntimes5ns-1:0] _sigb_;
    wire [Ntimes5ns-1:0] _sigc_;
    wire [Ntimes5ns-1:0] _sigd_;
    genvar j;
    generate
       for(j=0;j<Ntimes5ns;j=j+1) begin
          sky130_fd_sc_hd__and2_1 and1 (.A(~_bypass_[j]),.B(_siga_[j]),.X(_sigb_[j]));
          sky130_mm_sc_hd_dlyPoly5ns delay_unit (.in(_sigb_[j]), .out(_sigc_[j]));
          sky130_fd_sc_hd__mux2_1 mux1 (.A0(_sigc_[j]),.A1(_siga_[j]),.S( _bypass_[j]),.X(_sigd_[j]));
          assign _siga_[j] = (j==0) ? in : _sigd_[j-1];
       end             
       assign out = _sigd_[Ntimes5ns-1];
    endgenerate
endmodule
module adc_clkgen_with_edgedetect(
    input wire ena_in,             // enable signal from the digital clock core. 0 halts the self-clocked loop
    input wire start_conv_in,         // triggers a conversion once with edge-detection
    input wire ndecision_finish_in,   // comparator signalizes finished conversion
    output wire clk_dig_out,           // digital clock
    output wire clk_comp_out,          // comparator clock
    input wire enable_dlycontrol_in,  // 0 = max delays, 1 = configurable delays
    input wire [4:0] dlycontrol1_in,  // delay 1 of 3 in loop. Delay = 5ns*dlycontrol1
    input wire [4:0] dlycontrol2_in,  // delay 2 of 3 in loop. Delay = 5ns*dlycontrol2
    input wire [4:0] dlycontrol3_in,  // delay 3 of 3 in loop. Delay = 5ns*dlycontrol3
    input wire [5:0] dlycontrol4_in,  // edge detect pulse width. Delay = 5ns*dlycontrol4
    // integration of additional buffers for sample matrix
    input wire sample_p_in,           
    input wire sample_n_in,
    output wire sample_p_out,
    output wire sample_n_out
);
   wire enable_loop_w;
   wire ena_in_buffered_w;
   wire start_conv_buffered_w;
   wire ndecision_finish_buffered_w;
   wire clk_dig_unbuffered_w;
   wire clk_comp_unbuffered_w;

   //Input buffers
   sky130_fd_sc_hd__buf_1 inbuf_1 (.A(ena_in),.X(ena_in_buffered_w));
   sky130_fd_sc_hd__buf_1 inbuf_2 (.A(start_conv_in),.X(start_conv_buffered_w));
   sky130_fd_sc_hd__buf_1 inbuf_3 (.A(ndecision_finish_in),.X(ndecision_finish_buffered_w));
   
   //Output buffers
   sky130_fd_sc_hd__bufbuf_8 outbuf_1 (.A(clk_dig_unbuffered_w),.X(clk_dig_out));
   sky130_fd_sc_hd__bufbuf_8 outbuf_2 (.A(clk_comp_unbuffered_w),.X(clk_comp_out));

   // Output buffers for sample-signal-buffeing 
   // with delay, so matrix-sample is switched after gate is disabled
   wire sample_p_1;
   wire sample_n_1;

   //sample enable delay stage
   sky130_mm_sc_hd_dlyPoly5ns delay_sample_p11 (.in(sample_p_in), .out(sample_p_1));
   sky130_mm_sc_hd_dlyPoly5ns delay_sample_n12 (.in(sample_n_in), .out(sample_n_1));
   
   //sample enable output stage
   sky130_fd_sc_hd__bufbuf_8 outbuf_3 (.A(sample_p_1),.X(sample_p_out));
   sky130_fd_sc_hd__bufbuf_8 outbuf_4 (.A(sample_n_1),.X(sample_n_out));

   

   //Circuits
   adc_edge_detect_circuit edgedetect (.start_conv_in(start_conv_buffered_w),
                                       .ena_in(ena_in_buffered_w),
                                       .ena_out(enable_loop_w),
                                       .enable_dlycontrol_in(enable_dlycontrol_in),
                                       .dlycontrol_in(dlycontrol4_in));

   adc_clk_generation clkgen (.ndecision_finish_in(ndecision_finish_buffered_w),
                              .enable_loop_in(enable_loop_w),
                              .clk_dig_out(clk_dig_unbuffered_w),
                              .clk_comp_out(clk_comp_unbuffered_w),
                              .enable_dlycontrol_in(enable_dlycontrol_in),
                              .dlycontrol1_in(dlycontrol1_in),
                              .dlycontrol2_in(dlycontrol2_in),
                              .dlycontrol3_in(dlycontrol3_in));
endmodule
module adc_clk_generation(
   input wire ndecision_finish_in,   // 0 = comparator finished
   input wire enable_loop_in,        // 1 = self clocked loop enabled
   output wire clk_dig_out,           // clk for digital core
   output wire clk_comp_out,          // clk for comparator
   input wire enable_dlycontrol_in,  // 0 = max delays, 1 = configured delays
   input wire [4:0] dlycontrol1_in,  // delay1 = N times 5ns
   input wire [4:0] dlycontrol2_in,  // delay2 = N times 5ns
   input wire [4:0] dlycontrol3_in   // delay3 = N times 5ns
);
   wire ndecision_finish_delayed_w;
   wire clk_dig_delayed_w;
   wire net1_w;

    binary_delaycell #(.DLYCONTROL_BITWIDTH(5)) delay_155ns_1
    (
        .in(ndecision_finish_in), 
        .enable_dlycontrol_in(enable_dlycontrol_in), 
        .dlycontrol_in(dlycontrol1_in), 
        .out(ndecision_finish_delayed_w)
    );
    sky130_fd_sc_hd__inv_2 clkdig_inverter (.A(ndecision_finish_delayed_w),.Y(clk_dig_out));
    binary_delaycell #(.DLYCONTROL_BITWIDTH(5)) delay_155ns_2
    (
        .in(clk_dig_out), 
        .enable_dlycontrol_in(enable_dlycontrol_in), 
        .dlycontrol_in(dlycontrol2_in), 
        .out(clk_dig_delayed_w)
    );
    sky130_fd_sc_hd__nor2b_1 nor1 (.A(clk_dig_delayed_w),.B_N(enable_loop_in),.Y(net1_w)); //2 input nor, B inverted
    binary_delaycell #(.DLYCONTROL_BITWIDTH(5)) delay_155ns_3
    (
        .in(net1_w), 
        .enable_dlycontrol_in(enable_dlycontrol_in), 
        .dlycontrol_in(dlycontrol3_in), 
        .out(clk_comp_out)
    );
endmodule
module adc_edge_detect_circuit(
    input wire start_conv_in,          // Tell the ADC to start a conversion
    input wire ena_in,              // signal from the digital core to enable the self-clocked-loop
    output wire ena_out,            // enable the self-clocked-loop
    input wire enable_dlycontrol_in,   // 0 = max delays, 1 = configured delays
    input wire [5:0] dlycontrol_in     // delay = N times 5ns
);   
   // Internal wires
    wire start_conv_delayed_w;
    wire start_conv_edge_w;
   
    binary_delaycell #(.DLYCONTROL_BITWIDTH(6)) dly_315ns_1
    (
        .in(start_conv_in), 
        .enable_dlycontrol_in(enable_dlycontrol_in), 
        .dlycontrol_in(dlycontrol_in), 
        .out(start_conv_delayed_w)
    );
    sky130_fd_sc_hd__nor2b_1 nor1 (.A(start_conv_delayed_w),.B_N(start_conv_in),.Y(start_conv_edge_w)); // 2 input nor, B inverted 
    sky130_fd_sc_hd__or2_1 or1 (.A(start_conv_edge_w),.B(ena_in),.X(ena_out)); // 2 input or
endmodule
module binary_delaycell #(parameter DLYCONTROL_BITWIDTH = 5)
(
    input wire in,
    input wire enable_dlycontrol_in,
    input wire [DLYCONTROL_BITWIDTH-1:0] dlycontrol_in,
    output wire out
);

    wire [DLYCONTROL_BITWIDTH:0] signal_w;
    wire enable_dlycontrol_w;
    wire [DLYCONTROL_BITWIDTH-1:0] bypass_enable_w;
    wire [DLYCONTROL_BITWIDTH-1:0] bypass_w;

    sky130_fd_sc_hd__buf_4 enablebuffer (.A(enable_dlycontrol_in),.X(enable_dlycontrol_w));
    
    //instanciate binary coded delay cells
    genvar i;
    generate
       for (i = 0; i < DLYCONTROL_BITWIDTH; i=i+1) begin
            sky130_fd_sc_hd__inv_2  control_invert (.A(dlycontrol_in[i]),.Y(bypass_enable_w[i]));
            sky130_fd_sc_hd__and2_1 bypass_enable (.A(enable_dlycontrol_w),.B(bypass_enable_w[i]),.X(bypass_w[i])); // 2 input and, A inverted
            delaycell #(.N_TIMES_5NS(2**i)) dly_binary (
                .in(signal_w[i]),
                .bypass_in(bypass_w[i]),
                .out(signal_w[i+1])
            );
        end
    endgenerate
    assign signal_w[0] = in;
    assign out = signal_w[DLYCONTROL_BITWIDTH];
endmodule
module delaycell #(parameter N_TIMES_5NS = 32)
(
    input wire in,
    input wire bypass_in,
    output wire out
);
    wire [N_TIMES_5NS:0] signal_w;          
    genvar j;
    generate
       for(j=0;j<N_TIMES_5NS;j=j+1) begin
          sky130_mm_sc_hd_dlyPoly5ns delay_unit (.in(signal_w[j]), .out(signal_w[j+1]));
       end             
    endgenerate
    sky130_fd_sc_hd__and2b_1 and_bypass_switch (.A_N(bypass_in),.B(in),.X(signal_w[0])); // 2 input and, A inverted
    sky130_fd_sc_hd__mux2_1 out_mux (.A0(signal_w[N_TIMES_5NS]),.A1(in),.S(bypass_in),.X(out)); //2 input mux
endmodule
module adc_osr_tb;
    reg rst_n;
    reg data_valid_strobe;
    reg [2:0] osr_mode;
    reg [11:0] data;
    wire [15:0] result;
    wire conversion_finished;

adc_osr osr_dut (
   .data_valid_strobe(data_valid_strobe),
   .rst_n(rst_n),
   .osr_mode_in(osr_mode),
   .data_in(data),
   .data_out(result),
   .conversion_finished_osr_out(conversion_finished)
   );



   initial begin
   	$dumpfile("dump.vcd");
   	$dumpvars(0,
   		data_valid_strobe,
   		rst_n,
   		osr_mode,
   		data,
   		result,
   		conversion_finished,
        osr_dut);
   end
   
   integer i;

   initial begin
    data_valid_strobe=0;
    rst_n = 1;
    osr_mode = 3'b000;
    data=0;

    rst_n=1; #2;
    rst_n=0; #4;
    rst_n=1; #2;
    data = 12'h111; #2;
    data = 12'h222; #2;
    osr_mode = 3'b001;
    
    // 4 samples, result is h0018
    for (i = 0; i < 4 ; i = i + 1 ) begin 
        data = 12'h000 + i; #2;
    end
    
    // 16 samples, result is h890
    rst_n = 0; #2 rst_n = 1; 
    osr_mode = 3'b010;  
    for (i = 0; i < 16 ; i = i + 1 ) begin 
        data = 12'h890; #2;
    end

    // 16 samples, result is h8978
    osr_mode = 3'b010;   
    for (i = 0; i < 16 ; i = i + 1 ) begin 
        data = 12'h890+i; #2;
    end


    // 64 samples, result is h01F8
    osr_mode = 3'b011;   
    for (i = 0; i < 64 ; i = i + 1 ) begin 
        data = 12'h000+i; #2;
    end

    // 256 samples, result is h07F8
    osr_mode = 3'b100;   
    for (i = 0; i < 256 ; i = i + 1 ) begin 
        data = 12'h000+i; #2;
    end

    osr_mode = 3'b000; 
    data = 12'h123; #2;


    
    #1 $finish;
   end

   initial begin
    forever begin
        #1 data_valid_strobe = ~data_valid_strobe;
    end
   end

endmodule
module adc_row_col_decoder_tb;
    reg[11:0] data;
    reg       row_mode;
    reg       col_mode;
    wire[15:0] row_n;
    wire[15:0] rowon_n;
    wire[15:0] rowoff_n;
    wire[31:0] col_n;
    wire[31:0] col;
    wire[2:0]  bincap_n;
    wire       c0p_n;
    wire       c0n_n;

  adc_row_col_decoder decoder (
    .data_in(data),
   .row_mode(row_mode),
   .col_mode(col_mode),
    .row_out_n(row_n),
    .rowon_out_n(rowon_n),
    .rowoff_out_n(rowoff_n),
    .col_out_n(col_n),
    .col_out(col),
    .bincap_out_n(bincap_n),
    .c0p_out_n(c0p_n),
    .c0n_out_n(c0n_n)
    );

   initial begin
   	$dumpfile("dump.vcd");
   	$dumpvars(0,
   		data,
         row_mode,
         col_mode,
   		row_n,
   		rowon_n,
   		rowoff_n,
   		col_n,
   		col,
   		bincap_n,
   		c0p_n,
   		c0n_n,
      decoder);
   end
   
   integer i;

   initial begin
    data=0;
    row_mode = 1;
    col_mode = 1;
   	for(i=1;i<4096;i=i+1) begin
       #1 data=data+1;
    end
    #1 data=12'd4093;
    #1 data=12'd4094;
    #1 data=12'd4095;
    #1 $finish;
   end

endmodule
module tb_custom_ip_core;

  // Parameters
  parameter CLK_PERIOD = 10;  // Clock period in nanoseconds

  // Inputs
  reg clk;
  reg rst_n;
  reg [31:0] s_axis_tdata;
  reg s_axis_tvalid;
  reg m_axis_tready;
  reg [31:0] control_reg;

  // Outputs
  wire s_axis_tready;
  wire [31:0] m_axis_tdata;
  wire m_axis_tvalid;
  wire [31:0] status_reg;

  // Instantiate the custom IP core module
  custom_ip_core dut (
    .clk(clk),
    .rst_n(rst_n),
    .s_axis_tdata(s_axis_tdata),
    .s_axis_tvalid(s_axis_tvalid),
    .s_axis_tready(s_axis_tready),
    .m_axis_tdata(m_axis_tdata),
    .m_axis_tvalid(m_axis_tvalid),
    .m_axis_tready(m_axis_tready),
    .control_reg(control_reg),
    .status_reg(status_reg)
  );

  // Clock generation
  always begin
    clk = 1'b0;
    #(CLK_PERIOD/2);
    clk = 1'b1;
    #(CLK_PERIOD/2);
  end

  // Testbench stimulus
  initial begin
    // Initialize inputs
    rst_n = 1'b0;
    s_axis_tdata = 32'h0;
    s_axis_tvalid = 1'b0;
    m_axis_tready = 1'b1;
    control_reg = 32'h0;

    // Reset the module
    #(CLK_PERIOD*2);
    rst_n = 1'b1;

    // Test case 1: Send input data
    #(CLK_PERIOD*2);
    s_axis_tdata = 32'h12345678;
    s_axis_tvalid = 1'b1;
    #(CLK_PERIOD);
    s_axis_tvalid = 1'b0;
    wait(m_axis_tvalid);
    #(CLK_PERIOD);

    // Test case 2: Configure control register
    #(CLK_PERIOD*2);
    control_reg = 32'hABCDEF01;
    #(CLK_PERIOD*2);

    // Test case 3: Send input data with control register configured
    #(CLK_PERIOD*2);
    s_axis_tdata = 32'h87654321;
    s_axis_tvalid = 1'b1;
    #(CLK_PERIOD);
    s_axis_tvalid = 1'b0;
    wait(m_axis_tvalid);
    #(CLK_PERIOD);

    // Test case 4: Check status register
    #(CLK_PERIOD*2);
    $display("Status register: %h", status_reg);
    if (status_reg[7:0] == 8'd1)
      $display("Status register is correct");
    else
      $error("Incorrect status register value");

    // End the simulation
    #(CLK_PERIOD*10);
    $finish;
  end

  // Verify the output data
  always @(posedge clk) begin
    if (m_axis_tvalid) begin
      $display("Output data: %h", m_axis_tdata);
      if (m_axis_tdata == 32'h12345678 + control_reg)
        $display("Output data is correct");
      else
        $error("Incorrect output data");
    end
  end

endmodule
module tb_tcp_ip_stack;

  // Parameters
  parameter CLK_PERIOD = 10;  // Clock period in nanoseconds

  // Inputs
  reg clk;
  reg rst_n;
  reg [31:0] app_tx_data;
  reg app_tx_valid;
  reg [31:0] eth_rx_data;
  reg eth_rx_valid;
  reg eth_tx_ready;

  // Outputs
  wire app_tx_ready;
  wire [31:0] app_rx_data;
  wire app_rx_valid;
  wire [31:0] eth_tx_data;
  wire eth_tx_valid;
  wire eth_rx_ready;

  // Instantiate the TCP/IP stack module
  tcp_ip_stack dut (
    .clk(clk),
    .rst_n(rst_n),
    .app_tx_data(app_tx_data),
    .app_tx_valid(app_tx_valid),
    .app_tx_ready(app_tx_ready),
    .app_rx_data(app_rx_data),
    .app_rx_valid(app_rx_valid),
    .app_rx_ready(1'b1),
    .eth_tx_data(eth_tx_data),
    .eth_tx_valid(eth_tx_valid),
    .eth_tx_ready(eth_tx_ready),
    .eth_rx_data(eth_rx_data),
    .eth_rx_valid(eth_rx_valid),
    .eth_rx_ready(eth_rx_ready)
  );

  // Clock generation
  always begin
    clk = 1'b0;
    #(CLK_PERIOD/2);
    clk = 1'b1;
    #(CLK_PERIOD/2);
  end

  // Testbench stimulus
  initial begin
    // Initialize inputs
    rst_n = 1'b0;
    app_tx_data = 32'h0;
    app_tx_valid = 1'b0;
    eth_rx_data = 32'h0;
    eth_rx_valid = 1'b0;
    eth_tx_ready = 1'b1;

    // Reset the module
    #(CLK_PERIOD*2);
    rst_n = 1'b1;

    // Test case 1: Send application data
    #(CLK_PERIOD*2);
    app_tx_data = 32'h12345678;
    app_tx_valid = 1'b1;
    #(CLK_PERIOD);
    app_tx_valid = 1'b0;
    wait(eth_tx_valid);
    #(CLK_PERIOD);

    // Test case 2: Receive Ethernet data
    #(CLK_PERIOD*2);
    eth_rx_data = 32'h87654321;
    eth_rx_valid = 1'b1;
    #(CLK_PERIOD);
    eth_rx_valid = 1'b0;
    wait(app_rx_valid);
    #(CLK_PERIOD);

    // Test case 3: Send and receive multiple packets
    #(CLK_PERIOD*2);
    app_tx_data = 32'hAAAAAAAA;
    app_tx_valid = 1'b1;
    #(CLK_PERIOD);
    app_tx_data = 32'hBBBBBBBB;
    #(CLK_PERIOD);
    app_tx_data = 32'hCCCCCCCC;
    #(CLK_PERIOD);
    app_tx_valid = 1'b0;
    wait(eth_tx_valid);
    #(CLK_PERIOD*3);
    
    eth_rx_data = 32'h11111111;
    eth_rx_valid = 1'b1;
    #(CLK_PERIOD);
    eth_rx_data = 32'h22222222;
    #(CLK_PERIOD);
    eth_rx_data = 32'h33333333;
    #(CLK_PERIOD);
    eth_rx_valid = 1'b0;
    wait(app_rx_valid);
    #(CLK_PERIOD*3);

    // End the simulation
    #(CLK_PERIOD*10);
    $finish;
  end

  // Verify the transmitted Ethernet data
  always @(posedge clk) begin
    if (eth_tx_valid) begin
      $display("Transmitted Ethernet data: %h", eth_tx_data);
      if (eth_tx_data == 32'h12345678)
        $display("Ethernet transmit data is correct");
      else
        $error("Incorrect Ethernet transmit data");
    end
  end

  // Verify the received application data
  always @(posedge clk) begin
    if (app_rx_valid) begin
      $display("Received application data: %h", app_rx_data);
      if (app_rx_data == 32'h87654321)
        $display("Application receive data is correct");
      else
        $error("Incorrect application receive data");
    end
  end

endmodule
module risk_management (
  input wire clk,
  input wire rst_n,
  input wire [31:0] trade_data,
  input wire trade_valid,
  output reg trade_approved,
  // Position tracking
  input wire [31:0] position_update,
  input wire position_update_valid,
  output reg [31:0] current_position,
  // Exposure tracking
  input wire [31:0] exposure_update,
  input wire exposure_update_valid,
  output reg [31:0] current_exposure,
  // Risk checks
  input wire [31:0] max_exposure_limit,
  input wire [31:0] max_position_limit
);

  // Risk parameters
  parameter RISK_CHECK_EXPOSURE = 1;
  parameter RISK_CHECK_POSITION = 1;

  // Risk management logic
  always @(posedge clk) begin
    if (!rst_n) begin
      // Reset logic
      trade_approved <= 1;
      current_position <= 0;
      current_exposure <= 0;
    end else begin
      // Update position
      if (position_update_valid) begin
        current_position <= current_position + position_update;
      end

      // Update exposure
      if (exposure_update_valid) begin
        current_exposure <= current_exposure + exposure_update;
      end

      // Perform risk checks
      if (trade_valid) begin
        if (RISK_CHECK_EXPOSURE) begin
          if (current_exposure + trade_data[31:0] > max_exposure_limit) begin
            // Exposure limit exceeded
            trade_approved <= 0;
          end else begin
            trade_approved <= 1;
          end
        end

        if (RISK_CHECK_POSITION) begin
          if (current_position + trade_data[31:0] > max_position_limit) begin
            // Position limit exceeded
            trade_approved <= 0;
          end else begin
            trade_approved <= 1;
          end
        end
      end else begin
        trade_approved <= 1;
      end
    end
  end

endmodule
module ethernet_layer (
  input wire clk,
  input wire rst_n,
  
  // MAC interface
  output reg [47:0] mac_tx_data,
  output reg mac_tx_valid,
  input wire mac_tx_ready,
  input wire [47:0] mac_rx_data,
  input wire mac_rx_valid,
  output reg mac_rx_ready,
  
  // TCP/IP stack interface
  input wire [31:0] tcp_ip_tx_data,
  input wire tcp_ip_tx_valid,
  output reg tcp_ip_tx_ready,
  output reg [31:0] tcp_ip_rx_data,
  output reg tcp_ip_rx_valid,
  input wire tcp_ip_rx_ready
);

  // Ethernet frame parameters
  parameter PREAMBLE = 64'h55555555555555D5;
  parameter SFD = 8'hD5;
  parameter ETH_TYPE_IPV4 = 16'h0800;
  parameter MAC_ADDR_LOCAL = 48'h000A35000001;
  parameter MAC_ADDR_REMOTE = 48'h000A35000002;

  // Packet buffers
  reg [1023:0] tx_buffer;
  reg [10:0] tx_length;
  reg [1023:0] rx_buffer;
  reg [10:0] rx_length;

  // Ethernet layer logic
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      // Reset logic
      tx_length <= 0;
      rx_length <= 0;
      mac_tx_valid <= 0;
      tcp_ip_rx_valid <= 0;
      tcp_ip_tx_ready <= 1;
      mac_rx_ready <= 1;
    end else begin
      // Transmit packet
      if (tcp_ip_tx_valid && tcp_ip_tx_ready) begin
        tx_buffer <= {PREAMBLE, SFD, MAC_ADDR_REMOTE, MAC_ADDR_LOCAL, ETH_TYPE_IPV4, tcp_ip_tx_data};
        tx_length <= 14 + 20 + tcp_ip_tx_data[31:16];
      end

      if (mac_tx_ready && tx_length > 0) begin
        mac_tx_data <= tx_buffer[1023:976];
        mac_tx_valid <= 1;
        tx_buffer <= {tx_buffer[975:0], 48'h0};
        tx_length <= tx_length - 6;
      end else begin
        mac_tx_valid <= 0;
      end

      // Receive packet
      if (mac_rx_valid && mac_rx_ready) begin
        rx_buffer <= {rx_buffer[975:0], mac_rx_data};
        rx_length <= rx_length + 6;
      end

      if (rx_length >= 14 + 20) begin
        if (rx_buffer[1023:976] == MAC_ADDR_LOCAL && rx_buffer[959:944] == ETH_TYPE_IPV4) begin
          tcp_ip_rx_data <= rx_buffer[943:912];
          tcp_ip_rx_valid <= 1;
        end
        rx_buffer <= {rx_buffer[911:0], 112'h0};
        rx_length <= rx_length - 14 - 20;
      end else if (tcp_ip_rx_ready) begin
        tcp_ip_rx_valid <= 0;
      end

      // Update ready signals
      tcp_ip_tx_ready <= (tx_length == 0);
      mac_rx_ready <= (rx_length < 1024 - 6);
    end
  end

endmodule
module axi_stream_if #(
  parameter DATA_WIDTH = 32,
  parameter DEST_WIDTH = 4,
  parameter USER_WIDTH = 4,
  parameter ID_WIDTH = 4,
  parameter HAS_STRB = 0,
  parameter HAS_KEEP = 0,
  parameter HAS_LAST = 1,
  parameter HAS_DEST = 0,
  parameter HAS_USER = 0,
  parameter HAS_ID = 0
)(
  // AXI stream interface signals
  input wire aclk,
  input wire aresetn,
  input wire [DATA_WIDTH-1:0] tdata,
  input wire [DEST_WIDTH-1:0] tdest,
  input wire [USER_WIDTH-1:0] tuser,
  input wire [ID_WIDTH-1:0] tid,
  input wire [(DATA_WIDTH/8)-1:0] tstrb,
  input wire [(DATA_WIDTH/8)-1:0] tkeep,
  input wire tlast,
  input wire tvalid,
  output wire tready
);

  // AXI stream interface assignments
  assign tready = 1'b1; // Always ready to accept data

  // Implement your custom logic here
  // You can access the AXI stream signals (tdata, tdest, tuser, tid, tstrb, tkeep, tlast, tvalid)
  // and perform necessary operations based on your requirements

  // Example: Logging AXI stream data
  always @(posedge aclk) begin
    if (tvalid && tready) begin
      $display("AXI Stream Data: tdata=%h, tdest=%h, tuser=%h, tid=%h, tstrb=%h, tkeep=%h, tlast=%b",
               tdata, tdest, tuser, tid, tstrb, tkeep, tlast);
    end
  end

endmodule
module ip_layer (
  input wire clk,
  input wire rst_n,
  // Ethernet layer interface
  input wire [31:0] eth_rx_data,
  input wire eth_rx_valid,
  output wire eth_rx_ready,
  output wire [31:0] eth_tx_data,
  output wire eth_tx_valid,
  input wire eth_tx_ready,
  // TCP layer interface
  output wire [31:0] tcp_rx_data,
  output wire tcp_rx_valid,
  input wire tcp_rx_ready,
  input wire [31:0] tcp_tx_data,
  input wire tcp_tx_valid,
  output wire tcp_tx_ready
);

  // IP packet parameters
  parameter IP_VERSION = 4'h4;
  parameter IP_IHL = 4'h5;
  parameter IP_TOS = 8'h00;
  parameter IP_TTL = 8'h40;
  parameter IP_PROTOCOL_TCP = 8'h06;
  parameter IP_ADDR_LOCAL = 32'hC0A80001; // 192.168.0.1
  parameter IP_ADDR_REMOTE = 32'hC0A80002; // 192.168.0.2

  // Packet buffers
  reg [31:0] rx_buffer;
  reg rx_buffer_valid;
  reg [31:0] tx_buffer;
  reg tx_buffer_valid;

  // IP layer logic
  always @(posedge clk) begin
    if (!rst_n) begin
      // Reset logic
      rx_buffer_valid <= 0;
      tx_buffer_valid <= 0;
    end else begin
      // Receive packet
      if (eth_rx_valid && eth_rx_ready) begin
        rx_buffer <= eth_rx_data;
        rx_buffer_valid <= 1;
      end else if (tcp_rx_ready) begin
        rx_buffer_valid <= 0;
      end

      // Transmit packet
      if (tcp_tx_valid && tcp_tx_ready) begin
        tx_buffer <= {IP_VERSION, IP_IHL, IP_TOS, tcp_tx_data[15:0], 16'h0000, IP_TTL, IP_PROTOCOL_TCP, 16'h0000, IP_ADDR_LOCAL, IP_ADDR_REMOTE, tcp_tx_data};
        tx_buffer_valid <= 1;
      end else if (eth_tx_ready) begin
        tx_buffer_valid <= 0;
      end
    end
  end

  // Receive path
  assign tcp_rx_data = rx_buffer;
  assign tcp_rx_valid = rx_buffer_valid && (rx_buffer[31:28] == IP_VERSION) && (rx_buffer[27:24] == IP_IHL) && (rx_buffer[23:16] == IP_PROTOCOL_TCP);
  assign eth_rx_ready = !rx_buffer_valid || tcp_rx_ready;

  // Transmit path
  assign eth_tx_data = tx_buffer;
  assign eth_tx_valid = tx_buffer_valid;
  assign tcp_tx_ready = !tx_buffer_valid || eth_tx_ready;

endmodule
module custom_ip_core (
  input wire clk,
  input wire rst_n,
  // AXI stream interface for input
  input wire [31:0] s_axis_tdata,
  input wire s_axis_tvalid,
  output reg s_axis_tready,
  // AXI stream interface for output
  output reg [31:0] m_axis_tdata,
  output reg m_axis_tvalid,
  input wire m_axis_tready,
  // Control and status signals
  input wire [31:0] control_reg,
  output reg [31:0] status_reg
);

  // Packet buffer
  reg [31:0] packet_buffer [0:255];
  reg [7:0] packet_length;

  // Internal registers
  reg [31:0] internal_reg1;
  reg [31:0] internal_reg2;

  // State machine
  parameter STATE_IDLE = 2'b00;
  parameter STATE_PROCESS = 2'b01;
  parameter STATE_TRANSMIT = 2'b10;

  reg [1:0] current_state;
  reg [1:0] next_state;

  // Custom IP core logic
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      // Reset logic
      packet_length <= 0;
      internal_reg1 <= 0;
      internal_reg2 <= 0;
      current_state <= STATE_IDLE;
      s_axis_tready <= 1;
      m_axis_tvalid <= 0;
      status_reg <= 0;
    end else begin
      case (current_state)
        STATE_IDLE: begin
          if (s_axis_tvalid && s_axis_tready) begin
            // Receive input data
            packet_buffer[packet_length] <= s_axis_tdata;
            packet_length <= packet_length + 1;
            if (s_axis_tdata[31:24] == 8'hFF) begin
              // End of packet marker received
              next_state <= STATE_PROCESS;
            end
          end
        end

        STATE_PROCESS: begin
          // Process the received packet
          // Perform custom IP core functionality here
          internal_reg1 <= packet_buffer[0] + control_reg;
          internal_reg2 <= packet_buffer[1] * control_reg;
          // ...

          // Prepare the output packet
          packet_buffer[0] <= internal_reg1;
          packet_buffer[1] <= internal_reg2;
          // ...

          next_state <= STATE_TRANSMIT;
        end

        STATE_TRANSMIT: begin
          if (m_axis_tready && m_axis_tvalid) begin
            // Transmit output data
            if (packet_length > 0) begin
              m_axis_tdata <= packet_buffer[packet_length - 1];
              packet_length <= packet_length - 1;
            end else begin
              // End of packet
              m_axis_tdata <= 32'hFFFFFFFF;
              next_state <= STATE_IDLE;
            end
          end
        end
      endcase

      current_state <= next_state;
    end
  end

  // Ready signals
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      s_axis_tready <= 1;
      m_axis_tvalid <= 0;
    end else begin
      s_axis_tready <= (current_state == STATE_IDLE);
      m_axis_tvalid <= (current_state == STATE_TRANSMIT);
    end
  end

  // Status register
  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      status_reg <= 0;
    end else begin
      status_reg <= {24'b0, packet_length};
    end
  end

endmodule
module async_mem (/*AUTOARG*/
  // Outputs
  rd_data, 
  // Inputs
  wr_clk, wr_data, wr_cs, addr, rd_cs
  );

  parameter asz = 15,
	    depth = 32768;
  
  input       wr_clk;
  input [7:0] wr_data;
  input       wr_cs;

  input [asz-1:0] addr;
  inout [7:0] 	  rd_data;
  input 	  rd_cs;

  reg [7:0] 	  mem [0:depth-1];

  always @(posedge wr_clk)
    begin
      if (wr_cs)
	mem[addr] <= #1 wr_data;
    end

  assign rd_data = (rd_cs) ? mem[addr] : {8{1'bz}};
	  
endmodule // async_mem
module divider #(parameter DELAY=50000000) (
  input wire reset,
  input wire clock,
  output wire enable);
  
  reg  [31:0] count;
  wire [31:0] next_count;

  always @(posedge clock)
  begin
    if (reset)
      count <= 32'b0;
    else
      count <= next_count;
  end
  
  assign enable = (count == DELAY - 1) ? 1'b1 : 1'b0;
  assign next_count = (count == DELAY - 1) ? 32'b0 : count + 1;

endmodule
module async_mem2(
  input  wire           clkA,
  input  wire           clkB,
  input  wire [asz-1:0] addrA,
  input  wire [asz-1:0] addrB,
  input  wire           wr_csA,
  input  wire           wr_csB,
  input  wire     [7:0] wr_dataA,
  input  wire     [7:0] wr_dataB,
  output wire     [7:0] rd_dataA,
  output wire     [7:0] rd_dataB
);

  parameter asz = 15;
  parameter depth = 32768;
  
  reg [7:0] mem [0:depth-1];
  
  always @(posedge clkA) begin
    if (wr_csA)
      mem[addrA] <= wr_dataA;
  end
  
  always @(posedge clkB) begin
    if (wr_csB)
      mem[addrB] <= wr_dataB;
  end
  
  assign rd_dataA = mem[addrA];
  assign rd_dataB = mem[addrB];

endmodule
module timer_controller (
  input  wire        clock,
  input  wire        reset,
  input  wire        int_ack,
  output reg         int_req,
  input  wire [15:0] A,
  input  wire [7:0]  Di,
  output wire [7:0]  Do,
  input  wire        wr_n,
  input  wire        rd_n,
  input  wire        cs
);

  ////////////////////////////////////////////////
  // Timer Registers
  // 
  // DIV - Divider Register (FF04)
  //   Increments 16384 times a second
  //
  // TIMA - Timer Counter (FF05)
  //   Increments at frequency specified by TAC
  //
  // TMA - Timer Modulo (FF06)
  //   Value to load into TIMA on overflow
  //
  // TAC - Timer Control (FF07)
  //   Bit 2: 0 <= stop, 1 <= start
  //   Bit 1-0: 00 <= 4.096 KHz
  //            01 <= 262.144 KHz
  //            10 <= 65.536 KHz
  //            11 <= 16.384 KHz
  ////////////////////////////////////////////////
  
  reg[7:0] DIV;
  reg[7:0] TIMA;
  reg[7:0] TMA;
  reg[7:0] TAC;
  
  reg[7:0] reg_out;
  
  parameter MAX_TIMER = 8'hFF;
  
  wire enable;
  wire e0, e1, e2, e3;
  
  divider #(1024) d0(reset, clock, e0);
  divider #(16) d1(reset, clock, e1);
  divider #(64) d2(reset, clock, e2);
  divider #(256) d3(reset, clock, e3);
  
  always @(posedge clock)
  begin
    if (reset)
    begin
      DIV <= 8'h0;
      TIMA <= 8'h0;
      TMA <= 8'h0;
      TAC <= 8'h0;
      int_req <= 1'b0;
      reg_out <= 8'h0;
    end
    else
    begin
    
      // Read / Write for registers
      if (cs)
      begin
        if (!wr_n)
        begin
          case (A)
            16'hFF04: DIV <= 8'h0;
            16'hFF05: TIMA <= Di;
            16'hFF06: TMA <= Di;
            16'hFF07: TAC <= Di;
          endcase
        end
        else if (!rd_n)
        begin
          case (A)
            16'hFF04: reg_out <= DIV;
            16'hFF05: reg_out <= TIMA;
            16'hFF06: reg_out <= TMA;
            16'hFF07: reg_out <= TAC;
          endcase
        end
      end
      
      // Clear overflow interrupt
      if (int_ack)
        int_req <= 1'b0;
      
      // Increment timers
      if (enable)
      begin
        if (TIMA == MAX_TIMER)
          int_req <= 1'b1;
        TIMA <= (TIMA == MAX_TIMER) ? TMA : TIMA + 1'b1;
      end
      
      if (e3)
      begin
        DIV <= DIV + 1'b1;
      end
      
    end
  end
  
  assign Do = (cs) ? reg_out : 8'hZZ;
  assign enable =
    (TAC[2] == 0) ? 1'b0 :
    (TAC[1:0] == 0) ? e0 :
    (TAC[1:0] == 1) ? e1 :
    (TAC[1:0] == 2) ? e2 :
    (TAC[1:0] == 3) ? e3 : 1'b0;

endmodule
module joypad_controller(
  input  wire        clock,
  input  wire        reset,
  input  wire        int_ack,  
  output reg         int_req,
  input  wire [15:0] A,
  input  wire  [7:0] Di,
  output wire  [7:0] Do,
  input  wire        rd_n,
  input  wire        wr_n,
  input  wire        cs,
  output reg   [1:0] button_sel,
  input  wire  [3:0] button_data
);
  
  ////////////////////////////////////////////////
  // Joypad Registers
  // 
  // JOYP - Joypad (FF00)
  //   Bit 5: 0 <= select button keys (R/W)
  //   Bit 4: 0 <= select direction keys (R/W)
  //   Bit 3: 0 <= Down  or Start
  //   Bit 2: 0 <= Up    or Select
  //   Bit 1: 0 <= Left  or B
  //   Bit 0: 0 <= Right or A
  ////////////////////////////////////////////////

  always @(posedge clock) begin
    if (reset)
      int_req <= 0;
    else begin
      if (!wr_n) begin
        if (A == 16'hFF00)
          button_sel <= Di[5:4];
      end
    end
  end

  assign Do = (cs) ? { 2'b11, button_sel[1:0], button_data[3:0] } : 8'hFF;

endmodule
module joypad_snes_adapter_tb;

	// Inputs
	reg clock;
	reg reset;
  
	wire [1:0] button_sel;
	wire controller_data;

	// Outputs
	wire [3:0] button_data;
	wire controller_latch;
	wire controller_clock;

	// Instantiate the Unit Under Test (UUT)
	joypad_snes_adapter uut (
		.clock(clock), 
		.reset(reset), 
		.button_sel(button_sel), 
		.button_data(button_data), 
		.controller_data(controller_data), 
		.controller_latch(controller_latch), 
		.controller_clock(controller_clock)
	);

  assign button_sel = 2'b0;
  assign controller_data = 1'b0;

	initial begin
		// Initialize Inputs
		clock = 0;
		reset = 1;
    
    // Wait 100 ns for module reset to finish
    #100 reset = 0;
	end
  
  always begin
    #10 clock = !clock;
  end
      
endmodule
module joypad_snes_adapter(
  input  wire        clock,
  input  wire        reset,
  // to gameboy
  input  wire  [1:0] button_sel,
  output wire  [3:0] button_data,
  output reg  [15:0] button_state,
  // to controller
  input  wire        controller_data,
  output wire        controller_latch,
  output wire        controller_clock
);

  ////////////////////////////////////////////////////////
  // http://www.gamefaqs.com/snes/916396-snes/faqs/5395
  //
  // Note: This implementation does *not* match the
  //  timings specified in the documentation above.
  //  Instead, it uses a much simpler and slower 1KHz
  //  clock which provides pretty good responsiveness
  //  to button presses. Also note that the Atlys board
  //  only provides a 3.3V Vcc instead of the spec'd 5V.
  //
  // Note: Color of wires on my controller ext. cable
  //  Vcc (+5V) - Green
  //  Clock     - Blue
  //  Latch     - Yellow
  //  Data      - Red
  //  Ground    - Brown
  ////////////////////////////////////////////////////////

  parameter WAIT_STATE = 0;
  parameter LATCH_STATE = 1;
  parameter READ_STATE = 2;

  reg   [1:0] state;
  reg   [3:0] button_index;
  //reg  [15:0] button_state;
  
  /**
   * State transitions occur on the clock's positive edge.
   */
  always @(posedge clock) begin
    if (reset)
      state <= WAIT_STATE;
    else begin
      if (state == WAIT_STATE)
        state <= LATCH_STATE;
      else if (state == LATCH_STATE)
        state <= READ_STATE;
      else if (state == READ_STATE) begin
        if (button_index == 15)
          state <= WAIT_STATE;
      end
    end
  end
  
  /**
   * Button reading occurs on the negative edge to give
   * values from the controller time to settle.
   */
  always @(negedge clock) begin
    if (reset) begin
      button_index <= 4'b0;
      button_state <= 16'hFFFF;
    end else begin
      if (state == WAIT_STATE)
        button_index <= 4'b0;
      else if (state == READ_STATE) begin
        button_state[button_index] <= controller_data;
        button_index <= button_index + 1;
      end
    end
  end
  
  assign controller_latch = (state == LATCH_STATE) ? 1'b1 : 1'b0;
  assign controller_clock = (state == READ_STATE) ? clock : 1'b1;

  // button order is
  // B Y SELECT START UP DOWN LEFT RIGHT A X L R - - - -
  assign button_data =
    button_sel[0] == 1'b0 ? { button_state[7], button_state[6], button_state[4], button_state[5] } :
    button_sel[1] == 1'b0 ? { button_state[8], button_state[0], button_state[2], button_state[3] } : 4'b1111;

endmodule
module vga_controller(pixel_clock, reset, hsync, vsync, pixel_count, line_count);
    input pixel_clock;
    input reset;
    output hsync;
    output vsync;
    output [9:0] pixel_count;
    output [9:0] line_count;

	// output registers
	reg hsync, vsync;
	reg [9:0] pixel_count, line_count;
	wire [9:0] next_pixel, next_line;

	// parameters
	// 800x525 pixels for 640x480 display
	parameter NUM_LINES = 525;
	parameter NUM_PIXELS = 800;
	
	// visible parameters
	parameter WIDTH = 640;
	parameter HEIGHT = 480;
	
	// horizontal parameters (pixels)
	parameter H_FRONT_PORCH = 16;
	parameter H_SYNC = 96;
	parameter H_BACK_PORCH = 48;
	
	// vertical parameters (lines)
	parameter V_FRONT_PORCH = 11;
	parameter V_SYNC = 2;
	parameter V_BACK_PORCH = 32;
	
	always @(posedge pixel_clock) begin
		if(reset) begin
			pixel_count <= 10'b0;
			line_count <= 10'b0;
			hsync <= 1;
			vsync <= 1;
		end else begin
			pixel_count <= next_pixel;
			line_count <= next_line;
			
			// output synchronization signals
			hsync <= ~((next_pixel >= WIDTH + H_FRONT_PORCH) & 
						  (next_pixel < WIDTH + H_FRONT_PORCH + H_SYNC));
			vsync <= ~((next_line >= HEIGHT + V_FRONT_PORCH) &
						  (next_line < HEIGHT + V_FRONT_PORCH + V_SYNC));
		end
	end
	
	// next pixel and line
	assign next_pixel = (pixel_count >= NUM_PIXELS - 1) ? 1'b0 : pixel_count + 1'b1;
	assign next_line = (pixel_count >= NUM_PIXELS - 1) ? 
								((line_count >= NUM_LINES - 1) ? 1'b0 : line_count + 1'b1) : line_count;
								
	

endmodule
module oled_spi_tb;

	// Inputs
	reg clock;
	reg reset;
	reg shutdown;

	// Outputs
	wire cs;
	wire sdin;
	wire sclk;
	wire dc;
	wire res;
	wire vbatc;
	wire vddc;

	// Instantiate the Unit Under Test (UUT)
	oled_spi uut (
		.clock(clock), 
		.reset(reset), 
		.shutdown(shutdown), 
		.cs(cs), 
		.sdin(sdin), 
		.sclk(sclk), 
		.dc(dc), 
		.res(res), 
		.vbatc(vbatc), 
		.vddc(vddc)
	);

	initial begin
		// Initialize Inputs
		clock = 0;
		reset = 1;
		shutdown = 0;

		// Wait 100 ns for global reset to finish
		#100 reset = 0;
	end
  
  always begin
    #10 clock = !clock;
  end
      
endmodule
module cls_spi_tb;

	// Inputs
	reg clock;
	reg reset;
	reg [31:0] data;
	reg miso;

	// Outputs
	wire ss;
	wire mosi;
	wire sclk;

	// Instantiate the Unit Under Test (UUT)
	cls_spi uut (
		.clock(clock), 
		.reset(reset), 
		.data(data), 
		.ss(ss), 
		.mosi(mosi), 
		.miso(miso), 
		.sclk(sclk)
	);

	initial begin
		// Initialize Inputs
		clock = 0;
		reset = 1;
		data = 32'h89ABCDEF;
		miso = 0;

		// Wait 100 ns for global reset to finish
		#100 reset = 0;
	end
  
  always begin
    #10 clock = !clock;
  end
      
endmodule
module tv80_reg (/*AUTOARG*/
  // Outputs
  DOBH, DOAL, DOCL, DOBL, DOCH, DOAH, BC, DE, HL,
  // Inputs
  AddrC, AddrA, AddrB, DIH, DIL, clk, CEN, WEH, WEL
  );
    input  [2:0] AddrC;
    output [7:0] DOBH;
    input  [2:0] AddrA;
    input  [2:0] AddrB;
    input  [7:0] DIH;
    output [7:0] DOAL;
    output [7:0] DOCL;
    input  [7:0] DIL;
    output [7:0] DOBL;
    output [7:0] DOCH;
    output [7:0] DOAH;
    input  clk, CEN, WEH, WEL;
	 
	 output [15:0] BC;
	 output [15:0] DE;
	 output [15:0] HL;

  reg [7:0] RegsH [0:7];
  reg [7:0] RegsL [0:7];

  always @(posedge clk)
    begin
      if (CEN)
        begin
          if (WEH) RegsH[AddrA] <= DIH;
          if (WEL) RegsL[AddrA] <= DIL;
        end
    end
          
  assign DOAH = RegsH[AddrA];
  assign DOAL = RegsL[AddrA];
  assign DOBH = RegsH[AddrB];
  assign DOBL = RegsL[AddrB];
  assign DOCH = RegsH[AddrC];
  assign DOCL = RegsL[AddrC];

  // break out ram bits for waveform debug
  wire [7:0] H = RegsH[2];
  wire [7:0] L = RegsL[2];
  
  assign BC = { RegsH[0], RegsL[0] };
  assign DE = { RegsH[1], RegsL[1] };
  assign HL = { RegsH[2], RegsL[2] };
  
// synopsys dc_script_begin
// set_attribute current_design "revision" "$Id: tv80_reg.v,v 1.1 2004-05-16 17:39:57 ghutchis Exp $" -type string -quiet
// synopsys dc_script_end
endmodule
module tt_um_rejunity_1_58bit (
    input  wire [7:0] ui_in,    // Dedicated inputs
    output wire [7:0] uo_out,   // Dedicated outputs
    input  wire [7:0] uio_in,   // IOs: Input path
    output wire [7:0] uio_out,  // IOs: Output path
    output wire [7:0] uio_oe,   // IOs: Enable path (active high: 0=input, 1=output)
    input  wire       ena,      // will go high when the design is enabled
    input  wire       clk,      // clock
    input  wire       rst_n     // reset_n - low to reset
);
    assign uio_oe  = 0;         // bidirectional IOs set to INPUT
    assign uio_out = 0;         // drive bidirectional IO outputs to 0

    wire reset = ! rst_n;

    // decode ternary weights
    wire [3:0] weights_zero = ~ { |ui_in[1:0], |ui_in[3:2],  |ui_in[5:4], |ui_in[7:6] };
    wire [3:0] weights_sign =   {  ui_in[1  ],  ui_in[3  ],   ui_in[5  ],  ui_in[7  ] };

    // wire [3:0] weights_zero = ~ { |ui_in[7:6], |ui_in[5:4],  |ui_in[3:2], |ui_in[1:0] };
    // wire [3:0] weights_sign =   {  ui_in[7  ],  ui_in[5  ],   ui_in[3  ],  ui_in[1  ] };

    // @TODO: special weight to initiate readout
    wire       initiate_read_out = !ena;
    
    systolic_array systolic_array(
        .clk(clk),
        .reset(reset),

        .in_left_zero(weights_zero),
        .in_left_sign(weights_sign),
        .in_top(uio_in),

        .restart_inputs(initiate_read_out),
        .reset_accumulators(initiate_read_out),
        .copy_accumulator_values_to_out_queue(initiate_read_out),
        .restart_out_queue(initiate_read_out),
        
        .out(uo_out)
    );

endmodule
module tt_um_rejunity_1_58bit (
    input  wire [7:0] ui_in,    // Dedicated inputs
    output wire [7:0] uo_out,   // Dedicated outputs
    input  wire [7:0] uio_in,   // IOs: Input path
    output wire [7:0] uio_out,  // IOs: Output path
    output wire [7:0] uio_oe,   // IOs: Enable path (active high: 0=input, 1=output)
    input  wire       ena,      // will go high when the design is enabled
    input  wire       clk,      // clock
    input  wire       rst_n     // reset_n - low to reset
);
    assign uio_oe  = 0;         // bidirectional IOs set to INPUT
    assign uio_out = 0;         // drive bidirectional IO outputs to 0

    wire reset = ! rst_n;

    // decode ternary weights
    wire [3:0] weights_zero = ~ { |ui_in[1:0], |ui_in[3:2],  |ui_in[5:4], |ui_in[7:6] };
    wire [3:0] weights_sign =   {  ui_in[1  ],  ui_in[3  ],   ui_in[5  ],  ui_in[7  ] };

    // wire [3:0] weights_zero = ~ { |ui_in[7:6], |ui_in[5:4],  |ui_in[3:2], |ui_in[1:0] };
    // wire [3:0] weights_sign =   {  ui_in[7  ],  ui_in[5  ],   ui_in[3  ],  ui_in[1  ] };

    // @TODO: special weight to initiate readout
    wire       initiate_read_out = !ena;
    
    systolic_array systolic_array(
        .clk(clk),
        .reset(reset),

        .in_left_zero(weights_zero),
        .in_left_sign(weights_sign),
        .in_top(uio_in),
        .reset_accumulators(initiate_read_out),
        .copy_accumulator_values_to_out_queue(initiate_read_out),
        .restart_out_queue(initiate_read_out),
        
        .out(uo_out)
    );

endmodule