Поиск столбцов в двумерном массиве в Verilog - PullRequest
0 голосов
/ 14 апреля 2019

У меня есть следующий код:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 04/07/2019 01:20:06 PM
// Design Name: 
// Module Name: data_generator_v1
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


  module data_generator_v1 #(
    // Define parameters 
    parameter integer MAPPING_NUMBER = 196  // MAPPING NUMBER IS USED TO SET A SPECIFIC PROBABILITY (16 BIT SCALING --> MAX VALUE = 65535 --> MAPPING NUMBER = 65535 * 0.03 == 196)
  )
  (
    input S_AXI_ACLK ,   // Input clock 
    input S_AXI_ARESETN, // RESET signal (active low )
    input start_twister,
    output reg [1022:0] rec_vector = 1023'd0,
    output reg start_decoding = 1'b0 ,
    output integer random_vector_bit_errors = 0 
  );

  // Mersenne Twister signals ----------------------------------------------------------------------
  wire [63:0] output_axis_tdata ;
  wire output_axis_tvalid ;
  wire output_axis_tready ;
  wire busy ;
  wire [63:0] seed_val ;
  wire seed_start ;
  //--------------------------------------------------------------------------------------------------

  // Signals ----------------------------------------------------------------------------------------
  wire [3:0] random_nibble ;   
  integer nibble_count = 256 ; // initialize to 256 
  reg [1023:0] random_vector = 1024'd0;
  reg sample_random_vector = 1'b0;
  reg [9:0] bit_errors = 10'd0 ;

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

  // Generate numbers with a specific probability 
  assign random_nibble[0] = (output_axis_tdata[15:0]  < MAPPING_NUMBER) ? 1 : 0 ;
  assign random_nibble[1] = (output_axis_tdata[31:16] < MAPPING_NUMBER) ? 1 : 0 ;
  assign random_nibble[2] = (output_axis_tdata[47:32] < MAPPING_NUMBER) ? 1 : 0 ;
  assign random_nibble[3] = (output_axis_tdata[63:48] < MAPPING_NUMBER) ? 1 : 0 ;  

  // Generate a random vector ------------------------------------------------------------------------
  always@(posedge S_AXI_ACLK) begin 
    if(S_AXI_ARESETN == 1'b0 ) begin 
      random_vector            <= 1024'd0 ;
      sample_random_vector     <= 1'b0 ;
      nibble_count             <= 256 ;
      random_vector_bit_errors <= 0 ;
      bit_errors               <= 0 ;
    end 
    else begin 
      if(output_axis_tvalid == 1'b1) begin 
        if(nibble_count == 0 ) begin 
          random_vector            <= random_vector ;
          sample_random_vector     <= 1'b1 ;
          nibble_count             <= 256  ;
          random_vector_bit_errors <= bit_errors ;
          bit_errors               <= 0 ;
        end
        else begin 
          nibble_count             <= nibble_count - 1 ;  // 256*4 == 1024 bit vector 
          sample_random_vector     <= 1'b0 ;
          random_vector            <= (random_vector << 4) ^ random_nibble ;
          random_vector_bit_errors <= random_vector_bit_errors ;
          if(nibble_count == 256) begin 
            case(random_nibble[2:0])
              3'b000 : bit_errors <= bit_errors  ;
              3'b001 : bit_errors <= bit_errors + 1 ;
              3'b010 : bit_errors <= bit_errors + 1 ;
              3'b011 : bit_errors <= bit_errors + 2 ;
              3'b100 : bit_errors <= bit_errors + 1 ;
              3'b101 : bit_errors <= bit_errors + 2 ;
              3'b110 : bit_errors <= bit_errors + 2 ;
              3'b111 : bit_errors <= bit_errors + 3 ;
            endcase
          end 
          else begin 
            case (random_nibble) 
              4'b0000 : bit_errors <= bit_errors ;
              4'b0001 : bit_errors <= bit_errors + 1 ;
              4'b0010 : bit_errors <= bit_errors + 1 ;
              4'b0011 : bit_errors <= bit_errors + 2 ;
              4'b0100 : bit_errors <= bit_errors + 1 ;
              4'b0101 : bit_errors <= bit_errors + 2 ;
              4'b0110 : bit_errors <= bit_errors + 2 ;
              4'b0111 : bit_errors <= bit_errors + 1 ;
              4'b1000 : bit_errors <= bit_errors + 1 ;
              4'b1001 : bit_errors <= bit_errors + 2 ;
              4'b1010 : bit_errors <= bit_errors + 2 ;
              4'b1011 : bit_errors <= bit_errors + 3 ;
              4'b1100 : bit_errors <= bit_errors + 2 ;
              4'b1101 : bit_errors <= bit_errors + 3 ;
              4'b1110 : bit_errors <= bit_errors + 3 ;
              4'b1111 : bit_errors <= bit_errors + 4 ;
            endcase
          end
        end   
      end
    end 
  end 

  // Sample output for the next block 
  always@(posedge S_AXI_ACLK) begin 
    if(S_AXI_ARESETN == 1'b0) begin
      rec_vector     <= 1023'd0 ;    
      start_decoding <= 1'b0 ;
    end 
    else begin 
      if(sample_random_vector) begin 
        rec_vector     <= random_vector[1022:0] ;
        start_decoding <= 1'b1                  ;
      end 
      else begin 
        rec_vector     <= rec_vector ;
        start_decoding <= 1'b0       ;
      end 
    end  
  end 

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


  //  //-------------------------------------------------------------------------------------------------------------------------------------
  //    // STANDARD CLOCK AND RESET 
  //    //output_axis_tdata contains valid data when output_axis_tvalid is asserted 
  //    // output_axis_tready is input into the mersenne twister and we can use this to accept or stop the generation of new data streams 
  //    // busy is asserted when the mersenne twister is performing some computations 
  //    // seed val is not used . It will start will default seed
  //    // seed start --> not used 

  // Mersenne twister signal assignment 
  assign seed_val   = 64'd0 ;  // used for seeding purposes 
  assign seed_start = 1'b0 ;   // We do not want to assign a new seed so we proceed with the default one 
  assign output_axis_tready = (S_AXI_ARESETN == 1'b0 || start_twister == 0  ) ? 1'b0 : 1'b1 ; // knob to turn the twister on and off
  // MODULE INSTANTIATION
  axis_mt19937_64 AMT19937(S_AXI_ACLK,S_AXI_ARESETN,output_axis_tdata,output_axis_tvalid,output_axis_tready,busy,seed_val,seed_start) ;
  //    //-------------------------------------------------------------------------------------------------------------------------------------
endmodule

Тема этого вопроса - переменная: output reg [1022: 0] rec_vector = 1023'd0

Я загружаю этот вектор, используя генератор случайных чисел Мерсенна Твистера.Twister Mersenne предоставляет 64-битное число, которое затем отображается в 4-битное число.256 таких 4-битных чисел генерируются для заполнения одной строки в переменной rec_vector.

Теперь мне нужно выбрать каждую строку в этом двумерном массиве и отправить ее для декодирования.Это простоЯ могу написать что-то вроде rec_vector [row_index], чтобы получить конкретную строку.После того, как я строю операцию над каждой из строк, мне нужно выполнить ту же операцию и над столбцами.Как я могу получить столбцы из этого 2-го массива?

Обратите внимание, что простой подход, как создание проводов и их назначение, например: codeword_column [0] = {rec_vector [0] [0], rec_vector [1] [0] ....., rec_vector [1022] [0]} не работает.Если я это сделаю, использование будет взорвано, так как теперь я делаю асинхронное чтение для 2-го массива, и этот 2-й массив больше не может быть выведен как блок памяти, так как блок памяти может поддерживать только синхронные чтения.

Буду очень признателен за любые замечания по этому поводу.Спасибо, что нашли время, чтобы прочитать это

1 Ответ

0 голосов
/ 14 апреля 2019

Я дам это как полный ответ, а не как комментарий, как похожий вопрос, возникший недавно: Доступ к миллиону битов

На самом деле то, что вы спрашиваете«Как я могу получить доступ к 2d-массиву в строке и в режиме столбца».

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

Как только у вас будет много битов, слишком много, чтобы хранить их в регистрах, вам придется прибегнуть к воспоминаниям.Так как же вам получить доступ к строкам и в столбцах в памяти?
И ответ очень неудовлетворительный: «Вы не можете».

К сожалению,Память реализована в виде длинных рядов битов, а аппаратное обеспечение позволяет выбирать только одну строку за раз.Чтобы получить доступ к столбцам, вы должны пройтись по адресам, прочитав одну строку и выбрав нужные столбцы.Это означает, что чтение одного элемента столбца стоит один такт.

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

Вы также можете ускорить доступ, сохраняя две строки за раз.Например, массив 8x8 байтов может быть сохранен как 16x4, и чтение дает вам доступ к двум строкам одновременно и, таким образом, к двум элементам столбца.(Но это приводит к уменьшению отдачи, в результате вы снова получаете один огромный ряд регистров.)

Комбинируя это с двухпортовым доступом, вы получаете четыре столбца за такт.

Так же, как последнее предупреждение, которое также упомянуто в приведенной выше ссылке: FPGA имеют два типа памяти:

  • Синхронная запись и асинхронное чтение, для которых они должны использовать LUT..
  • Синхронная запись и чтение , для которых они могут использовать банки внутренней памяти.

Последние имеют наибольший объем памяти.Таким образом, если вы напишите свой код для использования первого, вы можете быстро найти себя вне ресурсов.

...