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

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

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

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

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

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

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

Итак. 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

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

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


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

9 minutes ago, dimka76 said:

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

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

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


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

12 минут назад, dimka76 сказал:

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

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

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


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

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

4 minutes ago, dimka76 said:

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

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

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

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

 

1 minute ago, iosifk said:

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

:scratch_one-s_head::wacko2: 

Удачи! Rob.

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


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

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. Естественно если это допустимо по логике дизайна.  

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

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


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

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 и т.д.), чтобы автомар раньше времени не вышел с состояния

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


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

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

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

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


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

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 (....)

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


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

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

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


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

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

11 minutes ago, dimka76 said:

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

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

 

Удачи! Rob. 

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


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

1 hour ago, Nick_K said:

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

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

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

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

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

5 minutes ago, des00 said:

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

Какие такие ?

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


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

7 minutes ago, dimka76 said:

Какие такие ?

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

1 hour ago, RobFPGA said:

Удачи! Rob

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

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


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

1 час назад, dimka76 сказал:

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

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

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


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

18 hours ago, dimka76 said:

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

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

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

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


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

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

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

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


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

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

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

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

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

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

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

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

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

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