In my system, each pixel on an LCD screen is represented by 16-bits (RGBA):
typedef logic [15:0] pix;
In order to display characters on the screen, I have created a simple 8x8 typeface, whereby characters are stored such as:
typedef logic char_8x8 [7:0][7:0];
localparam char_8x8 txt_G = '{'h3C, 'h66, 'h03, 'h03, 'h73, 'h66, 'h7C, 'h00};
As they are currently stored (the hex numbers above), a 'b1 represents a turned-on pixel and 'b0 turned off.
Now, to display them, I need some method to convert each character to the following form:
typedef logic [15:0] char_8x8_colored [7:0][7:0];
Notice how now each pixel element also carries the 16 bits of color as a packed array. (Frankly I'm not 100% how the whole packed/unpacked affects code - even though I know the implementation difference).
The way this would work is, wherever there exists a 'b1 in the character array, this would be replaced with an element with value 'hFFFF (white) - and of course 'h0000 (black) for no pixel present.
I'm unsure of the best way to implement this in SystemVerilog.
Thanks.
As far as I know you the only type of indices you can use in systemverilog are slices (without stride). I know that numpy, pytorch, or octave for instance have much richer indexing options and could use something like colored[face] = foreground. To set the color of all the pixels turned on. But in systemverilog I would go with a function.
function char_8x8_colored color_out(
input char_8x8 face,
input pix background,
input pix foreground);
char_8x8_colored data;
begin
for(int i = 0; i < 8; i = i + 1) begin
for(int j = 0; j < 8; i = i + 1) begin
data[i][j] = face[i][j] ? foreground : background;
end
end
end
end
endfunction
This is a pure function this function can be synthesized using without any logic (only routing) if you pass a parameter such as txt_G as the face argument.
Related
Recently I have to use Verilog-A to generate a set of random numbers (sigmaX, sigmaY, sigmaZ). Statistically, each of them has mean=0 and std=1, and sigmaX^2+sigmaY^2+sigmaZ^2=1. The following code in test_solver.va file is writen in Verilog-A to realize such random numebr set at each time step:
`include "disciplines.h"
`include "constants.h"
module test_va(p,n,mb,mc,md,me,mf,mg);
inout p,n;
output mb,mc,md,me,mf,mg;
electrical p,n,mb,mc,md,me,mf,mg;
real randomX,randomY,randomZ; // Gaussian random variables with mean = 0, stdev = 1
real sigmaX,sigmaY,sigmaZ; // Normalized thermal noise vector components
integer seedX,seedY,seedZ; // Seed variables for RNG
integer random_seed;
//------------------------------------------------------------------//
// Define mag(x, y, z)
//------------------------------------------------------------------//
analog function real mag;
input x, y, z;
real x, y, z;
begin
mag = sqrt(pow(x,2)+pow(y,2)+pow(z,2));
end
endfunction
analog begin
random_seed = 1;
seedX = $random+random_seed;
seedY = $random+random_seed;
seedZ = $random+random_seed;
randomX = $rdist_normal(seedX, 0.0, 1.0);
randomY = $rdist_normal(seedY, 0.0, 1.0);
randomZ = $rdist_normal(seedZ, 0.0, 1.0);
sigmaX = randomX/mag(randomX, randomY, randomZ);
sigmaY = randomY/mag(randomX, randomY, randomZ);
sigmaZ = randomZ/mag(randomX, randomY, randomZ);
V(mb) <+ randomX;
V(mc) <+ randomY;
V(md) <+ randomZ;
V(me) <+ sigmaX;
V(mf) <+ sigmaY;
V(mg) <+ sigmaZ;
end
endmodule
I used HSPICE 2019 to test the random number output at each simulation step, by running the folloing test_solver.sp file:
Title Simple
.option post=1
.option probe=0
*.option runlvl=4
.option ingold=2
*.option accurate=1
*.option method=bdf
*.option bdfrtol=1e-5
*.option bdfatol=1e-5
.option numdgt=4
.option brief
.option measfile=1
.option lis_new=1
.option vaopts=str('-G')
.save
.hdl ./test_solver.va
vin 1 0 PULSE(0 0.5 2NS 1NS 1NS 10NS 20NS)
X 1 0 2 3 4 5 6 7 test_va
.tran 0.01n 20.0n 1E-10 uic
.print tran V(1) V(2) V(3) V(4) V(5) V(6) V(7)
.end
However, I noticed that it always generates an identical random number set (sigmaX, sigmaY, sigmaZ) if I run in HSPICE consecutively. But my requirement is to have different random number sets when running the same code consecutively.
I also noticed that if I change random_seed=1 in the test_solver.va file, for example, to random_seed=2 (or 3 or 4 ...) and run in HSPICE, it will generate a different random number set than before. But it still generates the same set when running the same code consecutively.
So I wonder if there is anything wrong with my test_solver.va code, or we have to change "random_seed=1" every time. Then it might not be easy to realize if I integrate this code into others and run many times.
First of all, pseudo-random number generators are deterministic. That means if you start with the same seed you will always get the same result.
I'm not aware of any way to do what you want directly in Verilog-A. I think that you will need to write your own function in 'C'. One technique that is often used is to call a high resolution timer and assume that the time in micro- or nanoseconds is essentially random. Alternatively you can call a function like getrandom().
The next problem is getting the 'C' random value back to your Verilog-A. I'm not familiar with HSPICE, but this can be done with Verilog PLI on some other simulators.
Alternatively you could wrap your simulation in a shell script and do something like this
script: read /dev/urandom and write a random number to a file
run hspice
in your Verilog-A use a system task like $fread to read the file that the script produced
It isn't hard to agree that parametrized module design is a good practice and data width is a good starting point.
I have been defining constants 0 and 1 of required bus or operand widths for years. That to avoid compiler warnings and to explicitly communicate the intention. Typically using something like:
parameter WIDTH = 16;
// ...
parameter ZERO = {WIDTH{1'b0}}; // all zeroes
parameter UNO = {{WIDTH-1{1'b0}}, 1'b1}; // all zeroes except LSB
This is all fine until I want to define an arbitrary constant with given parametrized WIDTH.
I certainly can write a constant with fixed width - but that's not what I want:
parameter FULL = 16'd57;
However, analogous construct using the parametric WIDTH fails with syntax error:
parameter LEVEL = WIDTH'd57; // <== *ERROR*
What is the proper syntax - if there is one?
This was a problem in Verilog because the RHS of a parameter assignment was used as the self-determined width of the parameter. SystemVerilog addressed this by allowing you to specify a datatype as part of a parameter declaration
parameter WIDTH = 16;
// ...
parameter bit [WIDTH-1:0] ZERO = '0; // all zeroes
parameter bit [WIDTH-1:0] UNO = 1; // all zeroes except LSB
parameter bit [WIDTH-1:0] LEVEL = 57;
The datatype does not change when overriding.
Another way is using a sizing cast
parameter LEVEL = WIDTH'(56);
But if you do it this way and override the parameter, the datatype becomes the width of the overriding value's type.
I am trying to make my debounce code more modular by passing in parameters that are the frequency and the desired bounce time to eliminate button/switch bounce. This is how I approached it:
module debounceCounter
#(
parameter CLOCK_FREQUENCY_Hz = 50_000_000,
parameter BOUNCE_TIME_s = 0.003
)
(
input wire sysClk, reset,
input wire i_async,
output reg o_sync
);
/* include tasks/functions */
`include "clog2.v"
/* constants */
parameter [(clog2(BOUNCE_TIME_s * CLOCK_FREQUENCY_Hz + 0.5) - 1) : 0]
MAX_COUNT = BOUNCE_TIME_s * CLOCK_FREQUENCY_Hz;
Synthesis using Xilinx ISE 14.7 Throws this error:
Xst:850 - "../../rtl/verilog/debounceCounter.v" line0: Unsupported real
constant
How can I get around this issue so that I can determine the counter size and max count value based on parameters being passed in from code above this module in the heirarchy? A majority of my code has sizes of variables and such determined by frequency generics, so not being able to use methods like VHDL has proven to create problems in my designs.
Seems to work fine on Vivado 2016.3 (the oldest I have available). I think the problem is that 2014.7 is too old to support this. You didn't show the contents of the `include, but I'm assuming its the one from AR# 44586. If so, it should take and return integers and it will truncate the real floating point values for you. Floating point arithmetic is fine to use in Verilog/SystemVerilog testbenches and parameters.
How can I get around this issue so that I can determine the counter
size and max count value based on parameters being passed in from code
above this module in the heirarchy?
Update to a recent version. 2017.1 or 2017.3 are working good for me. I tested the following on 2016.3 and it also worked fine.
Try using SystemVerilog (.sv) which supports the $clog2() system function natively without the `include. Not sure when .sv started working, but probably needs 2015+.
Verify that your version of clog2 in the clog2.v header matches the following
NOTE: There is another pretty serious bug in the code you posted.
When you want to get the MSB required to hold a constant expression "x" the pattern should be $clog2((x)+1)-1. You have only added 0.5 instead of 1. This causes there to not be enough bits whenever the result of the floating point expression "x" falls between 2^n and (2^n + 0.5). For example, what you have erronously computes the constant as 17'h0 instead of 18'h4_0000 for the the frequency 87381333 but it still appears to work for your example at 50Mhz. Murphy's law says you will accidentally fall into this narrow bad range at the worst possible time, but never during testing :).
For reference, this is what I tested, with the `include expanded inline:
`timescale 1ns / 1ps
module debounceCounter
#(
//parameter CLOCK_FREQUENCY_Hz = 50_000_000,
parameter CLOCK_FREQUENCY_Hz = 87381333, // whoops
parameter BOUNCE_TIME_s = 0.003
)
(
input wire sysClk, reset,
input wire i_async,
output reg o_sync
);
/* include tasks/functions */
//`include "clog2.v"
function integer clog2;
input integer value;
begin
value = value-1;
for (clog2=0; value>0; clog2=clog2+1)
value = value>>1;
end
endfunction
/* constants */
//parameter [(clog2(BOUNCE_TIME_s * CLOCK_FREQUENCY_Hz + 0.5) - 1) : 0] // <- BUG!!! 0.5 should 1
parameter [(clog2(BOUNCE_TIME_s * CLOCK_FREQUENCY_Hz + 1) - 1) : 0]
MAX_COUNT = BOUNCE_TIME_s * CLOCK_FREQUENCY_Hz;
initial
$display("MAX_COUNT %d", MAX_COUNT);
endmodule
Type Real is not synthesizable. Draw/Create your design before you translate into/write HDL and you will realize this. Ask yourself, "What does a real synthesize to in gates?"
For those tools (e.g. Synplify) that do "support" Type Real, it is just a vendor interpretation, and as such is impossible to "support" since it is not defined as part of any HDL standard. The implication: If you had a simulator that interprets Type Real one way, and your synthesizer (likely) interprets it another way, you will get sim/syn mismatches. You may get away with them, depending on what you are trying to accomplish, but, it would still be considered poor design practice.
Behavioral code, for modeling and use in testbenches, as stated above, a different story as it is not synthesized.
Is it possible to write a function that can detect the input data width automatically? For example, consider the parity function below:
function parity;
input [31:0] data;
parity = ^ data;
endfunction
When parity(data) is called, the input data should be limited to 32 bits.
Alternatively, one could write a macro, such as `PARITY(data) in which the system function $bits can detect the width of data and make the macro width-independent. Is it possible to have the same flexibility for functions?
Edit: I need my code to be synthesizable.
You can create a parameterized function. See section 13.8 in the LRM. It looks like the function must be declared inside a class like this:
virtual class C #(parameter WIDTH=32);
static function parity (input [WIDTH-1:0] data);
parity=^data;
endfunction
endclass
Then when you call the function parameterized it with the bits task:
assign parity_bit = C#($bits(data))::parity(data);
Working example on EDA Playground.
You can use macros. The function can be declared like:
`define PARITY(FUNC_name, WIDTH) \
function FUNC_name (input [WIDTH-1:0] data); \
begin \
FUNC_name = ^ data; \
end \
endfunction
and you can call it with:
`PARITY(parity, 32);
assign parity_bit = parity(data);
This code is synthesizable in xilinx, altera and synopsys tools
It is possible using unbounded arrays.
Unfortunately SystemVerilog doesn't have decent support for unbounded arrays. The LRM seems to equate unbounded with dynamic, which suggests it's going to be almost impossible to create something synthesisable. VHDL has unbounded arrays which are supported by tools and incredibly useful so it's a pity that SystemVerilog didn't include this feature properly.
Here is an example:
function automatic logic parity(input logic data[]);
logic p = 0;
for (int i=0; i<data.size(); i++)
p ^= data[i];
return p;
//return = ^data; <--- not allowd on unpacked arrays?
endfunction
logic [7:0] data_in;
logic result;
logic data_in_unpacked [] = new[$bits(data_in)];
always_comb begin
// Convert to unpacked array (better way to do this?)
for (int i=0; i<$bits(data_in); i++)
data_in_unpacked[i] = data_in[i];
result = parity(data_in_unpacked);
end
This is running on Modelsim on EDAPlayground here: http://www.edaplayground.com/x/3tS
EDIT 1: Updated the code - I just realised it's possible to call new[] at initialisation and thus statically, so in theory synthesis tools could support this. It would be interesting to synthesise this and see...
EDIT 2: Thought I'd try synthesising and unsurprisingly Quartus doesn't like this:
Error (10170): Verilog HDL syntax error at testing.sv(10) near text "]"; expecting an operand
Error (10170): Verilog HDL syntax error at testing.sv(18) near text "]"; expecting an operand
Error (10112): Ignored design unit "my_parity" at testing.sv(2) due to previous errors
Interesting question. According to my knowledge, I don't think that's possible. I would also stay away from macros (even more problems). I can propose a synthesizable workaround:
When calling your function parity on widths lesser than your defined width pad your data with 0's like this: assign my_parity_bits = parity({16'd0, my_data}); Hopefully, synthesis tool would ignore those 0's but you will have to check it yourself.
If you want to perform such operation on large data buses in a convenient way you will have to write some more Verilog. E.g. a module that would accept a WIDTH parameter and actual data as an input vector. To do this, I would advise you to write a generic module that does exactly what your function parity does. Then, write a module which will be a parity wrapper. Inside this wrapper I would perform math operations on input WIDTH parameter to determine number of parity modules needed for input data and instantiate those modules in a generate loop.
Remember that Verilog is a hardware description language, thus such limitations. Think about what your code will synthesize into when writing RTL.
Quick update on using the paramaterized virtual class idea posted above. Stack overflow won't let me leave comments so I had to post a new answer. I just wanted to add that I tried this in Vivado, and it appears to work correctly in synthesis. Using nguthrie's solution above, I can do
logic [7:0] data;
assign data = {sw, btn};
assign led[0] = C#($bits(data))::parity(data);
This is in Vivado 2021
So I am working with 64 bit floating point numbers on Verilog for synthesis, all are in the region of {-1,1}. Now, I am trying to create something like a Histogram which I guess I could do by creating a RAM to work like a 2D array. But I am facing issues with the rounding.
For Example,
I have a value 0.94394(FltPt). I would like to convert this into just,
0.82394 = 8 and 0.8862 =9 (All data are in 64 bit flt pt)
so that I can access that specific address on the RAM.
What would be the the most ideal way to round this, using another multiplier is too much overhead. Is there some trick I could do by truncating a part of the bits? Should I convert them to Fixed Point?
Two options I can think of:
The simplest is to change your bins so the boundaries are powers of 2. Then you can just use the some of bits of the input directly to address your histogram. I would have to go look at the floating point format to know which bits to use.
The other possibility is to just do a bunch of comparisons to see what bin to put it. L
You would have do this for both of the coordinates.
reg [4:0] ram_aadr;
always #* begin
if(data < -.95)
ram_addr = 5'd0;
else if(data < -.85)
ram_addr = 5'd1;
...
else if(data < .95)
ram_addr = 5'd19;
else
ram_addr = 5'd20;
end