I found this code which controls an LCD display of an FPGA but it can't seen to understand some of the code, in particular this part
type LCD_CMDS_T is array(integer range <>) of std_logic_vector(9 downto 0);
constant LCD_CMDS : LCD_CMDS_T := ( 0 => "00"&X"3C", --Function Set
1 => "00"&X"0C", --Display ON, Cursor OFF, Blink OFF
2 => "00"&X"01", --Clear Display
3 => "00"&X"02", --return home
4 => "10"&X"48", --H
5 => "10"&X"65", --e
6 => "10"&X"6C", --l
7 => "10"&X"6C", --l
8 => "10"&X"6F", --o
9 => "10"&X"20", --blank
10 => "10"&X"46", --F
11 => "10"&X"72", --r
12 => "10"&X"6F", --o
13 => "10"&X"6D", --m
14 => "10"&X"20", --blank
15 => "10"&X"44", --D
16 => "10"&X"69", --i
17 => "10"&X"67", --g
18 => "10"&X"69", --i
19 => "10"&X"6C", --l
20 => "10"&X"65", --e
21 => "10"&X"6E", --n
22 => "10"&X"74", --t
23 => "00"&X"18"); --Shift left
signal lcd_cmd_ptr : integer range 0 to LCD_CMDS'HIGH + 1 := 0;
I understand that an array has been made to hold values of character to be displayed on the display. but i don't understand this line.
signal lcd_cmd_ptr : integer range 0 to LCD_CMDS'HIGH + 1 := 0;
Can anyone help me to understand whats done here
This signal is being created to index into the string that was created. The constant LCD_CMDS is an array that needs to be indexed. The signal lcd_cmd_ptr is indexing into that constant to drive the display. It is an integer than can be from 0 to 23 in this case.
I bet somewhere there's a line that has:
LCD_CMDS(lcd_cmd_ptr)
signal lcd_cmd_ptr : integer range 0 to LCD_CMDS'HIGH + 1 := 0;
This code defines a signal which can range from 0 to 'whatever the highest index in the LCD_CMDS array is + 1'.
The 'tick' attributes in VHDL are very useful for writing generic code. To be completely generic, the line above ought to be:
signal lcd_cmd_ptr : integer range LCD_CMDS'low to LCD_CMDS'HIGH + 1;
then if someone removed the entry for item 0 in the array, the signal would have a more limited range. Note that explicitly initialising to '0' in the original case and to LCD_CMDS'LOW in the most generic case is not necessary. The VHDL spec guarantees that integers are always initialised to the lowest value they are allowed to have.
If the signal above only needed to go up to the highest value in the array, you could write more concisely:
signal lcd_cmd_ptr : integer range LCD_CMDS'range;
Again, no explicit initialisation required.
Related
I want to understand and improve an VHDL code I got.
In the VHDL implementation there is the following part:
m1(000) <= MetricA(000) + BrMet(3);
m1(001) <= MetricA(001) + BrMet(1);
m1(002) <= MetricA(002) + BrMet(0);
m1(003) <= MetricA(003) + BrMet(2);
m1(004) <= MetricA(004) + BrMet(0);
m1(005) <= MetricA(005) + BrMet(2);
m1(006) <= MetricA(006) + BrMet(3);
m1(007) <= MetricA(007) + BrMet(1);
m1(008) <= MetricA(008) + BrMet(2);
m1(009) <= MetricA(009) + BrMet(0);
m1(010) <= MetricA(010) + BrMet(1);
m1(011) <= MetricA(011) + BrMet(3);
m1(012) <= MetricA(012) + BrMet(1);
m1(013) <= MetricA(013) + BrMet(3);
m1(014) <= MetricA(014) + BrMet(2);
m1(015) <= MetricA(015) + BrMet(0);
where
type BRANCH_METRIC is array (3 downto 0) of STD_LOGIC_VECTOR (7 downto 0);
signal BrMet: RANCH_METRIC := (OTHERS =>(OTHERS => '0'));
type PATH_METRIC is array (15downto 0) of STD_LOGIC_VECTOR (7 downto 0);
signal MetricA: PATH_METRIC := (OTHERS =>(OTHERS => '0'));
My questions:
1. m1(001), .... m1(015) , MetricA(001), .... MetricA(015) mean a value in a position:
m1(001) means a value on the first cell, m1(015) is on the 15th cell.
Can BrMet(0) mean something else?
2. My task is to rewrite code above using for-loop.
I can write :
for i in 1 to 15 loop
m1(i) <= MetricA(i) + BrMet(?);
How can I add BrMet in this loop?
I was thinking to create a table as:
Tab = {3,1,0,2,0,2...}
{3,1,0,2,0,2...} expresses BrMet(3), BrMet(1), BrMet(0) and so on
and the I would write the loop as
for i in 1 to 15 loop
m1(i) <= MetricA(i) + Tab(i);
But unfortunately I didnt find any information how to create a table in VHDL. There is LUT table , bit It doesnt pass for it.
"m1(001) means a value on the first cell, m1(015) is on the 15th cell"
If by "first cell" you mean the cell with the smallest index then no, m1(1) is not the "first" cell, it is the "second" (and m1(15) is the "sixteenth") because you declared your array type with 0 as the "first" index, not 1. Note that, according these array definitions your loops are probably wrong: they should start at index 0, not 1.
"Can BrMet(0) mean something else?"
Else than what? BrMet(0) is the cell of array BrMet with the smallest index.
"How can I add BrMet in this loop?"
You apparently know how to declare array types and use them. This is no different. Just declare an array type and a constant of this type:
type BrMetIdx_t is array(0 to 15) of integer;
constant BrMetIdx: BrMetIdx_t := (3, 1, 0, 2, 0, 2, 3, 1, 2, 0, 1, 3, 1, 3, 2, 0);
...
for i in 0 to 15 loop
m1(i) <= MetricA(i) + BrMet(BrMetIdx(i));
end loop;
...
Note: it would probably be safer to restrict the type of elements of BrMetIdx_t arrays to integers in the 0 to 3 range:
type BrMetIdx_t is array(0 to 15) of integer range 0 to 3;
This way, if there is a typo with, e.g., value 4, in your constant declaration you will get a clear error message from the compiler.
Note: you don't have to declare your array types with a "downto" index range. This is a common practice for vectors of bits because indexing them from right to left is also common but for your m1, MetricA and BrMet arrays you could probably as well index them in a more "natural" way:
type BRANCH_METRIC is array (0 to 3) of STD_LOGIC_VECTOR (7 downto 0);
type PATH_METRIC is array (0 to 15) of STD_LOGIC_VECTOR (7 downto 0);
This would probably help the global understanding.
Note: I doubt that you will ever use multiple drive for the path and branch metrics of your (Viterbi?) decoder. It would thus be safer to use an unresolved type like std_ulogic_vector instead of std_logic_vector. This way, if by accident you create a multiple drive situation, you will get a clear error message from the compiler instead of spending hours trying to understand why you see all these X values during simulation.
I was wondering about how to create a multidimensional matrix using Ada language, I mean, stacking i number of matrix of j x k dimension:
One way I have found is using multidimensional arrays, quite easy.
Are there other ways to accomplish it? Maybe using Ada.Containers.Vectors or mixing it within the array declaration? Any formal library?
Thanks
Here are two examples that might be of use.
The first example shows the use of an array of multi-dimensional arrays. When using this method you need, at some point, to fix the size of the stack of matrices (here: during the declaration of S, the size is fixed to 4). Memory is preallocated to hold all four matrices.
The second example shows the use of an Ada vector container to which matrices can be added. Vectors are "dynamic arrays". Memory is allocated when matrices added.
The Ada standard library that ships with (recent versions of) the GNAT compiler contains formal containers packages (see also here).
example_1.adb
with Ada.Text_IO; use Ada.Text_IO;
procedure Example_1 is
type Rows is new Natural range 0 .. 2;
type Cols is new Natural range 0 .. 2;
type Matrix is array (Rows, Cols) of Integer;
-- A 2D matrix.
type Stack is array (Natural range <>) of Matrix;
-- Stack of 2D matrices.
S : constant Stack (1 .. 4) :=
(1 => (others => (others => 1)),
2 => (others => (others => 2)),
3 => (others => (others => 3)),
4 => (others => (others => 4)));
begin
for Mtx of S loop -- using "of", not "in", such to iterate over the elements.
for R in Rows loop
Put ("[");
for C in Cols loop
Put (Mtx (R, C)'Image);
end loop;
Put_Line (" ]");
end loop;
New_Line;
end loop;
end Example_1;
example_2.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
procedure Example_2 is
type Rows is new Natural range 0 .. 2;
type Cols is new Natural range 0 .. 2;
type Matrix is array (Rows, Cols) of Integer;
-- A 2D matrix.
package Stacks is new Ada.Containers.Vectors (Natural, Matrix);
use Stacks;
subtype Stack is Stacks.Vector;
-- Stack of 2D matrices.
Empty_Stack : constant Stack := Stacks.Empty_Vector;
-- An empty stack.
S : Stack;
-- Instead of using Append (..) shown below, you can also
-- initialize the stack using:
--
-- S : Stack := Empty_Stack
-- & (others => (others => 1))
-- & (others => (others => 2))
-- & (others => (others => 3))
-- & (others => (others => 4));
begin
S.Append ((others => (others => 1)));
S.Append ((others => (others => 2)));
S.Append ((others => (others => 3)));
S.Append ((others => (others => 4)));
-- ...
for Mtx of S loop -- using "of", not "in", such to iterate over the elements.
for R in Rows loop
Put ("[");
for C in Cols loop
Put (Mtx (R, C)'Image);
end loop;
Put_Line (" ]");
end loop;
New_Line;
end loop;
end Example_2;
output (same for both examples)
[ 1 1 1 ]
[ 1 1 1 ]
[ 1 1 1 ]
[ 2 2 2 ]
[ 2 2 2 ]
[ 2 2 2 ]
[ 3 3 3 ]
[ 3 3 3 ]
[ 3 3 3 ]
[ 4 4 4 ]
[ 4 4 4 ]
[ 4 4 4 ]
You could also try standard Ada packages Real Vectors and Matrices or Complex Vectors and Matrices which also provide some operations on matrices. It can be the easiest way to accomplish it.
I'm trying to design an AXI_master peripheral with vivado. I used the axi peripheral generator in vivado menu and modified the vhdl code generated.
In vhdl code there is a function clogb2 declared with following code:
function clogb2 (bit_depth : integer) return integer is
variable depth : integer := bit_depth;
variable count : integer := 1;
begin
for clogb2 in 1 to bit_depth loop -- Works for up to 32 bit integers
if (bit_depth <= 2) then
count := 1;
else
if(depth <= 1) then
count := count;
else
depth := depth / 2;
count := count + 1;
end if;
end if;
end loop;
return(count);
end;
This works in simulation (GHDL) but fail in synthesis with error :
[Synth 8-403] loop limit (65538) exceeded
I tried to increase loop limit in vivado with following tcl command :
set_param synth.elaboration.rodinMoreOptions "rt::set_parameter max_loop_limit <X>"
As explained here, but vivado synthesize with an infinite time and never finish.
Do you know how to solve this problem ?
You could also try a different path. Although floating point is not supported in logic (although support is increasing), it is allowed for internal calculations and such. (By at least Xilinx and Altera/Intel).
Try this:
use ieee.math_real.all;
function ceillog2(input : positive) return natural is
begin
return integer(ceil(log2(real(input))));
end function;
Try constraining the range of the input, for example:
function clogb2 (bit_depth : integer range 1 to 32) return integer is
Also, if Vivado is generating code that it cannot compile, this is a bug that you should report on the Xilinx forums.
Finally I found a solution that work by rewriting the function with a big case :
function clogb2 (bit_depth : integer) return integer is
begin
case bit_depth is
when 0 to 2 => return( 1);
when (2** 1)+1 to 2** 2 => return( 2);
when (2** 2)+1 to 2** 3 => return( 3);
when (2** 3)+1 to 2** 4 => return( 4);
when (2** 4)+1 to 2** 5 => return( 5);
when (2** 5)+1 to 2** 6 => return( 6);
when (2** 6)+1 to 2** 7 => return( 7);
when (2** 7)+1 to 2** 8 => return( 8);
when (2** 8)+1 to 2** 9 => return( 9);
when (2** 9)+1 to 2**10 => return(10);
when (2**10)+1 to 2**11 => return(11);
when (2**11)+1 to 2**12 => return(12);
when (2**12)+1 to 2**13 => return(13);
when (2**13)+1 to 2**14 => return(14);
when (2**14)+1 to 2**15 => return(15);
when (2**15)+1 to 2**16 => return(16);
when (2**16)+1 to 2**17 => return(17);
when (2**17)+1 to 2**18 => return(18);
when (2**18)+1 to 2**19 => return(19);
when (2**19)+1 to 2**20 => return(20);
when (2**20)+1 to 2**21 => return(21);
when (2**21)+1 to 2**22 => return(22);
when (2**22)+1 to 2**23 => return(23);
when (2**23)+1 to 2**24 => return(24);
when (2**24)+1 to 2**25 => return(25);
when (2**25)+1 to 2**26 => return(26);
when (2**26)+1 to 2**27 => return(27);
when (2**27)+1 to 2**28 => return(28);
when (2**28)+1 to 2**29 => return(29);
when (2**29)+1 to 2**30 => return(30);
when (2**30)+1 to (2**31)-1 => return(31);
when others => return(0);
end case;
end;
With this weird code structure, that works in synthesis and simulation.
This recursive version synthesises:
function clogb2 (bit_depth : integer) return integer is
begin
if bit_depth <= 1 then
return 0;
else
return clogb2(bit_depth / 2) + 1;
end if;
end function clogb2;
You can use it to dimension other things, eg
entity counter is
generic (max_count : POSITIVE);
port (clock, reset : in std_logic;
Q : out std_logic_vector(clogb2(max_count) downto 0)
);
end;
or you can use it as combinational logic:
process (I)
begin
O <= clogb2(I);
end process;
BTW: you would be better using an integer subtype for your input:
function clogb2 (bit_depth : positive) return integer is
-- ^
-- |
This question is a continuation to my last question.
As I mentioned before, I'm trying to interface to a classic HD44780 LCD. I have implemented local ram to which I write the data I wish to show up on the display.
The ram is defined this way (slight change from last question):
type ram_type is array (integer range <>) of std_logic_vector(7 downto 0);
signal lcd_mem : ram_type(0 to 16*2-1);
I would like to display a bunch of constant characters and a number in a certain location on the LCD, I tried doing this by writing directly to lcd_mem this way:
lcd_mem <= (0 => x"45", 1 => x"72", 2 => x"72", 3 => x"6F", 4 => x"72", 5 => x"73", 6 => x"3A", 15 => x"30", 16 => x"54", 17 => x"58", 18 => x"3A", 30 => x"4D", 31 => x"3A", others => x"20");
Line 79:
lcd_mem(22 to 28) <= get_ascii(1234567); --to_integer(unsigned(n_bits(39 downto 20)))
the integer 1234567 will later be replaced by the to_integer comment.
I have written the get_ascii function which is supposed to convert the integer into bcd representation and than to ascii by adding 0x30 to the bcd representation.
Here is a part of the function:
variable num : ram_type(0 to 16*2-1);
variable temp : std_logic_vector(number'range);
variable bcd : unsigned ((4*7-1) downto 0) := (others => '0');
.
.
.
num(0) := std_logic_vector(bcd(3 downto 0) + x"30");
num(1) := std_logic_vector(bcd(7 downto 4) + x"30");
num(2) := std_logic_vector(bcd(11 downto 8) + x"30");
num(3) := std_logic_vector(bcd(15 downto 12) + x"30");
num(4) := std_logic_vector(bcd(19 downto 16) + x"30");
num(5) := std_logic_vector(bcd(23 downto 20) + x"30");
num(6) := std_logic_vector(bcd(27 downto 24) + x"30");
return num;
When compiling I'm getting the following error:
Error (10511): VHDL Qualified Expression error at display_ber.vhd(79): get_ascii type specified in Qualified Expression must match ram_type type that is implied for expression by context
I can't quiet understand the meaning of the message.
I have tried defining a shorter variable of ram_type(0 to 6) to receive the value from the get_ascii function but that didn't help.
Ok, apparently this happen because I defined the type "ram_type" in both the package and the architecture.
After deleting the "ram_type" definition in the architecture the error is gone.
For an application I am creating I would like to use a decoder that helps write to one of 42 registers. In order to account for all possible registers, I need a 6 bit input since the ceiling of lg(42) is 6.
However, this will create a 6 to 64 decoder, leaving me with an extra 12 outputs that I do not know how to handle. I know that in VHDL I can write a case statement for it:
case input is
when "000000" => output <= reg0;
when "000001" => output <= reg1;
.
.
.
when others => output <= ???;
end case;
Hopefully everything else will be designed so that an input > 41 does not occur, but how should the code be written to handle that case? Is there a way to handle it without stopping the application some how? Or, as an alternative, is there a way to write a decoder that has only 42 outputs?
An easier way to write this is:
type regs_type is array (integer range <>) of std_logic_vector(7 downto 0);
signal regs : regs_type (0 to 41) := (others => (others => '0'));
...
output <= regs(to_integer(unsigned(input));
Assuming 'input' is an std_logic_vector, and that your registers are 8-bits wide.
Then use the regs array for your registers 0-41. I suppose if you wanted to be explicit about registers 42+, you could create an array of size 64, and leave the upper elements unconnected, but I believe the above code would achieve the same thing.
If your registers actually have meaningful names, not just reg0 etc, you can have a separate block of code connecting these to the regs array, example:
regs(0) <= setup_reg;
regs(1) <= data_out;
and so on. If I was doing it this way, I would have defined constants for the regs index values, example:
constant SETUP_REG_ADDRESS : integer := 0;
constant DATA_OUT_ADDRESS : integer := 1;
...
regs(SETUP_REG_ADDRESS) <= setup_reg;
regs(DATA_OUT_ADDRESS) <= data_out;
Alternatively, if you wanted to keep the case statement, you could write your others clause as
when others => output <= (others => '-');
This 'don't care' value allows the tools to do whatever is the most efficient in these cases that you believe to be unreachable anyway. If you were concerned about something undefined being assigned to output if input somehow did exceed 41, you could always replace the '-' with a '0'.