Перейти к содержанию
    

Как создать модуль с переменным кол-вом портов?

От параметра количество портов не изменится. А чтобы собрать/разобрать упакованный массив - для этого SV и интерфейсы не нужны.

module we_no_need_thats_system_verilog(
input [234:0] all_in,
input [345:0] all_out
);
assign clk = all_in[0];
assign reset_n = all_in[1];
assign data = all_in[66:2];
.....
.....
assign cs = all_in[234];
и.т.д и.т.п
.....
endmodule

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

module we_no_need_thats_system_verilog(
input [234:0] all_in,
input [345:0] all_out
);
assign clk = all_in[0];
assign reset_n = all_in[1];
assign data = all_in[66:2];
.....
.....
assign cs = all_in[234];
и.т.д и.т.п
.....
endmodule

Не надо ёрничать.

Был конкретный вопрос с примером. Советую прочитать, а потом выступать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

От параметра количество портов не изменится. А чтобы собрать/разобрать упакованный массив - для этого SV и интерфейсы не нужны.

Количество портов изменится внутри интерфейса. От параметра. У модуля это меняться не может, у интерфейса может.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Количество портов изменится внутри интерфейса. От параметра. У модуля это меняться не может, у интерфейса может.

Можно пример?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Вышел из положения следующим образом.

 

Собственно, многопортовый параметризируемый модуль:

module data_mux
    #(
        parameter num_inputs = 3,
        parameter datawidth = 60
    )
    (
        input reset,
        input clk,

        input [num_inputs*datawidth-1:0] datain,
        input [num_inputs-1:0] cs_in,

        output reg [datawidth-1:0] dataout,
        output reg data_ready
    );

    integer i;

    always @(posedge clk, posedge reset) begin
        if(reset) begin
            dataout <= 0;
            data_ready <= 0;
        end
        else begin
            data_ready <= |cs_in;
            for(i = 0; i < num_inputs; i= i + 1) begin
                if(cs_in[i] == 1) dataout <= datain[i*datawidth +: datawidth];
            end
        end
    end

endmodule

 

 

А в надмодуле используется следующий синтаксический сахар:

    // map data sources to single bus
    localparam datawidth = 60;
    localparam num_sources = 4;

    wire [num_sources*datawidth-1:0] mapped_data;
    wire [num_sources-1:0] mapped_cs;

    `define map_data(index, cs_signal, data) \
        assign mapped_data[index*datawidth +: datawidth] = data; \
        assign mapped_cs[index] = cs_signal

    `map_data(0, cs_sync_link,      60'h C0FFEE000C0FFEE);
    `map_data(1, ping_req,          60'h 000F00DF00DF00D);
    `map_data(2, adc_data_ready,    {12'd0, adc_data});
    `map_data(3, do_echo,           serdes_rxfifo_data[59:0]);

    wire [datawidth-1:0] data_to_send;
    wire send;

    data_mux datamux
        (
            .reset          (reset),
            .clk            (clk_100),

            .datain         (mapped_data),
            .cs_in          (mapped_cs),

            .dataout        (data_to_send),
            .data_ready     (send)
        );
        defparam
            datamux.num_inputs = num_sources,
            datamux.datawidth = datawidth;

 

В итоге, дальнейшие манипуляции по добавлению нового порта сводятся лишь к:

1. Правке параметра num_sources

2. Добавлению волшебной строчки `map_data(port_index, my_cs_signal, data_for_this_cs_signal);

 

Пока что очень удобно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно пример?

Из рабочего проекта (выбрал попроще). Это интерфейс, цель которого - раздать сигналы от внешней шины памяти, зацепленной на внешний микропроцессор, по модулям внутри интерфейса.

interface mmr_i 
#(
    parameter     AW   = 13,  // common address width
    parameter     DW   = 16,  // data width
    parameter     DAW  = 5,   // device address width (is a part of AW)
    parameter int N    = 1    // number of the devices
);

// types

typedef bit [DW-1:0]  data_t;
typedef data_t        q_bundle_t[N];

//  public
bit [AW-1:0] addr;
bit [DW-1:0] data;
bit          wren;
bit [DW-1:0] q;

//  private
q_bundle_t   q_bundle;

// functions
function automatic data_t qmux(q_bundle_t x, int n);
    return x[n];
endfunction

// logic

assign q = qmux(q_bundle, addr[AW-DAW-1:DAW]);


//  modports

modport port
(
    output  addr,
    output  data,
    output  wren,
    input   q
);

genvar i;
generate
    for(i = 0; i < N; i++) begin : mport

        bit dev_sel;

        assign dev_sel = addr[AW-DAW-1:DAW] == i;

        modport dev
        (
            input  .addr    (  addr[DAW-1:0]  ),
            input  .data    (  data           ),
            input  .wren    (  wren           ),
            input  .sel     (  dev_sel        ),
            output .q       (  q_bundle[i]    )
        );

    end
endgenerate

endinterface

 

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

mmr_i            // объявляем объект интерфейса
    #(
        .AW  ( 13 ),
        .DW  ( 16 ),
        .DAW ( 4  ),
        .N   ( 7  )
     )
mmr();

...

module_m
module_inst
(

    .clk       ( clk ),
    .rst       ( rst ),

    ...
    .mmr     ( mmr.mport[4].dev )    // сгенерированный модпорт (линк к модулю)

);

...

memory_port_m #(
                .ADDR_WIDTH               ( 24                      ),
                .BANK_ADDR_WIDTH          ( 2                       ),
                .EXT_ADDR_WIDTH           ( BF_ADDR_WIDTH           ),
                .BF_DATA_WIDTH            ( BF_DATA_WIDTH           ),
                .VM_DATA_WIDTH            ( VM_DATA_WIDTH           ),
                .BF_AGENT_BUF_CAPACITY    ( BF_AGENT_BUF_CAPACITY   ),
                .VM_AGENT_BUF_CAPACITY    ( VM_AGENT_BUF_CAPACITY/2 )
               )
memory_port
(
    .clk          ( clk   ),
    .hfclk        ( hfclk ),
    .clk_s        ( clk_s ),
    .rst          ( rst   ),

    //----------------------------------
    //
    //   Agents
    //
    .bf_wr0       ( bf_wr0 ),
    .bf_rd0       ( bf_rd0 ),

    .vm_wr0       ( vm_wr0.agent ),
    .vm_rd0       ( vm_rd0.agent ),

    //----------------------------------
    //
    //   MMRs
    //
    .mmr          ( mmr      ),  // "статический" модпорт (шина на внешний проц)
    ...

У каждого модуля, который имеет регистры, отмапленные на на шину внешнего проца, есть подключение порта вида:

 

.mmr ( mmr.mport[..].dev )

 

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

 

P.S. Инстанции модулей показаны обрезанными. Если что-то пропустил/неточно сказал, прошу извинить, не могу в данный момент сделать тщательно, тороплюсь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 dxp красиво!!!

 

Это только ква такое сейчас собрать может или симплифай с вивадой тоже обучены?

 

ЗЫ. правда задача даже близко не похожа на задачу TC. т.к. как ни крути, а порт у модуля все же один. А пихать всю логику в интерфейс ИМХО не комильфо.

 

PPS. ЕМНИП в модуль можно передать массив интерфейсов, у меня работало в симуляторе, но на тот момент ни один синтезатор не смог собрать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 dxp красиво!!!

 

Это только ква такое сейчас собрать может или симплифай с вивадой тоже обучены?

 

ЗЫ. правда задача даже близко не похожа на задачу TC. т.к. как ни крути, а порт у модуля все же один. А пихать всю логику в интерфейс ИМХО не комильфо.

 

PPS. ЕМНИП в модуль можно передать массив интерфейсов, у меня работало в симуляторе, но на тот момент ни один синтезатор не смог собрать.

Я может чего-то не понимаю, но нельзя ли задачу ТС решить таким простым способом, как объявить структуру через typedef во внешнем инклюде ( в ней могут быть как шины, так и просто обычные проволоки),

а затаем через параметр модуля повторить её столько раз сколько нужно? Это конечно не так красиво как с интерфейсами, кроме того для входов и выходов придётся делать две структуры, зато соберётся любым синтезатором, даже без поддержки SV.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Один из способов "работы" со структурами в verilog, аналогично упакованным структурам в sv - это объявить гомогенную шину, а в файле, подключаемом через `include, предоставлять сервисные параметры и функции доступа к кускам этой шины, как к полям.

 

Задача с многомерными шинами, у которых что-то там зависит от параметров, решается аналогично.

 

Полноценной работой это назвать, конечно, нельзя, т.к. при elaboration никаких соответствий типов при подключении не проверяется, но все же хоть какой-то выход.

 

Я может чего-то не понимаю, но нельзя ли задачу ТС решить таким простым способом, как объявить структуру через typedef во внешнем инклюде ( в ней могут быть как шины, так и просто обычные проволоки),

а затаем через параметр модуля повторить её столько раз сколько нужно? Это конечно не так красиво как с интерфейсами, кроме того для входов и выходов придётся делать две структуры, зато соберётся любым синтезатором, даже без поддержки SV.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Был конкретный вопрос с примером.

 

количество портов не может зависить от параметра.

 

Может я не правильно выразился...... я не хочу завести parameter, в понимании синтаксиса verilog, и потом этот пораметр прикрутить к кол-ву портов модуля. под словами "какойнить параметр" я не имел ввиду только parameter, я имел ввиду что где-то как-то указать, например: parameter, property, define, typdef, QEditLine, TComboBox, set_module_property..... и т.п. Меняя этот "параметр" менялось бы кол-во портов и соответсвенно графическое отображение.

про скриптовые языки я уже понял.

 

про интерфейсы внутри модуля - не очень понятно. ну будет внутри модуля что-то там делится. Но внешне на графике всёравно будет один толстый порт, в который нужно объеденять все шины.

 

 

ps

количество портов не может зависить от параметра.

ну в мегакорках же зависит

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это только ква такое сейчас собрать может или симплифай с вивадой тоже обучены?

Квартус и квеста держат, за другие не скажу, не пробовали.

 

А пихать всю логику в интерфейс ИМХО не комильфо.

Не всю, а только необходимую. Тем более, по задаче ТС там и логики-то нет - только генерация портов внутри интерфейса в соответствии с заданными параметрами.

 

Что касается логики, то у нас есть ещё ряд успешных применений интерфейсов. В частности, есть интерфейсы, которые занимаются упаковкой/распаковкой данных - шина на внешнюю память 32 бита, а внутри ПЛИС данные от модулей имеют меньшую разрядность (8, 10, 16 бит) - интерфейс сам упаковывает данные при записи и распаковывает при чтении. Очень удобно. Реализация интерфейсов:

interface mem_wr_i
   #(
       parameter AW  = 24,    // address width of physical memory space
       parameter DW  = 32,    // data width of physical memory space
       parameter ADW = 16,    // application word data width
       parameter CAP = 512    // capacity of the agent fifo buffer
    )
(
   input clk,
   input rst
);

localparam FACTOR = DW/ADW;

//------------------------------------------
//
//     Common
//
bit                         start;
bit                         up;
bit                         load;
bit                         busy;
bit                         full;
bit                         empty;

bit [    clog2(FACTOR)-1:0]  pack_cnt;

bit [FACTOR-1-1:0][ADW-1:0]  data;        // -1 because MSBs of data_agent need not to fix in medium register

//------------------------------------------
//
//     Application
//
bit [AW+clog2(FACTOR)-1:0]  addr_app;
bit [       bits(CAP)-1:0]  count_app;
bit [             ADW-1:0]  data_app;
bit [       bits(CAP)-1:0]  fifo_cnt_app;  

//------------------------------------------
//
//     Agent
//
//
bit [              AW-1:0]  addr_agent;
bit [              DW-1:0]  data_agent;
bit [bits(CAP/FACTOR)-1:0]  count_agent;
bit [bits(CAP/FACTOR)-1:0]  fifo_cnt_agent; 
bit                         load_agent;


function automatic int iassign(input int x, input int y);

   return x & (y | ~y);


endfunction

//------------------------------------------
//
//     Logic
//
assign load_agent   = load && (pack_cnt == FACTOR-1);
assign fifo_cnt_app = fifo_cnt_agent*FACTOR;
assign count_agent  = count_app/FACTOR;
assign addr_agent   = addr_app/FACTOR;
assign data_agent   = { data_app, data };

always_ff @(posedge clk) begin
   if(rst) begin
       pack_cnt <= 0; 
   end
   else begin
       if(load) begin
           data[pack_cnt] <= data_app;
           pack_cnt       <= pack_cnt + 1;
           if(pack_cnt == FACTOR-1) begin
               pack_cnt <= 0;
           end
       end
   end
end

//------------------------------------------
//
//     Modports
//
modport app
(
   output  .data     ( data_app     ),
   output  start,
   output  .count    ( count_app    ),
   output  .addr     ( addr_app     ),
   output  load,
   output  up,
   input   busy,
   input   full,
   input   empty,
   input   .fifo_cnt ( fifo_cnt_app )

);

modport agent
(                                       
   input   .data     ( data_agent   ),
   input   start,
   input   .count    ( count_agent  ),
   input   .addr     ( addr_agent   ),
   input   .load     ( load_agent   ),
   input   up,
   output  busy,
   output  full,
   output  empty,
   output  .fifo_cnt ( fifo_cnt_agent )

);


endinterface

//------------------------------------------------------------------------------

interface mem_rd_i
   #(
       parameter AW  = 24,    // address width of physical memory space
       parameter DW  = 32,    // data width of physical memory space
       parameter ADW = 16,    // application word data width
       parameter CAP = 512    // capacity of the agent fifo buffer
    )
(
   input clk,
   input rst
);

localparam FACTOR = DW/ADW;

//------------------------------------------
//
//     Common
//
bit                         start;
bit                         up;
bit                         get;
bit                         busy;
bit                         full;
bit                         empty;

bit [    clog2(FACTOR)-1:0] pack_cnt;

bit [ FACTOR-1:0][ADW-1:0]  data;        

//------------------------------------------
//
//     Application
//
bit [AW+clog2(FACTOR)-1:0]  addr_app;
bit [       bits(CAP)-1:0]  count_app;
bit [             ADW-1:0]  data_app;
bit [       bits(CAP)-1:0]  fifo_cnt_app;  
//bit                         get_app;

//------------------------------------------
//
//     Agent
//
bit [              AW-1:0]  addr_agent;
bit [              DW-1:0]  data_agent;
bit [bits(CAP/FACTOR)-1:0]  count_agent;
bit [bits(CAP/FACTOR)-1:0]  fifo_cnt_agent; 
bit                         get_agent;


//------------------------------------------
//
//     Logic
//
assign get_agent    = get && (pack_cnt == FACTOR-1);
assign fifo_cnt_app = fifo_cnt_agent*FACTOR;
assign count_agent  = count_app/FACTOR;
assign addr_agent   = addr_app/FACTOR;
assign data         = data_agent;
assign data_app     = data[pack_cnt];

always_ff @(posedge clk) begin
   if(rst) begin
       pack_cnt <= 0; 
   end
   else begin
       if(get) begin
           pack_cnt   <= pack_cnt + 1;
           if(pack_cnt == FACTOR-1) begin
               pack_cnt <= 0;
           end
       end
   end
end

//------------------------------------------
//
//     Modports
//
//

modport app
(
   input   .data     ( data_app     ),
   output  start,
   output  .count    ( count_app    ),
   output  .addr     ( addr_app     ),
   output  get,
   output  up, 
   input   busy,
   input   full,
   input   empty,
   input   .fifo_cnt ( fifo_cnt_app )

);

modport agent
(                                       
   output  .data     ( data_agent   ),
   input   start,
   input   .count    ( count_agent  ),
   input   .addr     ( addr_agent   ),
   input   .get      ( get_agent    ),
   input   up,
   output  busy,
   output  full,
   output  empty,
   output  .fifo_cnt ( fifo_cnt_agent )

);

endinterface

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

 

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

 

Вообще, SV интерфейс очень гибкая штука. Помимо линкования модулей он может использоваться хоть локально - при этом он похож на структуру с возможностью определения порций кода внутри неё. Получается что-то вроде модуля с некоторыми ограничениями (к сожалению, внутри интерфейса нельзя инстанцировать модули - т.е., скажем, тот же модуль FIFO внутри интерфейса сделать нельзя, что очень жаль; остаётся описывать логику FIFO кодом, но это далеко не всегда годный вариант), но в ряде случаев такое использование проще и удобнее, нежели инстанцирование модуля: удобство заключается, например, в том, что не нужно заводить пачку сигналов (пусть даже объединённых в структуру) для подключения к портам модуля - потроха интерфейса можно юзать напрямую инлайн (как на AHDL :) ), это уменьшает писанину и сокращает количество сущностей. Для небольших законченных по смыслу порций логики реализация в виде интерфейса вместо модуля часто оказывается значительно удобнее. Рекомендую.

 

PPS. ЕМНИП в модуль можно передать массив интерфейсов, у меня работало в симуляторе, но на тот момент ни один синтезатор не смог собрать.

Квартус нынешний, вроде, уже поддерживает массив интерфейсов. Когда-то я очень хотел этой возможности, но синтезаторы не поддерживали (ква) или поддерживали с глюками (Precision). Теперь я понял, что то, что я хотел, отлично реализуется без всяких массивов на одном интерфейсе - там можно задать сколько угодно портов, включая руление свойствами (направление сигналов и их тип) каждого модпорта. Вот пример mmr_i из предыдущего поста как раз показывает, как можно из одного интерфейса объединять пачку портов на соответствующее количество модулей. Реально массив интерфейсов актуален в ситуации, когда есть эн модулей с одинаковыми интерфейсами, которые нужно упаковать в один модуль и манипулировать ими в цикле. Но и в этом случае всё можно сделать на одном интерфейсе со сгенерированными модпортами. Это только вопрос удобства.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Квартус нынешний, вроде, уже поддерживает массив интерфейсов.

Модуль "а" инстанцирует подмодули - "sub_a", в портах которых определен интерфейс "chan":

module	a #(
parameter 
PAR1= 14, 
PAR2 = 15,
COUNT_UNIT = 6	
)
(
// Input Ports
...

// Output Ports	
      ...

//Selecting the modport in the module port declaration
channel.master  chan[COUNT_UNIT-1:0] 

);

genvar c;	

generate
for (c = 0; c < COUNT_UNIT; c = c+1) begin: test

	sub_a #(
	  .PAR1(1)
	  )
	  sub_a_inst(		  
	  .clk,	
	  .data_i(scr__data_i),	
	  .addr(scr__addr_i),
	  .wr(scr__wr[c]),
	  .rst_n,		  		  
	  .scr_gate(scr_gate[c]),		  
	  .chan(chan[c])
	  );		

end
endgenerate

endmodule

 

Есть модуль top, который инстанцирует модуль "а" а также один "sub_a".

Вопрос в том, как "вытащить" из инстанцируемого модуля "а" один из интерфейсов и подключить его к "sub_a"???

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

module test(

 

`ifdef PRM_1

input a,

`endif

 

`ifdef PRM_2

input b,

`endif

 

input c,

 

output out

);

 

endmodule

 

тошнотворный способ

 

ну в мегакорках же зависит

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не понимаю в чем проблема. Если N портов одинаковой или даже разной разрядности, то берем один порт, а дальше в зависимости от параметров - расщепляем его на сколько угодно шин и всё.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос в том, как "вытащить" из инстанцируемого модуля "а" один из интерфейсов и подключить его к "sub_a"???

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...