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

Модуль с произвольным числом портов произвольной ширины на верилоге

По сути вопроса я наверное плохо объясняю. Во всяком случае ISE 14.4 часто ругается когда меняется порядок индексов, то есть если объявляли регистр как 3:0, то попытки в каких то действиях запихать в него обратный порядок вызывает ошибку. Тут надо специалиста который поймет о чем я несу и нормально сформулирует :)... я что-то не могу сразу примера вспомнить....

ISE 14.7 ест и не давиться

wire    [4*32-1 : 0] iram_rdata;
......
wire    [63 : 0] L__ordata_rslt;
......
  assign iram_rdata[0*32 +: 32] = oram_addr[0] ? N__ordata_rslt[32 +: 32] : N__ordata_rslt[0 +: 32]; // 64 bit
  assign iram_rdata[1*32 +: 32] = oram_addr[0] ? T__ordata_rslt[32 +: 32] : T__ordata_rslt[0 +: 32];
  assign iram_rdata[2*32 +: 32] = oram_addr[0] ? L__ordata_rslt[32 +: 32] : L__ordata_rslt[0 +: 32];
  assign iram_rdata[3*32 +: 32] =              dec__ordata_rslt; // 32 bit

в атаче скрин стандарта

post-3453-1409900197_thumb.png

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


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

судя по коду port_map и port_sizes связаны однозначно (позиционно через generate), тогда какой смысл вводить 2 переменных, рискуя ошибиться (port_map постоянно увеличивается, в зависимости от port_size) если это можно рассчитать по месту ?

 

а у вас нет произвольного числа параметров, у вас есть вектор port_sizes, длинна которого определенна в момент передачи параметра и nports который тоже определен при передаче параметра до создания параметра port_list.

 

Если будут проблемы с синтезом или пониманием синтезатора, то сделайте красивый финт. А именно, old-style Verilog 95 объявление, позволяет использовать в качестве разрядностей векторов localparam.

 

Т.е. по сути, задавать через параметр нужно только nports и port_sizes. Остальное будут вычисляемые параметры.

 

Если задать только два параметра (nports и port_sizes), то при итерировании в цикле да - мы сможем достать из вектора нужный размер для нужного порта. Но как посчитать смещение для этого порта, ведь нужно держать где-то сумму всех предыдущих размеров? Основная проблема-то именно в этом.

 

А так ваше предложение было бы почти идеальным решением. А совсем идеальным оно станет, имхо, если удастся обойтись только одним параметром - port_sizes, а все остальное - будет вычисляемым.

 

P.S.:

Т.е., в идеале нужно получить что-то такое:

        parameter nports = 8,
        parameter port_sizes = { 8'd6,  8'd1,  8'd8, 8'd4, 8'd2, 8'd3, 8'd2, 8'd1},

...

    localparam current_port_pos = 0;

    generate
        for(i = 0; i < nports; i = i + 1)
            begin: port
                localparam current_port_pos  = current_port_pos + port_sizes[i*8 +: 8] * 8;
                localparam current_port_size = port_sizes[i*8 +: 8] * 8;
                // и тогда доступ к порту i будет таким: 
                // datain[current_port_pos +: current_port_size]
            end
    endgenerate

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

 

________________________________________________________________________________

_______________________________

 

ISE 14.7 ест и не давиться

 

Квартус очень даже давится:

        output [15:0]   trx_data_out,
        input  [15:0]   data_from_trx

...

    assign trx_data_out[15:0] = data_from_trx[0:15];

 

выхлоп:

Error (10198): Verilog HDL error at pcm_test_hw.v(59): part-select direction is opposite from prefix index direction
Error (10784): HDL error at pcm_test_hw.v(16): see declaration for object "data_from_trx"
Error (12153): Can't elaborate top-level user hierarchy

 

Но если вручную расписать побитово через assign, то все будет работать.

Изменено пользователем ilkz

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


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

Если задать только два параметра (nports и port_sizes), то при итерировании в цикле да - мы сможем достать из вектора нужный размер для нужного порта. Но как посчитать смещение для этого порта, ведь нужно держать где-то сумму всех предыдущих размеров? Основная проблема-то именно в этом.

module data_packer
    #(
        parameter nports = 8,
        parameter port_sizes = { 8'd6,  8'd1,  8'd8, 8'd4, 8'd2, 8'd3, 8'd2, 8'd1},
        parameter max_port_size = 128  // max port size, bytes
    )
    (
        datain,
        port_ready,
        reset,
        clk,
        mode,
        byte,
        byte_ready,
        data_packed
    );

    //------------------------------------------------------------------------------------------------------
    // oops
    //------------------------------------------------------------------------------------------------------
    localparam port_map         = get_port_map(nports);
    localparam total_bits_len   = get_ports_list(nports) * 8;

    function [max_port_size*8-1 : 0] get_port_map (input integer nports);
        integer i, pipa;
    begin
        pipa = 0;
        get_port_map = 1'b0; // unsigned extend
        for (i = 0; i < nports; i = i + 1) begin
            get_port_map[i*8 +: 8] = pipa;
            pipa = pipa + port_sizes[i*8 +: 8];
        end
    end
    endfunction

    function integer get_ports_list (input integer nports);
        integer i;
    begin
        get_ports_list = 0;
        for (i = 0; i < nports; i = i + 1) begin
            get_ports_list = get_ports_list + port_sizes[i*8 +: 8];
        end
    end
    endfunction

    //------------------------------------------------------------------------------------------------------
    //
    //------------------------------------------------------------------------------------------------------
    input [total_bits_len - 1 : 0] datain;
    input [nports - 1 : 0] port_ready;

    input reset;
    input clk;

    input mode; // 0 - forced mode (any port_ready[*] signal raise serialization),
                    // 1 - wait mode (packer will be wait for all port_ready[*] signals before serialization,
                    //     port_ready[*] signals can come in any order and time)

    output reg [7:0] byte;
    output reg byte_ready;
    output reg data_packed;
bla-bla-bla

Какая проблема ? :)

 

Квартус очень даже давится:

правильно давиться, а спор с уважаемым Golikov A. о другом: использование +: и -: может применяться к векторам определенным в любом порядке.

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


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

Какая проблема ? :)

 

Ух е-мое как изящно олд-стайл нагнул нью-стайл :twak: . Проверил на моделяторе и на железе - все синтезируется и работает как задумано. Класс.

 

Век живи, век учись. B)

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


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

Век живи, век учись. B)

:) до кучи, при использовании такого стиля описания, возможно красивое решение файла параметров по умолчанию. Т.е.:создаете файл например parameters.vh, описываете в нем ваши параметры (в том числе с функциями преобразования), подключаете его в теле модуля сразу после секции портов(секцию параметров не трогаете). И так например во всем проекте. В итоге у вас есть файл параметров со значениями по умолчанию для всего проекта, при этому в любом инстансе модуля параметр может быть изменен индивидуально для модуля, не трогая все остальные инстансы.

 

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


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

assign iram_rdata[0*32 +: 32] = oram_addr[0] ? N__ordata_rslt[32 +: 32] : N__ordata_rslt[0 +: 32];

 

а так?

assign iram_rdata[31 : 0] = oram_addr[0] ? N__ordata_rslt[32 +: 32] : N__ordata_rslt[0 +: 32];

 

и как следствие

 

reg [31:0] Data;
....
Data <= oram_addr[0] ? N__ordata_rslt[32 +: 32] : N__ordata_rslt[0 +: 32];

 

И я не в коем случае не спорю%) я просто помню что где-то я воткнулся в эту не удобность, а вот где не помню...

 

до кучи, при использовании такого стиля описания, возможно красивое решение файла параметров по умолчанию. Т.е.:создаете файл например parameters.vh, описываете в нем ваши параметры (в том числе с функциями преобразования),

Во-во, у меня так знакомый так в проекте сделал, теперь нельзя просто выдрать модуль из проекта, надо еще параметры переносить или этот файл с собой тащить. Палка о 2 концах...

 

Ух е-мое как изящно олд-стайл нагнул нью-стайл

Век живи, век учись.

Недавно кто-то спрашивал про generate и там SM говорил что основное отличие генерейта в том что он реально генерит текст, и потому у него не может быть накапливающегося параметра в цикле от итерации к итерации, это как раз очень хороший пример различия простого for и generate.

 

в функция можно использовать for без генерайта, и следовательно

get_ports_list = 0;
        for (i = 0; i < nports; i = i + 1) begin
            get_ports_list = get_ports_list + port_sizes[i*8 +: 8];
        end

get_ports_list от итерации к итерации сохраняет свое "вычисленное" значение.

А в генерайте он лишь текст, и параметр, и потому цикл развернулся в кучу строчек вида

 

localparam current_port_pos = current_port_pos + port_sizes[i*8 +: 8] * 8;

 

то есть в определение константы от константы которой еще нет...

 

 

интересно попробовать так

 

integer  current_port_pos  = 0;

generate
        for(i = 0; i < nports; i = i + 1)
            begin: port
                current_port_pos  = current_port_pos + port_sizes[i*8 +: 8] * 8;
....

 

по идее тоже должно сработать...

 

 

 

 

правильно давиться, а спор с уважаемым Golikov A. о другом: использование +: и -: может применяться к векторам определенным в любом порядке.

 

еще раз все перечитал. Правильно ли я понимаю:

если мы берем

reg [15:0] Data;

то мы не можем делать Data[0:15] , Data[7:10] и так далее... но можем Data[0 +: 16], Data [7 +: 4]?

почему то мне казалось что во втором случае тоже ругань была... И да я понял главная моя ошибка, не в моменте присвоения, а в выборе куска вектора в другом порядке нежели при объявлении... вот где я всех запутал

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


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

а так?

и как следствие

assign iram_rdata[31  :  0] = oram_addr[0] ? N__ordata_rslt[31 -: 32] : N__ordata_rslt[0 +: 32];

ISE 14.7 собирает без проблем

 

Во-во, у меня так знакомый так в проекте сделал, теперь нельзя просто выдрать модуль из проекта, надо еще параметры переносить или этот файл с собой тащить. Палка о 2 концах...

если вырвали из SVN, от какая разница один или 2 файла. если взяли себе в проект, то потратить 5 минут на копипаст не вижу сложностей.

 

еще раз все перечитал. Правильно ли я понимаю:

если мы берем

reg [15:0] Data;

то мы не можем делать Data[0:15] , Data[7:10] и так далее... но можем Data[0 +: 16], Data [7 +: 4]?

Да

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


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

все понятно, это приятно... А порядок бит какой останется, как в объявлении?

то есть в случае

 

reg [31 : 0] Data1

reg [0 : 31] Data2

 

Data1[3 +: 2] == Data1 [4:3]

Data2[3 +: 2] == Data2 [3:4]

 

это опасно для понимания, может стать причиной ошибок... Или же порядок бит будет как указан?

 

 

 

если вырвали из SVN, от какая разница один или 2 файла. если взяли себе в проект, то потратить 5 минут на копипаст не вижу сложностей.

взять себе в проект, улучшить и вернуть, или когда там улучшиться взять себе опять вот где были сложности. Файл тащить там какие то варнинги сыпались, да и проект по идиологии был что все параметры были в модулях, а этот модуль выбивается. А если дописать параметры внутрь, то любой перенос надо не забывать их вставлять - убирать. В общем проблемы как всегда не в технологии, а в идиологии, если все проекты делать с внешним файлом констант - то вопросов нет.

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


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

reg [31 : 0] Data1

reg [0 : 31] Data2

 

Data1[3 +: 2] == Data1 [4:3]

Data2[3 +: 2] == Data2 [3:4]

да, будет именно так. потому что порядок вектора оговорен стандартом vector[msb : lsb], а вот индексация вектора, с точки зрения направления может быть любой.

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


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

!!! Hotfix !!!

В модуле обнаружилась веселая ошибка, приводящая к тому, что при использовании нескольких портов Квартус ругался. Ну и еще по мелочи пара исправлений. Выкладываю обновленный код.
`include "timescale.v"

module data_packer
    #(
        parameter nports = 8,
        parameter port_sizes = {8'd6, 8'd1, 8'd8, 8'd4, 8'd2, 8'd3, 8'd2, 8'd1},
        parameter max_port_size = 8 // max port size, bytes
    )
    (
        datain,
        port_ready,
        reset,
        clk,
        mode,       // 0 - forced mode (any port_ready[*] signal raise serialization),
                    // 1 - wait mode (packer will be wait for all port_ready[*] signals before serialization,
                    //     port_ready[*] signals can come in any order and time)
        byte,
        byte_ready,
        data_packed
    );

    function [max_port_size*nports*8-1 : 0] get_port_map (input integer nports);
        integer i, tmp;
        begin
            tmp = 0;
            get_port_map = 1'b0; // unsigned extend
            for (i = 0; i < nports; i = i + 1) begin
                get_port_map[i*8 +: 8] = tmp;
                tmp = tmp + port_sizes[i*8 +: 8];
            end
        end
    endfunction

    function integer get_ports_list (input integer nports);
        integer i;
        begin
            get_ports_list = 0;
            for (i = 0; i < nports; i = i + 1) get_ports_list = get_ports_list + port_sizes[i*8 +: 8];
        end
    endfunction

    localparam port_map         = get_port_map(nports);
    localparam total_bits_len   = get_ports_list(nports) * 8;

    input [total_bits_len - 1 : 0] datain;
    input [nports - 1 : 0] port_ready;
    input reset;
    input clk;
    input mode;

    output reg [7:0] byte;
    output reg byte_ready;
    output reg data_packed;

    reg [total_bits_len - 1 : 0] buffer;
    reg [nports - 1 : 0] ports_stored;
    reg [$clog2(max_port_size * nports) : 0] byte_cnt, offset;

    wire all_ports_stored = &ports_stored;
    wire serialize_en = byte_cnt > 0;
    wire serialization_done = {byte_ready, serialize_en} == 2'b10;

    integer n;
    genvar i, j;

    generate
        for(i = 0; i < nports; i = i + 1)
            begin: port
                localparam port_pos  = port_map[i*8 +: 8] * 8;
                localparam port_size = port_sizes[i*8 +: 8] * 8;

                always @(posedge clk, posedge reset) begin
                    if(reset) begin
                        buffer[port_pos +: port_size] <= 0;
                        ports_stored[i] <= 0;
                    end
                    else begin
                        if(port_ready[i]) begin
                            buffer[port_pos +: port_size] <= datain[port_pos +: port_size];
                            ports_stored[i] <= 1;
                        end
                        if(byte_ready) ports_stored[i] <= 0;
                        if(serialization_done) buffer[port_pos +: port_size] <= 0;
                    end
                end
            end
    endgenerate

    always @(posedge clk, posedge reset) begin
        if(reset) begin
            byte <= 0;
            byte_ready <= 0;
            data_packed <= 0;
            byte_cnt <= 0;
            offset <= 0;
        end
        else begin
            for(n = 0; n < nports; n = n + 1) begin
                if(port_ready[n] & !mode) begin
                    byte_cnt <= port_sizes[n*8 +: 8];
                    offset <= port_map[n*8 +: 8];
                end
            end

            if(mode & all_ports_stored) begin
                byte_cnt <= (total_bits_len >> 3);
                offset <= 0;
            end
            if(byte_cnt > 0) byte_cnt <= byte_cnt - 1;

            byte <= serialize_en ? buffer[((byte_cnt + offset - 1) * 8) +: 8] : byte;
            byte_ready <= serialize_en;
            data_packed <= serialization_done;
        end
    end

endmodule

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


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

а кто может объяснить смысл жтой записи?

 

`define register_port(n) port_sizes[n * 8 +: 8]

 

мы определили глобальный параметр register_port с произвольной размерностью. а что потом делает порт_сайз? он вроде как еще не определен...

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


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

Макрофункция, которую обрабатывает препроцессор.

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

Хороший документ на эту тему http://www.veripool.org/papers/Preproc_Goo...Bos10_paper.pdf

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


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

GAYVER, это макрос, который позволяет упростить определение параметра port_list (см. пример использования в самом первом посте). Без этого макроса было бы

    localparam port_list   =  port_sizes[0 +: 8] +  port_sizes[8 +: 8] +  port_sizes[16 +: 8];

соответственно, надо помнить про индексы, высчитывать их. Это муторно.

Макрос позволяет это действо скрыть:

    localparam port_list   = `register_port(0) + `register_port(1) + `register_port(2);

 

Кроме того, в последней версии кода этот параметр вообще ушел и никаких дополнительных макросов не требуется. Там использование гораздо проще:

data_packer dp
    (
            .reset          (reset),
            .clk            (sys_clk),

            .mode           (mode),

            .datain         ({port2, port1, port0}),
            .port_ready     (rdy_port),

            .byte           (),
            .byte_ready     (),
            .data_packed    ()
    )
         dp.nports = 3,                                         // задаем количество используемых портов
         dp.port_sizes = {8'd3, 8'd8, 8'd6},            // задаем разрядности каждого порта
         dp.max_port_size = 8;                             // разрядность самого толстого используемого порта (в нашем случае 8, но можно задать с запасом)

 

 

 

gotcha, сюрпрайз можно словить, если писать не аккуратно и использовать не так как задумано разработчиками. Но в целом Вы правы, с вычисляемыми макросами надо быть очень осторожным, особенно при их разработке.

Изменено пользователем ilkz

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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