UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
364 Views
Registered: ‎06-11-2019

Verilog vs VHDL

I'm trying to create a Verilog block that is equivalent to a VHDL source I have.

Here's the VHDL... it's a simple multi-stage pipeline register with variable port width.

library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;

entity pipe_reg is
    generic (
        G_PIPE_CLOCKS   : natural;
        G_DATA_LENGTH   : positive
    );
    port (
        clk             : in  std_logic;
        rst             : in  std_logic;
        din_tdata       : in  std_logic_vector(G_DATA_LENGTH-1 downto 0);
        din_tvalid      : in  std_logic;
        din_tlast       : in  std_logic;
        dout_tdata      : out std_logic_vector(G_DATA_LENGTH-1 downto 0);
        dout_tvalid     : out std_logic;
        dout_tlast      : out std_logic
    );
end entity pipe_reg;

architecture RTL of pipe_reg is

    type T_Delay_Tdata is array (0 to G_PIPE_CLOCKS-1) of std_logic_vector(G_DATA_LENGTH-1 downto 0);
    signal delay_tdata  : T_Delay_Tdata;
    signal delay_tvalid : std_logic_vector(0 to G_PIPE_CLOCKS-1);
    signal delay_tlast  : std_logic_vector(0 to G_PIPE_CLOCKS-1);

begin

    G_ZERO : if G_PIPE_CLOCKS = 0 generate
        dout_tvalid <= din_tvalid;
        dout_tdata  <= din_tdata;
        dout_tlast  <= din_tlast;
    end generate G_ZERO;

    G_NONZERO : if G_PIPE_CLOCKS /= 0 generate
        S_REG : process(clk) begin
            if rising_edge(clk) then
                if rst = '1' then
                    delay_tvalid <= (others => '0');
                else
                    for i in 0 to G_PIPE_CLOCKS-1 loop
                        if i = 0 then
                            delay_tdata(0)  <= din_tdata;
                            delay_tvalid(0) <= din_tvalid;
                            delay_tlast(0)  <= din_tlast;
                        else
                            delay_tdata(i)  <= delay_tdata(i-1);
                            delay_tvalid(i) <= delay_tvalid(i-1);
                            delay_tlast(i)  <= delay_tlast(i-1);
                        end if;
                    end loop;
                end if;
            end if;
        end process;
        dout_tdata  <= delay_tdata(G_PIPE_CLOCKS-1);
        dout_tvalid <= delay_tvalid(G_PIPE_CLOCKS-1);
        dout_tlast  <= delay_tlast(G_PIPE_CLOCKS-1);
    end generate G_NONZERO;

end RTL;

Here's the Verilog I came up with:

module pipe_reg_v #(
    parameter	G_PIPE_CLOCKS = 2,
    parameter   G_DATA_LENGTH = 32) (

    input clk,
    input rst,
    input [(G_DATA_LENGTH-1):0] din_tdata,
    input din_tvalid,
    input din_tlast,

    output [(G_DATA_LENGTH-1):0] dout_tdata,
    output dout_tvalid,
    output dout_tlast);

    // internal registers

    reg [(G_DATA_LENGTH-1):0] delay_tdata [0:(G_PIPE_CLOCKS-1)];
    reg [0:(G_PIPE_CLOCKS-1)] delay_tvalid;
    reg [0:(G_PIPE_CLOCKS-1)] delay_tlast;

    // internal signals

generate
    if (G_PIPE_CLOCKS == 0)
        begin: G_ZERO
        assign dout_tvalid = din_tvalid;
        assign dout_tdata  = din_tdata;
        assign dout_tlast  = din_tlast;
        end // G_ZERO
    else
        begin: G_NONZERO
        integer i;
        always @ (posedge clk)
            begin // always @ (posedge clk)
            if (rst == 1)
                begin // if (rst == 1)
                delay_tvalid <= 'd0;
                //delay_tlast <= 'd0;
                //for(i=0;i<G_PIPE_CLOCKS; i=i+1)
                    //begin // for(i=0;i<G_PIPE_CLOCKS; i=i+1)
                    //delay_tdata[i] <= 'd0;
                    //end // for(i=0;i<G_PIPE_CLOCKS; i=i+1)
                end  // if (rst == 1)
            else
                begin // else
                for(i=0; i<G_PIPE_CLOCKS; i=i+1)
                    begin //for(i=0; i<G_PIPE_CLOCKS; i=i+1)
                    if (i == 0)
                        begin // if (i == 0)
                        delay_tdata[0]  <= din_tdata;
                        delay_tvalid[0] <= din_tvalid;
                        delay_tlast[0]  <= din_tlast;
                        end // if (i == 0)
                    else
                        begin // else
                        delay_tdata[i]  <= delay_tdata[i-1];
                        delay_tvalid[i] <= delay_tvalid[i-1];
                        delay_tlast[i]  <= delay_tlast[i-1];
                        end // else
                    end // for(i=0; i<G_PIPE_CLOCKS; i=i+1)
                end // else
             end // always @ (posedge clk)
        assign dout_tdata  = delay_tdata[G_PIPE_CLOCKS-1];
        assign dout_tvalid = delay_tvalid[G_PIPE_CLOCKS-1];
        assign dout_tlast  = delay_tlast[G_PIPE_CLOCKS-1];
        end // G_NONZERO
endgenerate
endmodule

Here's the test bench I came up with to look at the two side-by-side:

module pipe_reg_tb(
    );
    parameter	PIPE_CLOCKS = 4;
    parameter   DATA_LENGTH = 14;
    
    reg clk, reset;
    reg [(DATA_LENGTH-1):0] din_tdata;
    reg din_tvalid;
    reg din_tlast;

    wire [(DATA_LENGTH-1):0] dout_tdata;
    wire dout_tvalid;
    wire dout_tlast;
    
    wire [(DATA_LENGTH-1):0] dout_tdata_ref;
    wire dout_tvalid_ref;
    wire dout_tlast_ref;

    pipe_reg_v uut  (
        .clk         (clk),
        .rst         (reset),
        .din_tdata   (din_tdata),
        .din_tvalid  (din_tvalid),
        .din_tlast   (din_tlast),
        .dout_tdata  (dout_tdata),
        .dout_tvalid (dout_tvalid),
        .dout_tlast  (dout_tlast)
        );
    defparam uut.G_PIPE_CLOCKS = PIPE_CLOCKS;
    defparam uut.G_DATA_LENGTH = DATA_LENGTH;    

    pipe_reg uut_ref (
        .clk         (clk),
        .rst         (reset),
        .din_tdata   (din_tdata),
        .din_tvalid  (din_tvalid),
        .din_tlast   (din_tlast),
        .dout_tdata  (dout_tdata_ref),
        .dout_tvalid (dout_tvalid_ref),
        .dout_tlast  (dout_tlast_ref)
        );
    defparam uut_ref.G_PIPE_CLOCKS = PIPE_CLOCKS;
    defparam uut_ref.G_DATA_LENGTH = DATA_LENGTH; 
    initial
    begin
        clk = 1;
        reset = 0;
        din_tvalid = 0;
        din_tlast = 0;
        #5
        din_tvalid = 1;
        din_tdata = 'd17;
        #10
        din_tdata = 'd18;
        #10
        din_tdata = 'd19;
        #10
        din_tdata = 'd20;                        
        #10
        din_tdata = 'd21;
        #10
        din_tdata = 'd22;
        #10
        din_tdata = 'd23;
        #10
        din_tdata = 'd24;
        #10
        din_tdata = 'd25;
        #10
        din_tdata = 'd26;
        #10
        din_tdata = 'd27;
        #10
        din_tdata = 'd28;
        #10
        din_tdata = 'd29;
        #10
        din_tlast = 1;
        din_tdata = 'd30;
        #100
        din_tvalid = 0;
        #10
        reset = 1;     
    end
    always
        #5 clk = !clk;
endmodule

When I generate the elaboration schematic using the test bench as the top level and expand out the two UUTs, I get two blocks that look pretty similar.  There is a small difference (an array of mux in the VHDL (uut_ref) vs. single muxed in the Verilog (uut) connected to the clock enable lines of the delay_tdata registers, but functionally it looks like they should be the same.

schematic.png

But when I simulate them side-by-side, I get a little different behavior when I set rst high:

Screenshot from 2019-11-22 09-55-30.png

You see the difference in behavior at 250ns... in uut, dout_tdata and dout_tlast values are held, whereas in uut_ref they're not.

If I look at my Verilog code for when rst is high:

            if (rst == 1)
                begin // if (rst == 1)
                delay_tvalid <= 'd0;
                //delay_tlast <= 'd0;
                //for(i=0;i<G_PIPE_CLOCKS; i=i+1)
                    //begin // for(i=0;i<G_PIPE_CLOCKS; i=i+1)
                    //delay_tdata[i] <= 'd0;
                    //end // for(i=0;i<G_PIPE_CLOCKS; i=i+1)
                end  // if (rst == 1)

and uncomment out the last several lines before the end statement, the behavior of the two is the same.  But the elaboration schematic is not.

I'm kind of a newb at this... what am I missing?  Might it have to do with the differences in how Verilog and VHDL handle 2d arrays?

Any help would be appreciated.

Thanks,
Scott

0 Kudos
8 Replies
345 Views
Registered: ‎07-23-2019

Re: Verilog vs VHDL

 

I think you should have

        dout_tdata  <= delay_tdata[G_PIPE_CLOCKS-1];
        dout_tvalid <= delay_tvalid[G_PIPE_CLOCKS-1];
        dout_tlast  <= delay_tlast[G_PIPE_CLOCKS-1];

instead of

        assign dout_tdata  = delay_tdata[G_PIPE_CLOCKS-1];
        assign dout_tvalid = delay_tvalid[G_PIPE_CLOCKS-1];
        assign dout_tlast  = delay_tlast[G_PIPE_CLOCKS-1];

in your verilog code.

0 Kudos
326 Views
Registered: ‎06-11-2019

Re: Verilog vs VHDL


@archangel-lightworks wrote:

 

I think you should have

        dout_tdata  <= delay_tdata[G_PIPE_CLOCKS-1];
        dout_tvalid <= delay_tvalid[G_PIPE_CLOCKS-1];
        dout_tlast  <= delay_tlast[G_PIPE_CLOCKS-1];

instead of

        assign dout_tdata  = delay_tdata[G_PIPE_CLOCKS-1];
        assign dout_tvalid = delay_tvalid[G_PIPE_CLOCKS-1];
        assign dout_tlast  = delay_tlast[G_PIPE_CLOCKS-1];

in your verilog code.


That doesn't work... for each statement I get, for example, 'dout_tdata is an unknown type'

From what I understand, ports are, by default, type wire, so they should be set by continuous assignment.

0 Kudos
Scholar dgisselq
Scholar
218 Views
Registered: ‎05-21-2015

Re: Verilog vs VHDL

scott.bennett@jhuapl.edu,

Ok, I've stared at this pretty hard and I'm not seeing it either.  Have you discovered anything?

Dan

0 Kudos
162 Views
Registered: ‎06-11-2019

Re: Verilog vs VHDL

At this point, I haven't.

Honestly, the Verilog makes more sense as to what I should be seeing.  I'm not sure why the VHDL makes any changes to those two lines, since they're not explicitly changed at that point in the code.

So I've basically moved on.  I may revisit this as I integrate this into my overall code if I get things that look screwy.

Thanks,
Scott

0 Kudos
Scholar dpaul24
Scholar
155 Views
Registered: ‎08-07-2014

Re: Verilog vs VHDL

scott.bennett@jhuapl.edu,

Are you using the Vivado xsim?

If this is not a school exercise..............easy way out......is to enable mixed-mode simulation in Vivado! :-)

--------------------------------------------------------------------------------------------------------
FPGA enthusiast!
All PMs will be ignored
--------------------------------------------------------------------------------------------------------
0 Kudos
120 Views
Registered: ‎06-11-2019

Re: Verilog vs VHDL

Yes, I am using Vivado xsim.

While it's not a school exercise, it is something I'm doing at least partially for learning purposes.  I'm more familiar with Verilog than VHDL, so I'm taking advantage of that familiarity to learn all these blocks within a larger project and to better understand VHDL.

But there are some other project-specific reasons that I'm doing this as well, so I can't necessarily just use mixed-mode.

0 Kudos
Adventurer
Adventurer
81 Views
Registered: ‎05-09-2018

Re: Verilog vs VHDL

What version of the simulator are you using.

It seems appears that this is a simulator bug (The VHDL code is not behaving corectly).

I ran your code in 2019.1.3 and it appears to work properly there.

 

0 Kudos
Adventurer
Adventurer
74 Views
Registered: ‎05-09-2018

Re: Verilog vs VHDL

FYI,

I also ran it in Modelsim. It behaves properly there as well.

I did have to change the instantion mode for the VHDL to this (For Modelsim).

I believe this is a more compatible way of passing parameters to a VHDL submodule.

 pipe_reg #(4,14) uut_ref 
(
        .clk         (clk),
        .rst         (reset),
        .din_tdata   (din_tdata),
        .din_tvalid  (din_tvalid),
        .din_tlast   (din_tlast),
        .dout_tdata  (dout_tdata_ref),
        .dout_tvalid (dout_tvalid_ref),
        .dout_tlast  (dout_tlast_ref)
        );

 

0 Kudos