我想创建一个ROM (就像一个查找表)来存储ASCII字符,当我从ROM中提取字符时,我可以在视频屏幕上显示它。
假设字符以8个像素为列,16个像素为行(16*8),并且每个像素获得10位值- 10'b 1111111111表示最大亮度,10'b 0000000000表示最小亮度。
既然我不能在verilog中创建一个2D数组,我该如何创建一个1D数组并实现它呢?
发布于 2015-11-29 00:41:56
您可以使用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
endmodulechardef.hex将是一个文本文件,每行包含10位十六进制数字。前8个十六进制数字将是第一个字符的第一次扫描的像素。接下来,对第一个字符进行第二次扫描,直到第8个像素对第一个字符进行第二次扫描。然后,第二个字符的第一次扫描的8个像素,依此类推。
请注意,即使你不能在Verilog中使用n维矩阵(使用n>=3),你也可以利用你的维数是2的幂(256x16x8),所以可以使用一个1D向量来实现它,只需将索引连接起来形成一个唯一的内存地址(好的,正如你所使用的,如果你把它看作一个位元素矩阵而不是一个10位元素向量,它实际上是一个2D向量)。
还要注意的是,尽管你已经要求了一个非块RAM解决方案,但你会想要使用它,因为像这样的reg的分布式内存解决方案肯定会消耗你许多宝贵的逻辑资源,并且需要很长时间才能合成,我看不出为什么这个ROM不能在块RAM中实现。
假设您的视频控制器将有两个计数器:例如,x和y。假设您的活动区域是640x480,并且您要绘制的字符ASCII码存储在character (一个8位reg)中,您可以这样做:
wire [9:0] pixel;
charmem chartable (
.clk(clk),
.charaddr(character),
.scanaddr(y[3:0]),
.pixeladdr(x[2:0]),
.pixel(pixel)
);要使charmem在视频控制器未更新活动区域时输出黑色像素,可以向其添加videoenable信号,因此如果该信号为“1”,则该像素是从只读存储器中检索的像素,否则是黑色像素。
always @(posedge clk) begin
if (videoenable == 1'b1)
scan <= chars[{charaddr,scanaddr,pixeladdr}];
else
scan <= 10'h000;
endvideoenable将按如下方式更新:
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发布于 2015-11-29 00:10:28
在中,二维数组不能位于端口输入/输出。但是它们可以在模块中的中声明和使用。
此处,存储器为80位宽,深度为16。因此,地址宽度必须为log2(16) = 4,为4位宽。
你可以像下面这样实现一些东西(宽视图伪代码)。这里,mem[0]是最小地址块,且每个块具有第0位作为最低有效位,第79位作为最低有效位:
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)位wide.Following是压缩数组的方法:
// 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.在使用压缩数组和未压缩数组之间没有任何区别(或者可能有一点区别)。因此,最好使用混合数据块阵列。
有关将数据从文件加载到只读存储器的信息,请参阅this链接。尽管$readmemh应该让它成为non-synthesizable.
有关使用访问内存的更多信息,请参阅this链接。该网站展示了可合成模块。
有关二维数组,请参阅this问题。
https://stackoverflow.com/questions/33972595
复制相似问题