Jump to content

    
dimka76

Помогите ускорить проект на Verilog

Recommended Posts

Здравствуйте.

ПЛИСами занимаюсь редко и мало.

Использую их в качестве дополнительной периферии для микроконтроллеров. Проекты низкоскоростные.

Но вот сейчас похоже скорости стало не хватать.

Про констрейны читал. Но понимание и практика их применения  нулевая. Раньше хватало скоростей без констрейнов.

Итак. FPGA Lattice XP2. Среда Diamond.

Synthesize Tool - Symplify Pro.

Внутренняя частота, вырабатываемая внутренней PLL, от которой все тактируется, 125 МГц.

Сейчас временной анализ показывает, что актуальная получается 125,4 МГц. И я переживаю, что запасик уж очень маленький.

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

image.thumb.png.641963d77e70843e2fe406847c89c062.png

Вот сам код модуля


module reg_mux(
	input wire clk,
    input wire i_rst,
    input wire [11:0] sel,
    input wire strob,
	input wire [31:0] data_in_1,	
    input wire [31:0] data_in_2,	
    input wire [31:0] data_in_3,	
    input wire [31:0] z_in_1,	
    input wire [31:0] z_in_2,	
    input wire [31:0] z_in_3,
	output reg [15:0] data_out
);

reg [15:0] register; 

always @(posedge clk or posedge i_rst)
begin
    if(i_rst)
        begin
           data_out[15:0] <= 16'd0; 
           register[15:0] <= 16'd0; 
        end
    else
       if(strob)
           case(sel)
               12'b000000000001 : 
                    begin
                        register[15:0] <= data_in_1[31:16];
                        data_out[15:0] <= data_in_1[15:0];
                    end
               12'b000000000100 : 
                    begin 
                        register[15:0] <= data_in_2[31:16];
                        data_out[15:0] <= data_in_2[15:0];
                    end
               12'b000000010000 : 
                    begin 
                        register[15:0] <= data_in_3[31:16];
                        data_out[15:0] <= data_in_3[15:0];
                    end  
               12'b000001000000 : 
                    begin
                        register[15:0] <= z_in_1[31:16];
                        data_out[15:0] <= z_in_1[15:0];
                    end
               12'b000100000000 : 
                    begin 
                        register[15:0] <= z_in_2[31:16];
                        data_out[15:0] <= z_in_2[15:0];
                    end
               12'b010000000000 : 
                    begin 
                        register[15:0] <= z_in_3[31:16];
                        data_out[15:0] <= z_in_3[15:0];
                    end   
               12'b000000000010, 12'b000000001000, 12'b000000100000,
               12'b000010000000, 12'b001000000000, 12'b100000000000 : 
                    data_out[15:0] <= register[15:0];  
               default : 
                    begin  
                        data_out[15:0] <= 16'd0; 
                        register[15:0] <= 16'd0; 
                    end
           endcase
end

endmodule

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

Share this post


Link to post
Share on other sites
9 minutes ago, dimka76 said:

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

избавиться от 12 ти битных "адресов", а вот способы избавления есть разные)

Share this post


Link to post
Share on other sites
12 минут назад, dimka76 сказал:

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

Вместо мультиплексора взять распределенную память, если в лэтисе она есть. С минимальной латентностью...

Share this post


Link to post
Share on other sites

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

4 minutes ago, dimka76 said:

И я переживаю, что запасик уж очень маленький.

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

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

Ну а по коду  в вашем случае  можно посоветовать предварительно декодировать селектор sel на такт раньше с регистром на выходе.  Это уменьшит крит. путь  для mux. Естественно если это допустимо по логике дизайна.  

 

1 minute ago, iosifk said:

Вместо мультиплексора взять распределенную память, если в лэтисе она есть. С минимальной латентностью...

:scratch_one-s_head::wacko2: 

Удачи! Rob.

Share this post


Link to post
Share on other sites
21 minutes ago, des00 said:

избавиться от 12 ти битных "адресов", а вот способы избавления есть разные)


module reg_mux(
	input wire clk,
    input wire i_rst,
    input wire [11:0] sel,
    input wire strob,
	input wire [31:0] data_in_1,	
    input wire [31:0] data_in_2,	
    input wire [31:0] data_in_3,	
    input wire [31:0] z_in_1,	
    input wire [31:0] z_in_2,	
    input wire [31:0] z_in_3,
	output reg [15:0] data_out
);

reg [15:0] register; 

always @(posedge clk or posedge i_rst)
begin
    if(i_rst)
        begin
           data_out[15:0] <= 16'd0; 
           register[15:0] <= 16'd0; 
        end
    else
       if(strob)
        begin
            if(sel[0])
                begin
                    register[15:0] <= data_in_1[31:16];
                    data_out[15:0] <= data_in_1[15:0];
                end
            if(sel[2])
                begin
                    register[15:0] <= data_in_2[31:16];
                    data_out[15:0] <= data_in_2[15:0];
                end
            if(sel[4])
                begin
                    register[15:0] <= data_in_3[31:16];
                    data_out[15:0] <= data_in_3[15:0];
                end
            if(sel[6])
                begin
                    register[15:0] <= z_in_1[31:16];
                    data_out[15:0] <= z_in_1[15:0];
                end
            if(sel[8])
                begin
                    register[15:0] <= z_in_2[31:16];
                    data_out[15:0] <= z_in_2[15:0];
                end
            if(sel[10])
                begin
                    register[15:0] <= z_in_3[31:16];
                    data_out[15:0] <= z_in_3[15:0];
                end
            if(sel[1] || sel[3] || sel[5] || sel[7] || sel[9] || sel[11])
                data_out[15:0] <= register[15:0]; 
                
	end 

end

endmodule

Попробовал так.

Частота выросла до 131 МГц.

17 minutes ago, RobFPGA said:

Ну а по коду  в вашем случае  можно посоветовать предварительно декодировать селектор sel на такт раньше с регистром на выходе.  Это уменьшит крит. путь  для mux. Естественно если это допустимо по логике дизайна.  

Это интересно, но не понял сути идеи. Что именно должно быть на выходе предлагаемого вами декодера ?

Share this post


Link to post
Share on other sites
16 minutes ago, dimka76 said:

always @(posedge clk or posedge i_rst)
begin
    if(i_rst)
        begin
           data_out[15:0] <= 16'd0; 
           register[15:0] <= 16'd0; 
        end
    else
       if(strob)
        begin
            if(sel[0])
                begin
                    register[15:0] <= data_in_1[31:16];
                    data_out[15:0] <= data_in_1[15:0];
                end
            if(sel[2])
                begin
                    register[15:0] <= data_in_2[31:16];
                    data_out[15:0] <= data_in_2[15:0];
                end
            if(sel[4])
                begin
                    register[15:0] <= data_in_3[31:16];
                    data_out[15:0] <= data_in_3[15:0];
                end
            if(sel[6])
                begin
                    register[15:0] <= z_in_1[31:16];
                    data_out[15:0] <= z_in_1[15:0];
                end
            if(sel[8])
                begin
                    register[15:0] <= z_in_2[31:16];
                    data_out[15:0] <= z_in_2[15:0];
                end
            if(sel[10])
                begin
                    register[15:0] <= z_in_3[31:16];
                    data_out[15:0] <= z_in_3[15:0];
                end
            if(sel[1] || sel[3] || sel[5] || sel[7] || sel[9] || sel[11])
                data_out[15:0] <= register[15:0]; 
                
	end 

end

В этом месте было бы хорошо разделить на 2 процесса (читай вставить дополнительные промежуточные регистры):

по чётным унарным сигналам захлопывать данные в промежуточный pipeline FF (ну или просто в промежуточный регистр), а уже по нечётным засовывать в выходной сдвиговый регистр.

Что-то типа такого:

always @(posedge clk or posedge i_rst)
begin
  ...
    else
       if(strob)
        begin
            if(sel[0])
                    pipe_ff <= data_in_1;
            if(sel[2])
                    pipe_ff <= data_in_2;
            if(sel[4])
                    pipe_ff <= data_in_3;
            if(sel[6])
                    pipe_ff <= z_in_1;
            if(sel[8])
                    pipe_ff <= z_in_2;
            if(sel[10])
                    pipe_ff <= z_in_3;
	end 

end

always @(posedge clk or posedge i_rst)
begin
      ...
       if(strob)
        begin
            if(sel_reg[1] || sel_reg[3] || sel_reg[5] || sel_reg[7] || sel_reg[9] || sel_reg[11])
                data_out <= pipe_ff[16:31];
			else
              	data_out <= pipe_ff[15:0]
        end
end

Также нужно не забыть дополнительно пропайплайнить все сигналы управления (strob, sel и т.д.), чтобы автомар раньше времени не вышел с состояния

Share this post


Link to post
Share on other sites

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

32 minutes ago, dimka76 said:

Это интересно, но не понял сути идеи. Что именно должно быть на выходе предлагаемого вами декодера ?

У вас 12 бит кодируют  8 состояний    соответсвенно можно на такт раньше сделать  предварительное кодирование  

...
// либо в bin
reg [2:0] sel_r;
  case (sel)
    12'b000000000001 : sel_r <= 3'd1;

    12'b000000000100 : sel_r <= 3'd2;
  ...

// на следующем такте    
  case (sel_r)
    3'd0: begin
      register[15:0] <= data_in_1[31:16];
      data_out[15:0] <= data_in_1[15:0];
    end
...    
    
// либо в onehot     
reg [7:0] sel_r;

  12'b000000000001 : sel_r <= 1<<0;

  12'b000000000100 : sel_r <= 1<<1;
  ...
    
// на следующем такте     
  case (1'b1) // synthesis parallel_case full_case
    sel_r[0]: begin
      register[15:0] <= data_in_1[31:16];
      data_out[15:0] <= data_in_1[15:0];
    end
...    

 

Удачи! Rob

Share this post


Link to post
Share on other sites
1 hour ago, RobFPGA said:

У вас 12 бит кодируют  8 состояний    соответсвенно можно на такт раньше сделать  предварительное кодирование  

......

У меня уже до этого обратное проедоленоого вами производится

module addr_dec(clk, i_rst, addr, a_out) /* synthesis syn_romstyle = "EBR" */;

input wire clk;  
input  wire i_rst;
input  [3:0] addr;	
output wire [11:0] a_out;

reg [11:0] out ;

always @(posedge clk or posedge i_rst)
begin
    if(i_rst)
       out <= 12'd0; 
    else
       case(addr) 
            4'd0:    out <=  12'b000000000001;
            4'd1:    out <=  12'b000000000010;
            4'd2:    out <=  12'b000000000100;
            4'd3:    out <=  12'b000000001000;
            4'd4:    out <=  12'b000000010000;
            4'd5:    out <=  12'b000000100000;
            4'd6:    out <=  12'b000001000000;
            4'd7:    out <=  12'b000010000000;
            4'd8:    out <=  12'b000100000000;
            4'd9:    out <=  12'b001000000000;
            4'd10:   out <=  12'b010000000000;
            4'd11:   out <=  12'b100000000000;
            default: out <=  12'b000000000000;   
      endcase
end

assign a_out = out;

endmodule

И далее

 

 addr_dec AD1 ( .clk(clk_150), .i_rst(g_rst), .addr(addres[3:0]), .a_out(code)) /* synthesis syn_romstyle = "EBR" */;
    
reg_mux RM1 ( .clk(clk_150), .i_rst(g_rst), .sel(code), .strob(rd_strobe), 
             .data_in_1(quad_out_1), .data_in_2(quad_out_2), .data_in_3(quad_out_3), 
             .z_in_1(z_out_1), .z_in_2(z_out_2), .z_in_3(z_out_3),
             .data_out(reg_out));

Наверное стоит убрать addr_dec AD1 (...), а  addres[3:0]) напрямую заводить в  reg_mux RM1 (....)

Share this post


Link to post
Share on other sites

ИМХО, вот такие перлы из-за того, что не читают хендбук на целевую ПЛИС, о том какие строительные кубики есть в этой песочнице)

Share this post


Link to post
Share on other sites

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

11 minutes ago, dimka76 said:

Наверное стоит убрать addr_dec AD1 (...), а  addres[3:0]) напрямую заводить в  reg_mux RM1 (....)

Может быть.  Тут надо понимать как наиболее оптимально  реализуется mux на  архитектуре вашей FPGA (в зависимости от размера и архитектуры LUT).  Я с Lattice не работал  поэтом точно не скажу - но есть 2  варианта  либо классический бинарный mux - или ohehot AND/OR  структура. 

 

Удачи! Rob. 

Share this post


Link to post
Share on other sites
1 hour ago, Nick_K said:

В этом месте было бы хорошо разделить на 2 процесса (читай вставить дополнительные промежуточные регистры):

по чётным унарным сигналам захлопывать данные в промежуточный pipeline FF (ну или просто в промежуточный регистр), а уже по нечётным засовывать в выходной сдвиговый регистр.

Что-то типа такого:

Также нужно не забыть дополнительно пропайплайнить все сигналы управления (strob, sel и т.д.), чтобы автомар раньше времени не вышел с состояния

Боюсь, что это может разойтись с логикой работы моего устройства. Да и все данные, которые здесь используются формируются внутри ПЛИС и привязаны к одному и тому же клоку.

5 minutes ago, des00 said:

ИМХО, вот такие перлы из-за того, что не читают хендбук на целевую ПЛИС, о том какие строительные кубики есть в этой песочнице)

Какие такие ?

Share this post


Link to post
Share on other sites
7 minutes ago, dimka76 said:

Какие такие ?

вы с латтисом работаете, вам и карты в руки .Полагаю что в документе LatticeXP2 Family Data Sheet - Architecture - PFU Blocks должны быть описаны основные кубики. А дальше, ваше сопоставление хотелок, строительным кубикам и вперед, делать оптимальный, для целевой плис, код.

1 hour ago, RobFPGA said:

Удачи! Rob

забыли еще AND-OR мультиплексор. техника древняя, но кое где рабочая)

Share this post


Link to post
Share on other sites
1 час назад, dimka76 сказал:

это может разойтись с логикой работы моего устройства

Тогда лишь остаётся в явном виде описать коммутацию на 1-битных мультиплексорах.

Share this post


Link to post
Share on other sites
18 hours ago, dimka76 said:

Наверное стоит убрать addr_dec AD1 (...), а  addres[3:0]) напрямую заводить в  reg_mux RM1 (....)

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

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

Share this post


Link to post
Share on other sites

Перейдите на one hot. Это быстрее, чем текущий if-else.

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

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.