Initializing a memory block in SystemVerilog from outside a module - initialization

I have a SystemVerilog module like:
module my_mod(...);
reg [31:0] mem [64];
...
I want to be able to instantiate that module with a particular set of initial values. So far, I do it with an initial block inside my_mod, but I want to be able to do it from outside, so different instances/tests of the module have different values. Something like:
my_mod #(.INITIAL_VALS(multi_dimensional_reg)) mm(...);
How can I do it?

You can use a parameter to initialize a memory and then override instances as you need.
module my_mod #(
logic [31:0] INITIAL_VALS[64] = '{0:0, 1:2, 3:4, 4:6, default:'x} )
();
logic [31:0] mem [64];
initial mem = INITIAL_VALS;
endmodule
module top;
my_mod #(.INITIAL_VALS('{default:0}) ) m1();
endmodule
Note that you have to override all (64) elements of the array. You can use a function as well as a literal assignment pattern.

Related

Vector of registers size can not be parametrized by module parameter

I want to use module parameter as a size parameter of Vector, which contains registers, and I try next code:
package Test;
import Vector :: *;
(* synthesize *)
module mkTest #(
parameter UInt#(32) qsize
) (Empty);
Vector#(qsize,Reg#(Bit#(8))) queue <- replicateM (mkReg (0));
endmodule
endpackage
But compiling this module with bsc I get next error message:
Verilog generation
bsc -verilog -remove-dollar Test.bsv
Error: "Test.bsv", line 9, column 11: (T0008)
Unbound type variable `qsize'
bsc version:
Bluespec Compiler (build e55aa23)
If I use not Registers as a type of Vector elements, everything is OK. Next code will produce no errors:
package Test;
import Vector :: *;
(* synthesize *)
module mkTest #(
parameter UInt#(32) qsize
) (Empty);
Vector#(qsize,Bit#(8)) queue = replicate(0);
endmodule
endpackage
And I can not understand, why qsize is Unbound as it is clearly declared as a parameter? If I did something wrong, could you please help me and explain, how to make parameterized size Vector of Regs correctly?
I have asked this question in one of the Bluespec repositories on github and Rishiyur S. Nikhil gave me a very full explanation. See https://github.com/BSVLang/Main/issues/4
In short: Vector as a first parameter needs a type, not UInt (or Int or something else). So the right way to do will be:
Make an interface for module and make it type-polymorphic
Use type from that interface as a Vector size parameter
package Test;
import Vector :: *;
interface Queue_IFC #(numeric type qsize_t);
method Bool done;
endinterface
module mkQueue ( Queue_IFC #(qsize_t) );
Vector #(qsize_t, Reg #(Bit #(8))) queue <- replicateM (mkReg (0));
endmodule
endpackage

XQuery: using global var in function

I need to use a counter to remember how many node I have dealed with. So I defined a global var $classCounter. For some unknown reasons, I get an error from zorba:
test.xqy>:15,9: error [zerr:XSST0004]: "local:owlClassNameBuilerHelper": function declared nonsequential but has sequential body
I really don't understand what this error means. How to implement a global counter in XQuery?
The whole xqy file is:
declare namespace rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
declare namespace owl="http://www.w3.org/2002/07/owl#";
declare namespace xsd="http://www.w3.org/2001/XMLSchema#";
declare namespace rdfs="http://www.w3.org/2000/01/rdf-schema#";
import module namespace functx="http://www.functx.com";
declare variable $srcDoc:="test_xsd.xml"; (:need to adjust the input XSD file here:)
declare variable $defaultXMLNS:="http://www.test.com#";
declare variable $defaultXMLBase:=$defaultXMLNS;
declare variable $classCounter:=0;
declare function local:owlClassNameBuilerHelper($pnode as node()*)
as xs:string?
{
$classCounter:=classCounter+1;
let $tmp:=""
return
(
"haha"
(:if(functx:if-empty($pnode/#name, "-1")!="-1") (:if the name attr doesn't exist:)
then data($pnode/ancestor::element[1]/#name) (:get the name attr of first ancestor named element:)
else data($pnode/#name):)
)
};
element rdf:RDF
{
namespace {""} {$defaultXMLNS},
namespace {"owl"} {"http://www.w3.org/2002/07/owl#"},
namespace {"xsd"} {"http://www.w3.org/2001/XMLSchema#"},
namespace {"rdfs"} {"http://www.w3.org/2000/01/rdf-schema#"},
attribute xml:base {$defaultXMLBase}
}
command line:
zorba -i -f -q test.xqy
I need to use a counter to remember how many node I have dealed with.
Firstly, XQuery is a functional programming language. That's a completely different processing model: you can't "remember" what you have "dealt with", because there is no memory and no time dimension. Functions are mathematical functions, they can't have side-effects like updating global variables.
Now, the error message suggests to me that the particular XQuery processor you are using (Zorba) has extensions that allow you to depart from the pure functional programming model; but you are using the extensions incorrectly. In particular, if you want a function to have side-effects then you must declare the function as such. You'll have to look in the Zorba documentation for how to do that, because there is no standard.

parameterized task to swap two values in SystemVerilog

I want to write a generic-width swap, but I'm not sure what the syntax should be.
My first guess:
task automatic swap #( int W=1 ) ( ref logic [W-1:0] a, ref logic [W-1:0] b );
begin
automatic logic[W-1:0] temp=a; a=b; b=temp;
end endtask
But I get the following error (from Cadence irun):
ncvlog: *E,SVNOCS: Class specialization syntax not allowed in method name for out-of-block method declaration.
Also, what is the syntax to invoke such a task?
Tasks and functions cannot have their own parameters. You can achieve the same effect by declaring a static method in a parameterized class. The methods can be made more generic by making the parameter a data type instead of a bit width. Example:
class generic #(type T=logic);
// Note: you may want to replace 'ref' with 'inout'
static function void swap( ref T a, b );
{b,a} = {a,b};
endfunction
endclass
Then somewhere in your code, you can do this like:
generic#(logic[4:0])::swap( my_a, my_b);
generic#(int)::swap( my_int_a, my_int_b);
generic#(my_struct_st)::swap( my_struct_a, my_struct_b);
generic#(my_class)::swap( my_class_a, my_class_b);
generic#(virtural my_interface)::swap( my_if_a, my_if_b);

gcl_memcpy auto detection of pointer types

I have a trivial kernel running on OS X that returns a single int. The essential bits are:
cl_int d;
cl_int* dptr = &d;
void* dev_d = gcl_malloc(sizeof(cl_int),NULL,CL_MEM_WRITE_ONLY);
// ... stuff to setup dispatch queue
dispatch_sync(queue, ^{
// ... running the kernel stuff
gcl_memcpy((void*)&d, dev_d, sizeof(cl_int)); // this gives d==0
gcl_memcpy((void*)dptr, dev_d, sizeof(cl_int)); // this gives correct d
});
Question is, what is the difference between &d and dptr? I've always thought of them as essentially interchangeable, but gcl_memcpy seems to be making a distinction. Any ideas? I can obviously just use the dptr solution, but I'm still curious what's happening.
I don't think this has to do with the gcl_memcpy call specifically. I think it has to do with your GCD call.
When you call dispatch_sync, your block gets a copy of the variables you use in it. In fact, in similar situations, I get a warning from my compiler about using &d in the block, since it's probably a common mistake.
So in your main function you have a variable d at Address1 with value 0 and a variable dptr at Address2 with value Address1. In your dispatch block you have a variable d at Address3 with value 0 and a variable dptr at Address4 with value Address1. So when you write to &d within your dispatch block, you are putting the value in Address3 which you won't see outside of your dispatch block. When you write to dptr in your dispatch block, you are putting the value in Address1, which is what you expect.
Or to put it another way, your call to dispatch_queue is like calling a function defined like
void myfunction(cl_int d, cl_int* dptr).
If you're skeptical of my answer, I suggest you try this with a simple assignment instead of the gcl_malloc call.

How to output a multidimensional array slice

Let's say I have a multidimensional array:
logic [7:0] mda [7:0];
What I'm now trying to do, is assigning mda[7:4] to an output port, i.e. defined as follow:
output [31:0] odata;
Of course, I can do it by using concatenation:
assign odata = {mda[7], mda[6], mda[5], mda[4]};
But there should be (and probably is) an easier way to do this. The first try would be:
assign odata = mda[7:4];
which is wrong, because types (unpacked <-> packed array) don't match. All my tries of casting (e.g. 32'(mda[7:4])) failed. Question is: what is the best way to assign that slice to an output port?
You can use a for loop... Most synthesis tools have no trouble with for loops over constant ranges:
module dut(output [31:0] odata);
logic [7:0] mda [7:0];
reg[31:0] data;
always #* begin
data = 0;
for(int i=7; i >=4; i--) begin
data <<= 8;
data |= mda[i];
end
end
assign odata = data;
endmodule
Here's a quick test: http://www.edaplayground.com/x/GfM
You can use the streaming operator:
initial begin
logic[31:0] data;
mda[7] = 'hde;
mda[6] = 'had;
mda[5] = 'hbe;
mda[4] = 'hef;
data = { >> { mda[7:4] }};
$display("data = ", data);
end
This works perfectly in a procedural context, but not in a continuous assignment context (for some reason). This means this doesn't work:
assign odata = { >> { mda[7:4] }};
You'll have to figure out a workaround here where you do the streaming in a procedural context (maybe some always block) and then assign the result to your wire.

Resources