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

verilog - запихнуть константы

Уважаемые,

 

У меня такой вопрос - как в верилоге запихнуть заранее известные константы в память?

 

Сейчас я делаю так:

 

function signed [31:0] COEF(input [6:0] num)
case (num)
0: COEF = 12312;
1: COEF = 45634;
...
127: COEF = 346523;
endcase
endfunction

 

А потом в коде пишу что-то вроде такого:

 

  a <= b + COEF(x);

 

Однако, у меня создается впечатление, что все эти константы квактус размещает в регистрах.

 

Вопрос - как сделать так, чтобы они поместились в блоки памяти циклона?

 

заранее благодарен.

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


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

Квартус понимает (по крайней мере 7 версии) такое вот

reg [7:0] mem [255:0];
initial mem = $readmem("mem_initialization_filename.mif");

За синтаксис не ручаюсь, проверить сейчас не на чем. Это вроде в мануале по квартусу упоминается, кажись в разделе "Синтез".

 

Также можно сделать визардом память, и указать для нее HEX файл с инициализационной информацией.

 

P.S. Вот нашел: http://www.altera.com/literature/hb/qts/qts_qii5v1_03.pdf страница 9-7 "Initial Constructs and Memory System Tasks"

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


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

Квартус понимает (по крайней мере 7 версии) такое вот

reg [7:0] mem [255:0];
initial mem = $readmem("mem_initialization_filename.mif");

За синтаксис не ручаюсь, проверить сейчас не на чем. Это вроде в мануале по квартусу упоминается, кажись в разделе "Синтез".

 

Также можно сделать визардом память, и указать для нее HEX файл с инициализационной информацией.

 

P.S. Вот нашел: http://www.altera.com/literature/hb/qts/qts_qii5v1_03.pdf страница 9-7 "Initial Constructs and Memory System Tasks"

 

квартус умирает так...

ладно... буду пробовать. спасибо.

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


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

ладно... буду пробовать. спасибо.

COEF через регистр пропустите. Должен тогда в память положить автоматом.

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


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

COEF через регистр пропустите. Должен тогда в память положить автоматом.

 

 

не ложет, зараза...

 

вот код... в нем хотелось бы заменить функцию на что-либо более читаемое...

кажый инклюд содержит строки типа:

0: COEF = ...

1: COEF =

...

127: COEF =

 

 

module fir128
#(
    // Parameter Declarations
    parameter INPUT_WIDTH = 32,    // these two
    parameter COEF_WIDTH = 32,    // must be equal
    parameter OUTPUT_WIDTH = 16,
    parameter ACC_WIDTH = 64,
    parameter DLENGTH = 128
)
(
    // Input Ports
    input clk10,
    input in_latch,
    input reset_n,
    input signed [INPUT_WIDTH-1:0] data_i,
    input signed [INPUT_WIDTH-1:0] data_q,
    input [1:0] coef_set,

    // Output Ports
    output reg data_valid,
    output reg [OUTPUT_WIDTH-1:0] data_out_i,
    output reg [OUTPUT_WIDTH-1:0] data_out_q
);

(* ramstyle = "M9K" *) reg signed [INPUT_WIDTH-1:0] delay_i [DLENGTH-1:0];
(* ramstyle = "M9K" *) reg signed [INPUT_WIDTH-1:0] delay_q [DLENGTH-1:0];

reg signed [ACC_WIDTH-1:0] acc_i, acc_q;
reg signed [INPUT_WIDTH-1:0] dnext_i, dnext_q;

reg signed [INPUT_WIDTH-1:0] cnext;

reg [6:0] rd_addr, wr_addr, ccnt;
reg latched;    

// to avoid overflow:
wire [OUTPUT_WIDTH-1:0] acc_final_i, acc_final_q;
assign acc_final_i = acc_i[ACC_WIDTH-2: ACC_WIDTH-OUTPUT_WIDTH-1];
assign acc_final_q = acc_q[ACC_WIDTH-2: ACC_WIDTH-OUTPUT_WIDTH-1];


integer i;
initial
begin
    acc_i <= 0;
    acc_q <= 0;
    rd_addr <= 0;
    wr_addr <= 0;
    latched <= 0;
    data_valid <= 0;
    ccnt <= 0;
    for (i=0; i<128; i = i + 1)
    begin
     delay_i[i] <= 0;
     delay_q[i] <= 0;  
    end
end
    

function signed [INPUT_WIDTH-1:0] COEF(input [6:0] num);
    // Optional Block Declarations
    case (coef_set)
        2'b00:
        begin
            case(num)
                0: COEF = 1*(2**(COEF_WIDTH-1)-1);
                default: COEF = 0;
            endcase
        end
        2'b01: 
        begin
            case (num)
                `include "coef0001.v"
                default: COEF = 0;
            endcase
        end
        2'b10:
        begin
            case (num)
                `include "coef15.v"
                default: COEF = 0;
            endcase
        end
        2'b11:
        begin
            case (num)
                `include "coef15fm.v"
                default: COEF = 0;
            endcase
        end
    endcase    
endfunction
    
always @(posedge clk10)
begin
    if (reset_n == 0)
        begin
            acc_i <= 0;
            acc_q <= 0;

            rd_addr <= 0;
            wr_addr <= 0;
            latched <= 0;
            data_valid <= 0;
            ccnt <= 0;
        end
    else if (!latched && in_latch  == 1'b1)
        begin
          acc_i <= 0;
            acc_q <= 0;

            latched <= 1;
            data_valid <= 0;
            
            dnext_i <= data_i;
            dnext_q <= data_q;

            cnext <= COEF(0);
            
            delay_i[wr_addr] <= data_i;
            delay_q[wr_addr] <= data_q;
            
            rd_addr <= wr_addr - 1;
            wr_addr <= wr_addr + 1;
            ccnt <= 1;
        end
    else if (latched)
        begin
            acc_i <= acc_i + dnext_i * cnext;
            acc_q <= acc_q + dnext_q * cnext;
            
            dnext_i <= delay_i[rd_addr];
            dnext_q <= delay_q[rd_addr];
      rd_addr <= rd_addr - 1;
      
            cnext <= COEF(ccnt);
            ccnt <= ccnt + 1;
            
            if (ccnt == 0)
                begin
                    data_valid <= 1;
                    latched <= 0;
                    ///------------------------- AVOID OVERFLOW - SATURATE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    data_out_i <= acc_final_i + ((acc_final_i != 16'h7fff) ? acc_i[ACC_WIDTH-OUTPUT_WIDTH-2] : 0);
                    data_out_q <= acc_final_q + ((acc_final_q != 16'h7fff) ? acc_q[ACC_WIDTH-OUTPUT_WIDTH-2] : 0);
                end    
        end
    // end if
end


endmodule

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


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

вот код... в нем хотелось бы заменить функцию на что-либо более читаемое...

Вы хотите, чтобы COEF был памятью. Так и описывайте его как память! Вы delay_i и delay_q ведь описали как память, вот и с коэффициентами поступите также.

reg [31:0] coeff [127:0];
initial begin
  coef[0] = ....
  coef[1] = ...
...
coef[127] = ...
end

либо с использованием $readmemb (не знаю, что значит умирает, у меня работало без проблем.)

 

Если у Вас  не будет попыток читать эту память асинхронно (а в приведенном исходнике этого вроде нет), то все будет с радостью упаковываться в блочную память.

 

В конце концов, попробуйте написать модуль, в котором только ПЗУ, меньше букв - проще найти причину поведения синтезатора.

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


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

не ложет, зараза...

 

Я хотел сказать, что такое на 128 ячеект точно в память упакует

(
input             clk,
input      [7:0]  addr,
output reg [15:0] cos_sin 
);

always @ (posedge clk)
begin
     case (addr)
    8'h00: cos_sin = 16'h7f00;

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


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

включите режим SV и опишите память. а еше лучше mif файл сделайте и поставте black-box

 

ЗЫ. не всегда квартус видит смысл ложить ром в память, если константы простые, то он может сделать все на логике.

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


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

Я хотел сказать, что такое на 128 ячеект точно в память упакует

(
input             clk,
input      [7:0]  addr,
output reg [15:0] cos_sin 
);

always @ (posedge clk)
begin
     case (addr)
    8'h00: cos_sin = 16'h7f00;

Для автора вопроса уточняю: в этом примере нет инициализации по ресету. И это так и должно быть! 

Квартус автоматом кладет в память начиная с 33 адресов.

Но изменив параметр в меню - можно запихнуть в память и меньше адресов. А то ругается, что память маленькая - делаю на регистрах. 

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


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

чего-то нихрена не получается...

серано как не крути фсе ложет на регистры.

На регистрах занимает около 1500 ле.

хм...

 

чего-то нихрена не получается...

серано как не крути фсе ложет на регистры.

На регистрах занимает около 1500 ле.

хм...

 

И еще квартус говорит так:

 

Internal Error: Sub-system: VRFX, File: /quartus/synth/vrfx/verific/verilog/veriname_elab.cpp, Line: 879

read to RAM wasn't mapped to a specific read port

Stack Trace:

 

0xE4F99 : VRFX_ELABORATOR::elaborate + 0x9DA09 (synth_vrfx)

0x80B5 : MEM_SEGMENT_INTERNAL::allocate + 0x95 (ccl_mem)

 

End-trace

 

Quartus II Version 9.0 Build 235 06/17/2009 SJ Web Edition

Service Pack Installed: 2

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


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

F вот для такого кода -

// altera message_off 10030

module dir128
#(    // Parameter Declarations
    parameter INPUT_WIDTH = 32,    // these two
    parameter COEF_WIDTH = 32,    // must be equal
    parameter OUTPUT_WIDTH = 32,
    parameter ACC_WIDTH = 64,
    parameter DLENGTH = 128)
(    // Input Ports
    input clk10,
    input [1:0] coef_set,
    input [6:0] cnt,
    input reset_n,
    
    output reg [OUTPUT_WIDTH-1:0] data_out_i);

(* ramstyle = "M9K" *) reg signed [INPUT_WIDTH-1:0] coef1 [0:DLENGTH-1];
(* ramstyle = "M9K" *) reg signed [INPUT_WIDTH-1:0] coef2 [0:DLENGTH-1];
(* ramstyle = "M9K" *) reg signed [INPUT_WIDTH-1:0] coef3 [0:DLENGTH-1];

initial begin
    $readmemh("coef0.lst",coef1);
    $readmemh("coef1.txt",coef2);
    $readmemh("coef2.txt",coef3);
end
    
always @(posedge clk10)
begin
    case (coef_set)
        0: data_out_i <= (cnt == 6'b0) ? 32'h7fffffff : 32'h0;
        1: data_out_i <= coef1[cnt];
        2: data_out_i <= coef2[cnt];
        3: data_out_i <= coef3[cnt];
    endcase
end
endmodule

 

Почему-то вообще странные вещи происходят:

1. Quartus ругается так:

Info: Found 3 instances of uninferred RAM logic

Info: RAM logic "coef1" is uninferred due to asynchronous read logic

Info: RAM logic "coef2" is uninferred due to asynchronous read logic

Info: RAM logic "coef3" is uninferred due to asynchronous read logic

 

2. После компиляции он не показывает, что используется память.

3. Временная симуляция дает бредовый результат, если 'cnt' переходит из 127 в 0

4. Функциональная вроде хорошо.

 

НО!!! возникает вопрос - куда квартус складывает константы???

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


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

    
always @(posedge clk10)
begin
    case (coef_set)
        0: data_out_i <= (cnt == 6'b0) ? 32'h7fffffff : 32'h0;
        1: data_out_i <= coef1[cnt];
        2: data_out_i <= coef2[cnt];
        3: data_out_i <= coef3[cnt];
    endcase
end
endmodule

 

Почему-то вообще странные вещи происходят:

1. Quartus ругается так:

Info: Found 3 instances of uninferred RAM logic

Info: RAM logic "coef1" is uninferred due to asynchronous read logic

Info: RAM logic "coef2" is uninferred due to asynchronous read logic

Info: RAM logic "coef3" is uninferred due to asynchronous read logic

 

абсолютно правильно ругается, нет у него памяти с асинхронным чтением, о чем он вас и предупреждает. из вашего кода это же очевидно. на 1 регистр у вас приходиться 3 блока памяти + мультиплексор 3в1. Куда по вашему он должен ставить этот мультиплексор ? что бы упахал в память надо было писать так :

 

always @(posedge clk10)
begin
  data_out_i_init <= (cnt == 6'b0) ? 32'h7fffffff : 32'h0;
  data_out_i_ram1 <= coef1[cnt];
  data_out_i_ram2 <= coef2[cnt];
  data_out_i_ram3 <= coef3[cnt];
end

always @(*)
begin
    case (coef_set)
        0: data_out_i = data_out_i_init;
        1: data_out_i = data_out_i_ram1;
        2: data_out_i = data_out_i_ram2;
        3: data_out_i = data_out_i_ram3;
    endcase
end

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


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

абсолютно правильно ругается, нет у него памяти с асинхронным чтением, о чем он вас и предупреждает. из вашего кода это же очевидно. на 1 регистр у вас приходиться 3 блока памяти + мультиплексор 3в1.

 

Тогда такой вопрос (а то я совсем запутался ...)

 

Если я выделяю памяти в 4 раза больше (длина вся 512 элементов):

 

(* ramstyle = "M9K" *) reg signed [iNPUT_WIDTH-1:0] coeffs [0 : DLENGTH*4-1];

 

потом формирую адрес для чтения как cra = {coeff_set,ccnt} (всего 9 бит)

 

и потом по защелке (и по clk10) читаю:

cnext <= coeffs[cra];

ccnt <= 1;

 

и далее по клоку clk10 :

cnext <= coeffs[cra];

ccnt <= ccnt + 1;

 

то получается тоже бред -

квартус выкидывает биты cnext и вообще получаются не правильные коэффициенты.

 

Где я ошибся?

 

wire [8:0] cread_address;
assign cread_address = {coef_set,ccnt};

always @(posedge clk10)
begin
    if (reset_n == 0)
        begin
            acc_i <= 0;
            acc_q <= 0;

            rd_addr <= 0;
            wr_addr <= 0;
            latched <= 0;
            data_valid <= 0;
            ccnt <= 0;
        //    $readmemh("coeffs.txt", coeffs);
        end
    else if (!latched && in_latch  == 1'b1)
        begin
          acc_i <= 0;
            acc_q <= 0;

            latched <= 1;
            data_valid <= 0;
            
            dnext_i <= data_i;
            dnext_q <= data_q;

            cnext <= coeffs[cread_address];    // should be always zero
            
            delay_i[wr_addr] <= data_i;
            delay_q[wr_addr] <= data_q;
            
            rd_addr <= wr_addr - 1;
            wr_addr <= wr_addr + 1;
            ccnt <= 1;
        end
    else if (latched)
        begin
            acc_i <= acc_i + dnext_i * cnext;
            acc_q <= acc_q + dnext_q * cnext;
            
            dnext_i <= delay_i[rd_addr];
            dnext_q <= delay_q[rd_addr];
            rd_addr <= rd_addr - 1;
      
            cnext <= coeffs[cread_address];
            ccnt <= ccnt + 1;
            
            if (ccnt == 0)
                begin
                    data_valid <= 1;
                    latched <= 0;
                    ///------------------------- AVOID OVERFLOW - SATURATE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    data_out_i <= acc_final_i + ((acc_final_i != 16'h7fff) ? acc_i[ACC_WIDTH-OUTPUT_WIDTH-2] : 0);
                    data_out_q <= acc_final_q + ((acc_final_q != 16'h7fff) ? acc_q[ACC_WIDTH-OUTPUT_WIDTH-2] : 0);
                end    
        end
    // end if
end

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


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

Тогда такой вопрос (а то я совсем запутался ...)

 

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

 

 
module fir_ram
#(
 parameter int pID_W  = 18,
 parameter int pOD_W  = 18
)
(
 iclk ,
 ival ,
 idat ,
 oval ,
 odat
);

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

 input  logic               iclk  ;
 input  logic               ival  ;
 input  logic [pID_W-1 : 0] idat  ;
 output logic               oval  ;
 output logic [pOD_W-1 : 0] odat  ;

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

 localparam int cC_W   = 18;
 localparam int cACC_W = pID_W + cC_W;

 typedef logic signed [pID_W-1 : 0]  dat_t;
 typedef logic signed [cC_W-1 : 0]   coe_t;
 typedef logic signed [cACC_W-1 : 0] acc_t;


 localparam coe_t cCOE [0 : 63] = '{
            58,
           -12,
          -115,
          -183,
          -139,
            43,
           285,
           419,
           281,
          -151,
          -663,
          -875,
          -482,
           463,
          1433,
          1665,
           674,
         -1233,
         -2904,
         -2930,
          -666,
          2979,
          5679,
          4960,
            15,
         -7078,
        -11781,
         -9280,
          2613,
         21542,
         41050,
         53404,
         53404,
         41050,
         21542,
          2613,
         -9280,
        -11781,
         -7078,
            15,
          4960,
          5679,
          2979,
          -666,
         -2930,
         -2904,
         -1233,
           674,
          1665,
          1433,
           463,
          -482,
          -875,
          -663,
          -151,
           281,
           419,
           285,
            43,
          -139,
          -183,
          -115,
           -12,
            58
   };

 logic [6 : 0] cnt;
 logic         cycle_done;
 logic [5 : 0] wptr;
 logic [5 : 0] rptr;

 logic sop, eop, val, done;

 dat_t dat [0 : 63]  ;
 dat_t dat2mult      /*synthesis ramstyle = "M4K, no_rw_check"*/;

 coe_t coe2mult      /*synthesis ramstyle = "M4K, no_rw_check"*/;

 acc_t mult;
 acc_t acc;
 //------------------------------------------------------------------------------------------------------
 //
 //------------------------------------------------------------------------------------------------------
 // synthesis translate_off
 initial begin : ini
   cnt       = 7'h40;
   wptr      = '0;
   rptr      = '0;
   dat       = '{default : 0};
   dat2mult  = '0;
   coe2mult  = '0;
   acc       = '0;
   oval      = '0;
   done      = '0;
 end
 // synthesis translate_on
 //------------------------------------------------------------------------------------------------------
 //
 //------------------------------------------------------------------------------------------------------

 assign cycle_done = cnt [6];

 always_ff @(posedge iclk) begin
   if (ival) begin
     cnt       <= '0;

     wptr      <= wptr + 1'b1;
     rptr      <= wptr;
     dat[wptr] <= idat;
   end
   else if (!cycle_done) begin
     cnt       <= cnt + 1'b1;
     coe2mult  <= cCOE[cnt];

     rptr      <= rptr - 1'b1;
     dat2mult  <= dat[rptr];
   end

   sop   <= !(|cnt[5:0]);
   val   <= !(cycle_done);
   eop   <= (&cnt[5:0]);
   //
 end

 assign mult = dat2mult * coe2mult;

 always_ff @(posedge iclk) begin
   done <= eop;

   if (sop)
     acc <= mult;
   else if (val)
     acc <= acc + mult;

   oval <= done;
   if (done)
     odat <= acc[cACC_W-1 : cACC_W - pOD_W];
 end

endmodule


// synthesis translate_off
module tb ;

 parameter int pID_W  = 18 ;
 parameter int pOD_W  = 19 ;



 logic               iclk  ;
 logic               ival  ;
 logic [pOD_W-1 : 0] idat  ;
 logic               oval  ;
 logic [pOD_W-1 : 0] odat  ;



 fir_ram
 #(
   .pID_W ( pID_W ) ,
   .pOD_W ( pOD_W )
 )
 fir_ram
 (
   .iclk ( iclk ) ,
   .ival ( ival ) ,
   .idat ( idat ) ,
   .oval ( oval ) ,
   .odat ( odat )
 );

 initial begin : ini
   iclk <= 1'b0;
   #5ns forever #5ns iclk = ~iclk;
 end

 initial begin : main
   ival <= '0;
   idat <= '0;
   repeat (2) @(posedge iclk);
   for (int i = 0; i < 128; i++) begin
     int data;
     data = (i == 64)*(2**(pID_W-1)-1);
     set_data(data);
   end
   repeat (63) set_data(0);
   $stop;
 end

 task set_data (input int data );
   ival <= 1'b1;
   idat <= data;
   @(posedge iclk);
   ival <= 1'b0;
   repeat (63) @(posedge iclk);
 endtask
endmodule
// synthesis translate_on

 

результат синтеза в ква

 

Resource Usage

Total logic elements 96 / 24,624 ( < 1 % )

-- Combinational with no register 18

-- Register only 20

-- Combinational with a register 58

 

Logic element usage by number of LUT inputs

-- 4 input functions 2

-- 3 input functions 49

-- <=2 input functions 25

-- Register only 20

 

Logic elements by mode

-- normal mode 26

-- arithmetic mode 50

 

Total registers* 78 / 24,964 ( < 1 % )

-- Dedicated logic registers 78 / 24,624 ( < 1 % )

-- I/O registers 0 / 340 ( 0 % )

 

Total LABs: partially or completely used 7 / 1,539 ( < 1 % )

User inserted logic elements 0

Global signals 1

M9Ks 2 / 66 ( 3 % )

Total block memory bits 2,240 / 608,256 ( < 1 % )

Total block memory implementation bits 18,432 / 608,256 ( 3 % )

Embedded Multiplier 9-bit elements 2 / 132 ( 2 % )

 

дальше думаю разберетесь :)

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


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

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

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

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

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

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

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

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

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

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