Jump to content

    
RobFPGA

Актуальный размер структуры определенной в interface

Recommended Posts

Приветствую

Возник вот такой вопрос- Есть   интерфейс  с пучком сигналов  которые для удобства определены как структура

interface if_TEST #(ID_WH=3) ;
  typedef struct packed {
    u1_t [ID_WH-1:0]  sig0;
    u1_t              sig1;
    u7_t              sig2;
    //...
  } st_TEST_t;

  st_TEST_t st;
  bit       valid;
  bit       ready;

  modport in (input  st, valid, output ready);
  modport ou (output st, valid, input  ready);
endinterface

и хочется мне в месте где такой интерфейс применяется  получить  актуальную ширину структуры в битах. Поскольку реальное значение будет зависит от параметра  который меняется при инстанцировании интерфейса.  Казалось  бы  что проще   

module test (if_TEST.in if_test, ...);
  localparam ST_WH = $bits(if_test.st);
  ...
    
module top (...);
 if_TEST #(4) if_test ();
 test i_test(.if_test(if_test), ...);
 ...

На что  получаю в Modelsim (Intel start edition 2020.1/2020.3)  маловразумительную  ошибку - 
** Error: (vsim-8894) In instance ".../i_test" parameter reference "if_test.st" through interface port "if_test" is not valid when the actual interface in the instance is an arrayed instance element or below a generate construct."
Маловразумительную потому что этот интерфейс инстанцирован сам по себе  - ни как array, ни из под generate.  :unknw:
Самое прикольное что в Qu все синтезируется как надо, а в Modelsim   такая вот засада. :cray:

Вот и ломаю  голову как сделать чтобы и в симе и в синтезе получать нужное заначене ширины.  

 

Удачи! Rob.

Share this post


Link to post
Share on other sites

Сам с таким напрямую не сталкивался, но товарищ мой на что-то подобное нарывался. И насколько помню, он придумал обходной финт (подробностей не помню, могу напутать, но вроде так): внутри интерфейса он завёл функцию, которую экспортировал (зачем-то это было нужно), и эта функция и возвращала ему размер. По коду получилось даже красивее - вроде инкапсуляции. :)

Share this post


Link to post
Share on other sites

Приветствую!

8 hours ago, dxp said:

Сам с таким напрямую не сталкивался, но товарищ мой на что-то подобное нарывался. И насколько помню, он придумал обходной финт (подробностей не помню, могу напутать, но вроде так): внутри интерфейса он завёл функцию, которую экспортировал (зачем-то это было нужно), и эта функция и возвращала ему размер. По коду получилось даже красивее - вроде инкапсуляции. :)

Чем дальше в лес тем толще глюки ... 

Я тоже решил сначала, сделаю стандартно и красиво -  через  функцию   

interface if_TEST #(ID_WH=3) ;
  ...
  localparam ST_SIZE = $bits(st);
  function int             st_size(); return $bits(st); endfunction 
  function [$bits(st)-1:0] st_wh();   return 1'b1;      endfunction 

  modport in (input  st, valid, output ready, import st_size, st_wh);
  modport ou (output st, valid, input  ready, import st_size, st_wh);
endinterface
  

module test (if_TEST.in if_test, ...);
  localparam ST_WH = if_test.st_size();    Ms: Error: External function 'if_test.st_size' may not be used in a constant expression. Qu: Error, ST_WH==0

  fifo i_fifo #(.WR_WH(if_test.st_size()), Ms: Error: External function 'if_test.st_size' may not be used in a constant expression. Qu: Error, ST_WH==0
  ...

 Облом, Ms, ругается что мол функция  для параметров должна быть  константной,  а внешняя функция из interface таковой может и не быть.   Qu получает из функции фигу  0. 

... через  localparam  в interface

module test (if_TEST.in if_test, ...);
  localparam ST_WH = if_test.ST_SIZE;    Ms: Ok.  Qu: Error (10742): Verilog HDL error at ...: constant expression cannot contain a hierarchical identifier


  fifo i_fifo #(.WR_WH(if_test.ST_SIZE), Ms: Ok.  Qu: Error (10742): Verilog HDL error at ...: constant expression cannot contain a hierarchical identifier
  ...

Ms: Ok,   Qu: Облом  :cray: 

Дальше  пошли хитрости  и трюки   -  объявим  функцию в interface и получим не ее значение,  а формальную ширину выхода :wacko2:    

module test (if_TEST.in if_test, ...);
  localparam ST_WH = $bits(if_tx_frm.st_wh);    

  fifo i_fifo #(.WR_WH(ST_WH)), 
  ...

Ms: Облом, получаемый размер структуры  не соответствует  реальному, а равен значение с параметром по умолчанию.   В Qu все  Ok!.

Вытаскиваем из interface  тип структуры,  создаем  локальную  структуру с таким типом и от нее берем  ширину. (Классический путь героя - в обход :biggrin:)

module test (if_TEST.in if_test, ...);
  typedef  if_test.st_ST_t st_t;
  st_t  st;
  localparam ST_WH = $bits(st);    

  fifo i_fifo #(.WR_WH($bits(st)),
                .RD_WH(ST_WH),
  ...

Но путь героя тернист  -  поскольку в  Ms  для RD_WH   мы  получаем  одно значение ширины (неправильное, по умолчанию),  а для WR_WH  другое (правильное и актуальное)! :shok:  
То есть -   localparam ST_WH = $bits(st);  ST_WH  !=  $bits(st); !!!
Решил совместить  два последних  варианта в один,  в interface  будет функция возвращающая структуру   

  ...
  function st_ST_t get_st(); return st; endfunction 
  modport in (input  st, valid, output ready, import get_st);
  ...

а затем  будем получать ширину значения возвращаемую этой функции 

module test (if_TEST.in if_test, ...);

  fifo i_fifo #(.WR_WH($bits(if_test.get_st)),
                .RD_WH($bits(if_test.get_st)),
  ...

Как ни странно эта помесь  удава с ежом  работает,  но только напрямую,  без  присвоения промежуточным localparam 

 

Удачи! Rob. 

Share this post


Link to post
Share on other sites

Как-то у вас всё сложно. Я спросил у товарища, он мне показал код.

 

interface hash_pkt_pipeline_switch_fabric_i
                #(
                    parameter type                DATA_T           = logic [7:0],
                    parameter int                 STAGE_NUM        = 2,
                    parameter logic [1:STAGE_NUM] MUX_AUX_ENA      = STAGE_NUM'('0),
                    parameter logic [1:STAGE_NUM] MUX_MAIN_OUT_GET = STAGE_NUM'('0)
                 )
(
);

...
function automatic int f_data_width();
    return $bits(DATA_T);
endfunction : f_data_width
...
  
modport pipeline_port(
                        //--- 
                        import function int f_data_width(),
                        import function int f_stage_num(),
                        import function MuxSelect_t f_mux_aux_ena(),
                        
                        //--- 
                        input  mux_aux_in,
                        output mux_main_in
                     );
...  

Использование:

module ..._m
                #(
                   parameter type DATA_T    = logic [7:0],
                   parameter int  STAGE_NUM = 2
                 )
(
    input logic clk,
    input logic rst,

    hash_pkt_pipeline_switch_fabric_i.pipeline_port switch_fabric,
...
  
	...
    if(switch_fabric.f_data_width() != $bits(DATA_T)) begin
    ...
  

Работает у него в квесте и виваде.

 

Возможно тут проблема в том, что localparam в модуле вычисляется раньше, чем оживают объекты, к которым относятся и порты интерфейсов.

Share this post


Link to post
Share on other sites

Приветствую!

10 hours ago, dxp said:

Работает у него в квесте и виваде.

Спасибо вам и вашему товарищу!   

Увы, у меня другая комбинация проблем - Modelsim AE и Qu Standard.   :unknw: 
Qu к сожалению не поддерживает передачу type через parameter.  
К тому же как оказывается с точки зрения Ms это разные ситуации -  когда тип структуры передан как параметр в interface или когда тип структуры определен внутри interface.
В первом случае (в коде вашего товарища) действительно функцию можно использовать как константную, во втором (в моем) увы – Ms ругается на не-константность функции.  :scratch_one-s_head:

Чертовщина однако какая-то :diablo:

10 hours ago, dxp said:

Возможно тут проблема в том, что localparam в модуле вычисляется раньше, чем оживают объекты, к которым относятся и порты интерфейсов.

Это и понятно что есть какая-то  гонка констант в процессе инициализации сима.  Но я с таким еще не сталкивался.  Правда давно было  что то похожее, связанное с неопределенностью работы константной функций если она использует parameters напрямую в теле функций, а не через  аргументы.  Но чтобы  вот так -  присвоенное  значения locаlparam было неравно тому что присваивали встретил в первый раз. :shok:

 

Удачи! Rob.

Share this post


Link to post
Share on other sites

А почему бы решить задачу, вычисляя значение "снаружи" - т.е. без задействования внутренних структур, ведь исходные значения всех параметров известны, ну и просто тогда из них и вычислить (через функцию, например) искомое? Ну да, не особо красиво - работа в глобальном пространстве, но зато просто и переносимо.

Share this post


Link to post
Share on other sites

Приветствую!

5 hours ago, dxp said:

А почему бы решить задачу, вычисляя значение "снаружи" - т.е. без задействования внутренних структур, ведь исходные значения всех параметров известны, ну и просто тогда из них и вычислить (через функцию, например) искомое? Ну да, не особо красиво - работа в глобальном пространстве, но зато просто и переносимо.

В том то и дело что размер не всегда известен.  Размер части полей структур зависит от внешних параметров, которые задаются пользователем при инстанцирование модуля. К тому же таких  разных интерфейсов нужно под три десятка и почти все они проходят через разного типа FIFO.
Вот и возникла  идея упростить жизнь  себе ленивому  выработав единый шаблон таких  интерфейсов.  :boast:

 

Удачи!  Rob.

Share this post


Link to post
Share on other sites

Приветствую!

 

Вторая часть  "марлезонского балета"   Мигрирую   проект из под Qu  в  Vivado (v2020.2).

При синтезе опять  получаю  ошибки  на знакомые места 

if_TEST_A #(.ID_WH(WH)) if_A_name (...);
if_TEST_B #(.ID_WH(WH)) if_B_name (...);

localparam ST_A_WH = $bits(if_A_name.st_TEST_t);
localparam ST_B_WH = $bits(if_B_name.st_TEST_t); // $bits(if_B_name.st); 

Vv ругается  что не может найти иерархический путь  для  if_B_name.st_TEST_t.  Но  странно что ругается  только на строку с  if_B_name (рельное имя изменено).  И при этом  нормально компилит предыдущую строку с if_A_name :shok: Причем  в результате экспериментов  видно что вот не нравится ему почему-то какая-то комбинация  имени интерфейса, порядка определения  интерфейса и еще чего то там,  но из нескольких подобных  определений констант  все время ругается только на одну!!! Даже если переименовать  определение интерфейса или имя инстанса. Если же этот localparam  задать просто константой то все остальные подобные определения  нормально синтезируются!  Мистика  какая-то :wizard:

Исследовав еще немного эти паранормальные явления нашел что работает вариант с прямым получением  ширины через  $bits()

modue_name #(
  .A_WH($bits(if_A_name.st_ST_TEST_t)),
  .B_WH($bits(if_B_name.st))
) ...
  

А  еще  копнув  узнал что  если  обернуть все в generate  то  предыдущий вариант тоже работает 

if_TEST_A #(.ID_WH(WH)) if_A_name (...);
if_TEST_B #(.ID_WH(WH)) if_B_name (...);

genarate 
  localparam ST_A_WH = $bits(if_A_name.st);
  localparam ST_B_WH = $bits(if_B_name.st_TEST_t);

  modue_name #(
    .A_WH(ST_A_WH),
    .B_WH(ST_B_WH)
  ) ...

  ...  
endgenerate

Теперь вот  придется ломать голову как все же делать в рабочем проекте  чтобы не поломалось если звезды не так сойдутся  :scratch_one-s_head:
Ну или все переписывать  для передачи типа  структуры через parametr  :to_take_umbrage:  А это я  еще в xsim  не проверял  .... 

 

Удачи! Rob.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.