不使用Block ROM在verilog中创建ROM

时间:2015-11-28 14:46:21

标签: verilog

我想创建一个ROM(就像一个查找表),用于存储ASCII字符,当我从ROM中提取字符时,我可以在视频屏幕上显示它。

字符应该采用8像素列和16像素行(16 * 8),每个像素获得10位值 - 最大亮度和10'b 1111111111 最少10'b 0000000000。

因为,我不能在verilog中创建一个2D数组我应该如何创建一维数组并实现它?

2 个答案:

答案 0 :(得分:1)

您可以使用reg创建此类内存,如下所示:

module charmem (
  input wire clk,
  input wire [7:0] charaddr,
  input wire [3:0] scanaddr,
  input wire [2:0] pixeladdr,
  output reg [9:0] pixel
  );

  reg [9:0] chars[0:32767]; // 256 chars, 16 scans, 8 pixels
  initial begin
    $readmemh ("chardef.hex", chars, 0); // this IS synthesizable on Xilinx
  end

  always @(posedge clk) begin
    scan <= chars[{charaddr,scanaddr,pixeladdr}];
  end
endmodule

chardef.hex将是一个文本文件,每行10位十六进制数。前8个十六进制数字将是第一个字符的第一次扫描的像素。接下来,对于第一个字符的第二次扫描,接下来的8个像素,直到第一个字符的第16个扫描的8个像素为​​止。然后,第二个字符的第一次扫描的8个像素,依此类推。

请注意,即使您不能在Verilog中使用n维矩阵(n> = 3),您也可以利用您的维数为2的幂(256x16x8),因此可以使用1D向量来实现它,只是连接索引以形成一个唯一的内存地址(好吧,如果你把它看作是一个位元素矩阵而不是一个10位元素向量,它实际上是一个2D向量)。

另请注意,尽管您已经要求使用非Block-RAM解决方案,但您仍然希望使用它,因为像这样的reg的分布式内存解决方案肯定会占用您宝贵的许多逻辑资源,并且需要很长时间才能使用合成,我不明白为什么这个ROM无法在Block-RAM中实现。

假设您的视频控制器有两个计数器:xy。假设您的活动区域为640x480,并且您要绘制的字符ASCII代码存储在character(8位注册)中,您可以这样做:

wire [9:0] pixel;

charmem chartable (
  .clk(clk),
  .charaddr(character),
  .scanaddr(y[3:0]),
  .pixeladdr(x[2:0]),
  .pixel(pixel)
);

要在视频控制器未更新活动区域时使charmem输出黑色像素,您可以向其添加videoenable信号,因此如果它是&#39; 1&#39;,则像素是从ROM中检索到的,否则是黑色。

  always @(posedge clk) begin
    if (videoenable == 1'b1)
      scan <= chars[{charaddr,scanaddr,pixeladdr}];
    else
      scan <= 10'h000;
  end

videoenable将更新为:

reg videoenable;
always @* begin
  if (x >= 10'd0 && x <= 10'd639 &&
      y >= 10'd0 && y <= 10'd479)
      videoenable = 1'b1;
  else
      videoenable = 1'b0;
end

答案 1 :(得分:0)

二维数组不能位于Verilog中的端口输入/输出。但是可以内部模块中声明和使用。

此处,内存为80位宽,深度为16.因此,地址宽度必须为log2(16) = 4 4位宽。< / p>

您可以按如下方式实现内容(广义视图伪代码)。这里,mem[0]是最少的地址块,每个块的第0位为LSB,第79位为MSB:

module memory(address,read_en,clk,reset,out);

// clk,reset declarations

// address to be accessed in memory
input reg [3:0] address;
// read/write signal
input read_en;
//output signal, for data read from memory
output [79:0] out;

// internal memory, accessed through address only
reg [79:0] mem [16];

// inside always block
// clock synchronous block
always @(posedge clk, negedge reset)
begin
// reset logic, followed by: 
if(read_en)
begin
out <= mem[address];
end
end

endmodule

不使用内部存储器,通过地址会有点困难。这次存储器被声明为压缩数组,所以它的宽度为1280(16 * 80)。以下是打包数组的方法:

// rest all declarations are same.
reg [1279:0] mem;
out<=mem[(((address+1)*80)-1) -: 80];

-:运算符用于位切片。如下所示,请参阅Verilog slicing link以获取更多信息。

x -: Y, the start position is x and count down from x by Y. Y is necessarily a constant.

使用打包和解压缩的数组之间存在无差异(或者可能有一点差异)。所以,更喜欢使用混合块数组

要从文件将数据加载到ROM,请参阅this链接。虽然$readmemh会使不可合成

有关更多信息,请参阅this链接访问内存。此网站显示可合成模块

对于二维数组,请参阅this问题。