在Verilog中查找二维数组中的列

时间:2019-04-14 01:13:46

标签: verilog fpga

我有以下代码:

`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

这个问题的重点是变量:输出寄存器[1022:0] rec_vector = 1023'd0

我正在使用Mersenne Twister随机数生成器加载此向量。梅森捻线器提供一个64位数字,然后将其映射为4位数字。生成256个这样的4位数字,以填充rec_vector变量中的一行。

现在,我需要选择此二维数组中的每一行,并将其发送以进行解码。这很简单。我可以编写类似rec_vector [row_index]的内容来获取特定行。 在对每一行进行操作之后,我还需要对列执行相同的操作。如何从二维数组中取出列?

请注意,一种简单的方法,例如创建导线和分配它们,如: codeword_column [0] = {rec_vector [0] [0],rec_vector [1] [0] .....,rec_vector [1022] [0]}不起作用。如果执行此操作,则利用率将大打折扣,因为现在我正在对2-d数组进行异步读取,并且由于块ram仅支持同步读取,因此无法将2-d数组推断为block ram。

我真的很感激与此有关的任何投入。感谢您抽出宝贵时间阅读本

1 个答案:

答案 0 :(得分:0)

我将给出完整的答案,而不是作为不久前出现的类似问题的评论:Accessing a million bits

实际上,您要问的是“如何在列模式下访问行中的二维数组”。

仅当您使阵列完全不在寄存器中时,这才有可能。

一旦您拥有很多位,太多了以至于无法存储在寄存器中,您就必须依靠内存。那么,如何访问内存中列中的行?
答案是非常不令人满意的:“您不能。”

不幸的是,存储器是在长行中实现的,而硬件仅允许您一次只选择一行。要访问列,您必须遍历地址,读一行并选择所需的列。这意味着读取一个列元素需要一个时钟周期。

加快速度的首要方法是使用双端口内存。我知道的FPGA上的存储器都是双端口的。这样您就可以一次从不同的地址进行两次读取。

您还可以通过一次存储两行来加快访问速度。例如一个8x8字节的数组可以存储为16x4,读取使您一次可以访问两行,因此可以访问两个列元素。 (但是收益递减,您将再次得到一大堆寄存器。)

将其与双端口访问相结合,每个时钟周期为您提供四列。

在以上链接中也提到了最后一个警告:FPGA有两种类型的存储器:

  • 必须使用LUT的同步写入和异步读取。
  • 他们具有的同步写入可以使用内部存储库。

后者的存储量最大。因此,如果您编写代码以使用前者,则可以快速发现自己的资源不足。