Is there a difference between the two?
I have just changed from if(rdy) to if(rdy == 1) in some code for a project, and suddenly the output behaves totally different.
Assumes rdy is a 1-bit reg datatype in Verilog.
reg rdy;
if (rdy) <---> if (rdy!=1'b0)
if (rdy==1) <---> if (rdy==1'b1)
For synthesis, they will probably work the same. But be aware if rdy has more than 1 bit:
reg[7:0] rdy;
if (rdy) <---> if (rdy!=8'b00000000)
if (rdy==1) <---> if (rdy==8'b00000001)
The first one will probably be synthetized using an 8-input OR gate, while the second one will need a 7-input NOR gate and a 2-input AND gate.
There is no difference between the two.
reg is 4-state: 0, 1, x, z. Only if rdy is 1 will the if condition be true; otherwise, it is false.
module tb;
reg rdy;
always #(rdy) begin
if (rdy) begin
$display($time, " rdy=%b if (rdy) TRUE", rdy);
end else begin
$display($time, " rdy=%b if (rdy) FALSE", rdy);
end
if (rdy==1) begin
$display($time, " rdy=%b if (rdy==1) TRUE", rdy);
end else begin
$display($time, " rdy=%b if (rdy==1) FALSE", rdy);
end
$display;
end
initial begin
#5 rdy = 1'b1;
#5 rdy = 1'bx;
#5 rdy = 1'bz;
#5 rdy = 1'b0;
end
endmodule
Outputs:
5 rdy=1 if (rdy) TRUE
5 rdy=1 if (rdy==1) TRUE
10 rdy=x if (rdy) FALSE
10 rdy=x if (rdy==1) FALSE
15 rdy=z if (rdy) FALSE
15 rdy=z if (rdy==1) FALSE
20 rdy=0 if (rdy) FALSE
20 rdy=0 if (rdy==1) FALSE
Related
In a VHDL testbench, I have a function that parses a csv file in order to initialize a test array.
When running the function in the elaboration phase to set the values of a constant, the function behaves differently than when using the same function in simulation (e.g. initializing a signal during a reset)
The function code is:
constant cn_DATA_WIDTH : natural := 10;
constant cn_DATA_DEPTH : natural := 400;
type tav_data_array is array (0 to cn_DATA_DEPTH - 1) of std_logic_vector(cn_DATA_WIDTH - 1 downto 0);
function f_init_data_from_file (
s_file_path : in string;
i_column_index : in integer := 0
) return tav_data_array is
-- file parsing
file f_data_file_buf : text is in s_file_path;
variable vl_data_file_line : line;
variable vi_data_entry : integer;
variable vc_comma : character;
variable vb_good_num : boolean;
-- destination
variable vav_data_array : tav_data_array;
begin
-- Skip first line that contains header
readline (f_data_file_buf, vl_data_file_line);
for line_index in vav_data_array'range loop
readline (f_data_file_buf, vl_data_file_line);
read (vl_data_file_line, vi_data_entry, vb_good_num);
assert vb_good_num
report "Failed reading file : " & s_file_path
& ", at line = " & integer'image(line_index)
& ", at column = 0"
severity failure;
for column_index in 1 to i_column_index loop
read(vl_data_file_line, vc_comma);
read(vl_data_file_line, vi_data_entry, vb_good_num);
assert vb_good_num
report "Failed reading file : " & s_file_path
& ", at line = " & integer'image(line_index)
& ", at column = " & integer'image(column_index)
severity failure;
end loop;
vav_data_array(line_index) := std_logic_vector(to_unsigned(vi_data_entry, cn_DATA_WIDTH));
end loop;
return vav_data_array;
end function;
Function usage in elaboration:
constant cav_data : tav_data_array :=
f_init_data_from_file (
s_file_path => "my_path" ,
i_column_index => 3
);
Result: The test array is not initialized with the expected data. The data used for the initialization is column 0 instead of column 3.
Function usage in elaboration:
signal sav_data : tav_data_array;
-- ...
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
sav_data <=
f_init_data_from_file (
s_file_path => "my_path" ,
i_column_index => 3
);
else
-- ...
end if;
end if;
end process;
In this case, the data used for initialization is the proper one. Column 3 is used as expected.
Is there a reason for this different behavior? Or is this a bug with the tools I am using for simulation (Xilinx Vivado 2018.2)?
EDIT to create MRVE:
As requested, this is a minimal reproducible example. Some of the parameters
Source code:
-- MRVE
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
-- File parsing
use STD.textio.all;
use ieee.std_logic_textio.all;
entity file_bug_mrve is
end file_bug_mrve;
architecture a_file_bug_mrve of file_bug_mrve is
-- Actual data are 12 bits
constant cn_DATA_WIDTH : natural := 12;
constant cn_DATA_DEPTH : natural := 4; -- testbench is planned for 400 high priority cycles
type tav_data_array is array (0 to cn_DATA_DEPTH - 1) of std_logic_vector(cn_DATA_WIDTH - 1 downto 0);
-- Parse csv data file to retrieve all entries at specified columns
function f_init_data_from_file (
s_file_path : in string;
i_column_index : in integer := 0
) return tav_data_array is
-- file parsing
file f_data_file_buf : text is in s_file_path;
variable vl_data_file_line : line;
variable vi_data_entry : integer;
variable vc_comma : character;
variable vb_good_num : boolean;
-- destination
variable vav_data_array : tav_data_array;
begin
-- Skip first line
readline (f_data_file_buf, vl_data_file_line);
for line_index in vav_data_array'range loop
readline (f_data_file_buf, vl_data_file_line);
read (vl_data_file_line, vi_data_entry, vb_good_num);
assert vb_good_num
report "Failed reading file : " & s_file_path
& ", at line = " & integer'image(line_index)
& ", at column = 0"
severity failure;
for column_index in 1 to i_column_index loop
read(vl_data_file_line, vc_comma);
read(vl_data_file_line, vi_data_entry, vb_good_num);
assert vb_good_num
report "Failed reading file : " & s_file_path
& ", at line = " & integer'image(line_index)
& ", at column = " & integer'image(column_index)
severity failure;
end loop;
vav_data_array(line_index) := std_logic_vector(to_unsigned(vi_data_entry, cn_DATA_WIDTH));
end loop;
return vav_data_array;
end function;
constant cs_RSP_DATA_IN_FILE_PATH : string := "../../src/xls/file_bug_mrve.csv";
constant cn_RSP_DATA_IN_COLUMN_INDEX : natural := 3;
-- registers emulation
-- Setting init data to be processed in elaboration does not work
-- Data will be initialized with first column instead of third
signal sav_data : tav_data_array :=
f_init_data_from_file (
s_file_path => cs_RSP_DATA_IN_FILE_PATH ,
i_column_index => cn_RSP_DATA_IN_COLUMN_INDEX
);
-- infa Simulation
constant ct_CLOCK_PERIOD_100 : time := 10 ns;
constant ct_TEST_COMPLETION_TIME : time := ct_CLOCK_PERIOD_100 * 10;
signal s_clk : std_logic;
signal s_rst : std_logic;
signal sb_end : boolean := false;
begin
-- -----------------------------------------------------------------------------------------------------------------
-- Clock process definitions
-- -----------------------------------------------------------------------------------------------------------------
p_Clock_100 : process
begin
s_clk <= '0';
wait for ct_CLOCK_PERIOD_100/2;
s_clk <= '1';
wait for ct_CLOCK_PERIOD_100/2;
if sb_end then
wait;
end if;
end process;
-- -----------------------------------------------------------------------------------------------------------------
-- Main Stimulus process
-- -----------------------------------------------------------------------------------------------------------------
p_stimulous : process
begin
--
s_rst <= '0';
-- 1 clock cycle reset to avoid loading file multiple times
wait until rising_edge(s_clk);
s_rst <= '1';
wait until rising_edge(s_clk);
s_rst <= '0';
wait for ct_TEST_COMPLETION_TIME;
sb_end <= true;
end process;
p_main : process(s_clk)
begin
if rising_edge(s_clk) then
if s_rst = '1' then
-- Setting init data to be processed in simulation works
-- Data will be initialized with forth column as expected
sav_data <=
f_init_data_from_file (
s_file_path => cs_RSP_DATA_IN_FILE_PATH ,
i_column_index => cn_RSP_DATA_IN_COLUMN_INDEX
);
else
-- Nothing to do in MRVE
end if;
end if;
end process p_main;
end a_file_bug_mrve;
CSV file:
Ch0,Ch1,Ch2,Ch3
1,5,9,13
2,6,10,14
3,7,11,15
4,8,12,16
module mac #(
parameter integer A_BITWIDTH = 8,
parameter integer B_BITWIDTH = A_BITWIDTH,
parameter integer OUT_BITWIDTH = 20,
parameter integer C_BITWIDTH = OUT_BITWIDTH - 1
)
(
input clk,
input rstn,
input en,
input add,
input [A_BITWIDTH-1:0] data_a,
input [B_BITWIDTH-1:0] data_b,
input [C_BITWIDTH-1:0] data_c,
output reg done,
output [OUT_BITWIDTH-1:0] out
);
localparam
STATE_IDLE = 2'b00,
STATE_MULT = 2'b01,
STATE_ACCM = 2'b10;
reg [1:0] state;
reg signed [OUT_BITWIDTH-1:0] out_temp;
reg signed [A_BITWIDTH-1:0] data_a_bf;
reg signed [B_BITWIDTH-1:0] data_b_bf;
reg signed [C_BITWIDTH-1:0] data_c_bf;
assign out = out_temp;
always # (posedge clk or negedge rstn) begin
if(!rstn) begin
state <= STATE_IDLE;
data_a_bf <= {A_BITWIDTH{1'b0}};
data_b_bf <= {B_BITWIDTH{1'b0}};
data_c_bf <= {C_BITWIDTH{1'b0}};
done <= 1'b0;
out_temp <={OUT_BITWIDTH{1'b0}};
end
else begin
case(state)
STATE_IDLE: begin
// TO DO
// Done flag reset!
data_a_bf <= {A_BITWIDTH{1'b0}};
data_b_bf <= {B_BITWIDTH{1'b0}};
data_c_bf <= {C_BITWIDTH{1'b0}};
out_temp <={OUT_BITWIDTH{1'b0}};
done <= 1'b0;
if(en && !done) begin
// If en == 1 and done != 1, then running state.
// And capture data_a, data_b, data_c to buffer
data_a_bf <= data_a;
data_b_bf <= data_b;
data_c_bf <= data_c;
state <= STATE_MULT;
end
else begin
// If not, just waiting for condition.
end
end
STATE_MULT: begin
// TO DO;
if (!add) begin
// If add signal is low, do muliply with data_a_bf and data_b_bf.
//out_temp <= data_a_bf * data_b_bf;
out_temp <= {{{A_BITWIDTH{data_a_bf[7]}}, data_a_bf}*{{B_BITWIDTH{data_b_bf[7]}}, data_b_bf}}[15:0]; // >> this invokes a error, which is syntax error near "["
end
else begin
// If add signal is high, shift data_a_bf to match bit representation.
//out_temp <= {data_a_bf, 8'b0};
out_temp <= {data_a_bf, 8'b0};
end
state <= STATE_ACCM;
end
STATE_ACCM: begin
// TO DO
// Do add and make output 'done' flag high.( done = 1)
out_temp <= out_temp + data_c_bf;
done <= 1'b1;
state <= STATE_IDLE;
end
default:;
endcase
end
end
endmodule
I want to do 'bit select' concatenation of data_a_bf signed extension * data_b_bf signed extension and assign it to out_temp, but it occurs a syntax error. How can I do this?
I don't know how to do bit select of it.
I think you just need to see error line.
I just upload all code.
Selecting a bit of a concatenation is a feature of SystemVerilog, not Verilog. Make sure your file has a .sv file extension. The tool that you are using might also have a switch to turn on support for SystemVerilog.
A Verilog friendly solution would be to create a bit mask.
For example, change:
out_temp <= {{{A_BITWIDTH{data_a_bf[7]}}, data_a_bf}*{{B_BITWIDTH{data_b_bf[7]}}, data_b_bf}}[15:0]; // >> this invokes a error, which is syntax error near "["
To:
out_temp <= {{{A_BITWIDTH{data_a_bf[7]}}, data_a_bf}*{{B_BITWIDTH{data_b_bf[7]}}, data_b_bf}} & 'h0FFFF;
So I have to do an assigment where I have to write a counter which hase upcount mode = 1 -> increment = 5 and downcount mode = 0 -> decrement = -9. There is an invalid value of -69 which the counter should jump over.
There are also upper and lower bounds: -250 to 248.
To test our counter, a testbench was given.
I used the following if-else statement inside a process with the clk signal as sensitivity list entry.
if((cnt_intern + 5) <= 248) then
cnt_intern <= cnt_intern + 5;
end if;
if(cnt_intern = -69) then
cnt_intern <= cnt_intern + 5;
end if;
this did not work as it set the cnt_intern to -69, which the second if statement should prevent. I rewrote the if statement to the following:
if(cnt_intern <= 243) then#
if(cnt_intern = -73) then
cnt_intern <= cnt_intern + 10;
else
cnt_intern <= cnt_intern + 5;
end if;
end if;
This time it did work and it jumped over the vlaue -69 directly to -64.
Anyone knows why? what is wrong with the first way?
best regards
The reason for the observed behavior is that a signal assignment inside a process does not immediately change the signal value. Instead, a transaction is scheduled on the signal, which will take effect when the process suspends (i.e. when the end of the process or a wait statement is reached).
In your first example, if cnt_intern is -74 at the beginning of the process, the first if statement schedules as transaction, that means a change of the signal's value to -69 will take place at the end of the process if no other assignment schedules a transaction on cnt_intern. However, the actual value of cnt_intern stays -74 until the end of the process. So the second if statement will evaluate to false and do nothing. At the end of the process, the value of -69 is assigned to cnt_intern.
This concept seems confusing if you start working with hardware description languages, but it is essential.
You could use a helper variable to circumvent that issue and keep the code readable:
process(clk)
variable v_cnt_intern : integer;
begin
if rising_edge(clk) then
v_cnt_intern := cnt_intern;
if((v_cnt_intern + 5) <= 248) then
v_cnt_intern := v_cnt_intern + 5;
end if;
if (v_cnt_intern = -69) then
v_cnt_intern := v_cnt_intern + 5;
end if;
cnt_intern <= v_cnt_intern;
end if;
end process;
Other solutions are something like the code in your second example, which looks fine.
I am writing something in verilog in quartus, and appeared to me something strange, but pretty simple actually
This code increments the address correctly
module counter(
input wire clock,
input wire reset,
output reg [4:0]address
);
initial
begin
address = 5'b0
end
always#(posedge clock)
begin
if(reset)
begin
address <= 5'b0;
end
else
begin
address <= address + 5'b00001;
end
end
endmodule
this, the bits that change become not matter, it happens when I start the output to something other than 0
module counter(
input wire clock,
input wire reset,
output reg [4:0]address
);
initial
begin
address = 5'b11101;
end
always#(posedge clock)
begin
if(reset)
begin
address <= 5'b0;
end
else
begin
address <= address + 5'b00001;
end
end
endmodule
Does anyone know any way to solve this problem?
While it is difficult to tell exactly what you are saying, it seems you are curious as to why changing the starting value in the initial block seems to have no affect on where the counter starts.
It seems you are likely performing a reset as part of your testbench, so when you look at address, the value always starts at 0 (because the initial block setting is changed by the reset in the always block).
This part is suspicious to me:
if(reset)
begin
address <= 5'b0;
end
Should be:
if(reset)
begin
address <= 5'b00000;
end
You can try use this implementation with load and start signal:
module Counter(load,clk,start,data_in,data_out);
input load;
input clk;
input start;
input [5-1:0] data_in;
output [5-1:0] data_out;
reg [5-1:0] tmp;
initial
begin
tmp = 5'b0000;
end
always # ( posedge clk)
begin
if(~start)
begin
tmp <= 5'b0000;
end
else if(load)
tmp <= data_in;
else
tmp <= tmp + 1'b1;
end
assign data_out = tmp;
endmodule
Is it possible to add conditional asignments to a signal from within a 'with select' block. eg.
with state select
Data <= x"00" when IDLE,
(x"01" when Count = 0 else x"10") when DATA,
x"FF" when others;
This doesn't compile, but is it possible to include a second variable within this block?
Short answer is no.
You could do something like this instead.
process (Count, state)
variable countData : std_logic_vector (7 downto 0);
begin
if Count = 0 then
countData := x"01";
else
countData := x"10";
end if;
case state is
when IDLE => Data <= x"00";
when DATA => Data <= countData;
when others => Data <= x"FF";
end case;
end process;