Quite new to VHDL here, so I'm not entirely sure if this is feasible at all, but here goes:
In my test code for some RAM, I have 2 8-bit std_logic_vector variables wdata_a_v and wdata_b_v. This is all I need for the current setup, but if the ratio of read to write data length changes, I will need more variables of the name wdata_*_v. I'm trying to write the code generically so that it will function for any amount of these variables, but I don't want to declare 26 of them in the code when I will likely only need a few.
It would be nice if there was a way to declare a variable like so:
variable wdata_*_v : std_logic_vector (7 downto 0);
that would, behind the scenes, declare all of the variables that fit this framework so that I could write a loop without worrying about running out of variables.
If there's a way to write a function or procedure etc. to make this work, that would be excellent.
Yes, you can go with a 2d array, recipe:
entity TestHelper is
generic (n: natural range 2 to 255 := 8);
end TestHelper;
architecture behavioral of TestHelper is
type array2d is array (n-1 downto 0) of std_logic_vector(7 downto 0);
begin
process
variable a : array2d;
begin
a(0)(0) := '0';
end process;
end architecture behavioral;
EDIT: Now to use it and create similar code for each of wdata_*_v:
process
variable wdata_v : array2d;
begin
someLabel: for i in 0 to n-1 generate
wdata_v(i)(0) := '0';
x <= y and z;
...
end generate;
x <= '1';
...
anotherLabel: for i in 1 to n generate
...
end generate;
...
end process;
Related
I have a code written for multiplying two 53 bit numbers (written below). I am using shift-add strategy using two other 106 bit registers. This code is working fine. Now I have another 53 bit highly optimized hans carlson adder module written in form:
module hans_carlson_adder(input [52:0] a, b, input c_in, output [52:0] sum, output c_out);
I want to use this adder to do the summation line in for loop (mentioned in code). I am having problem instantiating the adder inside an always block. Plus I dont want to have 106 instances (due to for loop) of this adder. Can you please help with this code
module mul1(
output reg [105:0] c,
input [52:0] x,
input [52:0] y,
input clk,
input state
);
reg [105:0] p;
reg [105:0]a;
integer i;
always #(posedge clk) begin
if (state==1) begin
a={53'b0,x[52:0]};
p=106'b0; // needs to zeroed
for(i=0;i<106;i=i+1) begin
if(y[i]) begin
p=p+a; //THIS LINE NEEDS TO BE REPLACED WITH HANS CARLSONADDER
end
a=a<<1;
end
c<=p;
end else begin
c=0;
end
end
endmodule
First you need to instantiate your adder outside of the always block and connect it to signals:
wire [52:0] b;
reg [5:0] count;
assign b = c[count+7'd52:count];
wire [52:0] sum;
wire c_out;
// Add in x depending on the bits in y
// b has the running result bits that still apply at this point
hans_carlson_adder u0(x, b, 1'b0, sum, c_out);
Now because this is a pipelined adder you are going to need something to kick off the multiplication (I'll call that input start) and something that indicates that the result is available (I'll call that output reg done). You'll want to add them to your mul1 module definition. You can choose a slightly different protocol depending on your needs. It appears that you have something that you've been implementing with the input state. I'm also going to use start to initialize during each calculation so that I don't need a separate reset signal.
reg [52:0] shift;
always #(posedge clk) begin
if (start) begin
done <= 0;
count <= 0;
c <= 106'b0;
shift <= y;
end else if (count < 53) begin
if (shift[0]) begin
c[count+7'd52:count] <= sum;
c[count+7'd53] <= c_out;
end
count <= count + 1;
shift = shift >> 1;
end else begin
done <= 1;
end
end
If you want to make an optimization you could end once the shift signal is equal to 0. In this case the done signal would become high as soon as there were no more bits to add into the result, so multiplying by small values of y would take less cycles.
So I am designing a serial squarer. My program takes a basic binary counter, and uses each count of the counter to calculate squares in series. When I try to synthesize my code, depending on how I arrange my code, either synthesis runs almost infinitely, or the synthesis run just crashes entirely. So I figured that I cannot update my signal r_final => r_final + r_min1 because I remember that not being a thing in vhdl. So I have decided that I need to set r_final to a variable instead of a signal. I'm not sure how I should declare r_final as a variable. Can anyone provide some insight on how I can get r_final to update with itself?
This is my main code, the part in question is under the comment -- next state logic:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity serial_square is
port(
clk, reset: in std_logic;
q: out std_logic_vector (3 downto 0));
end serial_square;
architecture behavioral of serial_square is
signal r_reg : unsigned (3 downto 0) := "0000";
signal r_next : unsigned (3 downto 0);
signal r_2i : unsigned (3 downto 0);
signal r_min1 : unsigned (3 downto 0);
shared variable r_final : unsigned := "0000";
begin
-- register
process(clk,reset)
begin
if (reset='1') then
r_reg <= (others => '1');
elsif (clk'event and clk='1') then
r_reg <= r_final;
end if;
end process;
-- next state logic
r_next <= r_reg +1; -- r_reg + 1
r_2i <= r_next(2 downto 0) & '0'; -- multiply by 2
r_min1 <= r_2i - 1; -- minus one
r_final := r_min1 + r_final; -- add r_min1 to r_final, output should be the count r_next, squared.
--output logic
q <= std_logic_vector(r_reg);
end behavioral;
The update of r_final must be in the clocked process, so the next value is generated through a synchronous (clocked) update, since this is the structure that matches the available hardware.
Shared variables can't be synthesized, but is a feature only used for test benches.
I'm trying to make a Test Bench where a file of one single line, where posible characters are "1" and "0". I've to read them all, and use one by one as input in my DUT.
So, in my TB, I've defined a process like the following, in order to read the file an pass it values to my DUT.
stim_proc: process
file input_file: TEXT is in "DatosEntrada.dat";
variable rdline : LINE;
variable line_content : string ( 1 to 4);
variable readed_char : character;
variable j : integer := 0;
begin
while not endfile(input_file) loop
readline(input_file, rdline);
--read(rdline, line_content);
for j in 1 to rdline'length-1 loop
readed_char := line_content(j);
if (readed_char = '1') then
input <= '1';
else
input <= '0';
end if;
wait for clk_period;
end loop;
end loop;
end process;
I'm reading the first (and only) line of my file with the first readline execution. After this, this loop shouldn't execute again.
Then, data from file should be inside rdline. So I've to process it. In order to do it, I've tried to loop over rdline length, but this loop doesn't execute.
for j in 1 to rdline'length-1 loop
So I thought I need to read this line in order to loop over it, and tried to move its data to a string var. The problem is that vector var like string need to have a defined size, and I don't know the file line size.
I've tried reading each time 4 chars from rdline into a string, process it, then repeat. However, I couldn't make it work.
I've found quite lot examples about reading files which have defined line formats, like columns or expected integers.
But how can I read an unknown text of one line?
This readed_char := line_content(j); doesn't work when line_content isn't loaded. Otherwise your attempt to read values is basically sound.
The end of line is not contained in a read LINE buffer, there's no reason to not read the last character of rdline. An end of line is signaled by one or more format effectors other than horizontal tab, and just the line contents are present.
There's also this inference that you have some relationship to a clock edge and not just a clock period. The following example shows that. Note you can also supply an offset from an edge using a wait for time_value.
A loop constant is declared in the loop statement. The variable j you declared is not the same j the loop uses. The loop statement hides the j in the outer declarative region (the variable declaration in the process statement).
Your code treats any other character in the string buffer than '1' as a '0'. I didn't change that, do demonstrate it. You should be aware of the impact.
A LINE is an allocated string of some length dependent on the length of a line in your read file. Every time you call readline the string rdline points to is updated. It doesn't leak memory, the previous buffer rdline pointed to released. You can read the length by using the 'RIGHT attribute or as in this case simply consume all the characters.
There may be line length limits in a VHDL tool implementation. There are none defined in the standard other than the maximum length of a string (POSITIVE'RIGHT).
An MCVE:
library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
entity foo is
end entity;
architecture fum of foo is
signal input: std_logic ;
signal clk: std_logic := '0';
constant clk_period: time := 10 ns;
begin
stim_proc:
process
file input_file: TEXT is in "DatosEntrada.dat";
variable rdline: LINE;
-- variable line_content : string ( 1 to 4);
-- variable readed_char : character;
-- variable j: integer := 0;
begin
while not endfile(input_file) loop
readline(input_file, rdline);
--read(rdline, line_content);
-- for j in 1 to rdline'length - 1 loop -- EOL not in rdline
for j in rdline'range loop
-- readed_char := line_content(j);
-- if readed_char = '1' then
if rdline(j) = '1' then -- changed
input <= '1';
else
input <= '0';
end if;
-- wait for clk_period; -- sync to edge instead
wait until falling_edge(clk); -- input related to clk edge
end loop;
end loop;
wait; -- added prevents needless loops
end process;
CLOCK:
process
begin
wait for clk_period/2;
clk <= not clk;
if now > 32 * clk_period then
wait;
end if;
end process;
end architecture;
And for DatosEntrada.dat containing:
11011110001HELLO11230000
That produces:
Where you can see all non '1' characters are interpreted as '0'.
I'm still trying to get used to some of the quirks of VHDL and I'm having a bit of an issue. First off, I understand that shift operators like rol, ror, ssl, srl, etc. are not synthesizeable. The purpose of this lab is to use a golden model to check against a synthesizeable version of the same thing in a testbench.
Now, the purpose of this program is to convert thermometer code into a 3-bit binary number. So, in other words, thermometer code "00000001" = "001", "00000011" = "010", "00000111" = "011", etc. I'm basically trying to count the number of 1's in the string from right to left. There will be no case where a '0' is placed between the string of 1's, so the vector "00011101" is invalid and will never occur.
I've devised a non-synthesizeable (and so far, non-compile-able) algorithm that I can't figure out how to get working. Basically, the idea is to read the thermometer code, shift it right and increment a counter until the thermometer code equals zero, and then assign the counter value to the 3-bit std_logic_vector. Below is the code I've done so-far.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity therm2bin_g is
port(therm : inout std_logic_vector(6 downto 0); -- thermometer code
bin : out std_logic_vector(2 downto 0); -- binary code
i : integer range 0 to 7);
end therm2bin_g;
architecture behavioral_g of therm2bin_g is
begin
golden : process(therm)
begin
while(therm /= "00000000") loop
therm <= therm srl 1;
i = i + 1;
end loop;
bin <= std_logic'(to_unsigned(i,3));
end process golden;
behavioral_g;
here's a version that is synthesisable. the while loop is replaced by a for loop. srl is implemented explicitly:
entity therm2bin_g is
port(therm : inout std_logic_vector(6 downto 0); -- thermometer code
bin : out std_logic_vector(2 downto 0); -- binary code
i : out integer range 0 to 7);
end therm2bin_g;
architecture behavioral_g of therm2bin_g is
begin
golden : process(therm)
variable i_internal: integer range 0 to 7;
begin
i_internal:=0;
for idx in 0 to therm'length loop
if therm/="0000000" then
therm<='0' & therm(therm'left downto 1);
i_internal := i_internal + 1;
end if;
end loop;
bin<=std_logic_vector(to_unsigned(i_internal,bin'length));
i<=i_internal;
end process golden;
end behavioral_g;
"... operators like rol, ror, ssl, srl, etc. are not synthesizeable..."
Who says that on who's authority? Have you checked? On which synthesis tool? Was it a recent version, or a version from the early 1990s?
Note that the argument that some tools might not support it is just silly. The fact that some kitchens might not have an oven does not stop people from writing recipes for cake.
I would like to set bits of a std_logic_vector separately in order to easily set comments for individual bits or group of bits. Here is what I have:
signal DataOut : std_logic_vector(7 downto 0);
...
DataOut <= ( 5=>'1', -- Instruction defined
4=>'1', -- Data length control bit, high=8bit bus mode selected
3=>'1', -- Display Line Number ctrl bit, high & N3 option pin to VDD=3 lines display
2=>'0', -- Double height font type control byte, not selected
1 downto 0=>"01", -- Select Instruction table1
others=>'0' -- for bits 6,7
);
However, I've a problem with the "downto" statement, I get the following error using Xilinx ISE:
Type std_ulogic does not match with a string litteral
Any solution to avoid using the equivalent
1=>'0',
0=>'1',
and to allow me to set bits by block?
The assignment X downto Y => 'A' is correct when A is a element of array. For example, this snippet is correct:
1 downto 0 => '1',
And this snippet is wrong:
1 downto 0 => "01",
Therefore, your assignment is illegal. As your code, you can assign as:
DataOut <= ( 5 downto 3 =>'1',
2 downto 1 =>'0',
0 => '1',
others=>'0'
);
If you want to access/assign by a feild of array, you can use concatenation:
DataOut <= Something_0 & Something_1 & "01";
While Something_* is std_logic_vector
Another answer is concatenation using '&', which loses the clarity of named association, though you can recover some of the self-documentation with named constants
constant Instr_Defined : std_ulogic := '1';
constant Bus_8_Bit : std_ulogic := '1';
DataOut <= "00" & Instr_Defined
& Bus_8_Bit
& '1' -- description
& '0' -- ditto
& "01";
Another answer is to write a function to create instructions : this can make the main flow very simple and clear, while keeping the instruction encodings entirely separate and in a single place, e.g. in a package used wherever you need to know the instruction formats (perhaps in an assembler as well as the CPU)
DataOut <= Encode_Instruction(Instr_Defined, Bus_8_Bit, Font_Mode);
It's OK to use any of the preceding techniques, however verbose, in the function body. The more explicit and detailed the better; it isn't cluttering up the main design so you'll rarely look at it unless changing instruction formats.
do this:
DataOut(7 downto 6)<="00";
DataOut(5)<='1';
DataOut(4)<='1';
DataOut(3)<='1';
DataOut(2)<='1';
DataOut(1 downto 0)<="01";