Continue to Site

[SOLVED] OSERDES output data delay

alexeyey_0

Newbie
Newbie level 3
Joined
Apr 2, 2025
Messages
3
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
23
Hello everyone, I'm currently writing an image processing project on systemverilog (somewhat similar to MIPI DSI). When working with the Xilinx ip block, I encountered such a problem that the data is not displayed at the moment specified in the specification. I decided to compare the implementation on systemverilog and on vhdl. The result: there is a 0.1 ps delay on sv, and data is displayed strictly in clock cycles on vhdl. I want to get the result as on vhdl, that is, without delays in sending data to the output transmission line. What could be the problem and how to solve it? I am attaching 2 testbench, one is written strictly on sv, the other on vhdl. I also attach 2 time charts.: 1 - sv, 2 - vhdl
1. sv tb

Code:
`timescale 1ns / 1ps

module tb_dvi;

  logic clk = 0;
  logic clk_x5 = 0;
  logic [9:0] data = 10'b0;
  logic reset = 1;
  logic serial;

  logic shift1;
  logic shift2;
  logic ce_delay;
  logic [7:0] reset_delay;

  localparam time clock_period = 20;

  // Master OSERDESE2
  OSERDESE2 #(
    .DATA_RATE_OQ("DDR"),
    .DATA_RATE_TQ("DDR"),
    .DATA_WIDTH(10),
    .INIT_OQ(1'b1),
    .INIT_TQ(1'b1),
    .SERDES_MODE("MASTER"),
    .SRVAL_OQ(1'b0),
    .SRVAL_TQ(1'b0),
    .TBYTE_CTL("FALSE"),
    .TBYTE_SRC("FALSE"),
    .TRISTATE_WIDTH(1)
  ) master_serdes (
    .OFB(),
    .OQ(serial),
    .SHIFTOUT1(),
    .SHIFTOUT2(),
    .TBYTEOUT(),
    .TFB(),
    .TQ(),
    .CLK(clk_x5),
    .CLKDIV(clk),
    .D1(data[0]),
    .D2(data[1]),
    .D3(data[2]),
    .D4(data[3]),
    .D5(data[4]),
    .D6(data[5]),
    .D7(data[6]),
    .D8(data[7]),
    .OCE(ce_delay),
    .RST(reset),
    .SHIFTIN1(shift1),
    .SHIFTIN2(shift2),
    .T1(1'b0),
    .T2(1'b0),
    .T3(1'b0),
    .T4(1'b0),
    .TBYTEIN(1'b0),
    .TCE(1'b0)
  );

  // Slave OSERDESE2
  OSERDESE2 #(
    .DATA_RATE_OQ("DDR"),
    .DATA_RATE_TQ("DDR"),
    .DATA_WIDTH(10),
    .INIT_OQ(1'b1),
    .INIT_TQ(1'b1),
    .SERDES_MODE("SLAVE"),
    .SRVAL_OQ(1'b0),
    .SRVAL_TQ(1'b0),
    .TBYTE_CTL("FALSE"),
    .TBYTE_SRC("FALSE"),
    .TRISTATE_WIDTH(1)
  ) slave_serdes (
    .OFB(),
    .OQ(),
    .SHIFTOUT1(shift1),
    .SHIFTOUT2(shift2),
    .TBYTEOUT(),
    .TFB(),
    .TQ(),
    .CLK(clk_x5),
    .CLKDIV(clk),
    .D1(1'b0),
    .D2(1'b0),
    .D3(data[8]),
    .D4(data[9]),
    .D5(1'b0),
    .D6(1'b0),
    .D7(1'b0),
    .D8(1'b0),
    .OCE(ce_delay),
    .RST(reset),
    .SHIFTIN1(1'b0),
    .SHIFTIN2(1'b0),
    .T1(1'b0),
    .T2(1'b0),
    .T3(1'b0),
    .T4(1'b0),
    .TBYTEIN(1'b0),
    .TCE(1'b0)
  );

  always_ff @(posedge clk) begin
    ce_delay <= ~reset;
  end

  initial forever #(clock_period / 4) clk = ~clk;

  initial forever #(clock_period / 20) clk_x5 = ~clk_x5;
 
  initial begin
    #200 reset = 0;
    #200 data  = 10'b1100010101; // 10'h315
    #20  data  = 10'b1100110101; // 10'h335
    #20  data  = 10'b1100100100; // 10'h324
    #20  $finish;
  end
 
endmodule

2. vhdl tb

Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VComponents.all;

ENTITY tb_ser IS
END tb_ser;

ARCHITECTURE behavior OF tb_ser IS
  
    signal clk     : std_logic := '0';
    signal clk_x5  : std_logic := '0';
    signal data    : std_logic_vector(9 downto 0) := (others => '0');
    signal reset   : std_logic := '1'; -- Начальное состояние '1'
    signal serial  : std_logic := '0';

    signal shift1      : std_logic := '0';
    signal shift2      : std_logic := '0';
    signal ce_delay    : std_logic := '0';
    signal reset_delay : std_logic_vector(7 downto 0) := (others => '0');

    constant clock_period : time := 20 ns;
  
BEGIN

master_serdes : OSERDESE2
   generic map (
      DATA_RATE_OQ => "DDR",   -- DDR, SDR
      DATA_RATE_TQ => "DDR",   -- DDR, BUF, SDR
      DATA_WIDTH => 10,         -- Parallel data width (2-8,10,14)
      INIT_OQ => '1',          -- Initial value of OQ output (1'b0,1'b1)
      INIT_TQ => '1',          -- Initial value of TQ output (1'b0,1'b1)
      SERDES_MODE => "MASTER", -- MASTER, SLAVE
      SRVAL_OQ => '0',         -- OQ output value when SR is used (1'b0,1'b1)
      SRVAL_TQ => '0',         -- TQ output value when SR is used (1'b0,1'b1)
      TBYTE_CTL => "FALSE",    -- Enable tristate byte operation (FALSE, TRUE)
      TBYTE_SRC => "FALSE",    -- Tristate byte source (FALSE, TRUE)
      TRISTATE_WIDTH => 1      -- 3-state converter width (1,4)
   )
   port map (
      OFB       => open,
      OQ        => serial,
      SHIFTOUT1 => open,
      SHIFTOUT2 => open,
      TBYTEOUT  => open,
      TFB       => open,
      TQ        => open,
      CLK       => clk_x5,
      CLKDIV    => clk,
      D1 => data(0),
      D2 => data(1),
      D3 => data(2),
      D4 => data(3),
      D5 => data(4),
      D6 => data(5),
      D7 => data(6),
      D8 => data(7),
      OCE => ce_delay,
      RST => reset,
      SHIFTIN1 => SHIFT1,
      SHIFTIN2 => SHIFT2,
      T1 => '0',
      T2 => '0',
      T3 => '0',
      T4 => '0',
      TBYTEIN => '0',
      TCE => '0'
   );

slave_serdes : OSERDESE2
   generic map (
      DATA_RATE_OQ   => "DDR",
      DATA_RATE_TQ   => "DDR",
      DATA_WIDTH     => 10,
      INIT_OQ        => '1',
      INIT_TQ        => '1',
      SERDES_MODE    => "SLAVE",
      SRVAL_OQ       => '0',
      SRVAL_TQ       => '0',
      TBYTE_CTL      => "FALSE",
      TBYTE_SRC      => "FALSE",
      TRISTATE_WIDTH => 1
   )
   port map (
      OFB       => open,
      OQ        => open,
      SHIFTOUT1 => shift1,
      SHIFTOUT2 => shift2,
      TBYTEOUT  => open,
      TFB       => open,
      TQ        => open,
      CLK       => clk_x5,
      CLKDIV    => clk,
      D1       => '0',
      D2       => '0',
      D3       => data(8),
      D4       => data(9),
      D5       => '0',
      D6       => '0',
      D7       => '0',
      D8       => '0',
      OCE      => ce_delay,
      RST      => reset,
      SHIFTIN1 => '0',
      SHIFTIN2 => '0',
      T1       => '0',
      T2       => '0',
      T3       => '0',
      T4       => '0',
      TBYTEIN  => '0',
      TCE      => '0'
   );

delay_ce: process(clk)
    begin
        if rising_edge(clk) then
            ce_delay <= not reset;
        end if;
    end process;

    -- Генерация основного тактового сигнала (clk 50 MHz)
    clock_process : process
    begin
        while true loop
            clk <= '0';
            wait for clock_period / 4;
            clk <= '1';
            wait for clock_period / 4;
        end loop;
    end process;

    -- Генерация быстрого тактового сигнала (clk_x5 250 MHz)
    clock_x5_process : process
    begin
        while true loop
            clk_x5 <= '0';
            wait for clock_period / 20;
            clk_x5 <= '1';
            wait for clock_period / 20;
        end loop;
    end process;

    -- Стимулы для тестирования
    stim_proc: process
    begin
        wait for 200 ns;
        reset <= '0';  -- Сброс выключен
        wait for 200 ns;
      
        -- Подача данных на вход
        data <= "1100010101";  -- 10'h315 в двоичном формате
        wait for 20 ns;
        data <= "1100110101";  -- 10'h335
        wait for 20 ns;
        data <= "1100100100";  -- 10'h324
        wait for 20 ns;

        wait;
    end process;

END behavior;
 

Attachments

  • sv_tb.png
    sv_tb.png
    15.5 KB · Views: 39
  • vhdl_tb.png
    vhdl_tb.png
    13.4 KB · Views: 36
SystemVerilog uses an event-driven simulation model with delta cycles, where a small delay (e.g., 0.1 ps) can be introduced due to scheduling order.
Explicitly align ce_delay with posedge clk using non-blocking assignments (<=):
Code:
always_ff @(posedge clk) begin
    ce_delay <= ~reset;
end
Avoiding blocking (=) assignments inside clocked always blocks can reduce unexpected propagation delays.
 
SystemVerilog uses an event-driven simulation model with delta cycles, where a small delay (e.g., 0.1 ps) can be introduced due to scheduling order.
Explicitly align ce_delay with posedge clk using non-blocking assignments (<=):
Code:
always_ff @(posedge clk) begin
    ce_delay <= ~reset;
end
Avoiding blocking (=) assignments inside clocked always blocks can reduce unexpected propagation delays.
I'm already using it
 
At the SV SS, I see that serial, shift1, shift2, has a delayed transition after the rising_edge of the clk_x5.
But at the VHDL SS; the clk_x5 and serial seems to be rising/transiting to High at the same time.

In order to find out what is wrong or why the diff occurs, you need to show us the complete RTL code for both cases where you are driving serial, shift1, shift2!
 
At the SV SS, I see that serial, shift1, shift2, has a delayed transition after the rising_edge of the clk_x5.
But at the VHDL SS; the clk_x5 and serial seems to be rising/transiting to High at the same time.

In order to find out what is wrong or why the diff occurs, you need to show us the complete RTL code for both cases where you are driving serial, shift1, shift2!
I've dropped the testbench codes in this topic. I'm only considering the isolated operation of OSERDES so far. Only OSERDES and nothing more. If they work the same way in the test bench as in the images, then they will work the same way in the real project.
 


Write your reply...

LaTeX Commands Quick-Menu:

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top