Search code examples
vhdlvivado

How to compare two 'std_logic_vector' type in VHDL?


I'm trying to convert some code from Verilog to VHDL for project need. The original code is in Verilog, the aim of the code is to realizing MIG DDR2/3 write and read, partly shown as following:

module ddr3_rw #
( 
    parameter   integer                 WR_LEN      = 1024      ,
    parameter   integer                 DATA_WIDTH  = 128       ,
    parameter   integer                 ADDR_WIDTH  = 28
)(     
    input                               ui_clk                  ,
    input                               ui_clk_sync_rst         ,
    input                               init_calib_complete     ,

    input                               app_rdy                 ,
    input                               app_wdf_rdy             ,
    input                               app_rd_data_valid       ,
    input       [DATA_WIDTH - 1:0]      app_rd_data             ,
    output  reg [ADDR_WIDTH - 1:0]      app_addr                ,                    
    output                              app_en                  ,
    output                              app_wdf_wren            ,
    output                              app_wdf_end             ,
    output      [2:0]                   app_cmd                 ,
    output  reg [DATA_WIDTH - 1:0]      app_wdf_data            ,   
    output  reg                         error_flag
    );
        
localparam                  IDLE    = 4'b0001       ; 
localparam                  WRITE   = 4'b0010       ; 
localparam                  WAIT    = 4'b0100       ; 
localparam                  READ    = 4'b1000       ; 
//reg define ----------------------------------------
reg [3:0]                   cur_state               ;   
reg [3:0]                   next_state              ;   
reg [ADDR_WIDTH - 1:0]      rd_addr_cnt             ;
reg [ADDR_WIDTH - 1:0]      wr_addr_cnt             ;   
reg [ADDR_WIDTH - 1:0]      rd_cnt                  ;       
//wire define ---------------------------------------                                       
wire                        error                   ;   
wire                        rst_n                   ;  
wire                        wr_proc                 ;   
wire                        wr_last                 ;
wire                        rd_addr_last            ;
 

assign rst_n = ~ui_clk_sync_rst;
assign app_en = app_rdy && ((cur_state == WRITE && app_wdf_rdy) || cur_state == READ);              
assign app_wdf_wren = (cur_state == WRITE) && wr_proc;
assign app_wdf_end = app_wdf_wren; 
assign app_cmd = (cur_state == READ) ? 3'd1 :3'd0;
assign wr_proc = ~app_cmd && app_rdy && app_wdf_rdy;
assign wr_last = app_wdf_wren && (wr_addr_cnt == WR_LEN - 1) ;
assign rd_addr_last = (rd_addr_cnt == WR_LEN - 1) && app_rdy && app_cmd;

and here is how I convert:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_arith.ALL;
use IEEE.std_logic_unsigned;
use IEEE.std_logic_misc;
use IEEE.NUMERIC_STD.ALL;

entity ddr2_rw is
    generic (
        WR_LEN:         integer := 1024;
        DATA_WIDTH:     integer := 128;
        ADDR_WIDTH:     integer := 28);
    port (
        ui_clk:              in      std_logic;
        ui_clk_sync_rst:     in      std_logic;
        init_calib_complate: in      std_logic;
        app_rdy:             in      std_logic;
        app_wdf_rdy:         in      std_logic;
        app_rd_data_valid:   in      std_logic;
        app_rd_data:         out     std_logic_vector(DATA_WIDTH-1 downto 0);
        app_addr:            out     std_logic_vector(ADDR_WIDTH-1 downto 0);
        app_en:              out     std_logic;
        app_wdf_wren:        out     std_logic;
        app_wdf_end:         out     std_logic;
        app_cmd:             out     std_logic_vector(2 downto 0);
        app_wdf_data:        out     std_logic_vector(DATA_WIDTH-1 downto 0));
end ddr2_rw;

architecture ddr2_rw_arch of ddr2_rw is

    constant IDLE:      std_logic_vector(3 downto 0) := "0001";
    constant WRITE:     std_logic_vector(3 downto 0) := "0010";
    constant WAITTING:  std_logic_vector(3 downto 0) := "0100";
    constant READ:      std_logic_vector(3 downto 0) := "1000";
    
    type state is( IDLE, WRITE, WATTING, READ);
    signal cur_state, next_state:   state;

    signal rd_addr_cnt: std_logic_vector(ADDR_WIDTH-1 downto 0);
    signal wr_addr_cnt: std_logic_vector(ADDR_WIDTH-1 downto 0);
    signal rd_cnt:      std_logic_vector(ADDR_WIDTH-1 downto 0);
    
    signal rst_n:       std_logic;
    signal error:       std_logic;
    signal wr_proc:     std_logic;
    signal wr_last:     std_logic;
    signal rd_addr_last:std_logic;
    
begin
    rst_n <= not ui_clk_sync_rst;
    wr_last <= app_wdf_wren and (conv_integer(wr_addr_cnt) = WR_LEN-1);

    process begin
        case cur_state is 
            when WRITE =>   app_en <= app_rdy and app_wdf_rdy;
                            app_wdf_wren <= wr_proc;
                            app_wdf_end <= app_wdf_wren;
                            app_cmd <= "000";
            when READ =>    app_en <= app_rdy;
                            app_cmd <= "001";
                            wr_proc <= app_rdy and app_wdf_rdy;
            when others =>  app_en <= '0';
                            app_cmd <= "000";
        end case;
    end process;

end ddr2_rw_arch;

before that, I tried to convert assign app_en = app_rdy && ((cur_state == WRITE && app_wdf_rdy) || cur_state == READ); to app_en <= app_rdy and ((cur_state = WRITE and app_wdf_rdy) or cur_state = READ); in VHDL, but Vivado report "No suitable operator definition found for '='", so I changed this-alike code to case-clause block, as shown above. However there still have two errors in the clause wr_last <= app_wdf_wren and (conv_integer(wr_addr_cnt) = WR_LEN-1);, one is conv_integer function, Vivado report "No matching subprogram was found"; the other is still at =:"No suitable operator definition found for '='".

Now I have two question:

  1. How to fix theses errors?
  2. How to briefly write VHDL code to compare two array type such as std_logic_vector in VHDL, and return if it is identical?

Thank you for your time to answer these questions!


Solution

  • The problem you are having is the function conv_integer() does not accept a std_logic_vector as an argument. These are the 4 supported datatypes.

    You should do a double conversion for that. For more information on that I suggest reading on numeric_std, the official IEEE package, which you already include.

    Regarding your second error, I am not entirely sure, but I think the problem is you are using the equality operator in a signal assignment. This operator returns a boolean, which is not assignable to a std_logic signal and therefore cannot be used in the same line (Vivado thinks it must be another operator then).

    To try and fix both errors, as well as adding clarity to your code, I would change some lines to the following:

        signal wr_addr_cnt_is_wr_length : std_logic;
    
    begin
        rst_n <= not ui_clk_sync_rst;
        wr_addr_cnt_is_wr_length <= '1' when (to_integer(unsigned(wr_addr_cnt)) = (WR_LEN-1)) else '0';
        wr_last <= app_wdf_wren and wr_addr_cnt_is_wr_length;