Sara
Sara

Reputation: 21

Creating ROM in verilog without using Block ROM

I want to create a ROM (just like a look up table) for storing ASCII characters in a way that when I extract the character from the ROM, I can display it on a video screen.

Character is supposed to take 8 pixels column wise and 16 pixels row wise (16*8) and each pixel gets a 10 bit value- 10'b 1111111111 for maximum luminance and 10'b 0000000000 for minimum.

Since, I cannot create a 2D array in verilog how am I supposed to create a 1D array and implement this?

Upvotes: 2

Views: 10443

Answers (2)

sharvil111
sharvil111

Reputation: 4381

Two dimensional arrays can not be at port input/output in Verilog. But they can be declared and used within inside module.

Here, the memory is 80 bit wide and with a depth of 16. So, the address width must be log2(16) = 4, 4 bits wide.

You can implement something as follows (broad view pseudo-code). Here, mem[0] is least address block, and each block has 0th bit as LSB with 79th bit as 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

Without using internal memory, it would be a bit difficult to get through addresses. Memory is to be declared as packed array this time, so its 1280(16*80) bits wide.Following is method for packed array:

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

The -: operator is used for bit slicing. As follows, refer to Verilog slicing link for further information.

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

There is no difference (or perhaps, a little difference) between using packed and unpacked arrays. So, prefer using mixed block array.

For loading data into ROM from a file, refer to this link. Though $readmemh shall make it non-synthesizable.

For more information, on accessing memory using refer to this link. This site shows synthesizable module.

For two dimensional arrays, refer to this question.

Upvotes: 0

mcleod_ideafix
mcleod_ideafix

Reputation: 11428

You can create such memory using a reg, like this:

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 would be a text file with a 10 bit hex number per line. The first 8 hex numbers would be the pixels of the first scan of the first character. Next, the following 8 pixels for the second scan of the first character, and so until the 8 pixels of the 16-th scan of the first character. Then, the 8 pixels of the first scan of the second character, and so on.

Note that even you cannot use n-dimensional matrices in Verilog (with n>=3), you can take advantage of your dimensions being powers of two (256x16x8), so a 1D vector can be used to implement it, by just concatenating the indexes to form a unique memory address (well, as yo usee, it's actually a 2D vector if you see it as a bit element matrix instead of a 10-bit element vector).

Note too that, despite you have asked for a non block-RAM solution, you will want to use that, as a distributed memory solution for a reg like this will surely eat many of your precious logic resources and will take ages to synthesize, and I don't see a reason why this ROM cannot be implemented in block-RAM.

Let assume that your video controller will have two counters: x, y for instance. Assuming your active region is 640x480, and the character ASCII code you want to draw is stored in character (a 8 bit reg), you may do as this:

wire [9:0] pixel;

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

To make charmem to output a black pixel when the video controller is not updating the active region, you can add a videoenable signal to it, so if it is '1', the pixel is the one retrieved from the ROM, otherwise is a black.

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

videoenable would be updated as this:

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

Upvotes: 1

Related Questions