我想创建一个ROM(就像一个查找表),用于存储ASCII字符,当我从ROM中提取字符时,我可以在视频屏幕上显示它。
字符应该采用8像素列和16像素行(16 * 8),每个像素获得10位值 - 最大亮度和10'b 1111111111 最少10'b 0000000000。
因为,我不能在verilog中创建一个2D数组我应该如何创建一维数组并实现它?
答案 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中实现。
假设您的视频控制器有两个计数器:x
,y
。假设您的活动区域为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问题。