I have some data from a 1 bit serial port which comes in multiples of bytes of variant lengths as such:
byte expected_1 [$] = {8'hBA, 8'hDD, 8'hC0, 8'hDE};
byte expected_2 [$] = {8'h01, 8'h23, 8'h45, 8'h67, 8'h89, 8'hAB, 8'hCD, 8'hEF};
At each positive clock edge, one bit is sent. I need to testbench hundereds of sequences ( maybe thousand in the future ) so I want to automate the process with assertions in system verilog. The new 2012 standard allows for queues to be passed to properties, but can the queues be sent though a recursive property? I received some error about hierarchical ref.
This is what I have so far (with help from #Greg here):
default clocking sck #(posedge sck); endclocking : sck
sequence seq_serial(logic signal, logic [7:0] expected); // check each bit
byte idx = 7;
(signal == expected[idx], idx--)[*8];
endsequence : seq_serial
property recurring_queue(bit en, logic data, byte data_e [$])
int queue_size = data_e.size;
logic [7:0] expected = data_e.pop_front();
if(queue_size != 0) (
!en throughout (seq_serial(data, expected) ##1 recurring_queue(en, data, data_e))
);
endproperty : recurring_queue
`define ez_assert(exp)
assert property (recurring_queue(en, data, exp))
else $error("Bad Sequence # time: %t. Info: %m", $time);
Calling the assertion in my testbench should be as easy as this:
A1 : `ez_assert(expected_1);
The error messages read:
1) passing hierarchical ref to be used in another hierarchical ref is not supported
2) Illegal SVA property in RHS of'##' expression
3) Local variable queue_size referenced in expression before getting initialized
I'm open to other ideas for asserting long variable-length serial sequences.
Try the same strategy as seq_serial:
sequence seq_queue_pattern(bit en, logic data, byte expt_queue [$]);
int qidx = 0;
( !en throughout (seq_serial(data,expt_queue[qidx]), qidx++)[*] )
##1 (qidx==expt_queue.size);
endsequence : seq_queue_pattern
asrt_expected_1 : assert property ( $fell(en) |-> seq_queue_pattern(en,data,expected_1));
asrt_expected_2 : assert property ( $fell(en) |-> seq_queue_pattern(en,data,expected_2));
This assertion will fail if en is high or the seq_serial chain does not match expected. Do not that parenthicy location matters:
en is don't care one clock after final seq_serial completes:
( !en throughout (seq_serial(data,expt_queue[qidx]), qidx++)[*] ) ##1 (qidx==expt_queue.size)
en must be low one clock after final seq_serial completes or failes and don't care after that
!en throughout ( (seq_serial(data,expt_queue[qidx]), qidx++)[*] ##1
(qidx==expt_queue.size) )
en must be low one clock after final seq_serial completes and don't care after that
!en throughout ( (seq_serial(data,expt_queue[qidx]), qidx++)[*] ##1
(qidx==expt_queue.size) ) ##1 (qidx==expt_queue.size)
Queues within sequences and properties are new and may not be fully supported by all simulators yet. To work around this limitation, use a parametrized macro to create a sequence for each expected queue stream:
`define asrt_qpat(en,monitor, expt_queue) \
sequence seq_queue_pattern__``expt_queue (bit en, logic data); \
int qidx = 0; \
(!en throughout (seq_serial(data,expt_queue[qidx]), qidx++)[*]) \
##1 (qidx==expt_queue.size); \
endsequence : seq_queue_pattern__``expt_queue \
\
asrt_``expt_queue : assert property( #(posedge clk) \
$fell(en) |=> seq_queue_pattern__``expt_queue (en,monitor) ) \
else $error("Bad Sequence # time: %t. Info: %m", $time);
`asrt_qpat(en,data[0],expected_1)
`asrt_qpat(en,data[1],expected_2)
Related
I'm hoping someone with more VHDL experience can enlighten me! To summarise, I have an LCD entity and a Main entity which instantiates it. The LCD takes an 84-character wide string ("msg"), which seems to cause me huge problems as soon as I index it using a variable or signal. I have no idea what the reason for this is, however, since the string is displaying HEX values, and each clock cycle, I read a 16-bit value... I need to update 4 characters of the string for each nybble of this 16-bit value. This doesn't need to be done in a single clock cycle, since a new value is read after a large number of cycles... however, experimenting with incrementing a "t" variable, and only changing string values one "t" at a time makes no difference for whatever reason.
The error is: "Error (170048): Selected device has 26 RAM location(s) of type M4K" However, the current design needs more than 26 to successfully fit
Here is the compilation report with the problem:
Flow Status Flow Failed - Tue Aug 08 18:49:21 2017
Quartus II 64-Bit Version 13.0.1 Build 232 06/12/2013 SP 1 SJ Web Edition
Revision Name Revision1
Top-level Entity Name Main
Family Cyclone II
Device EP2C5T144C6
Timing Models Final
Total logic elements 6,626 / 4,608 ( 144 % )
Total combinational functions 6,190 / 4,608 ( 134 % )
Dedicated logic registers 1,632 / 4,608 ( 35 % )
Total registers 1632
Total pins 50 / 89 ( 56 % )
Total virtual pins 0
Total memory bits 124,032 / 119,808 ( 104 % )
Embedded Multiplier 9-bit elements 0 / 26 ( 0 % )
Total PLLs 1 / 2 ( 50 % )
The RAM summary table contains 57 rows, of "LCD:display|altsyncram:Mux####_rtl_0|altsyncram_####:auto_generated|ALTSYNCRAM"
Here is the LCD entity:
entity LCD is
generic(
delay_time : integer := 50000;
half_period : integer := 7
);
port(
clk : in std_logic;
SCE : out std_logic := '1';
DC : out std_logic := '1';
RES : out std_logic := '0';
SCLK : out std_logic := '1';
SDIN : out std_logic := '0';
op : in std_logic_vector(2 downto 0);
msg : in string(1 to 84);
jx : in integer range 0 to 255 := 0;
jy : in integer range 0 to 255 := 0;
cx : in integer range 0 to 255 := 0;
cy : in integer range 0 to 255 := 0
);
end entity;
The following code is what causes the problem, where a, b, c and d are variables which are incremented by 4 after each read:
msg(a) <= getHex(data(3 downto 0));
msg(b) <= getHex(data(7 downto 4));
msg(c) <= getHex(data(11 downto 8));
msg(d) <= getHex(data(15 downto 12));
Removing some of these lines causes the memory and logic element usages to both drop, but they still seem absurdly high, and I don't understand the cause.
Replacing a, b, c and d with integers, like 1, 2, 3 and 4 causes the problem to go away completely, with the logic elements at 22%, and RAM usage at 0%!
If anybody has any ideas at all, I'd be very grateful! I will post the full code below in case anybody needs it... but be warned, it's a bit messy, and I feel like the problem could be simple. Many thanks in advance!
Main.vhd
LCD.vhd
There are a few issues here.
The first is that HDL synthesis tools do an awful lot of optimization. What this basically means is if you don't properly connect up input and output parts to/from something it is likely (but not certain) to get eliminated by the optimizer.
The second is you have to be very careful with loops and functions. Basically loops will be unrolled and functions will be inlined, so a small ammount of code can generate an awful lot of logic.
The third is that under some cicumstances arrays will be translated to memory elements.
As pointed out in a comment this loop is the root cause of the large ammounts of memory usage.
for j in 0 to 83 loop
for i in 0 to 5 loop
pixels((j*6) + i) <= getByte(msg(j+1), i);
end loop;
end loop;
This has the potential to use a hell of a lot of memory resources. Each call to "getByte" requires a read port on (parts of) "ram" but blockrams only have two read ports. So "ram" gets duplicated to satisfy the need for more read ports. The inner loop is reading different parts of the same location so basically each iteration of the outer loop needs an independent read port on the ram. So that is about 40 copies of the ram. Reading the cyclone 2 datasheet each copy will require 2 m4k blocks
So why doesn't this happen when you use numbers instead of the variables a,b,c and d?
If the compiler can figure out something is a constant it can compute it at compile time. This would limit the number of calls to "pixels" that have to actually be translated to memory blocks rather that just having their result hardcoded. Still i'm surprised it's dropping to zero.
I notice your code doesn't actually have any inputs other than the clock and a "rx" input that doesn't actually seem to be being used for anything, so it is quite possible that the synthesizer may be figuring out a hell of a lot of stuff at build time. Often eliminating one bit of code can allow another bit to be eliminated until you have nothing left.
I want to store filter coefficients(fixed values) in ROM using verilog.Below is the code for ROM using case.
module rom_using_case (
address , // Address input
data , // Data output
read_en , // Read Enable
ce // Chip Enable
);
input [3:0] address;
output [7:0] data;
input read_en;
input ce;
reg [7:0] data ;
always # (ce or read_en or address)
begin
case (address)
0 : data = 10;
1 : data = 55;
2 : data = 244;
3 : data = 0;
4 : data = 1;
5 : data = 8'hff;
6 : data = 8'h11;
7 : data = 8'h1;
8 : data = 8'h10;
9 : data = 8'h0;
10 : data = 8'h10;
11 : data = 8'h15;
12 : data = 8'h60;
13 : data = 8'h90;
14 : data = 8'h70;
15 : data = 8'h90;
endcase
end
endmodule
what does the case block do in the above code?
can i store filter coefficients in data variable in the case block?
can i access those filter coefficients?
As you state the coefficients will be stored in a RAM LUT or in a ROM block.
The code is (somewhat) self-descriptive, the always is sensitive to the address then each time the address changes its value the stored value will be assigned to data, case is the selector for which location of the memory block will be assinged to data.
Your implementation is enough for small filters, but if you need a lot of coefficients it will get hard to maintain.
For this purpose you can use the $readmemh or $readmemb. Those are verilog intrisic tasks.
From: https://www.csee.umbc.edu/~tinoosh/cmpe415/slides/Rom-LUT-verilog.pdf
The $readmemh system task expects the content of the named file to be
a sequence of hexadecimal numbers, separated by spaces or line breaks.
Similarly, $readmemb expects the file to contain a sequence of binary.
Here is a snippet which shows how to use it:
reg [19:0] data_ROM [0:511];
...
initial $readmemh("rom.data", data_ROM);
always #(address)
if (ce & read_en)
d_out = data_ROM[address];
The "rom.data" contains the coefficients in text. For example, in your case:
8'hA
8'h37
8'hF4
8'h0
8'h1
8'hff
8'h11
8'h1
8'h10
8'h0
8'h10
8'h15
8'h60
8'h90
8'h70
8'h90
I'm trying to implement the memory model as below, but I got these warning messages:
assign Data = (!CS && !OE) ? Mem[Address] : {WordSize{1'bz}};
|
ncelab: *W,BIGWIX (./sram.v,16|39): Memory index truncation.
Mem[Address] = Data;
|
ncelab: *W,BIGWIX (./sram.v,20|14): Memory index truncation.
Here is my code:
// RAM Model
//
module sram (Address, Data, CS, WE, OE);
parameter AddressSize = 2592;
parameter WordSize = 32;
input [AddressSize-1:0] Address;
inout [WordSize-1:0] Data;
input CS, WE, OE;
reg [WordSize-1:0] Mem [0:(1<<AddressSize)-1];
assign Data = (!CS && !OE) ? Mem[Address] : {WordSize{1'bz}};
always #(CS or WE)
if (!CS && !WE)
Mem[Address] = Data;
always #(WE or OE)
if (!WE && !OE)
$display("Operational error in RamChip: OE and WE both active");
endmodule
What does "Memory index truncation" mean?
You can get more verbose help on any Cadence Incisive warnings using nchelp:
nchelp ncelab BIGWIX
ncelab/BIGWIX =
A memory is being indexed. The index expression has a width
greater than a machine word, which is typically 32 bits.
Only 32 bits are used. This truncation may result in
undesired behavior.
As mentioned in the Comment, you probably do not want the Address input signal to be 2592 bits wide or your memory to have (1<<2592) locations.
I have an SV assertion which checks the property as below
propert my_property;
#(posedge clk) disable iff(reset) $rose(halt) ##0 ((rx_prio) > (expec_prio)) ##[0:$] $rose(rdy) |-> ##[1:100] (my_prio[rx_prio]==1'b1);
endproperty:my_property
I have the assertion as below:
MY_PROPERTY_CHECK:assert property (my_propert)
else
$error;
Here, the scenario is that, the antecedent is true and the consequent is checked between 1 & 100 clock cycles. After the antecedent, the clock is stopped due to clock gating for some time and then the clock starts ticking again. The signal my_prio[rx_prio] is asserted after the clock gating but again within 100 clock cycles. But I still get the assertion failure.
Not able to figure out the issue of failure. Does the clock gating in between the assertion check has an issue? Or any other reason failure?
Thanks.
There might be many threads starting. Try using local variables with display statements below. See IEEE Std 1800-2012 § 16.10 Local variables
propert my_property;
static int prop_cnt=0; // shared
local int prop_id; // Note: some require the "local", other need it omitted
#(posedge clk) disable iff(reset)
($rose(halt) ##0 ((rx_prio) > (expec_prio)),
prop_id=prop_cnt++,
$display("Spawn prop_id:%0d prop_cnt:%0d # %0t %m",
prop_id,prop_cnt,$time) )
##[0:$] ($rose(rdy),
$display("Trigger prop_id:%0d prop_cnt:%0d # %0t %m",
prop_id,prop_cnt,$time) )
|-> ##[1:100] (my_prio[rx_prio]==1'b1,
$display("Pass prop_id:%0d prop_cnt:%0d # %0t %m",
prop_id,prop_cnt,$time) );
endproperty : my_property
If you see Spawn-Spawn-Trigger, or Spawn-Trigger-Trigger, our anything outside of expected (i.e. Spawn-Triger-Pass) then there are unexpected threads.
If this is the case, then look into IEEE Std 1800-2012 § 16.9.8 First_match operation
first_match(
$rose(halt) ##0 ((rx_prio) > (expec_prio)) ##[0:$] $rose(rdy),
$display("Spawn-Trigger prop_id:%0d prop_cnt:%0d # %0t %m",
prop_id,prop_cnt,$time)
) |-> // ...
OR § 16.9.10 Sequence contained within another sequence
(
( $rose(halt) ##0 ((rx_prio) > (expec_prio)) ) within $rose(rdy)[->1],
$display("Spawn-Trigger prop_id:%0d prop_cnt:%0d # %0t %m",
prop_id,prop_cnt,$time)
) |-> // ...
You might want to create a sequence for the trigger.
As I don't know your setup, I could assume that you are maybe triggering on a clock further up the hierarchy that is not being gated, but you debug waves in the exact hierarchy where the clock is being gated.
If you are writing your assertions for an RTL block that cannot be retrofitted with assertions (it's VHDL/Verilog or you are not allowed to touch the file), use bind to instantiate your assertions inside that block: http://www.asic-world.com/systemverilog/assertions22.html
When I was config pll_reconfig module in Quartus II, the generate for statement in design have to specify different string parameter (filenames) to different instances.
I have tried these code:
genvar i;
generate
for (i=0; i<2; i=i+1) begin:u
rom #($sformatf("mif%d.mif",i)) U(
//signals connected.
);
end
endgenerate
It is said that the code is not synthesizable.
How can I specify variable string parameter in generate for block?
I had a similar problem but on a system that did not support $sformatf. My solution is a little dirty but may help others:
genvar i;
generate
for (i=0; i<10; i=i+1)
begin
mymodule #(.NAME("NAME0" + i) instance(.RESET(mreset) ... );
end
endgenerate
This works, I believe, by treating the string "NAME0" as a number (a 40-bit number). By adding i, you just increase the value by i and the result is the last ASCII char changes. Luckily '0' + i gives you '1', '2', '3' etc
The obvious flaw is this only works for 0-9, however there is a simple extension using divide and modulo arithmatic:
mymodule #(.NAME("NAME00" + (256 * (i / 10)) + (i % 10) ) ) ...
As a side note, I ran into issues using string concatenation {"NAME", i} because Verilog was treating i as 32-bit value so the string ends up as:
NAME 1
due to the extra 'unwanted' 24 bits which equate to 3 null characters